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

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: 
1.1.1.2 ! root     1709:        /* Now change sibling (if any) */
        !          1710:        if (hp->h_sibling && (tp = VTOH(hp->h_sibling))) {
1.1       root     1711:                hfs_vhashrem(tp);
                   1712:                H_HINT(tp) = 0;
                   1713:                H_FILEID(tp) = fid;
                   1714:                tp->h_xfcb->fcb_fcb.fcbFlNm = fid;
                   1715:                hfs_vhashinslocked(tp);
                   1716:        }
                   1717: }
                   1718: 
                   1719: 
                   1720: /*
                   1721: 
                   1722: #% fsync       vp      L L L
                   1723: #
                   1724:  vop_fsync {
                   1725:      IN struct vnode *vp;
                   1726:      IN struct ucred *cred;
                   1727:      IN int waitfor;
                   1728:      IN struct proc *p;
                   1729: 
                   1730:      */
                   1731: 
                   1732: 
                   1733: static int
                   1734: hfs_fsync(ap)
                   1735: struct vop_fsync_args /* {
                   1736:     struct vnode *a_vp;
                   1737:     struct ucred *a_cred;
                   1738:     int a_waitfor;
                   1739:     struct proc *a_p;
                   1740: } */ *ap;
                   1741: {
                   1742:     struct vnode               *vp = ap->a_vp ;
                   1743:     struct hfsnode             *hp;
                   1744:     int                                        retval = 0;
                   1745:     register struct buf *bp;
                   1746:     struct timeval             tv;
                   1747:     struct buf                         *nbp;
                   1748:     int                                s;
                   1749: 
                   1750:     DBG_FUNC_NAME("fsync");
                   1751:     DBG_VOP_LOCKS_DECL(1);
                   1752:     DBG_VOP_PRINT_FUNCNAME();DBG_VOP_CONT(("  "));
                   1753:     DBG_VOP_PRINT_VNODE_INFO(ap->a_vp);DBG_VOP_CONT(("\n"));
                   1754:     DBG_VOP_LOCKS_INIT(0,ap->a_vp, VOPDBG_LOCKED, VOPDBG_LOCKED, VOPDBG_LOCKED, VOPDBG_ZERO);
                   1755:     DBG_HFS_NODE_CHECK(ap->a_vp);
                   1756:        
                   1757: #if DIAGNOSTIC
                   1758:     DBG_ASSERT(*((int*)&vp->v_interlock) == 0);
                   1759: #endif
                   1760: 
                   1761:     if (vp->v_type == VCPLX) {
                   1762:                /* Ignore complex nodes; there's no data associated with them. */
                   1763:                DBG_ASSERT(vp->v_dirtyblkhd.lh_first == NULL);
                   1764:                DBG_VOP_LOCKS_TEST(E_NONE);
                   1765:        return E_NONE;
                   1766:     };
                   1767:        
                   1768: 
                   1769:     /*
                   1770:      * Flush all dirty buffers associated with a vnode.
                   1771:      */
                   1772: loop:
                   1773:        hp = VTOH(vp);
                   1774:     s = splbio();
                   1775:     for (bp = vp->v_dirtyblkhd.lh_first; bp; bp = nbp) {
                   1776:         nbp = bp->b_vnbufs.le_next;
                   1777:         if ((bp->b_flags & B_BUSY))
                   1778:             continue;
                   1779:         if ((bp->b_flags & B_DELWRI) == 0)
                   1780:             panic("hfs_fsync: not dirty");
                   1781:         bremfree(bp);
                   1782:         bp->b_flags |= B_BUSY;
                   1783:         bp->b_flags &= ~B_LOCKED;      /* Clear flag, should only be set on meta files */
                   1784:         splx(s);
                   1785:         /*
                   1786:          * Wait for I/O associated with indirect blocks to complete,
                   1787:          * since there is no way to quickly wait for them below.
                   1788:          */
                   1789:         DBG_VOP(("\t\t\tFlushing out phys block %d == log block %d\n", bp->b_blkno, bp->b_lblkno));
                   1790:         if (bp->b_vp == vp || ap->a_waitfor == MNT_NOWAIT)
                   1791:             (void) bawrite(bp);
                   1792:         else
                   1793:             (void) bwrite(bp);
                   1794:         goto loop;
                   1795:     }
                   1796: 
                   1797:     if (ap->a_waitfor == MNT_WAIT) {
                   1798:         while (vp->v_numoutput) {
                   1799:             vp->v_flag |= VBWAIT;
                   1800:             tsleep((caddr_t)&vp->v_numoutput, PRIBIO + 1, "hfs_fsync", 0);
                   1801:         }
                   1802: 
                   1803:         /* I have seen this happen for swapfile. So it is safer to
                   1804:          * check for dirty buffers again.  --Umesh
                   1805:          */
                   1806:         if (vp->v_dirtyblkhd.lh_first) {
                   1807:             vprint("hfs_fsync: dirty", vp);
                   1808:             splx(s);
                   1809:             goto loop;
                   1810:         }
                   1811:     }
                   1812:     splx(s);
                   1813: 
                   1814: #if DIAGNOSTIC
                   1815:     DBG_ASSERT(*((int*)&vp->v_interlock) == 0);
                   1816: #endif
                   1817: 
                   1818:     tv = time;
                   1819:     hp->h_lastfsync = tv.tv_sec;
                   1820:        if (H_FORKTYPE(hp) != kSysFile) {
                   1821:        retval = VOP_UPDATE(ap->a_vp, &tv, &tv, ap->a_waitfor == MNT_WAIT);
                   1822: 
                   1823:        if (retval != E_NONE) {
                   1824:                DBG_ERR(("%s: FLUSH FAILED: %s\n", funcname, H_NAME(hp)));
                   1825:        }
                   1826:     }
                   1827:        else
                   1828:         hp->h_meta->h_nodeflags &= ~(IN_ACCESS | IN_CHANGE | IN_MODIFIED | IN_UPDATE);
                   1829: 
                   1830:     if (ap->a_waitfor == MNT_WAIT) {
                   1831:       DBG_ASSERT(vp->v_dirtyblkhd.lh_first == NULL);
                   1832:     };
                   1833:     DBG_VOP_LOCKS_TEST(retval);
                   1834:     DBG_ASSERT(*((int*)&vp->v_interlock) == 0);
                   1835:     return (retval);
                   1836: }
                   1837: 
                   1838: 
                   1839: 
                   1840: /*
                   1841: 
                   1842: #% remove      dvp     L U U
                   1843: #% remove      vp      L U U
                   1844: #
                   1845:  vop_remove {
                   1846:      IN WILLRELE struct vnode *dvp;
                   1847:      IN WILLRELE struct vnode *vp;
                   1848:      IN struct componentname *cnp;
                   1849: 
                   1850:      */
                   1851: 
                   1852: int
                   1853: hfs_remove(ap)
                   1854: struct vop_remove_args /* {
                   1855:     struct vnode *a_dvp;
                   1856:     struct vnode *a_vp;
                   1857:     struct componentname *a_cnp;
                   1858: } */ *ap;
                   1859: {
                   1860:     struct vnode *vp = ap->a_vp;
                   1861:     struct vnode *dvp = ap->a_dvp;
                   1862:     struct vnode *ttp,*tp = NULL;
                   1863:     struct hfsnode *hp = VTOH(ap->a_vp);
                   1864:     struct hfsmount *hfsmp = HTOHFS(hp);
                   1865:     struct proc *p = CURRENT_PROC;
                   1866:     struct timeval tv;
                   1867:     int retval;
                   1868:     struct vnode *sibling_vp;
                   1869:     DBG_FUNC_NAME("remove");
                   1870: 
                   1871:     DBG_VOP_LOCKS_DECL(2);
                   1872:     DBG_VOP_PRINT_FUNCNAME();
                   1873:     DBG_VOP_PRINT_VNODE_INFO(ap->a_vp);
                   1874:     DBG_VOP_PRINT_CPN_INFO(ap->a_cnp);DBG_VOP_CONT(("\n"));
                   1875: 
                   1876:     /* see if they really meant to call VOP_RMDIR */
                   1877:     if (vp->v_type == VDIR)
                   1878:         return VOP_RMDIR(dvp, vp, ap->a_cnp);
                   1879: 
                   1880:     DBG_VOP_LOCKS_INIT(0,ap->a_dvp, VOPDBG_LOCKED, VOPDBG_UNLOCKED, VOPDBG_UNLOCKED, VOPDBG_POS);
                   1881:     DBG_VOP_LOCKS_INIT(1,ap->a_vp, VOPDBG_LOCKED, VOPDBG_UNLOCKED, VOPDBG_UNLOCKED, VOPDBG_POS);
                   1882: 
                   1883:     if ((hp->h_meta->h_pflags & (IMMUTABLE | APPEND)) ||
                   1884:         (VTOH(dvp)->h_meta->h_pflags & APPEND)) {
                   1885:         retval = EPERM;
                   1886:         goto out;
                   1887:     }
                   1888: 
                   1889:     /*  HFS does not have unlinking, do we cannot delete a file that is inuse */
                   1890:     DBG_VOP(("\tusecount = %d", vp->v_usecount));
                   1891:     if (VTOH(vp)->h_sibling) {
                   1892:         DBG_VOP_CONT((", sibling usecount = %d\n", VTOH(vp)->h_sibling->v_usecount));
                   1893:     }
                   1894:     else {
                   1895:         DBG_VOP_CONT(("\n"));
                   1896:     }
                   1897:     if (vp->v_usecount > 1) {
                   1898:         retval = EBUSY;
                   1899:         goto out;
                   1900:     }
                   1901:     /* Check other siblings for in use also */
                   1902:     tp = vp;
                   1903:        /* XXX SER Process all siblings here */
                   1904:        /* XXX SER MUST BE CHANGED BY MACOS X */
                   1905:     /* This unlocks the vnode!!!! Because vnode_uncache does the same
                   1906:         * so it depends on no context switches.
                   1907:      * See the comment in vnode_uncache()
                   1908:         */
                   1909:        /* Uncache everything */
                   1910:  sibling_loop:
                   1911:     sibling_vp = VTOH(tp)->h_sibling;  /* Note - this is a local copy for good reason! */
                   1912:     if (sibling_vp) {
                   1913:        VOP_UNLOCK(vp, 0, p);
                   1914:         if (vget(sibling_vp, LK_EXCLUSIVE | LK_RETRY, p)) {
                   1915:          /* Couldn't get the sibling - it might have gone away.
                   1916:             Clean up to try again from scratch */
                   1917:          vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
                   1918:          goto sibling_loop;
                   1919:        };
                   1920:         (void) vnode_uncache(sibling_vp);
                   1921:         vput(sibling_vp);
                   1922:        vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
                   1923:     };
                   1924: 
                   1925:     while (VTOH(tp)->h_sibling && (VTOH(tp)->h_sibling != vp)) {
                   1926:         simple_lock(&tp->v_interlock);
                   1927:         if (VTOH(tp)->h_sibling->v_usecount > 0) {
                   1928:             retval = EBUSY;
                   1929:             simple_unlock(&tp->v_interlock);
                   1930:             goto out;
                   1931:         }
                   1932:                ttp = tp;
                   1933:         tp = VTOH(tp)->h_sibling;
                   1934:         simple_unlock(&ttp->v_interlock);
                   1935:     }  
                   1936: 
                   1937:        /* Flush out any catalog changes */
                   1938:        /* XXX SER: This is a hack, becasue hfsDelete reads the data from the disk
                   1939:         * and not from memory which is more correct
                   1940:         */
                   1941:     if ((hp->h_meta->h_nodeflags & IN_MODIFIED) || (HTOFCB(hp)->fcbFlags & fcbModifiedMask))
                   1942:         {
                   1943:         DBG_ASSERT((hp->h_meta->h_nodeflags & IN_MODIFIED) != 0);
                   1944:         tv = time;
                   1945:         VOP_UPDATE(vp, &tv, &tv, 0);
                   1946:         }
                   1947: 
                   1948:     /* lock catalog b-tree */
                   1949:     retval = hfs_metafilelocking(hfsmp, kHFSCatalogFileID, LK_EXCLUSIVE, p);
                   1950:     if (retval != E_NONE) {
                   1951:         retval = EBUSY;
                   1952:         goto out;
                   1953:         }
                   1954: 
                   1955:     /* lock extents b-tree (also protects volume bitmap) */
                   1956:     retval = hfs_metafilelocking(hfsmp, kHFSExtentsFileID, LK_EXCLUSIVE, p);
                   1957:     if (retval != E_NONE) {
                   1958:         retval = EBUSY;
                   1959:         goto out2;     /* unlock catalog b-tree on the way out */
                   1960:         }
                   1961: 
                   1962:     /* remove the entry from the namei cache: */
                   1963:     cache_purge(VTOH(vp)->h_relative);
                   1964: 
                   1965:     /* remove entry from catalog and free any blocks used */
                   1966:     retval = hfsDelete (HTOVCB(hp), H_DIRID(hp), H_NAME(hp), TRUE, H_HINT(hp));
                   1967: 
                   1968:     hp->h_meta->h_mode = 0;                            /* Makes the node go away...see inactive */
                   1969:     tp = VTOH(vp)->h_sibling;                  /* Remember any siblings, to inactivate later */
                   1970: 
                   1971:     (void) hfs_metafilelocking(hfsmp, kHFSExtentsFileID, LK_RELEASE, p);
                   1972: out2:
                   1973:     (void) hfs_metafilelocking(hfsmp, kHFSCatalogFileID, LK_RELEASE, p);
                   1974: 
                   1975: out:;
                   1976: 
                   1977:     if (! retval)
                   1978:                VTOH(dvp)->h_meta->h_nodeflags |= IN_CHANGE | IN_UPDATE;
                   1979: 
                   1980:     if (dvp == vp) {
                   1981:         VRELE(vp);
                   1982:     } else {
                   1983:         VPUT(vp);
                   1984:     };
                   1985: 
                   1986:        /* Before leaving, remove any siblings also */
                   1987:        /* Note: vp and all its values are gone, so do not use */
                   1988:     if ((! retval) && (tp != NULL)) {
                   1989:         if (! vget (tp, LK_EXCLUSIVE, p)) {
                   1990:             VTOH(tp)->h_meta->h_mode = 0;                              /* Makes the node go away...see inactive */
                   1991:             VPUT(tp);
                   1992:                }
                   1993:     }
                   1994: 
                   1995:     VPUT(dvp);
                   1996:     DBG_VOP_LOCKS_TEST(retval);
                   1997:     return (retval);
                   1998: }
                   1999: 
                   2000: 
                   2001: #if 0  /* Now stubbed out in the vnode ops table with err_mknod */
                   2002: /*
                   2003:  * link vnode call
                   2004:  */
                   2005: /*
                   2006:  * HFS filesystems don't know what links are. But since we already called
                   2007:  * lookup() with create and lockparent, the parent is locked so we
                   2008:  * have to free it before we return the retval.
                   2009: #% link                vp      U U U
                   2010: #% link                targetPar_vp    L U U
                   2011: #
                   2012:  vop_link {
                   2013:      IN WILLRELE struct vnode *vp;
                   2014:      IN struct vnode *targetPar_vp;
                   2015:      IN struct componentname *cnp;
                   2016: 
                   2017:      */
                   2018: static int
                   2019: hfs_link(ap)
                   2020: struct vop_link_args /* {
                   2021:     struct vnode *a_vp;
                   2022:     struct vnode *a_tdvp;
                   2023:     struct componentname *a_cnp;
                   2024: } */ *ap;
                   2025: {
                   2026:     DBG_FUNC_NAME("link");
                   2027:     DBG_VOP_LOCKS_DECL(1);
                   2028:     DBG_VOP_PRINT_FUNCNAME();
                   2029:     DBG_VOP_PRINT_VNODE_INFO(ap->a_vp);
                   2030:     DBG_VOP_PRINT_CPN_INFO(ap->a_cnp);DBG_VOP_CONT(("\n"));
                   2031: 
                   2032:     DBG_VOP_LOCKS_INIT(0,ap->a_vp, VOPDBG_UNLOCKED, VOPDBG_UNLOCKED, VOPDBG_UNLOCKED, VOPDBG_POS);
                   2033:     DBG_VOP_LOCKS_INIT(1,ap->a_tdvp, VOPDBG_LOCKED, VOPDBG_UNLOCKED, VOPDBG_UNLOCKED, VOPDBG_POS);
                   2034: 
                   2035:     VOP_UNLOCK(ap->a_vp, 0, ap->a_cnp->cn_proc);
                   2036: 
                   2037:     VOP_ABORTOP(ap->a_tdvp, ap->a_cnp);
                   2038:     VPUT(ap->a_tdvp);
                   2039:     
                   2040:     DBG_VOP_LOCKS_TEST(EOPNOTSUPP);
                   2041:     return (EOPNOTSUPP);
                   2042: }
                   2043: #endif
                   2044: 
                   2045: /*
                   2046: 
                   2047: #% rename      sourcePar_vp    U U U
                   2048: #% rename      source_vp               U U U
                   2049: #% rename      targetPar_vp    L U U
                   2050: #% rename      target_vp               X U U
                   2051: #
                   2052:  vop_rename {
                   2053:      IN WILLRELE struct vnode *sourcePar_vp;
                   2054:      IN WILLRELE struct vnode *source_vp;
                   2055:      IN struct componentname *source_cnp;
                   2056:      IN WILLRELE struct vnode *targetPar_vp;
                   2057:      IN WILLRELE struct vnode *target_vp;
                   2058:      IN struct componentname *target_cnp;
                   2059: 
                   2060: 
                   2061:      */
                   2062: /*
                   2063: * On entry:
                   2064: *      source's parent directory is unlocked
                   2065: *      source file or directory is unlocked
                   2066: *      destination's parent directory is locked
                   2067: *      destination file or directory is locked if it exists
                   2068: *
                   2069: * On exit:
                   2070: *      all denodes should be released
                   2071: *
                   2072: */
                   2073: 
                   2074: static int
                   2075: hfs_rename(ap)
                   2076: struct vop_rename_args  /* {
                   2077:     struct vnode *a_fdvp;
                   2078:     struct vnode *a_fvp;
                   2079:     struct componentname *a_fcnp;
                   2080:     struct vnode *a_tdvp;
                   2081:     struct vnode *a_tvp;
                   2082:     struct componentname *a_tcnp;
                   2083: } */ *ap;
                   2084: {
                   2085:     struct vnode                       *target_vp = ap->a_tvp;
                   2086:     struct vnode                       *targetPar_vp = ap->a_tdvp;
                   2087:     struct vnode                       *source_vp = ap->a_fvp;
                   2088:     struct vnode                       *sourcePar_vp = ap->a_fdvp;
                   2089:     struct vnode                       *tp;
                   2090:     struct componentname       *target_cnp = ap->a_tcnp;
                   2091:     struct componentname       *source_cnp = ap->a_fcnp;
                   2092:     struct proc                        *p = source_cnp->cn_proc;
                   2093:     struct hfsnode                     *target_hp, *targetPar_hp, *source_hp, *sourcePar_hp;
                   2094:     u_short                                    doingdirectory = 0, oldparent = 0, newparent = 0;
                   2095:     int                                        retval = 0;
                   2096:     struct timeval                     tv;
                   2097:        struct hfsCatalogInfo catInfo;
                   2098:     int targetnamelen;
                   2099:     DBG_VOP_LOCKS_DECL(4);
                   2100: 
                   2101:     DBG_FUNC_NAME("rename");DBG_VOP_PRINT_FUNCNAME();DBG_VOP_CONT(("\n"));
                   2102:     DBG_VOP_CONT(("\t"));DBG_VOP_CONT(("Source:\t"));DBG_VOP_PRINT_VNODE_INFO(ap->a_fvp);DBG_VOP_CONT(("\n"));
                   2103:     DBG_VOP_CONT(("\t"));DBG_VOP_CONT(("SourcePar: "));DBG_VOP_PRINT_VNODE_INFO(ap->a_fdvp);DBG_VOP_CONT(("\n"));
                   2104:     DBG_VOP_CONT(("\t"));DBG_VOP_CONT(("Target:\t"));DBG_VOP_PRINT_VNODE_INFO(ap->a_tvp);DBG_VOP_CONT(("\n"));
                   2105:     DBG_VOP_CONT(("\t"));DBG_VOP_CONT(("TargetPar: "));DBG_VOP_PRINT_VNODE_INFO(ap->a_tdvp);DBG_VOP_CONT(("\n"));
                   2106:     DBG_VOP_CONT(("\t"));DBG_VOP_CONT(("SourceName:\t"));DBG_VOP_PRINT_CPN_INFO(ap->a_fcnp);DBG_VOP_CONT(("\n"));
                   2107:     DBG_VOP_CONT(("\t"));DBG_VOP_CONT(("TargetName:\t"));DBG_VOP_PRINT_CPN_INFO(ap->a_tcnp);DBG_VOP_CONT(("\n"));
                   2108:     DBG_VOP_LOCKS_INIT(0,ap->a_fdvp, VOPDBG_UNLOCKED, VOPDBG_UNLOCKED, VOPDBG_UNLOCKED, VOPDBG_POS);
                   2109:     DBG_VOP_LOCKS_INIT(1,ap->a_fvp, VOPDBG_UNLOCKED, VOPDBG_UNLOCKED, VOPDBG_UNLOCKED, VOPDBG_POS);
                   2110:     DBG_VOP_LOCKS_INIT(2,ap->a_tdvp, VOPDBG_LOCKED, VOPDBG_UNLOCKED, VOPDBG_UNLOCKED, VOPDBG_POS);
                   2111:     DBG_VOP_LOCKS_INIT(3,ap->a_tvp, VOPDBG_LOCKNOTNIL, VOPDBG_UNLOCKED, VOPDBG_UNLOCKED, VOPDBG_POS);
                   2112:     WRITE_CK(ap->a_fdvp, funcname);
                   2113:     DBG_HFS_NODE_CHECK(ap->a_fdvp);
                   2114:     DBG_HFS_NODE_CHECK(ap->a_tdvp);
                   2115: 
                   2116: #if DIAGNOSTIC
                   2117:     if ((target_cnp->cn_flags & HASBUF) == 0 ||
                   2118:         (source_cnp->cn_flags & HASBUF) == 0)
                   2119:         panic("hfs_rename: no name");
                   2120: #endif
                   2121: 
                   2122:     ASSERT((ap->a_fdvp->v_type == VDIR) && (ap->a_tdvp->v_type == VDIR));
                   2123:     target_hp = targetPar_hp = source_hp = sourcePar_hp = 0;
                   2124:        targetnamelen = target_cnp->cn_namelen;
                   2125: 
                   2126:     /*
                   2127:      * Check for cross-device rename.
                   2128:      */
                   2129:     if ((source_vp->v_mount != targetPar_vp->v_mount) ||
                   2130:         (target_vp && (source_vp->v_mount != target_vp->v_mount))) {
                   2131:         retval = EXDEV;
                   2132:         goto abortit;
                   2133:     }
                   2134: 
                   2135:     /*
                   2136:      * Check for access permissions
                   2137:      */
                   2138:     if (target_vp && ((VTOH(target_vp)->h_meta->h_pflags & (IMMUTABLE | APPEND)) ||
                   2139:                       (VTOH(targetPar_vp)->h_meta->h_pflags & APPEND))) {
                   2140:         retval = EPERM;
                   2141:         goto abortit;
                   2142:     }
                   2143: 
                   2144:     if ((retval = vn_lock(source_vp, LK_EXCLUSIVE, p)))
                   2145:         goto abortit;
                   2146: 
                   2147:     sourcePar_hp = VTOH(sourcePar_vp);
                   2148:     source_hp = VTOH(source_vp);
                   2149:     oldparent = H_FILEID(sourcePar_hp);
                   2150:     if ((source_hp->h_meta->h_pflags & (IMMUTABLE | APPEND)) || (sourcePar_hp->h_meta->h_pflags & APPEND)) {
                   2151:         VOP_UNLOCK(source_vp, 0, p);
                   2152:         retval = EPERM;
                   2153:         goto abortit;
                   2154:     }
                   2155: 
                   2156:     /*
                   2157:      * Be sure we are not renaming ".", "..", or an alias of ".". This
                   2158:      * leads to a crippled directory tree.  It's pretty tough to do a
                   2159:      * "ls" or "pwd" with the "." directory entry missing, and "cd .."
                   2160:      * doesn't work if the ".." entry is missing.
                   2161:      */
                   2162:     if ((source_hp->h_meta->h_mode & IFMT) == IFDIR) {
                   2163:         if ((source_cnp->cn_namelen == 1 && source_cnp->cn_nameptr[0] == '.')
                   2164:             || sourcePar_hp == source_hp
                   2165:             || (source_cnp->cn_flags&ISDOTDOT)
                   2166:             || (source_hp->h_meta->h_nodeflags & IN_RENAME)) {
                   2167:             VOP_UNLOCK(source_vp, 0, p);
                   2168:             retval = EINVAL;
                   2169:             goto abortit;
                   2170:         }
                   2171:         source_hp->h_meta->h_nodeflags |= IN_RENAME;
                   2172:         doingdirectory = TRUE;
                   2173:     }
                   2174: 
                   2175:     // Transit between abort and bad
                   2176: 
                   2177:     targetPar_hp = VTOH(targetPar_vp);
                   2178:     target_hp = target_vp ? VTOH(target_vp) : NULL;
                   2179:     newparent = H_FILEID(targetPar_hp);
                   2180: 
                   2181:     retval = VOP_ACCESS(source_vp, VWRITE, target_cnp->cn_cred, target_cnp->cn_proc);
                   2182:     if (doingdirectory && (newparent != oldparent)) {
                   2183:         if (retval)            /* write access check above */
                   2184:             goto bad;
                   2185:     }
                   2186: 
                   2187:     /*
                   2188:      * If the destination exists, then be sure its type (file or dir)
                   2189:      * matches that of the source.  And, if it is a directory make sure
                   2190:      * it is empty.  Then delete the destination.
                   2191:      */
                   2192:     if (target_vp) {
                   2193:         if (target_hp->h_dev != targetPar_hp->h_dev || target_hp->h_dev != source_hp->h_dev)
                   2194:             panic("rename: EXDEV");
                   2195: 
                   2196:         /*
                   2197:          * If the parent directory is "sticky", then the user must
                   2198:          * own the parent directory, or the destination of the rename,
                   2199:          * otherwise the destination may not be changed (except by
                   2200:                                                          * root). This implements append-only directories.
                   2201:          */
                   2202:         if ((targetPar_hp->h_meta->h_mode & S_ISTXT) && target_cnp->cn_cred->cr_uid != 0 &&
                   2203:             target_cnp->cn_cred->cr_uid != targetPar_hp->h_meta->h_uid &&
                   2204:             target_hp->h_meta->h_uid != target_cnp->cn_cred->cr_uid) {
                   2205:             retval = EPERM;
                   2206:             goto bad;
                   2207:         }
                   2208: 
                   2209:                /*
                   2210:                 * VOP_REMOVE will vput targetPar_vp so we better bump 
                   2211:                 * its ref count and relockit, always set target_vp to
                   2212:                 * NULL afterwards to indicate that were done with it.
                   2213:                 */
                   2214:                VREF(targetPar_vp);
                   2215:                if (target_vp->v_type == VREG) cache_purge(VTOH(target_vp)->h_relative);
                   2216:                retval = VOP_REMOVE(targetPar_vp, target_vp, target_cnp);
                   2217:                (void) vn_lock(targetPar_vp, LK_EXCLUSIVE, p);
                   2218: 
                   2219:                target_vp = NULL;
                   2220:         target_hp = NULL;              
                   2221:                
                   2222:         if (retval) goto bad;
                   2223: 
                   2224:     } else {
                   2225:         if (targetPar_hp->h_dev != source_hp->h_dev)
                   2226:             panic("rename: EXDEV");
                   2227:     };
                   2228: 
                   2229: 
                   2230:        if (newparent != oldparent)
                   2231:                vn_lock(sourcePar_vp, LK_EXCLUSIVE | LK_RETRY, p);
                   2232: 
                   2233:        /* lock catalog b-tree */
                   2234:        retval = hfs_metafilelocking(VTOHFS(source_vp), kHFSCatalogFileID, LK_EXCLUSIVE, p);
                   2235:        if (retval) goto badcataloglock;
                   2236:        
                   2237:        /* remove the existing entry from the namei cache: */
                   2238:        if (source_vp->v_type == VREG) cache_purge(VTOH(source_vp)->h_relative);
                   2239: 
                   2240:        retval = hfsMoveRename( HTOVCB(source_hp), H_DIRID(source_hp), H_NAME(source_hp),
                   2241:                                                        H_FILEID(VTOH(targetPar_vp)), target_cnp->cn_nameptr, &H_HINT(source_hp));
                   2242: 
                   2243:        if (retval == 0) {      
                   2244:            /* Look up the catalog entry just renamed since it might have been auto-decomposed */
                   2245:            catInfo.hint = H_HINT(source_hp);
                   2246:            retval = hfsLookup(HTOVCB(source_hp), H_FILEID(VTOH(targetPar_vp)), target_cnp->cn_nameptr, -1, 0, &catInfo);
                   2247:                targetnamelen = strlen(catInfo.spec.name);
                   2248:     }
                   2249: 
                   2250:        /* unlock catalog b-tree */
                   2251:        (void) hfs_metafilelocking(VTOHFS(source_vp), kHFSCatalogFileID, LK_RELEASE, p);
                   2252: 
                   2253:        if (newparent != oldparent)
                   2254:                VOP_UNLOCK(sourcePar_vp, 0, p);
                   2255: 
                   2256:        if (retval)  goto bad;
                   2257: 
                   2258:        H_DIRID(source_hp) = H_FILEID(VTOH(targetPar_vp));
                   2259: 
                   2260:     if (targetnamelen > source_hp->h_meta->h_namelen) {
                   2261:         if (source_hp->h_meta->h_nodeflags & IN_LONGNAME)
                   2262:           {
                   2263:             FREE(H_NAME(source_hp), M_HFSNODE);
                   2264:             MALLOC(H_NAME(source_hp), char *, targetnamelen+1, M_HFSNODE, M_WAITOK);
                   2265:           }
                   2266:         else if (targetnamelen > MAXHFSVNODELEN) {
                   2267:             MALLOC(H_NAME(source_hp), char *, targetnamelen+1, M_HFSNODE, M_WAITOK);
                   2268:             source_hp->h_meta->h_nodeflags |= IN_LONGNAME;
                   2269:         }
                   2270:     };
                   2271: 
                   2272:     source_hp->h_meta->h_namelen = targetnamelen;
                   2273:     copystr(catInfo.spec.name, H_NAME(source_hp), targetnamelen+1, NULL);
                   2274:     source_hp->h_meta->h_nodeflags &= ~IN_RENAME;
                   2275: 
                   2276: #if 0
                   2277:     source_hp->h_meta->h_nodeflags |= IN_CHANGE;
                   2278:     tv = time;
                   2279:     if ((retval = VOP_UPDATE(source_vp, &tv, &tv, 1))) {
                   2280:         VOP_UNLOCK(source_vp, 0, p);
                   2281:         goto bad;
                   2282:     }
                   2283: #endif
                   2284: 
                   2285:        /* Copy common fcb info to complex node */
                   2286:        tp = source_hp->h_relative;
                   2287:     if (tp) {
                   2288:                H_FILEID(VTOH(tp)) = H_FILEID(source_hp);
                   2289:        }
                   2290: 
                   2291:        /* Now copy common fcb info to siblings */
                   2292:        tp = source_hp->h_sibling;
                   2293:     while (tp) {
                   2294:                H_FILEID(VTOH(tp)) = H_FILEID(source_hp);
                   2295:         tp = VTOH(tp)->h_sibling;
                   2296:         if (tp == source_vp)
                   2297:                        break;
                   2298:        }
                   2299: 
                   2300:        /* Timestamp the parents, if this is a move */
                   2301:     if (newparent != oldparent) {
                   2302:         targetPar_hp->h_meta->h_nodeflags |= IN_UPDATE;
                   2303:         sourcePar_hp->h_meta->h_nodeflags |= IN_UPDATE;
                   2304:         tv = time;
                   2305:         HFSTIMES(targetPar_hp, &tv, &tv);
                   2306:         HFSTIMES(sourcePar_hp, &tv, &tv);
                   2307:         };
                   2308: 
                   2309:        VPUT(targetPar_vp);
                   2310:        VRELE(sourcePar_vp);
                   2311:     VPUT(source_vp);
                   2312: 
                   2313:     DBG_VOP_LOCKS_TEST(retval);
                   2314:     if (retval != E_NONE) {
                   2315:         DBG_VOP_PRINT_FUNCNAME();DBG_VOP_CONT(("\tReturning with error %d\n",retval));
                   2316:     }
                   2317:     return (retval);
                   2318: 
                   2319: badcataloglock:
                   2320:        if (newparent != oldparent)
                   2321:                VOP_UNLOCK(sourcePar_vp, 0, p);
                   2322:        
                   2323: bad:;
                   2324:     if (retval && doingdirectory)
                   2325:        source_hp->h_meta->h_nodeflags &= ~IN_RENAME;
                   2326: 
                   2327:     if (targetPar_vp == target_vp)
                   2328:            VRELE(targetPar_vp);
                   2329:     else
                   2330:            VPUT(targetPar_vp);
                   2331: 
                   2332:     if (target_vp)
                   2333:            VPUT(target_vp);
                   2334: 
                   2335:        VRELE(sourcePar_vp);
                   2336: 
                   2337:     if (VOP_ISLOCKED(source_vp))
                   2338:         VPUT(source_vp);
                   2339:        else
                   2340:        VRELE(source_vp);
                   2341: 
                   2342:     DBG_VOP_LOCKS_TEST(retval);
                   2343:     if (retval != E_NONE) {
                   2344:         DBG_VOP_PRINT_FUNCNAME();DBG_VOP_CONT(("\tReturning with error %d\n",retval));
                   2345:     }
                   2346:     return (retval);
                   2347: 
                   2348: abortit:;
                   2349: 
                   2350:     VOP_ABORTOP(targetPar_vp, target_cnp); /* XXX, why not in NFS? */
                   2351: 
                   2352:     if (targetPar_vp == target_vp)
                   2353:            VRELE(targetPar_vp);
                   2354:     else
                   2355:            VPUT(targetPar_vp);
                   2356: 
                   2357:     if (target_vp)
                   2358:            VPUT(target_vp);
                   2359: 
                   2360:     VOP_ABORTOP(sourcePar_vp, source_cnp); /* XXX, why not in NFS? */
                   2361: 
                   2362:        VRELE(sourcePar_vp);
                   2363:     VRELE(source_vp);
                   2364: 
                   2365:     DBG_VOP_LOCKS_TEST(retval);
                   2366:     if (retval != E_NONE) {
                   2367:         DBG_VOP_PRINT_FUNCNAME();DBG_VOP_CONT(("\tReturning with error %d\n",retval));
                   2368:     }
                   2369:     return (retval);
                   2370: }
                   2371: 
                   2372: 
                   2373: 
                   2374: /*
                   2375:  * Mkdir system call
                   2376: #% mkdir       dvp     L U U
                   2377: #% mkdir       vpp     - L -
                   2378: #
                   2379:  vop_mkdir {
                   2380:      IN WILLRELE struct vnode *dvp;
                   2381:      OUT struct vnode **vpp;
                   2382:      IN struct componentname *cnp;
                   2383:      IN struct vattr *vap;
                   2384: 
                   2385:      We are responsible for freeing the namei buffer, it is done in hfs_makenode(), unless there is
                   2386:     a previous error.
                   2387: 
                   2388: */
                   2389: 
                   2390: int
                   2391: hfs_mkdir(ap)
                   2392: struct vop_mkdir_args /* {
                   2393:     struct vnode *a_dvp;
                   2394:     struct vnode **a_vpp;
                   2395:     struct componentname *a_cnp;
                   2396:     struct vattr *a_vap;
                   2397: } */ *ap;
                   2398: {
                   2399:        struct proc             *p = CURRENT_PROC;
                   2400:     int                                retval;
                   2401:     int                                mode = MAKEIMODE(ap->a_vap->va_type, ap->a_vap->va_mode);
                   2402: 
                   2403:     DBG_FUNC_NAME("mkdir");
                   2404:     DBG_VOP_LOCKS_DECL(2);
                   2405:     DBG_VOP_PRINT_FUNCNAME();
                   2406:     DBG_VOP_PRINT_VNODE_INFO(ap->a_dvp);
                   2407:     DBG_VOP_PRINT_CPN_INFO(ap->a_cnp);DBG_VOP_CONT(("\n"));
                   2408: 
                   2409:     DBG_VOP_LOCKS_INIT(0,ap->a_dvp, VOPDBG_LOCKED, VOPDBG_UNLOCKED, VOPDBG_UNLOCKED, VOPDBG_POS);
                   2410:     DBG_VOP_LOCKS_INIT(1,*ap->a_vpp, VOPDBG_IGNORE, VOPDBG_LOCKED, VOPDBG_IGNORE, VOPDBG_POS);
                   2411: 
                   2412:     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));
                   2413:     WRITE_CK( ap->a_dvp, funcname);
                   2414:     DBG_HFS_NODE_CHECK(ap->a_dvp);
                   2415:     ASSERT(ap->a_dvp->v_type == VDIR);
                   2416: 
                   2417:        /* lock catalog b-tree */
                   2418:        retval = hfs_metafilelocking(VTOHFS(ap->a_dvp), kHFSCatalogFileID, LK_EXCLUSIVE, p);
                   2419:     if (retval != E_NONE) {
                   2420:        VOP_ABORTOP(ap->a_dvp, ap->a_cnp);
                   2421:                VPUT(ap->a_dvp);
                   2422:         DBG_VOP_LOCKS_TEST( retval);
                   2423:         return (retval);
                   2424:     }
                   2425: 
                   2426:        /* Create the vnode */
                   2427:     DBG_ASSERT((ap->a_cnp->cn_flags & SAVESTART) == 0);
                   2428:        retval = hfs_makenode(mode, ap->a_dvp, ap->a_vpp, ap->a_cnp);
                   2429:     DBG_VOP_UPDATE_VP(1, *ap->a_vpp);
                   2430: 
                   2431:        /* unlock catalog b-tree */
                   2432:        (void) hfs_metafilelocking(VTOHFS(ap->a_dvp), kHFSCatalogFileID, LK_RELEASE, p);
                   2433: 
                   2434:     if (retval != E_NONE) {
                   2435:         DBG_ERR(("%s: hfs_makenode FAILED: %s, %s\n", funcname, ap->a_cnp->cn_nameptr, H_NAME(VTOH(ap->a_dvp))));
                   2436:         DBG_VOP_LOCKS_TEST(retval);
                   2437:         return (retval);               
                   2438:     }
                   2439: 
                   2440:     DBG_VOP_LOCKS_TEST(E_NONE);
                   2441:     return (E_NONE);
                   2442: }
                   2443: 
                   2444: /*
                   2445:  * Rmdir system call.
                   2446: #% rmdir       dvp     L U U
                   2447: #% rmdir       vp      L U U
                   2448: #
                   2449:  vop_rmdir {
                   2450:      IN WILLRELE struct vnode *dvp;
                   2451:      IN WILLRELE struct vnode *vp;
                   2452:      IN struct componentname *cnp;
                   2453: 
                   2454:      */
                   2455: 
                   2456: int
                   2457: hfs_rmdir(ap)
                   2458: struct vop_rmdir_args /* {
                   2459:     struct vnode *a_dvp;
                   2460:     struct vnode *a_vp;
                   2461:     struct componentname *a_cnp;
                   2462: } */ *ap;
                   2463: {
                   2464:     struct vnode *vp = ap->a_vp;
                   2465:     struct vnode *dvp = ap->a_dvp;
                   2466:     struct hfsnode *hp = VTOH(vp);
                   2467:        struct proc *p = CURRENT_PROC;
                   2468:     int retval;
                   2469:     DBG_FUNC_NAME("rmdir");
                   2470:     DBG_VOP_LOCKS_DECL(2);
                   2471:     DBG_VOP_PRINT_FUNCNAME();
                   2472:     DBG_VOP(("\tParent: "));DBG_VOP_PRINT_VNODE_INFO(ap->a_dvp);DBG_VOP_CONT(("\n"));
                   2473:     DBG_VOP(("\tTarget: "));DBG_VOP_PRINT_VNODE_INFO(ap->a_vp);DBG_VOP_CONT(("\n"));
                   2474:     DBG_VOP(("\tTarget Name: "));DBG_VOP_PRINT_CPN_INFO(ap->a_cnp);DBG_VOP_CONT(("\n"));
                   2475: 
                   2476:     DBG_VOP_LOCKS_INIT(0,ap->a_dvp, VOPDBG_LOCKED, VOPDBG_UNLOCKED, VOPDBG_UNLOCKED, VOPDBG_POS);
                   2477:     DBG_VOP_LOCKS_INIT(1,ap->a_vp, VOPDBG_LOCKED, VOPDBG_UNLOCKED, VOPDBG_UNLOCKED, VOPDBG_POS);
                   2478: 
                   2479:     if (dvp == vp) {
                   2480:         VRELE(vp);
                   2481:         VPUT(vp);
                   2482:         DBG_VOP_LOCKS_TEST(EINVAL);
                   2483:         return (EINVAL);
                   2484:     }
                   2485: 
                   2486:     if (vp->v_usecount > 2) {
                   2487:         DBG_ERR(("%s: dir is busy, usecount is %d\n", funcname, vp->v_usecount ));
                   2488:                retval = EBUSY;
                   2489:                goto Err_Exit;
                   2490:     }
                   2491: 
                   2492:        /* lock catalog b-tree */
                   2493:        retval = hfs_metafilelocking(VTOHFS(vp), kHFSCatalogFileID, LK_EXCLUSIVE, p);
                   2494:        if (retval != E_NONE) {
                   2495:                goto Err_Exit;
                   2496:        }
                   2497: 
                   2498:        /* remove the entry from the namei cache: */
                   2499:        cache_purge(vp);
                   2500: 
                   2501:        /* remove entry from catalog */
                   2502:     retval = hfsDelete (HTOVCB(hp), H_DIRID(hp), H_NAME(hp), FALSE, H_HINT(hp));
                   2503:     hp->h_meta->h_mode = 0;                            /* Makes the vnode go away...see inactive */
                   2504: 
                   2505:        /* unlock catalog b-tree */
                   2506:        (void) hfs_metafilelocking(VTOHFS(vp), kHFSCatalogFileID, LK_RELEASE, p);
                   2507: 
                   2508:        /* Set the parent to be updated */
                   2509:     if (! retval)
                   2510:        VTOH(dvp)->h_meta->h_nodeflags |= IN_CHANGE | IN_UPDATE;
                   2511: 
                   2512: Err_Exit:;
                   2513:     if (dvp != 0) 
                   2514:                VPUT(dvp);
                   2515:     VPUT(vp);
                   2516: 
                   2517:     DBG_VOP_LOCKS_TEST(retval);
                   2518:     return (retval);
                   2519: }
                   2520: 
                   2521: /*
                   2522:  * symlink -- make a symbolic link
                   2523: #% symlink     dvp     L U U
                   2524: #% symlink     vpp     - U -
                   2525: #
                   2526: # XXX - note that the return vnode has already been VRELE'ed
                   2527: #      by the filesystem layer.  To use it you must use vget,
                   2528: #      possibly with a further namei.
                   2529: #
                   2530:  vop_symlink {
                   2531:      IN WILLRELE struct vnode *dvp;
                   2532:      OUT WILLRELE struct vnode **vpp;
                   2533:      IN struct componentname *cnp;
                   2534:      IN struct vattr *vap;
                   2535:      IN char *target;
                   2536: 
                   2537:      We are responsible for freeing the namei buffer, it is done in hfs_makenode(), unless there is
                   2538:     a previous error.
                   2539: 
                   2540: 
                   2541: */
                   2542: 
                   2543: int
                   2544: hfs_symlink(ap)
                   2545:     struct vop_symlink_args /* {
                   2546:         struct vnode *a_dvp;
                   2547:         struct vnode **a_vpp;
                   2548:         struct componentname *a_cnp;
                   2549:         struct vattr *a_vap;
                   2550:         char *a_target;
                   2551:     } */ *ap;
                   2552: {
                   2553:     register struct vnode *vp, **vpp = ap->a_vpp;
                   2554:        struct proc *p = CURRENT_PROC;
                   2555:     int len, retval;
                   2556:     DBG_FUNC_NAME("symlink");
                   2557:     DBG_VOP_LOCKS_DECL(2);
                   2558:     DBG_VOP_PRINT_FUNCNAME();
                   2559:     DBG_VOP_LOCKS_INIT(0,ap->a_dvp, VOPDBG_LOCKED, VOPDBG_UNLOCKED, VOPDBG_UNLOCKED, VOPDBG_POS);
                   2560:     DBG_VOP_LOCKS_INIT(1,*ap->a_vpp, VOPDBG_IGNORE, VOPDBG_UNLOCKED, VOPDBG_IGNORE, VOPDBG_POS);
                   2561: 
                   2562:     if (VTOVCB(ap->a_dvp)->vcbSigWord != kHFSPlusSigWord) {
                   2563:        VOP_ABORTOP(ap->a_dvp, ap->a_cnp);
                   2564:         VPUT(ap->a_dvp);
                   2565:         DBG_VOP((" ...sorry HFS disks don't support symbolic links.\n"));
                   2566:         DBG_VOP_LOCKS_TEST(EOPNOTSUPP);
                   2567:         return (EOPNOTSUPP);
                   2568:     }
                   2569: 
                   2570:        /* lock catalog b-tree */
                   2571:        retval = hfs_metafilelocking(VTOHFS(ap->a_dvp), kHFSCatalogFileID, LK_EXCLUSIVE, p);
                   2572:        if (retval != E_NONE) {
                   2573:        VOP_ABORTOP(ap->a_dvp, ap->a_cnp);
                   2574:        VPUT(ap->a_dvp);
                   2575:         DBG_VOP_LOCKS_TEST( retval);
                   2576:         return (retval);
                   2577:        }
                   2578: 
                   2579:        /* Create the vnode */
                   2580:        retval = hfs_makenode(IFLNK | ap->a_vap->va_mode, ap->a_dvp, vpp, ap->a_cnp);
                   2581:     DBG_VOP_UPDATE_VP(1, *ap->a_vpp);
                   2582: 
                   2583:        /* unlock catalog b-tree */
                   2584:        (void) hfs_metafilelocking(VTOHFS(ap->a_dvp), kHFSCatalogFileID, LK_RELEASE, p);
                   2585: 
                   2586:     if (retval != E_NONE) {
                   2587:         DBG_VOP_LOCKS_TEST(retval);
                   2588:         return (retval);
                   2589:        }
                   2590: 
                   2591: 
                   2592:     vp = *vpp;
                   2593:     len = strlen(ap->a_target);
                   2594:     retval = vn_rdwr(UIO_WRITE, vp, ap->a_target, len, (off_t)0,
                   2595:                      UIO_SYSSPACE, IO_NODELOCKED, ap->a_cnp->cn_cred, (int *)0,
                   2596:                      (struct proc *)0);
                   2597: 
                   2598: 
                   2599:     VPUT(vp);
                   2600:     DBG_VOP_LOCKS_TEST(retval);
                   2601:     return (retval);
                   2602: }
                   2603: 
                   2604: /*
                   2605:  * Dummy dirents to simulate the "." and ".." entries of the directory
                   2606:  * in a hfs filesystem.  HFS doesn't provide these. Note that each entry
                   2607:  * must be the same size as a hfs directory entry (44 bytes).
                   2608:  */
                   2609: static hfsdirentry  rootdots[2] = {
                   2610:     {
                   2611:         1,                                                             /* d_fileno                      */
                   2612:         sizeof(struct hfsdirentry),            /* d_reclen                      */
                   2613:         DT_DIR,                                                        /* d_type                        */
                   2614:         1,                                                             /* d_namlen                      */
                   2615:         "."                                                            /* d_name                        */
                   2616:     },
                   2617:     {
                   2618:         1,                                                             /* d_fileno                      */
                   2619:         sizeof(struct hfsdirentry),            /* d_reclen                      */
                   2620:         DT_DIR,                                                        /* d_type                        */
                   2621:         2,                                                             /* d_namlen                      */
                   2622:         ".."                                                   /* d_name                        */
                   2623:     }
                   2624: };
                   2625: 
                   2626: 
                   2627: /*     4.3 Note:
                   2628: *      There is some confusion as to what the semantics of uio_offset are.
                   2629: *      In ufs, it represents the actual byte offset within the directory
                   2630: *      "file."  HFS, however, just uses it as an entry counter - essentially
                   2631: *      assuming that it has no meaning except to the hfs_readdir function.
                   2632: *      This approach would be more efficient here, but some callers may
                   2633: *      assume the uio_offset acts like a byte offset.  NFS in fact
                   2634: *      monkeys around with the offset field a lot between readdir calls.
                   2635: *
                   2636: *      We could also speed things up by remembering the last offset position,
                   2637: *      but its not clear that that would buy us much (do readdirs need to
                   2638:                                                  *     be fast?) ??
                   2639: *
                   2640: *      The use of the resid uiop->uio_resid and uiop->uio_iov->iov_len
                   2641: *      fields is a mess as well.  The libc function readdir() returns
                   2642: *      NULL (indicating the end of a directory) when either
                   2643: *      the getdirentries() syscall (which calls this and returns
                   2644:                                *       the size of the buffer passed in less the value of uiop->uio_resid)
                   2645: *      returns 0, or a direct record with a d_reclen of zero.
                   2646: *      nfs_server.c:rfs_readdir(), on the other hand, checks for the end
                   2647: *      of the directory by testing uiop->uio_resid == 0.  The solution
                   2648: *      is to pad the size of the last struct direct in a given
                   2649: *      block to fill the block if we are not at the end of the directory.
                   2650: */
                   2651: 
                   2652: /*
                   2653:  * NOTE: We require a minimal buffer size of DIRBLKSIZ for two reasons. One, it is the same value
                   2654:  * returned be stat() call as the block size. This is mentioned in the man page for getdirentries():
                   2655:  * "Nbytes must be greater than or equal to the block size associated with the file,
                   2656:  * see stat(2)". Might as well settle on the same size of ufs. Second, this makes sure there is enough
                   2657:  * room for the . and .. entries that have to added manually.
                   2658:  */
                   2659: 
                   2660: /*                     
                   2661: #% readdir     vp      L L L
                   2662: #
                   2663: vop_readdir {
                   2664:     IN struct vnode *vp;
                   2665:     INOUT struct uio *uio;
                   2666:     IN struct ucred *cred;
                   2667:     INOUT int *eofflag;
                   2668:     OUT int *ncookies;
                   2669:     INOUT u_long **cookies;
                   2670:     */
                   2671: 
                   2672: 
                   2673: static int
                   2674: hfs_readdir(ap)
                   2675: struct vop_readdir_args /* {
                   2676:     struct vnode *vp;
                   2677:     struct uio *uio;
                   2678:     struct ucred *cred;
                   2679:     int *eofflag;
                   2680:     int *ncookies;
                   2681:     u_long **cookies;
                   2682: } */ *ap;
                   2683: {
                   2684:     register struct uio *uio = ap->a_uio;
                   2685:     struct hfsnode             *hp = VTOH(ap->a_vp);
                   2686:        struct proc                     *p = CURRENT_PROC;
                   2687:     ExtendedVCB                *vcb = HTOVCB(hp);
                   2688:     off_t                              off = uio->uio_offset;
                   2689:     size_t                             count;
                   2690:     size_t                             lost = 0;
                   2691:     CatalogNodeData    nodeData;
                   2692:     struct hfsdirentry catalogEntry;
                   2693:     FSSpec                             fileSpec;       /* 264 bytes */
                   2694:     UInt32                             dirID = H_FILEID(hp);
                   2695:     UInt32                             index = 0;
                   2696:     UInt32                             origOffset;
                   2697:     UInt32                             hint;
                   2698:     Boolean                            eofReached = FALSE;
                   2699:     int                                        retval = 0;
                   2700:     OSErr                              result = noErr;
                   2701: 
                   2702:     DBG_FUNC_NAME("readdir");
                   2703:     DBG_VOP_LOCKS_DECL(1);
                   2704: 
                   2705:     DBG_VOP_LOCKS_INIT(0,ap->a_vp, VOPDBG_LOCKED, VOPDBG_LOCKED, VOPDBG_LOCKED, VOPDBG_POS);
                   2706:     DBG_VOP_PRINT_FUNCNAME();
                   2707:     DBG_VOP_PRINT_VNODE_INFO(ap->a_vp);DBG_VOP_CONT(("\n"));
                   2708:     DBG_HFS_NODE_CHECK(ap->a_vp);
                   2709: 
                   2710:     /* We assume it's all one big buffer... */
                   2711:     if (uio->uio_iovcnt > 1) DEBUG_BREAK_MSG(("hfs_readdir: uio->uio_iovcnt = %d?\n", uio->uio_iovcnt));
                   2712: 
                   2713:     origOffset = uio->uio_offset;
                   2714:     count = uio->uio_resid;
                   2715:     /* Make sure we don't return partial entries.  */
                   2716:     count -= ((uio->uio_offset + count) % sizeof(hfsdirentry));
                   2717:     if (count <= 0) {
                   2718:         DBG_ERR(("%s: Not enough buffer to read in entries\n",funcname));
                   2719:         DBG_VOP_LOCKS_TEST(EINVAL);
                   2720:         return (EINVAL);
                   2721:     }
                   2722: 
                   2723:     /* Adjust uio to be on correct boundaries */
                   2724:     lost = uio->uio_resid - count;
                   2725:     uio->uio_resid = count;
                   2726:     uio->uio_iov->iov_len = count;
                   2727: 
                   2728:     DBG_VOP(("%s: offset Ox%lX, bytes Ox%lX\n",funcname,
                   2729:              (u_long)uio->uio_offset, uio->uio_iov->iov_len));
                   2730: 
                   2731:     /* Create the entries for . and ..
                   2732:         * We do it here since we are assuming that the directory is guarenteed to exist
                   2733:         */
                   2734:     index = 0;
                   2735:     if (uio->uio_offset < (2 * sizeof(struct hfsdirentry))) {
                   2736:         if ((uio->uio_offset > 0) && (uio->uio_offset != sizeof(struct hfsdirentry))) {
                   2737:             retval = EINVAL;
                   2738:             goto Exit;
                   2739:         }
                   2740:         index = 2;
                   2741:         if (uio->uio_offset == sizeof(struct hfsdirentry)) {
                   2742:             index = 1;
                   2743:         }
1.1.1.2 ! root     2744: 
        !          2745:                /* copy in the correct d_fileno */
        !          2746:         rootdots[0].fileno = dirID;
        !          2747:         rootdots[1].fileno = H_DIRID(hp);
        !          2748: 
1.1       root     2749:         retval = uiomove((caddr_t) (rootdots + uio->uio_offset), index * sizeof(struct hfsdirentry), uio);
1.1.1.2 ! root     2750:                if (retval != 0)
        !          2751:                        goto Exit;
        !          2752: 
1.1       root     2753:     };
                   2754: 
                   2755:     /* Compute the starting index in the directory */
                   2756:     index = (uio->uio_offset - sizeof(struct hfsdirentry)) / sizeof(struct hfsdirentry);
                   2757: 
                   2758:        /* lock catalog b-tree */
                   2759:        retval = hfs_metafilelocking(VTOHFS(ap->a_vp), kHFSCatalogFileID, LK_SHARED, p);
                   2760:     if (retval != E_NONE) {
                   2761:                goto Exit;
                   2762:     };
                   2763: 
                   2764:     hint = kNoHint;
                   2765:     while (uio->uio_resid > sizeof(struct hfsdirentry))
                   2766:       {
                   2767:         result = GetCatalogOffspring(vcb, dirID, index, &fileSpec, &nodeData, &hint);
                   2768:         if (result != noErr) {
                   2769:             if (result == cmNotFound) {
                   2770:                 eofReached = TRUE;
                   2771:                 if (origOffset == uio->uio_offset) {           /* we were already past eof */
                   2772:                     uio->uio_offset = 0;
                   2773:                     retval = E_NONE;
                   2774:                                        /* unlock catalog b-tree */
                   2775:                                        (void) hfs_metafilelocking(VTOHFS(ap->a_vp),
                   2776:                                                                                                kHFSCatalogFileID, LK_RELEASE, p);
                   2777:                                        goto Exit;
                   2778:                 }
                   2779:                 result = noErr;
                   2780:             }
                   2781:             retval = MacToVFSError(result);
                   2782:             break;
                   2783:         }
                   2784: 
                   2785:         /* Copy entry into the buffer */
                   2786:         catalogEntry.fileno = nodeData.nodeID;
                   2787:         catalogEntry.reclen = sizeof(struct hfsdirentry);
                   2788:         catalogEntry.type = (nodeData.nodeType == kCatalogFolderNode) ? DT_DIR : DT_REG;
                   2789:         catalogEntry.namelen = strlen(fileSpec.name);
                   2790:                (void) strncpy(catalogEntry.name, fileSpec.name, sizeof(catalogEntry.name));
                   2791: 
                   2792:         /* copy this entry into the user's buffer: */
                   2793:         retval = uiomove((caddr_t) &catalogEntry, sizeof(struct hfsdirentry), uio);
                   2794:         if (retval != E_NONE) {
                   2795:             DBG_ERR(("%s: uiomove returned %d.\n", funcname, retval));
                   2796:             break;
                   2797:         };
                   2798:         ++index;
                   2799:       };
                   2800: 
                   2801:        /* unlock catalog b-tree */
                   2802:        (void) hfs_metafilelocking(VTOHFS(ap->a_vp), kHFSCatalogFileID, LK_RELEASE, p);
                   2803: 
                   2804:     if (retval != E_NONE) {
                   2805:         DBG_ERR(("%s: retval %d when trying to read directory %ld: %s\n",funcname, retval,
                   2806:                 H_FILEID(hp), H_NAME(hp)));
                   2807:                goto Exit;
                   2808:     }
                   2809:     else if (vcb->vcbSigWord == kHFSPlusSigWord)
                   2810:        hp->h_meta->h_nodeflags |= IN_ACCESS;
                   2811: 
                   2812:     /* Bake any cookies */
                   2813:     if (!retval && ap->a_ncookies != NULL) {
                   2814:         struct dirent* dpStart;
                   2815:         struct dirent* dpEnd;
                   2816:         struct dirent* dp;
                   2817:         int ncookies;
                   2818:         u_long *cookies;
                   2819:         u_long *cookiep;
                   2820: 
                   2821:         /*
                   2822:         * Only the NFS server uses cookies, and it loads the
                   2823:         * directory block into system space, so we can just look at
                   2824:         * it directly.
                   2825:         */
                   2826:         if (uio->uio_segflg != UIO_SYSSPACE || uio->uio_iovcnt != 1)
                   2827:             panic("hfs_readdir: unexpected uio from NFS server");
                   2828:         dpStart = (struct dirent *)
                   2829:             (uio->uio_iov->iov_base - (uio->uio_offset - off));
                   2830:         dpEnd = (struct dirent *) uio->uio_iov->iov_base;
                   2831:         for (dp = dpStart, ncookies = 0;
                   2832:             dp < dpEnd && dp->d_reclen != 0;
                   2833:             dp = (struct dirent *)((caddr_t)dp + dp->d_reclen))
                   2834:             ncookies++;
                   2835:         MALLOC(cookies, u_long *, ncookies * sizeof(u_long), M_TEMP,
                   2836:             M_WAITOK);
                   2837:         for (dp = dpStart, cookiep = cookies;
                   2838:             dp < dpEnd;
                   2839:             dp = (struct dirent *)((caddr_t) dp + dp->d_reclen)) {
                   2840:             off += dp->d_reclen;
                   2841:             *cookiep++ = (u_long) off;
                   2842:         }
                   2843:         *ap->a_ncookies = ncookies;
                   2844:         *ap->a_cookies = cookies;
                   2845:     }
                   2846: 
                   2847: Exit:;
                   2848:        uio->uio_resid += lost;
                   2849: 
                   2850:     if (ap->a_eofflag)
                   2851:         *ap->a_eofflag = eofReached;
                   2852: 
                   2853:     DBG_VOP_LOCKS_TEST(retval);
                   2854:     return (retval);
                   2855: }
                   2856: 
                   2857: 
                   2858: /*
                   2859:  * readdirattr operation
                   2860:  */
                   2861: 
                   2862: /*                     
                   2863: 
                   2864: #
                   2865: #% readdirattr vp      L L L
                   2866: #
                   2867: vop_readdirattr {
                   2868:        IN struct vnode *vp;
                   2869:        IN struct attrlist *alist;
                   2870:        INOUT struct uio *uio;
                   2871:        INOUT int index;
                   2872:        INOUT int *eofflag;
                   2873:        OUT u_long *ncookies;
                   2874:        INOUT u_long **cookies;
                   2875:        IN struct ucred *cred;
                   2876: };
                   2877: 
                   2878: */
                   2879: 
                   2880: 
                   2881: static int
                   2882: hfs_readdirattr(ap)
                   2883: struct vop_readdirattr_args /* {
                   2884:     struct vnode *vp;
                   2885:     struct attrlist *alist;
                   2886:     struct uio *uio;
                   2887:     int index;
                   2888:     int *eofflag;
                   2889:     u_long *ncookies;
                   2890:     u_long **cookies;
                   2891:     struct ucred *cred;
                   2892: } */ *ap;
                   2893: {
                   2894:     struct vnode               *vp = ap->a_vp;
                   2895:     struct attrlist    *alist = ap->a_alist;
                   2896:     register struct uio *uio = ap->a_uio;
                   2897:     struct hfsnode             *hp = VTOH(ap->a_vp);
                   2898:     ExtendedVCB                *vcb = HTOVCB(hp);
                   2899:     off_t                              off = uio->uio_offset;
                   2900:     size_t                             count;
                   2901:     struct hfsCatalogInfo catalogInfo;
                   2902:     struct hfsCatalogInfo *catInfoPtr = NULL;
                   2903:     UInt32                             dirID = H_FILEID(hp);
                   2904:     UInt32                             index = 0;
                   2905:     OSErr                              result = noErr;
                   2906:     UInt32                             origOffset;
                   2907:     Boolean                            eofReached = FALSE;
                   2908:     int                                        retval = 0;
                   2909:     u_long                             fixedblocksize;
                   2910:     u_long                             maxattrblocksize;
                   2911:        u_long                          currattrbufsize;
                   2912:     void                               *attrbufptr = NULL;
                   2913:     void                               *attrptr;
                   2914:     void                               *varptr;
                   2915:     DBG_FUNC_NAME("readdirattr");
                   2916:     DBG_VOP_LOCKS_DECL(1);
                   2917:     
                   2918:     DBG_VOP_LOCKS_INIT(0,ap->a_vp, VOPDBG_LOCKED, VOPDBG_LOCKED, VOPDBG_LOCKED, VOPDBG_POS);
                   2919:     DBG_VOP_PRINT_FUNCNAME();
                   2920:     DBG_VOP_PRINT_VNODE_INFO(ap->a_vp);DBG_VOP_CONT(("\n"));
                   2921:     DBG_HFS_NODE_CHECK(ap->a_vp);
                   2922: 
                   2923:     if ((alist->bitmapcount != ATTR_BIT_MAP_COUNT) ||
                   2924:         ((alist->commonattr & ~ATTR_CMN_VALIDMASK) != 0) ||
                   2925:         ((alist->dirattr & ~ATTR_DIR_VALIDMASK) != 0) ||
                   2926:         ((alist->fileattr & ~ATTR_FILE_VALIDMASK) != 0) ||
                   2927:         ((alist->forkattr & ~ATTR_FORK_VALIDMASK) != 0)) {
                   2928:         DBG_ERR(("%s: bad attrlist\n", funcname));
                   2929:         DBG_VOP_LOCKS_TEST(EINVAL);
                   2930:         return EINVAL;
                   2931:     };
                   2932: 
                   2933:     /* Requesting volume information is illegal : */
                   2934:     if (alist->volattr != 0) {
                   2935:         DBG_ERR(("%s: requesting volume attribute is illegal\n", funcname));
                   2936:         DBG_VOP_LOCKS_TEST(EINVAL);
                   2937:         return EINVAL;
                   2938:     };
                   2939: 
                   2940:     /* Reject requests for unsupported options for now: */
                   2941:     if ((alist->commonattr & (ATTR_CMN_NAMEDATTRCOUNT | ATTR_CMN_NAMEDATTRLIST)) ||
                   2942:         (alist->fileattr & (ATTR_FILE_FILETYPE | ATTR_FILE_FORKCOUNT | ATTR_FILE_FORKLIST))) {
                   2943:         DBG_ERR(("%s: illegal bits in attlist\n", funcname));
                   2944:         DBG_VOP_LOCKS_TEST(EINVAL);
                   2945:         return EINVAL;
                   2946:     };
                   2947: 
                   2948:     origOffset         = uio->uio_offset;
                   2949:     count              = uio->uio_resid;
                   2950: 
                   2951:   /* Make sure we don't return partial entries.  */
                   2952:     count -= ((uio->uio_offset + count) % sizeof(hfsdirentry));
                   2953:     if (count <= 0) {
                   2954:         DBG_ERR(("%s: Not enough buffer to read in entries\n",funcname));
                   2955:         DBG_VOP_LOCKS_TEST(EINVAL);
                   2956:         return (EINVAL);
                   2957:     }
                   2958: 
                   2959:     DBG_VOP(("%s: offset Ox%lX, bytes Ox%lX\n",funcname,
                   2960:              (u_long)uio->uio_offset, (u_long)uio->uio_iov->iov_len));
                   2961: 
                   2962:        /* Preflight and alloc buffer to do packings */
                   2963:     maxattrblocksize = fixedblocksize = (sizeof(u_long) + AttributeBlockSize(alist));  /* u_long for length longword */
                   2964:     if (alist->commonattr & ATTR_CMN_NAME) maxattrblocksize += NAME_MAX + 1;
                   2965:     if (alist->commonattr & ATTR_CMN_NAMEDATTRLIST) maxattrblocksize += 0;                     /* XXX PPD */
                   2966:     if (alist->fileattr & ATTR_FILE_FORKLIST) maxattrblocksize += 0;                           /* XXX PPD */
                   2967: 
                   2968:     DBG_VOP(("%s: allocating Ox%lX byte buffer (Ox%lX + Ox%lX) for attributes...\n",
                   2969:                 funcname,
                   2970:                maxattrblocksize,
                   2971:                 fixedblocksize,
                   2972:                maxattrblocksize - fixedblocksize));
                   2973:     MALLOC(attrbufptr, void *, maxattrblocksize, M_TEMP, M_WAITOK);
                   2974:     attrptr = attrbufptr;
                   2975:     varptr = attrbufptr + fixedblocksize;                                      /* Point to variable-length storage */
                   2976:     DBG_VOP(("%s: attrptr = 0x%08X, varptr = 0x%08X...\n", funcname, (u_int)attrptr, (u_int)varptr));
                   2977: 
                   2978: #if 0
                   2979:     /* Create the entries for . and ..
                   2980:      * We do it here since we are assuming that the directory is guarenteed to exist
                   2981:      */
                   2982:     index = 0;
                   2983:     if (uio->uio_offset < (2 * sizeof(struct hfsdirentry))) {
                   2984:         if ((uio->uio_offset > 0) && (uio->uio_offset != sizeof(struct hfsdirentry))) {
                   2985:             retval = EINVAL;
                   2986:             goto Exit;
                   2987:         }
                   2988:         index = 2;
                   2989:         if (uio->uio_offset == sizeof(struct hfsdirentry)) {
                   2990:             index = 1;
                   2991:         }
                   2992:         retval = uiomove((caddr_t) (rootdots + uio->uio_offset), index * sizeof(struct hfsdirentry), uio);
                   2993:     };
                   2994: #endif
                   2995: 
                   2996:    /* Compute the starting index in the directory */
                   2997:     index = (uio->uio_offset - sizeof(struct hfsdirentry)) / sizeof(struct hfsdirentry);
                   2998: 
                   2999:     catalogInfo.hint = kNoHint;
                   3000:     while (uio->uio_resid > sizeof(struct hfsdirentry))
                   3001:       {
                   3002: 
                   3003:         result = GetCatalogOffspring(vcb, dirID, index, &catalogInfo.spec, &catalogInfo.nodeData, &catalogInfo.hint);
                   3004:         if (result != noErr) {
                   3005:             if (result == cmNotFound) {
                   3006:                 eofReached = TRUE;
                   3007:                 if (origOffset == uio->uio_offset) {           /* we were already past eof */
                   3008:                     uio->uio_offset = 0;
                   3009:                     retval = E_NONE;
                   3010:                     goto Err_Exit;
                   3011:                 }
                   3012:                 result = noErr;
                   3013:             }
                   3014:             retval = MacToVFSError(result);
                   3015:             break;
                   3016:         }
                   3017:         catInfoPtr = &catalogInfo;
                   3018: 
                   3019:         *((u_long *)attrptr)++ = 0;                    /* Reserve space for length field */
                   3020:         PackAttributeBlock(alist, vp, catInfoPtr, &attrptr, &varptr);
                   3021:         currattrbufsize = *((u_long *)attrbufptr) = (varptr - attrbufptr);             /* Store length of fixed + var block */
                   3022: 
                   3023:         /* Make sure that there is enough room to copy to */
                   3024:         if (currattrbufsize > uio->uio_resid)
                   3025:           {
                   3026:             if (uio->uio_offset == origOffset)
                   3027:               {
                   3028:                 DBG_ERR(("%s: Not enough buffer to read in entries\n",funcname));
                   3029:                 retval = EINVAL;
                   3030:                 goto Err_Exit;
                   3031:               }
                   3032:             break;
                   3033:           }
                   3034: 
                   3035:         DBG_VOP(("%s: copying Ox%lX bytes to user address 0x%08X.\n",funcname, currattrbufsize, (u_int)ap->a_uio->uio_iov->iov_base));
                   3036:         retval = uiomove((caddr_t)attrbufptr, currattrbufsize, ap->a_uio);
                   3037:         if (retval != E_NONE) {
                   3038:             DBG_ERR(("%s: error %d on uiomove.\n",funcname, retval));
                   3039:             break;
                   3040:         };
                   3041:         attrptr = (void *)((u_long)attrptr + currattrbufsize);
                   3042:         ++index;
                   3043:       };
                   3044: 
                   3045:    if (retval != E_NONE) {
                   3046:         DBG_ERR(("%s: retval %d when trying to read directory %ld: %s\n",funcname, retval,
                   3047:                 H_FILEID(hp), H_NAME(hp)));
                   3048:        retval = EINVAL;
                   3049:     };
                   3050: 
                   3051:     /* Bake any cookies */
                   3052:     if (!retval && ap->a_ncookies != NULL) {
                   3053:         struct dirent* dpStart;
                   3054:         struct dirent* dpEnd;
                   3055:         struct dirent* dp;
                   3056:         int ncookies;
                   3057:         u_long *cookies;
                   3058:         u_long *cookiep;
                   3059: 
                   3060:         /*
                   3061:         * Only the NFS server uses cookies, and it loads the
                   3062:         * directory block into system space, so we can just look at
                   3063:         * it directly.
                   3064:         */
                   3065:         if (uio->uio_segflg != UIO_SYSSPACE || uio->uio_iovcnt != 1)
                   3066:             panic("hfs_readdir: unexpected uio from NFS server");
                   3067:         dpStart = (struct dirent *)
                   3068:             (uio->uio_iov->iov_base - (uio->uio_offset - off));
                   3069:         dpEnd = (struct dirent *) uio->uio_iov->iov_base;
                   3070:         for (dp = dpStart, ncookies = 0;
                   3071:             dp < dpEnd && dp->d_reclen != 0;
                   3072:             dp = (struct dirent *)((caddr_t)dp + dp->d_reclen))
                   3073:             ncookies++;
                   3074:         MALLOC(cookies, u_long *, ncookies * sizeof(u_long), M_TEMP,
                   3075:             M_WAITOK);
                   3076:         for (dp = dpStart, cookiep = cookies;
                   3077:             dp < dpEnd;
                   3078:             dp = (struct dirent *)((caddr_t) dp + dp->d_reclen)) {
                   3079:             off += dp->d_reclen;
                   3080:             *cookiep++ = (u_long) off;
                   3081:         }
                   3082:         *ap->a_ncookies = ncookies;
                   3083:         *ap->a_cookies = cookies;
                   3084:     }
                   3085: 
                   3086: Err_Exit:;
                   3087: 
                   3088:     if (attrbufptr != NULL)
                   3089:                FREE(attrbufptr, M_TEMP);
                   3090: 
                   3091:     if (ap->a_eofflag)
                   3092:        *ap->a_eofflag = eofReached;
                   3093: 
                   3094:     DBG_VOP_LOCKS_TEST(retval);
                   3095:     return (retval);
                   3096: }
                   3097: 
                   3098: 
                   3099: /*
                   3100:  * Return target name of a symbolic link
                   3101: #% readlink    vp      L L L
                   3102: #
                   3103:  vop_readlink {
                   3104:      IN struct vnode *vp;
                   3105:      INOUT struct uio *uio;
                   3106:      IN struct ucred *cred;
                   3107:      */
                   3108: 
                   3109: int
                   3110: hfs_readlink(ap)
                   3111: struct vop_readlink_args /* {
                   3112: struct vnode *a_vp;
                   3113: struct uio *a_uio;
                   3114: struct ucred *a_cred;
                   3115: } */ *ap;
                   3116: {
                   3117:     int retval;
                   3118:     DBG_FUNC_NAME("readlink");
                   3119:     DBG_VOP_LOCKS_DECL(1);
                   3120:     DBG_VOP_PRINT_FUNCNAME();
                   3121:     DBG_VOP_PRINT_VNODE_INFO(ap->a_vp);DBG_VOP_CONT(("\n"));
                   3122: 
                   3123:     DBG_VOP_LOCKS_INIT(0,ap->a_vp, VOPDBG_LOCKED, VOPDBG_LOCKED, VOPDBG_LOCKED, VOPDBG_POS);
                   3124:     retval = VOP_READ(ap->a_vp, ap->a_uio, 0, ap->a_cred);
                   3125:     DBG_VOP_LOCKS_TEST(retval);
                   3126:     return (retval);
                   3127: 
                   3128: }
                   3129: 
                   3130: 
                   3131: /*
                   3132:  * hfs abort op, called after namei() when a CREATE/DELETE isn't actually
                   3133:  * done. If a buffer has been saved in anticipation of a CREATE, delete it.
                   3134: #% abortop     dvp     = = =
                   3135: #
                   3136:  vop_abortop {
                   3137:      IN struct vnode *dvp;
                   3138:      IN struct componentname *cnp;
                   3139: 
                   3140:      */
                   3141: 
                   3142: /* ARGSUSED */
                   3143: 
                   3144: static int
                   3145: hfs_abortop(ap)
                   3146: struct vop_abortop_args /* {
                   3147:     struct vnode *a_dvp;
                   3148:     struct componentname *a_cnp;
                   3149: } */ *ap;
                   3150: {
                   3151:     DBG_FUNC_NAME("abortop");
                   3152:     DBG_VOP_LOCKS_DECL(1);
                   3153:     DBG_VOP_PRINT_FUNCNAME();
                   3154:     DBG_VOP_PRINT_VNODE_INFO(ap->a_dvp);
                   3155:     DBG_VOP_PRINT_CPN_INFO(ap->a_cnp);DBG_VOP_CONT(("\n"));
                   3156: 
                   3157: 
                   3158:     DBG_VOP_LOCKS_INIT(0,ap->a_dvp, VOPDBG_IGNORE, VOPDBG_IGNORE, VOPDBG_IGNORE, VOPDBG_POS);
                   3159: 
                   3160:     if ((ap->a_cnp->cn_flags & (HASBUF | SAVESTART)) == HASBUF) {
                   3161:         FREE_ZONE(ap->a_cnp->cn_pnbuf, ap->a_cnp->cn_pnlen, M_NAMEI);
                   3162:     }
                   3163:     DBG_VOP_LOCKS_TEST(E_NONE);
                   3164:     return (E_NONE);
                   3165: }
                   3166: 
                   3167: // int prthfsactive = 0;               /* 1 => print out reclaim of active vnodes */
                   3168: 
                   3169: /*
                   3170: #% inactive    vp      L U U
                   3171: #
                   3172:  vop_inactive {
                   3173:      IN struct vnode *vp;
                   3174:      IN struct proc *p;
                   3175: 
                   3176:      */
                   3177: 
                   3178: static int
                   3179: hfs_inactive(ap)
                   3180: struct vop_inactive_args /* {
                   3181:     struct vnode *a_vp;
                   3182: } */ *ap;
                   3183: {
                   3184:     struct vnode *vp = ap->a_vp;
                   3185:     struct hfsnode *hp = VTOH(vp);
                   3186:     struct proc *p = ap->a_p;
                   3187:     struct timeval tv;
                   3188:     extern int prtactive;
                   3189: 
                   3190:     DBG_FUNC_NAME("inactive");
                   3191:     DBG_VOP_LOCKS_DECL(1);
                   3192:     DBG_VOP_PRINT_FUNCNAME();
                   3193:     DBG_VOP_PRINT_VNODE_INFO(ap->a_vp);DBG_VOP_CONT(("\n"));
                   3194: 
                   3195:     DBG_VOP_LOCKS_INIT(0,ap->a_vp, VOPDBG_LOCKED, VOPDBG_UNLOCKED, VOPDBG_UNLOCKED, VOPDBG_ZERO);
                   3196: 
                   3197:     /*
                   3198:         NOTE: vnodes need careful handling because fork vnodes that failed to be created
                   3199:               in their entirity could be getting cleaned up here, in which case h_meta == NULL...
                   3200:      */
                   3201:     if (prtactive && vp->v_usecount <= 0)
                   3202:         vprint("hfs_inactive: pushing active", vp);
                   3203: 
                   3204:     if (vp->v_usecount != 0)
                   3205:         DBG_VOP(("%s: bad usecount = %d\n",funcname,vp->v_usecount ));
                   3206: 
                   3207:     /* 
                   3208:         * Skip all complex nodes 
                   3209:         * At this point, there should be no fork nodes existing for its complex 
                   3210:         */
                   3211:     if (vp->v_type == VCPLX) {
                   3212: #if DIAGNOSTIC
                   3213:         if (vp->v_usecount == 0) {
                   3214:             struct vnode *tvp;
                   3215:             tvp  = hfs_vhashget(hp->h_dev, H_FILEID(hp), kDataFork);
                   3216:             DBG_ASSERT(tvp == NULL);
                   3217:             if (tvp)
                   3218:                 vput (tvp);
                   3219:             tvp  = hfs_vhashget(hp->h_dev, H_FILEID(hp), kRsrcFork);
                   3220:             DBG_ASSERT(tvp == NULL);
                   3221:             if (tvp)
                   3222:                 vput (tvp);
                   3223:         }
                   3224: #endif /* DIAGNOSTIC */
                   3225:         hp->h_meta->h_mode = 0;                                /* Makes the node go away */
                   3226:         goto out;
                   3227:     }
                   3228: 
                   3229:        /*
                   3230:      * Ignore inodes related to stale file handles.
                   3231:      */
                   3232:     if ((vp->v_type == VNON) || (hp->h_meta->h_mode == 0))
                   3233:         goto out;
                   3234:        
                   3235:     if (hp->h_meta->h_nodeflags & (IN_ACCESS | IN_CHANGE | IN_MODIFIED | IN_UPDATE)) {
                   3236:         tv = time;
                   3237:         VOP_UPDATE(vp, &tv, &tv, 0);
                   3238:     }
                   3239: 
                   3240: out:
                   3241:     VOP_UNLOCK(vp, 0, p);
                   3242:     /*
                   3243:      * If we are done with the inode, reclaim it
                   3244:      * so that it can be reused immediately.
                   3245:      */
                   3246:     if ((vp->v_type == VNON) || (hp->h_meta->h_mode == 0))
                   3247:         vrecycle(vp, (struct slock *)0, p);
                   3248: 
                   3249:     DBG_VOP_LOCKS_TEST(E_NONE);
                   3250:     return (E_NONE);
                   3251: }
                   3252: 
                   3253: /*
                   3254:  Ignored since the locks are gone......
                   3255: #% reclaim     vp      U I I
                   3256: #
                   3257:  vop_reclaim {
                   3258:      IN struct vnode *vp;
                   3259:      IN struct proc *p;
                   3260: 
                   3261:      */
                   3262: 
                   3263: static int
                   3264: hfs_reclaim(ap)
                   3265: struct vop_reclaim_args /* {
                   3266:     struct vnode *a_vp;
                   3267: } */ *ap;
                   3268: {
                   3269:     struct vnode *vp = ap->a_vp;
                   3270:     struct vnode *tp = NULL;
                   3271:     struct hfsnode *hp = VTOH(vp);
                   3272:     extern int prtactive;
                   3273:     DBG_FUNC_NAME("reclaim");
                   3274:     DBG_VOP_LOCKS_DECL(1);
                   3275:     DBG_VOP_PRINT_FUNCNAME();
                   3276:     DBG_VOP_PRINT_VNODE_INFO(ap->a_vp);DBG_VOP_CONT(("\n"));
                   3277: 
                   3278:     DBG_VOP_LOCKS_INIT(0, ap->a_vp, VOPDBG_UNLOCKED, VOPDBG_IGNORE, VOPDBG_IGNORE, VOPDBG_ZERO);
                   3279: 
                   3280:     /*
                   3281:         NOTE: vnodes need careful handling because fork vnodes that failed to be
                   3282:               created in their entirity could be getting cleaned up here, in which
                   3283:               case v_type == VNON and h_meta == NULL...
                   3284:      */
                   3285: 
                   3286:     if (prtactive && vp->v_usecount != 0)
                   3287:         vprint("hfs_reclaim(): pushing active", vp);
                   3288: 
                   3289:     hfs_vhashrem(hp);  
                   3290: 
                   3291:     /* release the file meta */
                   3292:     if ((vp->v_type == VREG) || (vp->v_type == VLNK)) {
                   3293:         DBG_ASSERT(hp->h_meta != NULL);
                   3294: 
                   3295:         if (H_FORKTYPE(hp) == kSysFile) {
                   3296:             /* XXX SER Here we release meta for kSysFile, which do not need it!!! */
                   3297:             FREE(hp->h_meta, M_HFSNODE);
                   3298:             hp->h_meta = NULL;
                   3299:         }
                   3300:         else {
                   3301:             HFSFILEMETA_LOCK_EXCLUSIVE(hp, CURRENT_PROC);
                   3302:             hp->h_meta->h_usecount--;                                                  /* XXX SER eventually remove h_usecount */
                   3303: 
                   3304:                        /*
                   3305:                         * if there are still more forks, make the fork ptr point to another
                   3306:                         */
                   3307:             if ((hp->h_meta->h_usecount > 0) && (hp->h_meta->h_fork == vp)) {
                   3308:                 hp->h_meta->h_fork = hp->h_sibling;
                   3309:                        }
                   3310:                                
                   3311: 
                   3312:             if ((H_FORKTYPE(hp) == kDataFork) && hp->h_relative) {
                   3313:                 DBG_ASSERT(VTOH(hp->h_relative)->h_relative != NULL);
                   3314:                 VTOH(hp->h_relative)->h_relative = NULL;               /* Mark the default node as NULL from a complex view */
                   3315:             };
                   3316: 
                   3317:             if (hp->h_sibling) {
                   3318:                 tp = vp;
                   3319:                 do {
                   3320:                     tp = VTOH(tp)->h_sibling;
                   3321:                 } while (VTOH(tp)->h_sibling != vp);
                   3322:                 VTOH(tp)->h_sibling = hp->h_sibling;
                   3323:                 if (VTOH(tp)->h_sibling == tp)                                 /* pointing to ourselves */
                   3324:                     VTOH(tp)->h_sibling = NULL;
                   3325:                 hp->h_sibling = NULL;
                   3326:             };
                   3327: 
                   3328:             HFSFILEMETA_UNLOCK(hp, CURRENT_PROC);
                   3329:             hp->h_meta = NULL;
                   3330: 
                   3331:             /* h_relative could be NULL, if a force unmount was done, and the complex node is already gone */
                   3332:             if (hp->h_relative) {
                   3333:                 DBG_ASSERT(H_FORKTYPE(VTOH(hp->h_relative)) == kDirCmplx);
                   3334:                 DBG_ASSERT((hp->h_relative)->v_type == VCPLX);
                   3335:                 VRELE (hp->h_relative);                                                                /* release the complex node */
                   3336:                 hp->h_relative = NULL;
                   3337:                        }
                   3338:         }
                   3339:     }
                   3340:     else if (vp->v_type == VCPLX) {
                   3341: #if DIAGNOSTIC
                   3342:                /* Unless a force unmount, no other forks should exist */
                   3343:         if (vp->v_usecount == 0) {
                   3344:             struct vnode *tvp;
                   3345:             tvp  = hfs_vhashget(hp->h_dev, H_FILEID(hp), kDataFork);
                   3346:             DBG_ASSERT(tvp == NULL);
                   3347:             if (tvp)
                   3348:                 vput (tvp);
                   3349:             tvp  = hfs_vhashget(hp->h_dev, H_FILEID(hp), kRsrcFork);
                   3350:             DBG_ASSERT(tvp == NULL);
                   3351:             if (tvp)
                   3352:                 vput (tvp);
                   3353:         }
                   3354: #endif /* DIAGNOSTIC */
                   3355: 
                   3356:         DBG_ASSERT(hp->h_meta != NULL);
                   3357:                tp = hp->h_meta->h_fork;
                   3358:                if (tp == NULL) {
                   3359:                                /* No more forks, so do nothing here */
                   3360:                     }
                   3361:                 else {
                   3362:                        /* This should only occur when a force unmount occurs */
                   3363:                        /* so, usually, no other forks should exist */
                   3364:                        VTOH(tp)->h_relative = NULL;
                   3365:                        if (VTOH(tp)->h_sibling)
                   3366:                                VTOH(VTOH(tp)->h_sibling)->h_relative = NULL;
                   3367:                        }
                   3368:                
                   3369:                  if (hp->h_meta->h_nodeflags & IN_LONGNAME) {
                   3370:                DBG_ASSERT(H_NAME(hp) != NULL);
                   3371:                        FREE(H_NAME(hp), M_HFSNODE);
                   3372:                        }
                   3373:                
                   3374:                  FREE(hp->h_meta, M_HFSNODE);
                   3375:                  hp->h_meta = NULL;
                   3376:                  hp->h_relative = NULL;
                   3377: 
                   3378:        }
                   3379:     else if (vp->v_type == VDIR) {
                   3380:         if (hp->h_meta->h_nodeflags & IN_LONGNAME)
                   3381:             FREE(H_NAME(hp), M_HFSNODE);
                   3382: 
                   3383:         FREE(hp->h_meta, M_HFSNODE);
                   3384:         hp->h_meta = NULL;
                   3385:         }
                   3386:        else
                   3387:            DBG_ASSERT(0);      /* Unexpected v_type !!!! XXX SER Change to panic */
                   3388: 
                   3389:     /*
                   3390:      * Purge old data structures associated with the inode.
                   3391:      */
                   3392:     cache_purge(vp);
                   3393:     if ((vp->v_type != VNON) && hp->h_devvp) {
                   3394:         VRELE(hp->h_devvp);
                   3395:         hp->h_devvp = 0;
                   3396:     }
                   3397: 
                   3398:     /* Free our data structs */
                   3399:     if (vp->v_type != VNON) {
                   3400:         DBG_ASSERT(hp->h_sibling == NULL);
                   3401:         DBG_ASSERT(hp->h_relative == NULL);
                   3402:         DBG_ASSERT(hp->h_meta == NULL);
                   3403:         FREE(hp->h_xfcb, M_HFSNODE);
                   3404:         FREE(vp->v_data, M_HFSNODE);
                   3405:     };
                   3406:     vp->v_data = NULL;
                   3407: 
                   3408:     DBG_VOP_LOCKS_TEST(E_NONE);
                   3409:     return (E_NONE);
                   3410: }
                   3411: 
                   3412: 
                   3413: /*
                   3414:  * Lock an hfsnode. If its already locked, set the WANT bit and sleep.
                   3415: #% lock                vp      U L U
                   3416: #
                   3417:  vop_lock {
                   3418:      IN struct vnode *vp;
                   3419:      IN int flags;
                   3420:      IN struct proc *p;
                   3421:      */
                   3422: 
                   3423: static int
                   3424: hfs_lock(ap)
                   3425: struct vop_lock_args /* {
                   3426:     struct vnode *a_vp;
                   3427:     int a_flags;
                   3428:     struct proc *a_p;
                   3429: } */ *ap;
                   3430: {
                   3431:     struct vnode * vp = ap->a_vp;
                   3432:     struct hfsnode *hp = VTOH(ap->a_vp);
                   3433:     int                        retval;
                   3434: 
                   3435:     DBG_FUNC_NAME("lock");
                   3436:     DBG_VOP_LOCKS_DECL(1);
                   3437:     DBG_VOP_PRINT_FUNCNAME();DBG_VOP_CONT((" "));
                   3438:     DBG_VOP_PRINT_VNODE_INFO(ap->a_vp);DBG_VOP_CONT((" flags = 0x%08X.\n", ap->a_flags));
                   3439:     DBG_VOP_LOCKS_INIT(0,ap->a_vp, VOPDBG_UNLOCKED, VOPDBG_LOCKED, VOPDBG_UNLOCKED, VOPDBG_ZERO);
                   3440: 
                   3441: #if DIAGNOSTIC
                   3442:     DBG_ASSERT(hp != (struct hfsnode *)NULL);
                   3443:     if (ap->a_flags & LK_INTERLOCK) {
                   3444:         DBG_ASSERT(*((int*)&vp->v_interlock) != 0);
                   3445:     } else {
                   3446:         DBG_ASSERT(*((int*)&vp->v_interlock) == 0);
                   3447:     };
                   3448:     if (H_FORKTYPE(hp) != kDirCmplx && (vp->v_flag & VSYSTEM) == 0) {
                   3449:         DBG_ASSERT(hp->h_meta != NULL);
                   3450:         if ((lockstatus(&hp->h_meta->h_fmetalock)) != (lockstatus(&hp->h_lock)))
                   3451:             DBG_VOP(("hfs_lock: Warning, mismatched locks. h_lock = %d.meta = %d\n", lockstatus(&hp->h_lock),                                                                  lockstatus(&hp->h_meta->h_fmetalock)));
                   3452:     }
                   3453: 
                   3454:     /* Attempting to lock the vnode */
                   3455:     if (lockstatus(&hp->h_lock) && ((ap->a_flags & LK_NOWAIT) == 0)) {
                   3456:         DBG_VOP(("hfs_lock: waiting for vnode lock (forkype = %d)...\n", H_FORKTYPE(hp)));
                   3457:     };
                   3458: #endif /* DIAGNOSTIC */
                   3459: 
                   3460:     retval = lockmgr(&hp->h_lock, ap->a_flags, &vp->v_interlock, ap->a_p);
                   3461:     if (retval != E_NONE) {
                   3462:         if ((ap->a_flags & LK_NOWAIT) == 0)
                   3463:             DBG_ERR(("hfs_lock: error %d trying to lock vnode (flags = 0x%08X).\n", retval, ap->a_flags));
                   3464:         goto Err_Exit;
                   3465:     };
                   3466: 
                   3467:     /* Now get a lock on the file meta lock if necessary */
                   3468:     if (H_FORKTYPE(hp) != kDirCmplx && (vp->v_flag & VSYSTEM) == 0) {
                   3469:         if (lockstatus(&hp->h_meta->h_fmetalock) && ((ap->a_flags & LK_NOWAIT) == 0))
                   3470:             DBG_VOP(("hfs_lock: waiting for meta-data lock...\n"));
                   3471: 
                   3472:         retval = lockmgr(&hp->h_meta->h_fmetalock, ap->a_flags & ~LK_INTERLOCK, (simple_lock_t) 0, ap->a_p);
                   3473:         if (retval != E_NONE) {
                   3474:             if ((ap->a_flags & LK_NOWAIT) == 0) {
                   3475:                 DBG_ERR(("hfs_lock: error %d trying to lock meta-data (flags = 0x%08X).\n", retval, ap->a_flags));
                   3476:             };
                   3477:             (void)lockmgr(&hp->h_lock, LK_RELEASE, (simple_lock_t) 0, ap->a_p);
                   3478:         };
                   3479:     };
                   3480: 
                   3481: Err_Exit:;
                   3482:     DBG_ASSERT(*((int*)&vp->v_interlock) == 0);
                   3483:     DBG_VOP_LOCKS_TEST(retval);
                   3484:     return (retval);
                   3485: }
                   3486: 
                   3487: /*
                   3488:  * Unlock an hfsnode.
                   3489: #% unlock      vp      L U L
                   3490: #
                   3491:  vop_unlock {
                   3492:      IN struct vnode *vp;
                   3493:      IN int flags;
                   3494:      IN struct proc *p;
                   3495: 
                   3496:      */
                   3497: int
                   3498: hfs_unlock(ap)
                   3499: struct vop_unlock_args /* {
                   3500:     struct vnode *a_vp;
                   3501:     int a_flags;
                   3502:     struct proc *a_p;
                   3503: } */ *ap;
                   3504: {
                   3505:     struct hfsnode *hp = VTOH(ap->a_vp);
                   3506:     struct vnode *vp = ap->a_vp;
                   3507:     int                retval = E_NONE;
                   3508: 
                   3509:     DBG_FUNC_NAME("unlock");
                   3510:     DBG_VOP_LOCKS_DECL(1);
                   3511:     DBG_VOP_PRINT_FUNCNAME();
                   3512:     DBG_VOP_PRINT_VNODE_INFO(vp);DBG_VOP_CONT((" flags = 0x%08X.\n", ap->a_flags));
                   3513:     DBG_VOP_LOCKS_INIT(0,vp, VOPDBG_LOCKED, VOPDBG_UNLOCKED, VOPDBG_LOCKED, VOPDBG_ZERO);
                   3514: 
                   3515: #if DIAGNOSTIC
                   3516:     DBG_ASSERT(hp != (struct hfsnode *)NULL);
                   3517:     if (ap->a_flags & LK_INTERLOCK) {
                   3518:         DBG_ASSERT(*((int*)&vp->v_interlock) != 0);
                   3519:     } else {
                   3520:         DBG_ASSERT(*((int*)&vp->v_interlock) == 0);
                   3521:     };
                   3522:     if (H_FORKTYPE(hp) != kDirCmplx && (vp->v_flag & VSYSTEM) == 0) {
                   3523:         DBG_ASSERT(hp->h_meta != NULL);
                   3524:     };
                   3525: #endif /* DIAGNOSTIC */
                   3526: 
                   3527:     DBG_ASSERT((ap->a_flags & (LK_EXCLUSIVE|LK_SHARED)) == 0);
                   3528:     retval = lockmgr(&hp->h_lock, ap->a_flags | LK_RELEASE, &vp->v_interlock, ap->a_p);
                   3529:     if (retval != E_NONE) {
                   3530:         DEBUG_BREAK_MSG(("hfs_unlock: error %d trying to unlock vnode (forktype = %d).\n", retval, H_FORKTYPE(hp)));
                   3531:     };
                   3532: 
                   3533:     DBG_ASSERT(*((int*)&vp->v_interlock) == 0);
                   3534: 
                   3535:     /* Release lock on the file meta lock */
                   3536:     if ((retval == E_NONE) && (H_FORKTYPE(hp) != kDirCmplx) && ((vp->v_flag & VSYSTEM) == 0)) {
                   3537:         retval = lockmgr(&hp->h_meta->h_fmetalock, (ap->a_flags & ~LK_INTERLOCK) | LK_RELEASE, (simple_lock_t) 0, ap->a_p);
                   3538:         if (retval != E_NONE) {
                   3539:             /* XXX PPD Wouldn't this be the perfect time to panic?  We're now half-unlocked! */
                   3540:             DEBUG_BREAK_MSG(("hfs_unlock: error %d trying to unlock meta-data (forktype = %d).\n", retval, H_FORKTYPE(hp)));
                   3541:         };
                   3542:     };
                   3543: 
                   3544:     DBG_ASSERT(*((int*)&vp->v_interlock) == 0);
                   3545:     DBG_VOP_LOCKS_TEST(retval);
                   3546:     return (retval);
                   3547: }
                   3548: 
                   3549: 
                   3550: /*
                   3551:  * Print out the contents of an hfsnode.
                   3552: #% print       vp      = = =
                   3553: #
                   3554:  vop_print {
                   3555:      IN struct vnode *vp;
                   3556:      */
                   3557: int
                   3558: hfs_print(ap)
                   3559: struct vop_print_args /* {
                   3560:     struct vnode *a_vp;
                   3561: } */ *ap;
                   3562: {
                   3563:     register struct vnode * vp = ap->a_vp;
                   3564:     register struct hfsnode *hp = VTOH( vp);
                   3565:     DBG_FUNC_NAME("print");
                   3566:     DBG_VOP_LOCKS_DECL(1);
                   3567:     DBG_VOP_PRINT_FUNCNAME();
                   3568:     DBG_VOP_PRINT_VNODE_INFO(ap->a_vp);
                   3569: 
                   3570:     DBG_VOP_LOCKS_INIT(0,ap->a_vp, VOPDBG_IGNORE, VOPDBG_IGNORE, VOPDBG_IGNORE, VOPDBG_POS);
                   3571: 
                   3572:     printf("tag VT_HFS, dirID %ld, on dev %d, %d", H_DIRID(hp),
                   3573:            major(hp->h_dev), minor(hp->h_dev));
                   3574:     /* lockmgr_printinfo(&hp->h_lock); */
                   3575:     printf("\n");
                   3576:     DBG_VOP_LOCKS_TEST(E_NONE);
                   3577:     return (E_NONE);
                   3578: }
                   3579: 
                   3580: 
                   3581: /*
                   3582:  * Check for a locked hfsnode.
                   3583: #% islocked    vp      = = =
                   3584: #
                   3585:  vop_islocked {
                   3586:      IN struct vnode *vp;
                   3587: 
                   3588:      */
                   3589: int
                   3590: hfs_islocked(ap)
                   3591: struct vop_islocked_args /* {
                   3592:     struct vnode *a_vp;
                   3593: } */ *ap;
                   3594: {
                   3595:     int                lockStatus;
                   3596:     //DBG_FUNC_NAME("islocked");
                   3597:     //DBG_VOP_LOCKS_DECL(1);
                   3598:     //DBG_VOP_PRINT_FUNCNAME();
                   3599:     //DBG_VOP_PRINT_VNODE_INFO(ap->a_vp);
                   3600: 
                   3601:     //DBG_VOP_LOCKS_INIT(0,ap->a_vp, VOPDBG_IGNORE, VOPDBG_IGNORE, VOPDBG_IGNORE, VOPDBG_ZERO);
                   3602: 
                   3603:     lockStatus = lockstatus(&VTOH( ap->a_vp)->h_lock);
                   3604:     //DBG_VOP_LOCKS_TEST(E_NONE);
                   3605:     return (lockStatus);
                   3606: }
                   3607: 
                   3608: /*
                   3609: 
                   3610: #% pathconf    vp      L L L
                   3611: #
                   3612:  vop_pathconf {
                   3613:      IN struct vnode *vp;
                   3614:      IN int name;
                   3615:      OUT register_t *retval;
                   3616: 
                   3617:      */
                   3618: static int
                   3619: hfs_pathconf(ap)
                   3620: struct vop_pathconf_args /* {
                   3621:     struct vnode *a_vp;
                   3622:     int a_name;
                   3623:     int *a_retval;
                   3624: } */ *ap;
                   3625: {
                   3626:     int retval = E_NONE;
                   3627:     DBG_FUNC_NAME("pathconf");
                   3628:     DBG_VOP_LOCKS_DECL(1);
                   3629:     DBG_VOP_PRINT_FUNCNAME();
                   3630:     DBG_VOP_PRINT_VNODE_INFO(ap->a_vp);
                   3631: 
                   3632:     DBG_VOP_LOCKS_INIT(0,ap->a_vp, VOPDBG_LOCKED, VOPDBG_LOCKED, VOPDBG_LOCKED, VOPDBG_POS);
                   3633: 
                   3634:     DBG_HFS_NODE_CHECK (ap->a_vp);
                   3635: 
                   3636:     switch (ap->a_name) {
                   3637:         case _PC_LINK_MAX:
                   3638:             *ap->a_retval = 1;
                   3639:             break;
                   3640:         case _PC_NAME_MAX:
                   3641:             *ap->a_retval = NAME_MAX;
                   3642:             break;
                   3643:         case _PC_PATH_MAX:
                   3644:             *ap->a_retval = PATH_MAX; /* 1024 */
                   3645:             break;
                   3646:         case _PC_CHOWN_RESTRICTED:
                   3647:             *ap->a_retval = 1;
                   3648:             break;
                   3649:         case _PC_NO_TRUNC:
                   3650:             *ap->a_retval = 0;
                   3651:             break;
                   3652:         default:
                   3653:             retval = EINVAL;
                   3654:     }
                   3655: 
                   3656:     DBG_VOP_LOCKS_TEST(retval);
                   3657:     return (retval);
                   3658: }
                   3659: 
                   3660: 
                   3661: 
                   3662: 
                   3663: 
                   3664: /*
                   3665:  * Advisory record locking support
                   3666: #% advlock     vp      U U U
                   3667: #
                   3668:  vop_advlock {
                   3669:      IN struct vnode *vp;
                   3670:      IN caddr_t id;
                   3671:      IN int op;
                   3672:      IN struct flock *fl;
                   3673:      IN int flags;
                   3674: 
                   3675:      */
                   3676: int
                   3677: hfs_advlock(ap)
                   3678: struct vop_advlock_args /* {
                   3679:     struct vnode *a_vp;
                   3680:     caddr_t  a_id;
                   3681:     int  a_op;
                   3682:     struct flock *a_fl;
                   3683:     int  a_flags;
                   3684: } */ *ap;
                   3685: {
                   3686:     register struct hfsnode *hp = VTOH(ap->a_vp);
                   3687:     register struct flock *fl = ap->a_fl;
                   3688:     register struct hfslockf *lock;
                   3689:     off_t start, end;
                   3690:     int retval;
                   3691:     DBG_FUNC_NAME("advlock");
                   3692:     DBG_VOP_LOCKS_DECL(1);
                   3693:     DBG_VOP_PRINT_FUNCNAME();
                   3694:     DBG_VOP_PRINT_VNODE_INFO(ap->a_vp);DBG_VOP(("\n"));
                   3695:     DBG_VOP_LOCKS_INIT(0,ap->a_vp, VOPDBG_UNLOCKED, VOPDBG_UNLOCKED, VOPDBG_UNLOCKED, VOPDBG_POS);
                   3696:     /*
                   3697:      * Avoid the common case of unlocking when inode has no locks.
                   3698:      */
                   3699:     if (hp->h_lockf == (struct hfslockf *)0) {
                   3700:         if (ap->a_op != F_SETLK) {
                   3701:             fl->l_type = F_UNLCK;
                   3702:             return (0);
                   3703:         }
                   3704:     }
                   3705:     /*
                   3706:      * Convert the flock structure into a start and end.
                   3707:      */
                   3708:     start = 0;
                   3709:     switch (fl->l_whence) {
                   3710:         case SEEK_SET:
                   3711:         case SEEK_CUR:
                   3712:             /*
                   3713:              * Caller is responsible for adding any necessary offset
                   3714:              * when SEEK_CUR is used.
                   3715:              */
                   3716:             start = fl->l_start;
                   3717:             break;
                   3718: 
                   3719:         case SEEK_END:
                   3720:             start = HTOFCB(hp)->fcbEOF + fl->l_start;
                   3721:             break;
                   3722: 
                   3723:         default:
                   3724:             return (EINVAL);
                   3725:     }
                   3726: 
                   3727:     if (start < 0)
                   3728:         return (EINVAL);
                   3729:     if (fl->l_len == 0)
                   3730:         end = -1;
                   3731:     else
                   3732:         end = start + fl->l_len - 1;
                   3733: 
                   3734:     /*
                   3735:      * Create the hfslockf structure
                   3736:      */
                   3737:     MALLOC(lock, struct hfslockf *, sizeof *lock, M_LOCKF, M_WAITOK);
                   3738:     lock->lf_start = start;
                   3739:     lock->lf_end = end;
                   3740:     lock->lf_id = ap->a_id;
                   3741:     lock->lf_hfsnode = hp;
                   3742:     lock->lf_type = fl->l_type;
                   3743:     lock->lf_next = (struct hfslockf *)0;
                   3744:     TAILQ_INIT(&lock->lf_blkhd);
                   3745:     lock->lf_flags = ap->a_flags;
                   3746:     /*
                   3747:      * Do the requested operation.
                   3748:      */
                   3749:     switch(ap->a_op) {
                   3750:         case F_SETLK:
                   3751:             retval = hfs_setlock(lock);
                   3752:             break;
                   3753: 
                   3754:         case F_UNLCK:
                   3755:             retval = hfs_clearlock(lock);
                   3756:             FREE(lock, M_LOCKF);
                   3757:             break;
                   3758: 
                   3759:         case F_GETLK:
                   3760:             retval = hfs_getlock(lock, fl);
                   3761:             FREE(lock, M_LOCKF);
                   3762:             break;
                   3763: 
                   3764:         default:
                   3765:             retval = EINVAL;
                   3766:             _FREE(lock, M_LOCKF);
                   3767:             break;
                   3768:     }
                   3769: 
                   3770:     DBG_VOP_LOCKS_TEST(retval);
                   3771:     return (retval);
                   3772: }
                   3773: 
                   3774: 
                   3775: 
                   3776: /*
                   3777:  * Update the access, modified, and node change times as specified by the
                   3778:  * IACCESS, IUPDATE, and ICHANGE flags respectively. The IMODIFIED flag is
                   3779:  * used to specify that the node needs to be updated but that the times have
                   3780:  * already been set. The access and modified times are taken from the second
                   3781:  * and third parameters; the node change time is always taken from the current
                   3782:  * time. If waitfor is set, then wait for the disk write of the node to
                   3783:  * complete.
                   3784:  */
                   3785: /*
                   3786: #% update      vp      L L L
                   3787:        IN struct vnode *vp;
                   3788:        IN struct timeval *access;
                   3789:        IN struct timeval *modify;
                   3790:        IN int waitfor;
                   3791: */
                   3792: 
                   3793: int
                   3794: hfs_update(ap)
                   3795:     struct vop_update_args /* {
                   3796:         struct vnode *a_vp;
                   3797:         struct timeval *a_access;
                   3798:         struct timeval *a_modify;
                   3799:         int a_waitfor;
                   3800:     } */ *ap;
                   3801: {
                   3802:     struct hfsnode     *hp;
                   3803:     struct proc        *p;
                   3804:     CatalogNodeData nodeData;
                   3805:     FSSpec                     nodeSpec;       /* 264 bytes */
                   3806:     int                        retval;
                   3807:     DBG_FUNC_NAME("update");
                   3808:     DBG_VOP_LOCKS_DECL(1);
                   3809:     DBG_VOP_PRINT_FUNCNAME();
                   3810:     DBG_VOP_PRINT_VNODE_INFO(ap->a_vp);DBG_VOP_CONT(("\n"));
                   3811:     DBG_VOP_LOCKS_INIT(0,ap->a_vp, VOPDBG_LOCKED, VOPDBG_LOCKED, VOPDBG_LOCKED, VOPDBG_ZERO);
                   3812: 
                   3813:     hp = VTOH(ap->a_vp);
                   3814: 
                   3815:     DBG_ASSERT(*((int*)&ap->a_vp->v_interlock) == 0);
                   3816:     DBG_ASSERT(ap->a_vp->v_type != VCPLX);
                   3817:     if (ap->a_vp->v_type == VCPLX) {   //XXX SER Shoulf never be true, change to a panic before ship
                   3818:         DBG_VOP_LOCKS_TEST(0);
                   3819:                return (0);
                   3820:     };
                   3821: 
                   3822:     if (H_FORKTYPE(hp) == kSysFile) {
                   3823:         hp->h_meta->h_nodeflags &= ~(IN_ACCESS | IN_CHANGE | IN_MODIFIED | IN_UPDATE);
                   3824:         DBG_VOP_LOCKS_TEST(0);
                   3825:         return (0);
                   3826:     }
                   3827: 
                   3828:     if (VTOVFS(ap->a_vp)->mnt_flag & MNT_RDONLY) {
                   3829:         hp->h_meta->h_nodeflags &= ~(IN_ACCESS | IN_CHANGE | IN_MODIFIED | IN_UPDATE);
                   3830:         DBG_VOP_LOCKS_TEST(0);
                   3831:         DBG_VOP(("hfs_update: returning 0 (all flags were cleared because the volume is read-only.\n"));
                   3832:         return (0);
                   3833:     }
                   3834:        
                   3835:     /* Check to see if MacOS set the fcb to be dirty, if so, translate it to IN_MODIFIED */
                   3836:     if (HTOFCB(hp)->fcbFlags &fcbModifiedMask)
                   3837:         hp->h_meta->h_nodeflags |= IN_MODIFIED;
                   3838: 
                   3839:     if ((hp->h_meta->h_nodeflags & (IN_ACCESS | IN_CHANGE | IN_MODIFIED | IN_UPDATE)) == 0) {
                   3840:         DBG_VOP_LOCKS_TEST(0);
                   3841:         DBG_VOP(("hfs_update: returning 0 because the metadata is unchanged.\n"));
                   3842:         return (0);
                   3843:     };
                   3844: 
                   3845:     if (hp->h_meta->h_nodeflags & IN_ACCESS)
                   3846:         hp->h_meta->h_atime = ap->a_access->tv_sec;
                   3847:     if (hp->h_meta->h_nodeflags & IN_UPDATE)
                   3848:         hp->h_meta->h_mtime = ap->a_modify->tv_sec;
                   3849:     if (hp->h_meta->h_nodeflags & IN_CHANGE) {
                   3850:         hp->h_meta->h_ctime = time.tv_sec;
                   3851:                /*
                   3852:                 * HFS dates that WE set must be adjusted for DST
                   3853:                 */
                   3854:                if ((HTOVCB(hp)->vcbSigWord == kHFSSigWord) && gTimeZone.tz_dsttime) {
                   3855:                        hp->h_meta->h_ctime += 3600;
                   3856:                        hp->h_meta->h_mtime = hp->h_meta->h_ctime;
                   3857:                }
                   3858:        }
                   3859: 
                   3860:        p = CURRENT_PROC;
                   3861:        /*
                   3862:         * Since VOP_UPDATE can be called from withing another VOP (eg VOP_RENAME),
                   3863:         * the Catalog b-tree may aready be locked by the current thread. So we
                   3864:         * allow recursive locking of the Catalog from within VOP_UPDATE.
                   3865:         */
                   3866: 
                   3867:        /* Lock the Catalog b-tree file */
                   3868:        retval = hfs_metafilelocking(HTOHFS(hp), kHFSCatalogFileID, LK_EXCLUSIVE | LK_CANRECURSE, p);
                   3869:        if (retval) {
                   3870:         DBG_VOP_LOCKS_TEST(retval);
                   3871:         DBG_ASSERT(*((int*)&ap->a_vp->v_interlock) == 0);
                   3872:         return (retval);
                   3873:     };
                   3874:     DBG_ASSERT(*((int*)&ap->a_vp->v_interlock) == 0);
                   3875: 
                   3876:     retval = GetCatalogNode(HTOVCB(hp), H_DIRID(hp), H_NAME(hp), H_HINT(hp), &nodeSpec, &nodeData, &(H_HINT(hp)));
                   3877:     if (retval != noErr) {
                   3878:         DBG_ERR(("hfs_update: error %d on GetCatalogNode...\n", retval));
                   3879:         retval = MacToVFSError(retval);
                   3880:         goto exit_relse;
                   3881:     };
                   3882: 
                   3883:        /* If there is a sibling (resource fork), copy its contents first */
                   3884:        /* This makes sure all changes in the FCB are reflected. i.e. LEOF, etc */
                   3885:        if (hp->h_sibling)
                   3886:        CopyVNodeToCatalogNode (hp->h_sibling, &nodeData);
                   3887: 
                   3888:     CopyVNodeToCatalogNode (HTOV(hp), &nodeData);
                   3889: 
                   3890:     retval = UpdateCatalogNode(HTOVCB(hp), H_DIRID(hp), H_NAME(hp), H_HINT(hp), &nodeData);
                   3891:     if (retval != noErr) {
                   3892:                DBG_ERR(("hfs_update: error %d on UpdateCatalogNode...\n", retval));
                   3893:         retval = MacToVFSError(retval);
                   3894:         goto exit_relse;
                   3895:     };
                   3896: 
                   3897:        /* After the updates are finished, clear the flags */
                   3898:     hp->h_meta->h_nodeflags &= ~(IN_ACCESS | IN_CHANGE | IN_MODIFIED | IN_UPDATE);
                   3899:        HTOFCB(hp)->fcbFlags &= ~fcbModifiedMask;
                   3900: 
                   3901:        /* Update general data */
                   3902:     if (ap->a_vp->v_type == VDIR) {
                   3903:         hp->h_size = sizeof (hfsdirentry) * (nodeData.valence + 2);
                   3904:        }
                   3905:        else {
                   3906:         hp->h_size = nodeData.rsrcPhysicalSize + nodeData.dataPhysicalSize;
                   3907:        }
                   3908: 
                   3909: 
                   3910: exit_relse:    
                   3911:         /* unlock the Catalog b-tree file */
                   3912:        (void) hfs_metafilelocking(HTOHFS(hp), kHFSCatalogFileID, LK_RELEASE, p);
                   3913: 
                   3914:     DBG_VOP(("hfs_update: returning %d.\n", retval));
                   3915:     DBG_VOP_LOCKS_TEST(retval);
                   3916:     DBG_ASSERT(*((int*)&ap->a_vp->v_interlock) == 0);
                   3917:        return (retval);
                   3918: }
                   3919: 
                   3920: 
                   3921: 
                   3922: 
                   3923: /*
                   3924:  * Allocate a new node
                   3925:  *
                   3926:  * Assumes that the catalog b-tree is locked
                   3927:  *
                   3928:  * Upon leaving, namei buffer must be freed.
                   3929:  *
                   3930:  */
                   3931: static int
                   3932: hfs_makenode(mode, dvp, vpp, cnp)
                   3933:     int mode;
                   3934:     struct vnode *dvp;
                   3935:     struct vnode **vpp;
                   3936:     struct componentname *cnp;
                   3937: {
                   3938:     register struct hfsnode *hp, *parhp;
                   3939:     struct timeval                     tv;
                   3940:     struct vnode                       *tvp;
                   3941:     struct hfsCatalogInfo      catInfo;
                   3942:     ExtendedVCB                                *vcb;
                   3943:     UInt8                                      forkType;
                   3944:     int                                        retval;
                   3945:     DBG_FUNC_NAME("makenode");
                   3946: 
                   3947:     parhp      = VTOH(dvp);
                   3948:     vcb                = HTOVCB(parhp);
                   3949:     *vpp       = NULL;
                   3950:        tvp     = NULL;
                   3951:     if ((mode & IFMT) == 0)
                   3952:         mode |= IFREG;
                   3953: 
                   3954: #if DIAGNOSTIC
                   3955:     if ((cnp->cn_flags & HASBUF) == 0)
                   3956:         panic("hfs_makenode: no name");
                   3957: #endif
                   3958: 
                   3959:     /* Create the Catalog B*-Tree entry */
                   3960:     retval = hfsCreate(vcb, H_FILEID(parhp), cnp->cn_nameptr, mode);
                   3961:     if (retval != E_NONE) {
                   3962:         DBG_ERR(("%s: hfsCreate FAILED: %s, %s\n", funcname, cnp->cn_nameptr, H_NAME(parhp)));
                   3963:         goto bad1;
                   3964:     }
                   3965: 
                   3966:     /* Look up the catalog entry just created: */
                   3967:     retval = hfsLookup(vcb, H_FILEID(parhp), cnp->cn_nameptr, cnp->cn_namelen, 0, &catInfo);
                   3968:     if (retval != E_NONE) {
                   3969:         DBG_ERR(("%s: hfsLookup FAILED: %s, %s\n", funcname, cnp->cn_nameptr, H_NAME(parhp)));
                   3970:         goto bad1;
                   3971:     }
                   3972: 
                   3973:     /* Create a vnode for the object just created: */
                   3974:     forkType = (catInfo.nodeData.nodeType == kCatalogFolderNode) ? kDirCmplx : kDataFork;
                   3975:     if ((retval = hfsGet(vcb, &catInfo, forkType, dvp, &tvp))) {
                   3976:         goto bad1;
                   3977:     }
                   3978: 
                   3979:     /* Set other vnode values not init'd in getnewvnode(). */
                   3980:     tvp->v_type = IFTOVT(mode);
                   3981: 
                   3982:        /* reinit hp from the passed in mode, only if hfsplus */
                   3983:     if (vcb->vcbSigWord == kHFSPlusSigWord) {
                   3984:         hp = VTOH(tvp);
                   3985:         hp->h_meta->h_gid = parhp->h_meta->h_gid;
                   3986:         if ((mode & IFMT) == IFLNK)
                   3987:             hp->h_meta->h_uid = parhp->h_meta->h_uid;
                   3988:         else
                   3989:             hp->h_meta->h_uid = cnp->cn_cred->cr_uid;
                   3990: 
                   3991:         hp->h_meta->h_nodeflags &= ~IN_UNSETACCESS;
                   3992:         hp->h_meta->h_nodeflags |= IN_ACCESS | IN_CHANGE | IN_UPDATE;
                   3993: 
                   3994:         hp->h_meta->h_mode = mode;
                   3995:         if ((hp->h_meta->h_mode & ISGID) && !groupmember(hp->h_meta->h_gid, cnp->cn_cred) &&
                   3996:             suser(cnp->cn_cred, NULL))
                   3997:             hp->h_meta->h_mode &= ~ISGID;
                   3998: 
                   3999:         if (cnp->cn_flags & ISWHITEOUT)
                   4000:             hp->h_meta->h_pflags |= UF_OPAQUE;
                   4001: 
                   4002:         /* Write out the new values */
                   4003:         tv = time;
                   4004:         if ((retval = VOP_UPDATE(tvp, &tv, &tv, 1)))
                   4005:             goto bad2;
                   4006:     }
                   4007: 
                   4008:        VTOH(dvp)->h_meta->h_nodeflags |= IN_CHANGE | IN_UPDATE;
                   4009:     tv = time;
                   4010:     if ((retval = VOP_UPDATE(dvp, &tv, &tv, 1)))
                   4011:         goto bad2;
                   4012: 
                   4013:     if ((cnp->cn_flags & (HASBUF | SAVESTART)) == HASBUF) {
                   4014:         FREE_ZONE(cnp->cn_pnbuf, cnp->cn_pnlen, M_NAMEI);
                   4015:     };
                   4016:     VPUT(dvp);
                   4017: #if MACH_NBC
                   4018:     if ((tvp->v_type == VREG)  && !(tvp->v_vm_info)){
                   4019:         vm_info_init(tvp);
                   4020:     }
                   4021: #endif /* MACH_NBC */
                   4022:     *vpp = tvp;
                   4023:     return (0);
                   4024: 
                   4025: bad2:
                   4026:     /*
                   4027:      * Write retval occurred trying to update the node
                   4028:      * or the directory so must deallocate the node.
                   4029:     */
                   4030:     /* XXX SER In the future maybe set *vpp to 0xdeadbeef for testing */
                   4031:     VPUT(tvp);
                   4032: 
                   4033: bad1:
                   4034:     if ((cnp->cn_flags & (HASBUF | SAVESTART)) == HASBUF) {
                   4035:         FREE_ZONE(cnp->cn_pnbuf, cnp->cn_pnlen, M_NAMEI);
                   4036:     };
                   4037:     VPUT(dvp);
                   4038: 
                   4039:     return (retval);
                   4040: 
                   4041: }
                   4042: 
                   4043: 
                   4044: /************************************************************************/
                   4045: /*     Entry for searchfs()                                                                                            */
                   4046: /************************************************************************/
                   4047: 
                   4048: #define        errSearchBufferFull     101             //      Internal search errors
                   4049: /*
                   4050: #
                   4051: #% searchfs    vp      L L L
                   4052: #
                   4053: vop_searchfs {
                   4054:     IN struct vnode *vp;
                   4055:     IN off_t length;
                   4056:     IN int flags;
                   4057:     IN struct ucred *cred;
                   4058:     IN struct proc *p;
                   4059: };
                   4060: */
                   4061: 
                   4062: //XXX  Optimize this call for calls being made from VDI
                   4063: int    hfs_search( ap )
                   4064: struct vop_searchfs_args *ap; /*
                   4065:  struct vnodeop_desc *a_desc;
                   4066:  struct vnode *a_vp;
                   4067:  void *a_searchparams1;
                   4068:  void *a_searchparams2;
                   4069:  struct attrlist *a_searchattrs;
                   4070:  u_long a_maxmatches;
                   4071:  struct timeval *a_timelimit;
                   4072:  struct attrlist *a_returnattrs;
                   4073:  u_long *a_nummatches;
                   4074:  u_long a_scriptcode;
                   4075:  u_long a_options;
                   4076:  struct uio *a_uio;
                   4077:  struct searchstate *a_searchstate;
                   4078: */
                   4079: {
                   4080:        CatalogRecord           catalogRecord;
                   4081:        BTreeKey                        *key;
                   4082:        FSBufferDescriptor      btRecord;
                   4083:        FCB*                            catalogFCB;
                   4084:        SearchState                     *searchState;
                   4085:        searchinfospec_t        searchInfo1;
                   4086:        searchinfospec_t        searchInfo2;
                   4087:        void                            *attributesBuffer;
                   4088:        void                            *variableBuffer;
                   4089:        short                           recordSize;
                   4090:        short                           operation;
                   4091:        u_long                          fixedBlockSize;
                   4092:        u_long                          eachReturnBufferSize;
                   4093:        struct proc                     *p                                              = CURRENT_PROC;
                   4094:        u_long                          nodesToCheck                    = 30;                           //      After we search 30 nodes we must give up time
                   4095:        u_long                          lastNodeNum                             = 0XFFFFFFFF;
                   4096:        ExtendedVCB                     *vcb                                    = VTOVCB(ap->a_vp);
                   4097:        int                                     err                                             = E_NONE;
                   4098: 
                   4099:     DBG_FUNC_NAME("hfs_search");
                   4100:        DBG_VOP_LOCKS_DECL(1);
                   4101: 
                   4102:     //XXX Parameter check a_searchattrs
                   4103: 
                   4104:        *(ap->a_nummatches)     = 0;
                   4105: 
                   4106:        if ( ap->a_options & ~SRCHFS_VALIDOPTIONSMASK )
                   4107:                return( EINVAL );
                   4108: 
                   4109:        if (ap->a_uio->uio_resid <= 0)
                   4110:                return (EINVAL);
                   4111: 
                   4112:        searchState     = (SearchState *)ap->a_searchstate;
                   4113: 
                   4114:        //      Check if this is the first time we are being called.
                   4115:        //      If it is, allocate SearchState and we'll move it to the users space on exit
                   4116:        if ( ap->a_options & SRCHFS_START )
                   4117:        {
                   4118:                bzero( (caddr_t)searchState, sizeof(SearchState) );
                   4119:                searchState->isHFSPlus  = ( vcb->vcbSigWord == kHFSPlusSigWord );
                   4120:                operation       = kBTreeFirstRecord;
                   4121:                ap->a_options &= ~SRCHFS_START;         //      clear the bit
                   4122:        }
                   4123:        else
                   4124:        {
                   4125:                operation       = kBTreeCurrentRecord;
                   4126:        }
                   4127: 
                   4128:        //      UnPack the search boundries, searchInfo1, searchInfo2
                   4129:        err = UnpackSearchAttributeBlock( ap->a_vp, ap->a_searchattrs, &searchInfo1, ap->a_searchparams1 );
                   4130:        if (err) return err;
                   4131:        err = UnpackSearchAttributeBlock( ap->a_vp, ap->a_searchattrs, &searchInfo2, ap->a_searchparams2 );
                   4132:        if (err) return err;
                   4133: 
                   4134:        btRecord.itemCount                      = 1;
                   4135:        btRecord.itemSize                       = sizeof( catalogRecord );
                   4136:        btRecord.bufferAddress          = &catalogRecord;
                   4137:        catalogFCB                                      = VTOFCB( vcb->catalogRefNum );
                   4138:        key                                                     = (BTreeKey*) &(searchState->btreeIterator.key);
                   4139:        fixedBlockSize                          = sizeof(u_long) + AttributeBlockSize( ap->a_returnattrs );     /* u_long for length longword */
                   4140:        eachReturnBufferSize            = fixedBlockSize;
                   4141:        
                   4142:        if ( ap->a_returnattrs->commonattr & ATTR_CMN_NAME )                            //XXX should be more robust
                   4143:                eachReturnBufferSize += NAME_MAX + 1;
                   4144: 
                   4145:     MALLOC( attributesBuffer, void *, eachReturnBufferSize, M_TEMP, M_WAITOK );
                   4146:        variableBuffer                          = attributesBuffer + fixedBlockSize;
                   4147: 
                   4148:        //      Lock catalog b-tree
                   4149:        err = hfs_metafilelocking( VTOHFS(ap->a_vp), kHFSCatalogFileID, LK_SHARED, p );
                   4150:        if ( err != E_NONE )
                   4151:        {
                   4152:         DBG_VOP_LOCKS_TEST( err );
                   4153:         goto ExitThisRoutine;
                   4154:     };
                   4155: 
                   4156:     //
                   4157:        //      Iterate over all the catalog btree records
                   4158:        //
                   4159:        
                   4160:        err = BTIterateRecord( catalogFCB, operation, &(searchState->btreeIterator), &btRecord, &recordSize );
                   4161: 
                   4162:        while( err == E_NONE )
                   4163:        {
                   4164:                if ( CheckCriteria( vcb, searchState, ap->a_options, ap->a_searchattrs, &catalogRecord, (CatalogKey *)key, &searchInfo1, &searchInfo2 ) == true )
                   4165:                {
                   4166:                        err = InsertMatch( ap->a_vp, ap->a_uio, &catalogRecord, (CatalogKey *)key, ap->a_returnattrs, attributesBuffer, variableBuffer, eachReturnBufferSize, ap->a_nummatches );
                   4167:                        if ( err != E_NONE )
                   4168:                                break;
                   4169:                }
                   4170:                
                   4171:                err = BTIterateRecord( catalogFCB, kBTreeNextRecord, &(searchState->btreeIterator), &btRecord, &recordSize );
                   4172:                
                   4173:                        if  ( *(ap->a_nummatches) >= ap->a_maxmatches )
                   4174:                                break;
                   4175: 
                   4176:                if ( searchState->btreeIterator.hint.nodeNum != lastNodeNum )
                   4177:                {
                   4178:                        lastNodeNum     = searchState->btreeIterator.hint.nodeNum;
                   4179:                        if ( --nodesToCheck == 0 )
                   4180:                                break;                                                          //      We must leave the kernel to give up time
                   4181:                }
                   4182:        }
                   4183: 
                   4184:        //      Unlock catalog b-tree
                   4185:        (void) hfs_metafilelocking( VTOHFS(ap->a_vp), kHFSCatalogFileID, LK_RELEASE, p );
                   4186: 
                   4187: 
                   4188:     if ( err == E_NONE )
                   4189:        {
                   4190:                err = EAGAIN;                                                           //      signal to the user to call searchfs again
                   4191:        }
                   4192:     else if ( err == errSearchBufferFull )
                   4193:        {
                   4194:                if ( *(ap->a_nummatches) > 0 )
                   4195:                        err = EAGAIN;
                   4196:                else
                   4197:                        err = ENOBUFS;
                   4198:        }
                   4199:        else if ( err == btNotFound )
                   4200:        {
                   4201:                err = E_NONE;                                                           //      the entire disk has been searched
                   4202:        }
                   4203: 
                   4204: ExitThisRoutine:
                   4205:         FREE( attributesBuffer, M_TEMP );
                   4206: 
                   4207:        return( err );
                   4208: }
                   4209: 
                   4210: 
                   4211: static Boolean
                   4212: ComparePartialUnicodeName ( register ConstUniCharArrayPtr str, register ItemCount s_len,
                   4213:                                                        register ConstUniCharArrayPtr find, register ItemCount f_len )
                   4214: {
                   4215:        if (f_len == 0 || s_len == 0)
                   4216:                return FALSE;
                   4217: 
                   4218:        do {
                   4219:                if (s_len-- < f_len)
                   4220:                        return FALSE;
                   4221:        } while (FastUnicodeCompare(str++, f_len, find, f_len) != 0);
                   4222: 
                   4223:        return TRUE;
                   4224: }
                   4225: 
                   4226: 
                   4227: static Boolean
                   4228: ComparePartialPascalName ( register ConstStr31Param str, register ConstStr31Param find )
                   4229: {
                   4230:        register u_char s_len = str[0];
                   4231:        register u_char f_len = find[0];
                   4232:        register u_char *tsp;
                   4233:        Str31 tmpstr;
                   4234: 
                   4235:        if (f_len == 0 || s_len == 0)
                   4236:                return FALSE;
                   4237: 
                   4238:        bcopy(str, tmpstr, s_len + 1);
                   4239:        tsp = &tmpstr[0];
                   4240: 
                   4241:        while (s_len-- >= f_len) {
                   4242:                *tsp = f_len;
                   4243: 
                   4244:                if (FastRelString(tsp++, find) == 0)
                   4245:                        return TRUE;
                   4246:        }
                   4247: 
                   4248:        return FALSE;
                   4249: }
                   4250: 
                   4251: //
                   4252: //     CheckCriteria()
                   4253: //
                   4254: Boolean CheckCriteria( ExtendedVCB *vcb, const SearchState *searchState, u_long searchBits,
                   4255:                                                struct attrlist *attrList, CatalogRecord *catalogRecord, CatalogKey *key,
                   4256:                                                searchinfospec_t  *searchInfo1, searchinfospec_t *searchInfo2 )
                   4257: {
                   4258:        Boolean                 matched;
                   4259:        CatalogNodeData catData;
                   4260:        attrgroup_t             searchAttributes;
                   4261:        
                   4262:        switch ( catalogRecord->recordType )
                   4263:        {
                   4264:                case kHFSFolderRecord:
                   4265:                case kHFSPlusFolderRecord:
                   4266:                        if ( (searchBits & SRCHFS_MATCHDIRS) == 0 )             //      If we are NOT searching folders
                   4267:                        {
                   4268:                                matched = false;
                   4269:                                goto TestDone;
                   4270:                        }
                   4271:                        break;
                   4272:                        
                   4273:                case kHFSFileRecord:
                   4274:                case kHFSPlusFileRecord:
                   4275:                                if ( (searchBits & SRCHFS_MATCHFILES) == 0 )            //      If we are NOT searching files
                   4276:                        {
                   4277:                                matched = false;
                   4278:                                goto TestDone;
                   4279:                        }
                   4280:                        break;
                   4281: 
                   4282:                default:                                                // Never match a thread record or any other type.
                   4283:                        return( false );                                // Not a file or folder record, so can't search it
                   4284:        }
                   4285:        
                   4286:        //      Change the catalog record data into a single common form
                   4287:        matched                         = true;                                                 //      Assume we got a match
                   4288:        catData.nodeType        = 0;                                                    //      mark this record as not in use
                   4289:        CopyCatalogNodeData( vcb, catalogRecord, &catData );
                   4290: 
                   4291:        /* First, attempt to match the name -- either partial or complete */
                   4292:        if ( attrList->commonattr & ATTR_CMN_NAME ) {
                   4293:                if ( searchState->isHFSPlus ) {
                   4294:                        /* Check for partial/full HFS Plus name match */
                   4295: 
                   4296:                        if ( searchBits & SRCHFS_MATCHPARTIALNAMES ) {
                   4297:                                matched = ComparePartialUnicodeName( key->hfsPlus.nodeName.unicode,
                   4298:                                                                                                         key->hfsPlus.nodeName.length,
                   4299:                                                                                                         (UniChar*)searchInfo1->name,
                   4300:                                                                                                         searchInfo1->nameLength );
                   4301:                        } else /* full HFS Plus name match */ { 
                   4302:                                matched = (FastUnicodeCompare(  key->hfsPlus.nodeName.unicode,
                   4303:                                                                                                key->hfsPlus.nodeName.length,
                   4304:                                                                                                (UniChar*)searchInfo1->name,
                   4305:                                                                                                searchInfo1->nameLength ) == 0);
                   4306:                        }
                   4307:                } else {
                   4308:                        /* Check for partial/full HFS name match */
                   4309: 
                   4310:                        if ( searchBits & SRCHFS_MATCHPARTIALNAMES )
                   4311:                                matched = ComparePartialPascalName(key->hfs.nodeName, (u_char*)searchInfo1->name);
                   4312:                        else /* full HFS name match */
                   4313:                                matched = (FastRelString(key->hfs.nodeName, (u_char*)searchInfo1->name) == 0);
                   4314:                }
                   4315:                
                   4316:                if ( matched == false || (searchBits & ~SRCHFS_MATCHPARTIALNAMES) == 0 )
                   4317:                        goto TestDone;  /* no match, or nothing more to compare */
                   4318:        }
                   4319:        
                   4320:        
                   4321:        //      Now that we have a record worth searching, see if it matches the search attributes
                   4322:        if ( (catData.nodeType == kCatalogFileNode) && ((attrList->fileattr & ATTR_FILE_VALIDMASK) != 0) )
                   4323:        {
                   4324:                searchAttributes        = attrList->fileattr;
                   4325:                //
                   4326:                //      File logical length (data fork)
                   4327:                //
                   4328:                if ( searchAttributes & ATTR_FILE_DATALENGTH )
                   4329:                {
                   4330:                        matched = CompareRange( catData.dataLogicalSize, searchInfo1->f.dataLogicalLength, searchInfo2->f.dataLogicalLength );
                   4331:                        if (matched == false) goto TestDone;
                   4332:                }
                   4333: 
                   4334:                //
                   4335:                //      File physical length (data fork)
                   4336:                //
                   4337:                if ( searchAttributes & ATTR_FILE_DATAALLOCSIZE )
                   4338:                {
                   4339:                        matched = CompareRange( catData.dataPhysicalSize, searchInfo1->f.dataPhysicalLength, searchInfo2->f.dataPhysicalLength );
                   4340:                        if (matched == false) goto TestDone;
                   4341:                }
                   4342: 
                   4343:                //
                   4344:                //      File logical length (resource fork)
                   4345:                //
                   4346:                if ( searchAttributes & ATTR_FILE_RSRCLENGTH )
                   4347:                {
                   4348:                        matched = CompareRange( catData.rsrcLogicalSize, searchInfo1->f.resourceLogicalLength, searchInfo2->f.resourceLogicalLength );
                   4349:                        if (matched == false) goto TestDone;
                   4350:                }
                   4351:                
                   4352:                //
                   4353:                //      File physical length (resource fork)
                   4354:                //
                   4355:                if ( searchAttributes & ATTR_FILE_RSRCALLOCSIZE )
                   4356:                {
                   4357:                        matched = CompareRange( catData.rsrcPhysicalSize, searchInfo1->f.resourcePhysicalLength, searchInfo2->f.resourcePhysicalLength );
                   4358:                        if (matched == false) goto TestDone;
                   4359:                }
                   4360:                
                   4361:                //
                   4362:                //      File logical length (resource + data fork)
                   4363:                //
                   4364:                if ( searchAttributes & ATTR_FILE_TOTALSIZE )
                   4365:                {
                   4366:                        matched = CompareRange( catData.rsrcLogicalSize + catData.dataLogicalSize, 
                   4367:                                                                        searchInfo1->f.resourceLogicalLength + searchInfo1->f.dataLogicalLength, 
                   4368:                                                                        searchInfo2->f.resourceLogicalLength + searchInfo2->f.dataLogicalLength );
                   4369:                        if (matched == false) goto TestDone;
                   4370:                }
                   4371:                
                   4372:                //
                   4373:                //      File physical length (resource + data fork)
                   4374:                //
                   4375:                if ( searchAttributes & ATTR_FILE_TOTALSIZE )
                   4376:                {
                   4377:                        matched = CompareRange( catData.rsrcPhysicalSize + catData.dataPhysicalSize, 
                   4378:                                                                        searchInfo1->f.resourcePhysicalLength + searchInfo1->f.dataPhysicalLength, 
                   4379:                                                                        searchInfo2->f.resourcePhysicalLength + searchInfo2->f.dataPhysicalLength );
                   4380:                        if (matched == false) goto TestDone;
                   4381:                }
                   4382:        }
                   4383:        //
                   4384:        //      Check the directory attributes
                   4385:        //
                   4386:        else if ( (catData.nodeType == kCatalogFolderNode) && ((attrList->dirattr & ATTR_DIR_VALIDMASK) != 0) )
                   4387:        {
                   4388:                searchAttributes        = attrList->dirattr;
                   4389:                
                   4390:                //
                   4391:                //      Directory valence
                   4392:                //
                   4393:                if ( searchAttributes & ATTR_DIR_ENTRYCOUNT )
                   4394:                {
                   4395:                        matched = CompareRange( catData.valence, searchInfo1->d.numFiles, searchInfo2->d.numFiles );
                   4396:                        if (matched == false) goto TestDone;
                   4397:                }
                   4398:        }
                   4399:        
                   4400:        //
                   4401:        //      Check the common attributes
                   4402:        //
                   4403:        searchAttributes        = attrList->commonattr;
                   4404:        if ( (searchAttributes & ATTR_CMN_VALIDMASK) != 0 )
                   4405:        {
                   4406:                //
                   4407:                //      Parent ID
                   4408:                //
                   4409:                if ( searchAttributes & ATTR_CMN_PAROBJID )
                   4410:                {
                   4411:                        HFSCatalogNodeID        parentID;
                   4412:                        
                   4413:                        if (searchState->isHFSPlus)
                   4414:                                parentID = key->hfsPlus.parentID;
                   4415:                        else
                   4416:                                parentID = key->hfs.parentID;
                   4417:                                
                   4418:                        matched = CompareRange( parentID, searchInfo1->parentDirID, searchInfo2->parentDirID );
                   4419:                        if (matched == false) goto TestDone;
                   4420:                }
                   4421: 
                   4422:                //
                   4423:                //      Finder Info & Extended Finder Info where extFinderInfo is last 32 bytes
                   4424:                //
                   4425:                if ( searchAttributes & ATTR_CMN_FNDRINFO )
                   4426:                {
                   4427:                        UInt32 *thisValue;
                   4428:                        thisValue = (UInt32 *) &catData.finderInfo[0];
                   4429: 
                   4430:                        //      Note: ioFlFndrInfo and ioDrUsrWds have the same offset in search info, so
                   4431:                        //      no need to test the object type here.
                   4432:                        matched = CompareMasked( thisValue, (UInt32 *) &searchInfo1->finderInfo, (UInt32 *) &searchInfo2->finderInfo, 8 );      //      8 * UInt32
                   4433:                        if (matched == false) goto TestDone;
                   4434:                }
                   4435: 
                   4436:                //
                   4437:                //      Create date
                   4438:                //
                   4439:                if ( searchAttributes & ATTR_CMN_CRTIME )
                   4440:                {
                   4441:                        matched = CompareRange( to_bsd_time(catData.createDate), searchInfo1->creationDate.tv_sec,  searchInfo2->creationDate.tv_sec );
                   4442:                        if (matched == false) goto TestDone;
                   4443:                }
                   4444:        
                   4445:                //
                   4446:                //      Mod date
                   4447:                //
                   4448:                if ( searchAttributes & ATTR_CMN_MODTIME )
                   4449:                {
                   4450:                        matched = CompareRange( to_bsd_time(catData.contentModDate), searchInfo1->modificationDate.tv_sec, searchInfo2->modificationDate.tv_sec );
                   4451:                        if (matched == false) goto TestDone;
                   4452:                }
                   4453:        
                   4454:                //
                   4455:                //      Backup date
                   4456:                //
                   4457:                if ( searchAttributes & ATTR_CMN_BKUPTIME )
                   4458:                {
                   4459:                        matched = CompareRange( to_bsd_time(catData.backupDate), searchInfo1->lastBackupDate.tv_sec, searchInfo2->lastBackupDate.tv_sec );
                   4460:                        if (matched == false) goto TestDone;
                   4461:                }
                   4462:        
                   4463:        }
                   4464: 
                   4465:        
                   4466: TestDone:
                   4467:        //
                   4468:        //      Finally, determine whether we need to negate the sense of the match (i.e. find
                   4469:        //      all objects that DON'T match).
                   4470:        //
                   4471:        if ( searchBits & SRCHFS_NEGATEPARAMS )
                   4472:                matched = !matched;
                   4473:        
                   4474:        return( matched );
                   4475: }
                   4476: 
                   4477: 
                   4478: //
                   4479: //     Adds another record to the packed array for output
                   4480: //
                   4481: static int InsertMatch( struct vnode *root_vp, struct uio *a_uio, CatalogRecord *catalogRecord,
                   4482:                                                CatalogKey *key, struct attrlist *returnAttrList, void *attributesBuffer,
                   4483:                                                void *variableBuffer, u_long bufferSize, u_long * nummatches )
                   4484: {
                   4485:        int                                             err;
                   4486:        void                                    *rovingAttributesBuffer;
                   4487:        void                                    *rovingVariableBuffer;
                   4488:        struct hfsCatalogInfo   catalogInfo;
                   4489:        u_long                                  packedBufferSize;
                   4490:        ExtendedVCB                             *vcb                    = VTOVCB(root_vp);
                   4491:        Boolean                                 isHFSPlus               = vcb->vcbSigWord == kHFSPlusSigWord;
                   4492: 
                   4493:        rovingAttributesBuffer  = attributesBuffer + sizeof(u_long);            //      Reserve space for length field
                   4494:        rovingVariableBuffer    = variableBuffer;
                   4495: 
                   4496:        CopyCatalogNodeData( vcb, catalogRecord, &catalogInfo.nodeData );
                   4497: 
                   4498:        catalogInfo.spec.parID = isHFSPlus ? key->hfsPlus.parentID : key->hfs.parentID;
                   4499: 
                   4500:        if ( returnAttrList->commonattr & ATTR_CMN_NAME )
                   4501:        {
                   4502:                u_long actualDstLen;
                   4503: 
                   4504:                /*      Return result in UTF-8 */
                   4505:                if ( isHFSPlus ) {
                   4506:                        err = ConvertUnicodeToUTF8(     key->hfsPlus.nodeName.length * sizeof(UniChar),
                   4507:                                                                                key->hfsPlus.nodeName.unicode,
                   4508:                                                                                sizeof(catalogInfo.spec.name),
                   4509:                                                                                &actualDstLen,
                   4510:                                                                                catalogInfo.spec.name);
                   4511:                 } else {
                   4512:                        err = ConvertMacRomanToUTF8( key->hfs.nodeName,
                   4513:                                                                                 sizeof(catalogInfo.spec.name),
                   4514:                                                                                 &actualDstLen,
                   4515:                                                                                 catalogInfo.spec.name);
                   4516:                }
                   4517:        }
                   4518: 
                   4519:        PackCatalogInfoAttributeBlock( returnAttrList,root_vp,  &catalogInfo, &rovingAttributesBuffer, &rovingVariableBuffer );
                   4520: 
                   4521:        packedBufferSize = rovingVariableBuffer - attributesBuffer;
                   4522: 
                   4523:        if ( packedBufferSize > a_uio->uio_resid )
                   4524:                return( errSearchBufferFull );
                   4525: 
                   4526:        (* nummatches)++;
                   4527:        
                   4528:        *((u_long *)attributesBuffer) = packedBufferSize;       //      Store length of fixed + var block
                   4529:        
                   4530:        err = uiomove( (caddr_t)attributesBuffer, packedBufferSize, a_uio );            //      XXX should be packedBufferSize
                   4531:        
                   4532:        if (err != E_NONE)
                   4533:                DBG_ERR(("InsertMatch: error %d on uiomove.\n", err));
                   4534:        
                   4535:        return( err );
                   4536: }
                   4537: 
                   4538: 
                   4539: static int
                   4540: UnpackSearchAttributeBlock( struct vnode *vp, struct attrlist  *alist, searchinfospec_t *searchInfo, void *attributeBuffer )
                   4541: {
                   4542:        attrgroup_t             a;
                   4543:        u_long                  bufferSize;
                   4544: 
                   4545:        ASSERT(searchInfo != NULL);
                   4546: 
                   4547:        bufferSize =  *((u_long *)attributeBuffer);
                   4548:        if (bufferSize == 0)
                   4549:                return (EINVAL);        /* XXX -DJB is a buffer size of zero ever valid for searchfs? */
                   4550: 
                   4551:        ++((u_long *)attributeBuffer);  //      advance past the size
                   4552:        
                   4553:        //
                   4554:        //      UnPack common attributes
                   4555:        //
                   4556:        a       = alist->commonattr;
                   4557:        if ( a != 0 )
                   4558:        {
                   4559:                if ( a & ATTR_CMN_NAME )
                   4560:                {
                   4561:                        char *s = attributeBuffer + ((attrreference_t *) attributeBuffer)->attr_dataoffset;
                   4562:                        size_t len = ((attrreference_t *) attributeBuffer)->attr_length;
                   4563: 
                   4564:                        if (len > sizeof(searchInfo->name))
                   4565:                                return (EINVAL);
                   4566: 
                   4567:                        if (VTOVCB(vp)->vcbSigWord == kHFSPlusSigWord) {
                   4568:                                ByteCount actualDstLen;
                   4569:                                /* Convert name to Unicode to match HFS Plus B-Tree names */
                   4570: 
                   4571:                                if (len > 0) {
                   4572:                                        if (ConvertUTF8ToUnicode(len-1, s, sizeof(searchInfo->name),
                   4573:                                                        &actualDstLen, (UniChar*)searchInfo->name) != 0)
                   4574:                                                return (EINVAL);
                   4575: 
                   4576: 
                   4577:                                        searchInfo->nameLength = actualDstLen / sizeof(UniChar);
                   4578:                                } else {
                   4579:                                        searchInfo->nameLength = 0;
                   4580:                                }
                   4581:                                ++((attrreference_t *)attributeBuffer);
                   4582: 
                   4583:                        } else {
                   4584:                                /* Convert name to pascal string to match HFS B-Tree names */
                   4585: 
                   4586:                                if (len > 0) {
                   4587:                                        if (ConvertUTF8ToMacRoman(len-1, s, (u_char*)searchInfo->name) != 0)
                   4588:                                                return (EINVAL);
                   4589: 
                   4590:                                        searchInfo->nameLength = searchInfo->name[0];
                   4591:                                } else {
                   4592:                                        searchInfo->name[0] = searchInfo->nameLength = 0;
                   4593:                                }
                   4594:                                ++((attrreference_t *)attributeBuffer);
                   4595:                        }
                   4596:                }
                   4597:                if ( a & ATTR_CMN_PAROBJID )
                   4598:                {
                   4599:                        searchInfo->parentDirID = ((fsobj_id_t *) attributeBuffer)->fid_objno;  /* ignore fid_generation */
                   4600:                        ++((fsobj_id_t *)attributeBuffer);
                   4601:                }
                   4602:                if ( a & ATTR_CMN_CRTIME )
                   4603:                {
                   4604:                        searchInfo->creationDate = *((struct timespec *)attributeBuffer);
                   4605:                        ++((struct timespec *)attributeBuffer);
                   4606:                }
                   4607:                if ( a & ATTR_CMN_MODTIME )
                   4608:                {
                   4609:                        searchInfo->modificationDate = *((struct timespec *)attributeBuffer);
                   4610:                        ++((struct timespec *)attributeBuffer);
                   4611:                }
                   4612:                if ( a & ATTR_CMN_BKUPTIME )
                   4613:                {
                   4614:                        searchInfo->lastBackupDate = *((struct timespec *)attributeBuffer);
                   4615:                        ++((struct timespec *)attributeBuffer);
                   4616:                }
                   4617:                if ( a & ATTR_CMN_FNDRINFO )
                   4618:                {
                   4619:                   bcopy( attributeBuffer, searchInfo->finderInfo, sizeof(u_long) * 8 );
                   4620:                   attributeBuffer += (sizeof(u_long) * 8 );
                   4621:                }
                   4622:        }
                   4623: 
                   4624:        a       = alist->dirattr;
                   4625:        if ( a != 0 )
                   4626:        {
                   4627:                if ( a & ATTR_DIR_ENTRYCOUNT )
                   4628:                {
                   4629:                        searchInfo->d.numFiles = *((u_long *)attributeBuffer);
                   4630:                        ++((u_long *)attributeBuffer);
                   4631:                }
                   4632:        }
                   4633: 
                   4634:        a       = alist->fileattr;
                   4635:        if ( a != 0 )
                   4636:        {
                   4637:                if ( a & ATTR_FILE_DATALENGTH )
                   4638:                {
                   4639:                        searchInfo->f.dataLogicalLength = *((off_t *)attributeBuffer);
                   4640:                        ++((off_t *)attributeBuffer);
                   4641:                }
                   4642:                if ( a & ATTR_FILE_DATAALLOCSIZE )
                   4643:                {
                   4644:                        searchInfo->f.dataPhysicalLength = *((off_t *)attributeBuffer);
                   4645:                        ++((off_t *)attributeBuffer);
                   4646:                }
                   4647:                if ( a & ATTR_FILE_RSRCLENGTH )
                   4648:                {
                   4649:                        searchInfo->f.resourceLogicalLength     = *((off_t *)attributeBuffer);
                   4650:                        ++((off_t *)attributeBuffer);
                   4651:                }
                   4652:                if ( a & ATTR_FILE_RSRCALLOCSIZE )
                   4653:                {
                   4654:                        searchInfo->f.resourcePhysicalLength = *((off_t *)attributeBuffer);
                   4655:                        ++((off_t *)attributeBuffer);
                   4656:                }
                   4657:        }
                   4658: 
                   4659:        return (0);
                   4660: }
                   4661: 
                   4662: 
                   4663: 
                   4664: 
                   4665: #if DBG_VOP_TEST_LOCKS
                   4666: 
                   4667: 
                   4668: void DbgVopTest( int maxSlots,
                   4669:                  int retval,
                   4670:                  VopDbgStoreRec *VopDbgStore,
                   4671:                  char *funcname)
                   4672: {
                   4673:     int index;
                   4674: 
                   4675:     for (index = 0; index < maxSlots; index++)
                   4676:       {
                   4677:         if (VopDbgStore[index].id != index) {
                   4678:             DEBUG_BREAK_MSG(("%s: DBG_VOP_LOCK: invalid id field (%d) in target entry (#%d).\n", funcname, VopDbgStore[index].id, index));
                   4679:         };
                   4680: 
                   4681:         if ((VopDbgStore[index].vp != NULL) &&
                   4682:             ((VopDbgStore[index].vp->v_data==NULL) || (VTOH(VopDbgStore[index].vp)->h_valid != HFS_VNODE_MAGIC)))
                   4683:             continue;
                   4684: 
                   4685:         switch (VopDbgStore[index].inState)
                   4686:           {
                   4687:             case VOPDBG_IGNORE:
                   4688:             case VOPDBG_SAME:
                   4689:                 /* Do Nothing !!! */
                   4690:                 break;
                   4691:             case VOPDBG_LOCKED:
                   4692:             case VOPDBG_UNLOCKED:
                   4693:             case VOPDBG_LOCKNOTNIL:
                   4694:               {
                   4695:                   if (VopDbgStore[index].vp == NULL && (VopDbgStore[index].inState != VOPDBG_LOCKNOTNIL)) {
                   4696:                       DBG_ERR (("%s: InState check: Null vnode ptr in entry #%d\n", funcname, index));
                   4697:                   } else if (VopDbgStore[index].vp != NULL) {
                   4698:                       switch (VopDbgStore[index].inState)
                   4699:                         {
                   4700:                           case VOPDBG_LOCKED:
                   4701:                           case VOPDBG_LOCKNOTNIL:
                   4702:                               if (VopDbgStore[index].inValue == 0)
                   4703:                                 {
                   4704:                                   kprintf ("%s: Entry: not LOCKED:", funcname);
                   4705:                                   DBG_VOP_PRINT_VNODE_INFO(VopDbgStore[index].vp); kprintf ("\n");
                   4706:                                 }
                   4707:                               break;
                   4708:                           case VOPDBG_UNLOCKED:
                   4709:                               if (VopDbgStore[index].inValue != 0)
                   4710:                                 {
                   4711:                                   kprintf ("%s: Entry: not UNLOCKED:", funcname);
                   4712:                                   DBG_VOP_PRINT_VNODE_INFO(VopDbgStore[index].vp); kprintf ("\n");
                   4713:                                 }
                   4714:                               break;
                   4715:                         }
                   4716:                   }
                   4717:                   break;
                   4718:               }
                   4719:             default:
                   4720:                 DBG_ERR (("%s: DBG_VOP_LOCK on entry: bad lock test value: %d\n", funcname, VopDbgStore[index].errState));
                   4721:           }
                   4722: 
                   4723: 
                   4724:         if (retval != 0)
                   4725:           {
                   4726:             switch (VopDbgStore[index].errState)
                   4727:               {
                   4728:                 case VOPDBG_IGNORE:
                   4729:                     /* Do Nothing !!! */
                   4730:                     break;
                   4731:                 case VOPDBG_LOCKED:
                   4732:                 case VOPDBG_UNLOCKED:
                   4733:                 case VOPDBG_SAME:
                   4734:                   {
                   4735:                       if (VopDbgStore[index].vp == NULL) {
                   4736:                           DBG_ERR (("%s: ErrState check: Null vnode ptr in entry #%d\n", funcname, index));
                   4737:                       } else {
                   4738:                           VopDbgStore[index].outValue = lockstatus(&VTOH(VopDbgStore[index].vp)->h_lock);
                   4739:                           switch (VopDbgStore[index].errState)
                   4740:                             {
                   4741:                               case VOPDBG_LOCKED:
                   4742:                                   if (VopDbgStore[index].outValue == 0)
                   4743:                                     {
                   4744:                                       kprintf ("%s: Error: not LOCKED:", funcname);
                   4745:                                       DBG_VOP_PRINT_VNODE_INFO(VopDbgStore[index].vp); kprintf ("\n");
                   4746:                                    }
                   4747:                                   break;
                   4748:                               case VOPDBG_UNLOCKED:
                   4749:                                   if (VopDbgStore[index].outValue != 0)
                   4750:                                     {
                   4751:                                       kprintf ("%s: Error: not UNLOCKED:", funcname);
                   4752:                                       DBG_VOP_PRINT_VNODE_INFO(VopDbgStore[index].vp); kprintf ("\n");
                   4753:                                     }
                   4754:                                   break;
                   4755:                               case VOPDBG_SAME:
                   4756:                                   if (VopDbgStore[index].outValue != VopDbgStore[index].inValue)
                   4757:                                       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));
                   4758:                                   break;
                   4759:                             }
                   4760:                       }
                   4761:                       break;
                   4762:                   }
                   4763:                 case VOPDBG_LOCKNOTNIL:
                   4764:                     if (VopDbgStore[index].vp != NULL) {
                   4765:                         VopDbgStore[index].outValue = lockstatus(&VTOH(VopDbgStore[index].vp)->h_lock);
                   4766:                         if (VopDbgStore[index].outValue == 0)
                   4767:                             DBG_ERR (("%s: Error: Not LOCKED: 0x%x\n", funcname, (u_int)VopDbgStore[index].vp));
                   4768:                     }
                   4769:                     break;
                   4770:                 default:
                   4771:                     DBG_ERR (("%s: Error: bad lock test value: %d\n", funcname, VopDbgStore[index].errState));
                   4772:               }
                   4773:           }
                   4774:         else
                   4775:           {
                   4776:             switch (VopDbgStore[index].outState)
                   4777:               {
                   4778:                 case VOPDBG_IGNORE:
                   4779:                     /* Do Nothing !!! */
                   4780:                     break;
                   4781:                 case VOPDBG_LOCKED:
                   4782:                 case VOPDBG_UNLOCKED:
                   4783:                 case VOPDBG_SAME:
                   4784:                     if (VopDbgStore[index].vp == NULL) {
                   4785:                         DBG_ERR (("%s: OutState: Null vnode ptr in entry #%d\n", funcname, index));
                   4786:                     };
                   4787:                     if (VopDbgStore[index].vp != NULL)
                   4788:                       {
                   4789:                         VopDbgStore[index].outValue = lockstatus(&VTOH(VopDbgStore[index].vp)->h_lock);
                   4790:                         switch (VopDbgStore[index].outState)
                   4791:                           {
                   4792:                             case VOPDBG_LOCKED:
                   4793:                                 if (VopDbgStore[index].outValue == 0)
                   4794:                                   {
                   4795:                                     kprintf ("%s: Out: not LOCKED:", funcname);
                   4796:                                     DBG_VOP_PRINT_VNODE_INFO(VopDbgStore[index].vp); kprintf ("\n");
                   4797:                                  }
                   4798:                                 break;
                   4799:                             case VOPDBG_UNLOCKED:
                   4800:                                 if (VopDbgStore[index].outValue != 0)
                   4801:                                   {
                   4802:                                     kprintf ("%s: Out: not UNLOCKED:", funcname);
                   4803:                                     DBG_VOP_PRINT_VNODE_INFO(VopDbgStore[index].vp); kprintf ("\n");
                   4804:                                   }
                   4805:                                 break;
                   4806:                             case VOPDBG_SAME:
                   4807:                                 if (VopDbgStore[index].outValue != VopDbgStore[index].inValue)
                   4808:                                     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));
                   4809:                                 break;
                   4810:                           }
                   4811:                       }
                   4812:                     break;
                   4813:                 case VOPDBG_LOCKNOTNIL:
                   4814:                     if (VopDbgStore[index].vp != NULL) {
                   4815:                         if (&VTOH(VopDbgStore[index].vp)->h_lock == NULL) {
                   4816:                             DBG_ERR (("%s: DBG_VOP_LOCK on out: Null lock on vnode 0x%x\n", funcname, (u_int)VopDbgStore[index].vp));
                   4817:                         }
                   4818:                         else {
                   4819:                             VopDbgStore[index].outValue = lockstatus(&VTOH(VopDbgStore[index].vp)->h_lock);
                   4820:                             if (VopDbgStore[index].outValue == 0)
                   4821:                               {
                   4822:                                 kprintf ("%s: DBG_VOP_LOCK on out: Should be LOCKED:", funcname);
                   4823:                                 DBG_VOP_PRINT_VNODE_INFO(VopDbgStore[index].vp); kprintf ("\n");
                   4824:                               }
                   4825:                         }
                   4826:                     }
                   4827:                     break;
                   4828:                 default:
                   4829:                     DBG_ERR (("%s: DBG_VOP_LOCK on out: bad lock test value: %d\n", funcname, VopDbgStore[index].outState));
                   4830:               }
                   4831:           }
                   4832: 
                   4833:         VopDbgStore[index].id = -1;            /* Invalidate the entry to allow panic-free re-use */
                   4834:       }        
                   4835: }
                   4836: 
                   4837: #endif /* DBG_VOP_TEST_LOCKS */
                   4838: 
                   4839: /*****************************************************************************
                   4840: *
                   4841: *      VOP Table
                   4842: *
                   4843: *****************************************************************************/
                   4844: 
                   4845: 
                   4846: struct vnodeopv_entry_desc hfs_vnodeop_entries[] = {
                   4847:     { &vop_default_desc, vn_default_error },
                   4848:     { &vop_lookup_desc, hfs_lookup },                  /* lookup */
                   4849:     { &vop_create_desc, hfs_create },                  /* create */
                   4850:     { &vop_mknod_desc, err_mknod },                            /* mknod (NOT SUPPORTED) */
                   4851:     { &vop_open_desc, hfs_open },                              /* open */
                   4852:     { &vop_close_desc, hfs_close },                            /* close */
                   4853:     { &vop_access_desc, hfs_access },                  /* access */
                   4854:     { &vop_getattr_desc, hfs_getattr },                        /* getattr */
                   4855:     { &vop_setattr_desc, hfs_setattr },                        /* setattr */
                   4856:     { &vop_read_desc, hfs_read },                              /* read */
                   4857:     { &vop_write_desc, hfs_write },                            /* write */
                   4858:     { &vop_ioctl_desc, hfs_ioctl },                            /* ioctl */
                   4859:     { &vop_select_desc, hfs_select },                  /* select */
                   4860:     { &vop_exchange_desc, hfs_exchange },              /* exchange */
                   4861:     { &vop_mmap_desc, hfs_mmap },                              /* mmap */
                   4862:     { &vop_fsync_desc, hfs_fsync },                            /* fsync */
                   4863:     { &vop_seek_desc, hfs_seek },                              /* seek */
                   4864:     { &vop_remove_desc, hfs_remove },                  /* remove */
                   4865:     { &vop_link_desc, err_link },                              /* link (NOT SUPPORTED) */
                   4866:     { &vop_rename_desc, hfs_rename },                  /* rename */
                   4867:     { &vop_mkdir_desc, hfs_mkdir },                            /* mkdir */
                   4868:     { &vop_rmdir_desc, hfs_rmdir },                            /* rmdir */
                   4869:     { &vop_mkcomplex_desc,hfs_mkcomplex },             /* mkcomplex */
                   4870:     { &vop_getattrlist_desc,hfs_getattrlist },  /* getattrlist */
                   4871:     { &vop_setattrlist_desc,hfs_setattrlist },  /* setattrlist */
                   4872:     { &vop_symlink_desc, hfs_symlink },                        /* symlink */
                   4873:     { &vop_readdir_desc, hfs_readdir },                        /* readdir */
                   4874:     { &vop_readdirattr_desc, hfs_readdirattr },        /* readdirattr */
                   4875:     { &vop_readlink_desc, hfs_readlink },              /* readlink */
                   4876:     { &vop_abortop_desc, hfs_abortop },                        /* abortop */
                   4877:     { &vop_inactive_desc, hfs_inactive },              /* inactive */
                   4878:     { &vop_reclaim_desc, hfs_reclaim },                        /* reclaim */
                   4879:     { &vop_lock_desc, hfs_lock },                              /* lock */
                   4880:     { &vop_unlock_desc, hfs_unlock },                  /* unlock */
                   4881:     { &vop_bmap_desc, hfs_bmap },                              /* bmap */
                   4882:     { &vop_strategy_desc, hfs_strategy },              /* strategy */
                   4883:     { &vop_print_desc, hfs_print },                            /* print */
                   4884:     { &vop_islocked_desc, hfs_islocked },              /* islocked */
                   4885:     { &vop_pathconf_desc, hfs_pathconf },              /* pathconf */
                   4886:     { &vop_advlock_desc, hfs_advlock },                        /* advlock */
                   4887:     { &vop_reallocblks_desc, hfs_reallocblks },        /* reallocblks */
                   4888:     { &vop_truncate_desc, hfs_truncate },              /* truncate */
                   4889:     { &vop_allocate_desc, hfs_allocate },              /* allocate */
                   4890:     { &vop_update_desc, hfs_update },                  /* update */
                   4891:        { &vop_searchfs_desc,hfs_search },                      /* search fs */
                   4892:     { &vop_bwrite_desc, vn_bwrite },                   /* bwrite */
                   4893:     { &vop_pagein_desc, hfs_pagein },           /* pagein */
                   4894:     { &vop_pageout_desc, hfs_pageout },         /* pageout */
                   4895:     { NULL, NULL }
                   4896: };
                   4897: 
                   4898: struct vnodeopv_desc hfs_vnodeop_opv_desc =
                   4899: { &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.