Annotation of XNU/bsd/hfs/hfs_lookup.c, revision 1.1.1.1

1.1       root        1: /*
                      2:  * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
                      3:  *
                      4:  * @APPLE_LICENSE_HEADER_START@
                      5:  * 
                      6:  * The contents of this file constitute Original Code as defined in and
                      7:  * are subject to the Apple Public Source License Version 1.1 (the
                      8:  * "License").  You may not use this file except in compliance with the
                      9:  * License.  Please obtain a copy of the License at
                     10:  * http://www.apple.com/publicsource and read it before using this file.
                     11:  * 
                     12:  * This Original Code and all software distributed under the License are
                     13:  * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
                     14:  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
                     15:  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
                     16:  * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
                     17:  * License for the specific language governing rights and limitations
                     18:  * under the License.
                     19:  * 
                     20:  * @APPLE_LICENSE_HEADER_END@
                     21:  */
                     22: /*
                     23:  * Copyright (c) 1989, 1993
                     24:  *     The Regents of the University of California.  All rights reserved.
                     25:  * (c) UNIX System Laboratories, Inc.
                     26:  * All or some portions of this file are derived from material licensed
                     27:  * to the University of California by American Telephone and Telegraph
                     28:  * Co. or Unix System Laboratories, Inc. and are reproduced herein with
                     29:  * the permission of UNIX System Laboratories, Inc.
                     30:  *
                     31:  * Redistribution and use in source and binary forms, with or without
                     32:  * modification, are permitted provided that the following conditions
                     33:  * are met:
                     34:  * 1. Redistributions of source code must retain the above copyright
                     35:  *       notice, this list of conditions and the following disclaimer.
                     36:  * 2. Redistributions in binary form must reproduce the above copyright
                     37:  *       notice, this list of conditions and the following disclaimer in the
                     38:  *       documentation and/or other materials provided with the distribution.
                     39:  * 3. All advertising materials mentioning features or use of this software
                     40:  *       must display the following acknowledgement:
                     41:  *     This product includes software developed by the University of
                     42:  *     California, Berkeley and its contributors.
                     43:  * 4. Neither the name of the University nor the names of its contributors
                     44:  *       may be used to endorse or promote products derived from this software
                     45:  *       without specific prior written permission.
                     46:  *
                     47:  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
                     48:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
                     49:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
                     50:  * ARE DISCLAIMED.     IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
                     51:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
                     52:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
                     53:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
                     54:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
                     55:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
                     56:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
                     57:  * SUCH DAMAGE.
                     58:  *
                     59:  *     @(#)hfs_lookup.c        1.0
                     60:  *     derived from @(#)ufs_lookup.c   8.15 (Berkeley) 6/16/95
                     61:  *
                     62:  *     (c) 1998-1999   Apple Computer, Inc.     All Rights Reserved
                     63:  *     (c) 1990, 1992  NeXT Computer, Inc.     All Rights Reserved
                     64:  *     
                     65:  *
                     66:  *     hfs_lookup.c -- code to handle directory traversal on HFS/HFS+ volume
                     67:  *
                     68:  *     MODIFICATION HISTORY:
                     69:  *     21-May-1999 Don Brady           Add support for HFS rooting.
                     70:  *      25-Feb-1999 Clark Warner       Fixed the error case of VFS_VGGET when
                     71:  *                                      processing DotDot (..) to relock parent
                     72:  *     23-Feb-1999 Pat Dirks           Finish cleanup around Don's last fix in "." and ".." handling.
                     73:  *     11-Nov-1998 Don Brady           Take out VFS_VGET that got added as part of previous fix.
                     74:  *     14-Oct-1998 Don Brady           Fix locking policy volation in hfs_lookup for ".." case
                     75:  *                                                             (radar #2279902).
                     76:  *      4-Jun-1998 Pat Dirks           Split off from hfs_vnodeops.c
                     77:  */
                     78: 
                     79: #include <sys/param.h>
                     80: #include <sys/namei.h>
                     81: #include <sys/buf.h>
                     82: #include <sys/file.h>
                     83: #include <sys/mount.h>
                     84: #include <sys/vnode.h>
                     85: #include <paths.h>
                     86: 
                     87: #include       "hfs.h"
                     88: #include       "hfs_dbg.h"
                     89: #include       "hfscommon/headers/FileMgrInternal.h"
                     90: 
                     91: u_int16_t      GetForkFromName(struct componentname  *cnp);
                     92: int                    hfs_vget_sibling(struct vnode *vdp, u_int16_t forkType, struct vnode **vpp);
                     93: int            hfs_vget_catinfo(struct vnode *parent_vp, struct hfsCatalogInfo *catInfo, u_int32_t forkType, struct vnode **target_vpp);
                     94: 
                     95: /*
                     96:  *     XXX SER fork strings.
                     97:  * Put these someplace better
                     98:  */
                     99: #define gHFSForkIdentStr       "/"
                    100: #define gDataForkNameStr       "data"
                    101: #define gRsrcForkNameStr       "rsrc"
                    102: 
                    103: 
                    104: extern int cache_lookup(struct vnode *dvp, struct vnode **vpp, struct componentname *cnp);
                    105: extern void cache_enter(struct vnode *dvp, struct vnode *vp, struct componentname *cnp);
                    106: 
                    107: #if DBG_VOP_TEST_LOCKS
                    108: extern void DbgVopTest(int maxSlots, int retval, VopDbgStoreRec *VopDbgStore, char *funcname);
                    109: #endif
                    110: 
                    111: /*****************************************************************************
                    112: *
                    113: *      Operations on vnodes
                    114: *
                    115: *****************************************************************************/
                    116: 
                    117: 
                    118: /*     
                    119:  * FROM FREEBSD 3.1
                    120:  * Convert a component of a pathname into a pointer to a locked hfsnode.
                    121:  * This is a very central and rather complicated routine.
                    122:  * If the file system is not maintained in a strict tree hierarchy,
                    123:  * this can result in a deadlock situation (see comments in code below).
                    124:  *
                    125:  * The cnp->cn_nameiop argument is LOOKUP, CREATE, RENAME, or DELETE depending
                    126:  * on whether the name is to be looked up, created, renamed, or deleted.
                    127:  * When CREATE, RENAME, or DELETE is specified, information usable in
                    128:  * creating, renaming, or deleting a directory entry may be calculated.
                    129:  * Notice that these are the only operations that can affect the directory of the target.
                    130:  *
                    131:  * If flag has LOCKPARENT or'ed into it and the target of the pathname
                    132:  * exists, lookup returns both the target and its parent directory locked.
                    133:  * When creating or renaming and LOCKPARENT is specified, the target may
                    134:  * not be ".". When deleting and LOCKPARENT is specified, the target may
                    135:  * be "."., but the caller must check to ensure it does an vrele and vput
                    136:  * instead of two vputs.
                    137:  *
                    138:  * LOCKPARENT and WANTPARENT actually refer to the parent of the last item,
                    139:  * so if ISLASTCN is not set, they should be ignored. Also they are mutually exclusive, or
                    140:  * WANTPARENT really implies DONTLOCKPARENT. Either of them set means that the calling
                    141:  * routine wants to access the parent of the target, locked or unlocked.
                    142:  *
                    143:  * Keeping the parent locked as long as possible protects from other processes
                    144:  * looking up the same item, so it has to be locked until the hfsnode is totally finished
                    145:  *
                    146:  * This routine is actually used as VOP_CACHEDLOOKUP method, and the
                    147:  * filesystem employs the generic hfs_cache_lookup() as VOP_LOOKUP
                    148:  * method.
                    149:  *
                    150:  * hfs_cache_lookup() performs the following for us:
                    151:  *     check that it is a directory
                    152:  *     check accessibility of directory
                    153:  *     check for modification attempts on read-only mounts
                    154:  *     if name found in cache
                    155:  *             if at end of path and deleting or creating
                    156:  *             drop it
                    157:  *              else
                    158:  *             return name.
                    159:  *     return VOP_CACHEDLOOKUP()
                    160:  *
                    161:  * Overall outline of hfs_lookup:
                    162:  *
                    163:  *     handle simple cases of . and ..
                    164:  *     search for name in directory, to found or notfound
                    165:  * notfound:
                    166:  *     if creating, return locked directory, leaving info on available slots
                    167:  *     else return error
                    168:  * found:
                    169:  *     if at end of path and deleting, return information to allow delete
                    170:  *     if at end of path and rewriting (RENAME and LOCKPARENT), lock target
                    171:  *       inode and return info to allow rewrite
                    172:  *     if not at end, add name to cache; if at end and neither creating
                    173:  *       nor deleting, add name to cache
                    174:  */
                    175: 
                    176: /*     
                    177:  *     Lookup *nm in directory *pvp, return it in *a_vpp.
                    178:  *     **a_vpp is held on exit.
                    179:  *     We create a hfsnode for the file, but we do NOT open the file here.
                    180: 
                    181: #% lookup      dvp L ? ?
                    182: #% lookup      vpp - L -
                    183: 
                    184:        IN struct vnode *dvp - Parent node of file;
                    185:        INOUT struct vnode **vpp - node of target file, its a new node if the target vnode did not exist;
                    186:        IN struct componentname *cnp - Name of file;
                    187: 
                    188:  *     When should we lock parent_hp in here ??
                    189:  */
                    190: 
                    191: int
                    192: hfs_lookup(ap)
                    193:        struct vop_cachedlookup_args /* {
                    194:                struct vnode *a_dvp;
                    195:                struct vnode **a_vpp;
                    196:                struct componentname *a_cnp;
                    197:        } */ *ap;
                    198: {
                    199:        struct vnode                                    *parent_vp;
                    200:        struct vnode                                    *target_vp;
                    201:        struct vnode                                    *tparent_vp;
                    202:        struct hfsnode                                  *parent_hp;                             /* parent */
                    203:        struct componentname                    *cnp;
                    204:        struct ucred                                    *cred;
                    205:        struct proc                                             *p;
                    206:        struct hfsCatalogInfo                   catInfo;
                    207:        u_int32_t                                               parent_id;
                    208:        u_int32_t                                               nodeID;
                    209:        u_int16_t                                               targetLen;
                    210:        u_int16_t                                               forkType;
                    211:        int                                                     flags;
                    212:        int                                                             lockparent;                                             /* !0 => lockparent flag is set */
                    213:        int                                                             wantparent;                                             /* !0 => wantparent or lockparent flag */
                    214:        int                                                             nameiop;
                    215:        int                                                             retval;
                    216:        u_char                                                  isDot, isDotDot, found;
                    217:        DBG_FUNC_NAME("lookup");
                    218:        DBG_VOP_LOCKS_DECL(2);
                    219:        DBG_VOP_LOCKS_INIT(0,ap->a_dvp, VOPDBG_LOCKED, VOPDBG_IGNORE, VOPDBG_IGNORE, VOPDBG_POS);
                    220:        DBG_VOP_LOCKS_INIT(1,*ap->a_vpp, VOPDBG_IGNORE, VOPDBG_LOCKED, VOPDBG_IGNORE, VOPDBG_POS);
                    221:        DBG_VOP_PRINT_FUNCNAME();DBG_VOP_CONT(("\n"));
                    222:        DBG_HFS_NODE_CHECK(ap->a_dvp);
                    223:         
                    224: 
                    225:        /*
                    226:         * Do initial setup
                    227:         */
                    228:        parent_vp               = ap->a_dvp;
                    229:        cnp                             = ap->a_cnp;
                    230:        parent_hp               = VTOH(parent_vp);                              /* parent */
                    231:        target_vp               = NULL;
                    232:        targetLen               = cnp->cn_namelen;
                    233:        nameiop                 = cnp->cn_nameiop;
                    234:        cred                    = cnp->cn_cred;
                    235:        p                               = cnp->cn_proc;
                    236:        lockparent              = cnp->cn_flags & LOCKPARENT;
                    237:        wantparent              = cnp->cn_flags & (LOCKPARENT|WANTPARENT);
                    238:        flags                   = cnp->cn_flags;
                    239:        parent_id               = H_FILEID(parent_hp);
                    240:        nodeID                  = kUnknownID;
                    241:        found                   = FALSE;
                    242:        isDot                   = FALSE;
                    243:        isDotDot                = FALSE;
                    244:        catInfo.hint    = 0;
                    245:        retval                  = E_NONE;
                    246:        forkType                = kUndefinedFork;
                    247: 
                    248: 
                    249: 
                    250:        /*
                    251:         * We now have a segment name to search for, and a directory to search.
                    252:         *
                    253:         */
                    254: 
                    255:        /*
                    256:         * First check to see if it is a . or .., else look it up.
                    257:         */
                    258: 
                    259:        if (flags & ISDOTDOT) {                                                                 /* Wanting the parent */
                    260:                isDotDot = TRUE;
                    261:                found = TRUE;                                                                           /* .. is always defined */
                    262:                nodeID = H_DIRID(parent_hp);
                    263:        }                                                                                                               /* Wanting ourselves */
                    264:        else if ((cnp->cn_nameptr[0] == '.') && (targetLen == 1)) {
                    265:                isDot = TRUE;
                    266:                found = TRUE;                                                                           /* We always know who we are */
                    267:        } 
                    268:        else {                                                                                                  /* Wanting something else */
                    269:                /* lock catalog b-tree */
                    270:                retval = hfs_metafilelocking(VTOHFS(parent_vp), kHFSCatalogFileID, LK_SHARED, p);
                    271:                if (retval)
                    272:                           goto Err_Exit;
                    273: 
                    274:                catInfo.hint = kNoHint;
                    275:                retval = hfsLookup (VTOVCB(parent_vp), parent_id, cnp->cn_nameptr, targetLen, &catInfo);
                    276:        
                    277:        /* unlock catalog b-tree */
                    278:                (void) hfs_metafilelocking(VTOHFS(parent_vp), kHFSCatalogFileID, LK_RELEASE, p);
                    279:        
                    280:                if (retval == E_NONE)
                    281:                        found = TRUE;
                    282:        };
                    283: 
                    284: 
                    285:        /*
                    286:         * At this point we know IF we have a valid dir/name.
                    287:         */
                    288: 
                    289: 
                    290:        retval = E_NONE;
                    291:        if (! found) {
                    292:        /*
                    293:         * This is a non-existing entry
                    294:         *
                    295:         * If creating, and at end of pathname and current
                    296:         * directory has not been removed, then can consider
                    297:         * allowing file to be created.
                    298:         */
                    299:        if ((nameiop == CREATE || nameiop == RENAME ||
                    300:                        (nameiop == DELETE &&
                    301:                        (ap->a_cnp->cn_flags & DOWHITEOUT) &&
                    302:                        (ap->a_cnp->cn_flags & ISWHITEOUT))) &&
                    303:                        (flags & ISLASTCN)) {
                    304:                /*
                    305:                 * Access for write is interpreted as allowing
                    306:                 * creation of files in the directory.
                    307:                 */
                    308:                retval = VOP_ACCESS(parent_vp, VWRITE, cred, cnp->cn_proc);
                    309:                if (retval)
                    310:                        return (retval);
                    311:        
                    312:                cnp->cn_flags |= SAVENAME;
                    313:                if (!lockparent)
                    314:                        VOP_UNLOCK(parent_vp, 0, p);
                    315:                retval = EJUSTRETURN;
                    316:                goto Err_Exit;
                    317:                }
                    318:        
                    319:                /*
                    320:                 * Insert name into cache (as non-existent) if appropriate.
                    321:                 */
                    322: 
                    323:                /*
                    324:                * XXX SER - Here we would store the name in cache as non-existant if not trying to create it, but,
                    325:        * the name cache IS case-sensitive, thus maybe showing a negative hit, when the name
                    326:        * is only different by case. So hfs does not support negative caching. Something to look at.
                    327:        * (See radar 2293594 for a failed example)
                    328:                if ((cnp->cn_flags & MAKEENTRY) && nameiop != CREATE)
                    329:                        cache_enter(parent_vp, *vpp, cnp);
                    330:                */
                    331:        
                    332:                retval = ENOENT;
                    333:        }
                    334:        else {
                    335:                /*
                    336:                 * We have found an entry
                    337:                 *
                    338:                 * Here we have to decide what type of vnode to create.
                    339:                 * There are 3 type of objects that are given:
                    340:                 * 1. '.': return the same dp
                    341:                 * 2. '..' return the parent of dp, always a VDIR
                    342:                 * 3. catinfo rec: return depending on type:
                    343:                 *  A. VDIR, nodeType is kCatalogFolderNode
                    344:                 *  B. VLINK nodeType is kCatalogFileNode, the mode is IFLNK (esp. if it is a link to a directory e.g. bar/link/foo)
                    345:                 *  C. VREG, nodeType is kCatalogFileNode, forkType at this point is unknown
                    346:                 * To determine the forkType, we can use this algorithm (\0 in the strings mean the NULL character):
                    347:                 * a. forkType is kDataType iff ISLASTCN is set (as in the case of the default fork e.g. data/foo).
                    348:                 * b. forkType is kDataType iff ISLASTCN is not set and the namePtr is followed by "/?AppleHFSFork/data\0"
                    349:                 * c. forkType is kRsrcType iff ISLASTCN is not set and the namePtr is followed by "/?AppleHFSFork/rsrc\0"
                    350:                 * If the latter two are correct, then we 'consume' the remaining of the name buffer
                    351:                 * and set the cnp as appropriate.
                    352:                 * Anything else returns an retval
                    353:                 */
                    354: 
                    355:                
                    356:                /*
                    357:                 * If deleting, and at end of pathname, return
                    358:                 * parameters which can be used to remove file.
                    359:                 * If the wantparent flag isn't set, we return only
                    360:                 * the directory (in ndp->ndvp), otherwise we go
                    361:                 * on and lock the hfsnode, being careful with ".".
                    362:                 *
                    363:                 * Forks cannot be deleted so scan-ahead is illegal, so just return the default fork
                    364:                 */
                    365:                if (nameiop == DELETE && (flags & ISLASTCN)) {
                    366:                        /*
                    367:                        * Write access to directory required to delete files.
                    368:                        */
                    369:                        retval = VOP_ACCESS(parent_vp, VWRITE, cred, cnp->cn_proc);
                    370:                        if (retval)
                    371:                                goto Err_Exit;
                    372:        
                    373:                        if (isDot) {                                    /* Want to return ourselves */
                    374:                                VREF(parent_vp);
                    375:                                target_vp = parent_vp;
                    376:                                goto Err_Exit;
                    377:                        }
                    378:                        else if (isDotDot) {
                    379:                                retval = VFS_VGET(parent_vp->v_mount, &nodeID, &target_vp);
                    380:                                if (retval)
                    381:                                        goto Err_Exit;
                    382:                        }
                    383:                        else {
                    384:                                retval = hfs_vget_catinfo(parent_vp, &catInfo, kAnyFork, &target_vp);
                    385:                                if (retval)
                    386:                                        goto Err_Exit;
                    387:                        };
                    388: 
                    389: 
                    390:                        /*
                    391:                         * If directory is "sticky", then user must own
                    392:                         * the directory, or the file in it, else she
                    393:                         * may not delete it (unless she's root). This
                    394:                         * implements append-only directories.
                    395:                         */
                    396:                        if ((parent_hp->h_meta->h_mode & ISVTX) &&
                    397:                                        cred->cr_uid != 0 &&
                    398:                                        cred->cr_uid != parent_hp->h_meta->h_uid &&
                    399:                                        target_vp->v_type != VLNK &&
                    400:                                        VTOH(target_vp)->h_meta->h_uid != cred->cr_uid) {
                    401:                                VPUT(target_vp);
                    402:                                retval = EPERM;
                    403:                                goto Err_Exit;
                    404:                        }
                    405: #if HFS_HARDLINKS
                    406:                        /*
                    407:                         * If this is a link node then we need to save the name
                    408:                         * (of the link) so we can delete it from the catalog b-tree.
                    409:                         * In this case, hfs_remove will then free the component name.
                    410:                         */
                    411:                        if (target_vp && (VTOH(target_vp)->h_meta->h_metaflags & IN_DATANODE))
                    412:                                cnp->cn_flags |= SAVENAME;
                    413: #endif
                    414:          
                    415:                        if (!lockparent)
                    416:                                VOP_UNLOCK(parent_vp, 0, p);
                    417:                        goto Err_Exit;
                    418:                 };
                    419:        
                    420:                /*
                    421:                 * If rewriting 'RENAME', return the hfsnode and the
                    422:                 * information required to rewrite the present directory
                    423:                 */
                    424:                if (nameiop == RENAME && wantparent && (cnp->cn_flags & ISLASTCN)) {
                    425:        
                    426:                        if ((retval = VOP_ACCESS(parent_vp, VWRITE, cred, cnp->cn_proc)) != 0)
                    427:                                goto Err_Exit;
                    428: 
                    429:                        /*
                    430:                         * Careful about locking second inode.
                    431:                         * This can only occur if the target is ".". like 'mv foo/bar foo/.'
                    432:                         */
                    433:                        if (isDot) {
                    434:                                retval = EISDIR;
                    435:                                goto Err_Exit;
                    436:                        }
                    437:                        else if (isDotDot) {
                    438:                                retval = VFS_VGET(parent_vp->v_mount, &nodeID, &target_vp);
                    439:                                if (retval)
                    440:                                        goto Err_Exit;
                    441:                        }
                    442:                        else {
                    443:                                /* If then name differs in case, then act like it does not exist 
                    444:                                 * This allows renaming foo->Foo
                    445:                                 */     
                    446:                                if (strncmp(cnp->cn_nameptr, catInfo.spec.name, targetLen)) {
                    447:                                        if (!lockparent)
                    448:                                                VOP_UNLOCK(parent_vp, 0, p);
                    449:                                        retval = EJUSTRETURN;
                    450:                                        goto Err_Exit;
                    451:                                };
                    452: 
                    453:                                retval = hfs_vget_catinfo(parent_vp, &catInfo, kAnyFork, &target_vp);
                    454:                                if (retval)
                    455:                                        goto Err_Exit;
                    456:                        };
                    457:                        
                    458:                        cnp->cn_flags |= SAVENAME;
                    459:                        if (!lockparent)
                    460:                                VOP_UNLOCK(parent_vp, 0, p);
                    461:                        goto Err_Exit;
                    462:                /* Finished...all is well, goto the end */
                    463:                 };
                    464:        
                    465:                /*
                    466:                 * Step through the translation in the name.  We do not `vput' the
                    467:                 * directory because we may need it again if a symbolic link
                    468:                 * is relative to the current directory.  Instead we save it
                    469:                 * unlocked as "tparent_vp".  We must get the target hfsnode before unlocking
                    470:                 * the directory to insure that the hfsnode will not be removed
                    471:                 * before we get it.  We prevent deadlock by always fetching
                    472:                 * inodes from the root, moving down the directory tree. Thus
                    473:                 * when following backward pointers ".." we must unlock the
                    474:                 * parent directory before getting the requested directory.
                    475:                 * There is a potential race condition here if both the current
                    476:                 * and parent directories are removed before the VFS_VGET for the
                    477:                 * hfsnode associated with ".." returns.  We hope that this occurs
                    478:                 * infrequently since we cannot avoid this race condition without
                    479:                 * implementing a sophisticated deadlock detection algorithm.
                    480:                 * Note also that this simple deadlock detection scheme will not
                    481:                 * work if the file system has any hard links other than ".."
                    482:                 * that point backwards in the directory structure.
                    483:                 */
                    484:        
                    485:                tparent_vp = parent_vp;
                    486:                if (isDotDot) {
                    487:                        VOP_UNLOCK(tparent_vp, 0, p);   /* race to get the inode */
                    488:                        if ((retval = VFS_VGET(parent_vp->v_mount, &nodeID, &target_vp))) {
                    489:                        vn_lock(tparent_vp, LK_EXCLUSIVE | LK_RETRY, p);
                    490:                        goto Err_Exit;
                    491:                }
                    492:                        if (lockparent && (flags & ISLASTCN) &&
                    493:                            (retval = vn_lock(tparent_vp, LK_EXCLUSIVE, p))) {
                    494:                                vput(target_vp);
                    495:                                goto Err_Exit;
                    496:                        }
                    497:                }
                    498:                else if (isDot) {
                    499:                        VREF(parent_vp);        /* we want ourself, ie "." */
                    500:                        target_vp = parent_vp;
                    501:                }
                    502:                else {
                    503:                        mode_t mode;
                    504:                        /* 
                    505:                         * Determine what fork to get, currenty 3 scenarios are supported:
                    506:                         * 1. ./foo: if it is a dir, return a VDIR else return data fork
                    507:                         * 2. ./foo/.__Fork/data: return data fork
                    508:                         * 3. ./foo/.__Fork/rsrc: return resource fork
                    509:                         * So the algorithm is:
                    510:                         * If the object is a directory
                    511:                         *      then return a VDIR vnode
                    512:                         * else if ISLASTCN is true
                    513:                         *      then get the vnode with forkType=kDataFork
                    514:                         * else
                    515:                         *      compare with the remaining cnp buffer with "/.__Fork/"
                    516:                         *      if a match
                    517:                         *              then compare string after that with either 'data' or 'rsrc'
                    518:                         *              if match
                    519:                         *                      then 
                    520:                         *                      'consume' rest of cnp, setting appropriate values and flags
                    521:                         *                      return vnode depending on match
                    522:                         *              else
                    523:                         *                      bad fork name
                    524:                         *      else
                    525:                         *              illegal path after a file object
                    526:                         */
                    527: 
                    528:                        mode = (mode_t)(catInfo.nodeData.cnd_permissions & 0x0000FFFF);
                    529:                        
                    530:                        if (catInfo.nodeData.cnd_type == kCatalogFolderNode) {
                    531:                                forkType = kDirectory;                          /* Really ignored */
                    532:                        } 
                    533:                        else if ((mode & IFMT) == IFLNK) {
                    534:                                forkType = kDataFork;
                    535:                        }                                                                       /* After this point, nodeType should be a file */
                    536:                        else if (flags & ISLASTCN) {                    /* Create a default fork */
                    537:                                forkType = kDataFork;
                    538:                }
                    539:                        else {                                                                  /* determine what fork was specified */
                    540:                                forkType = GetForkFromName(cnp);
                    541:                                flags |= ISLASTCN;                                      /* To know to unlock the parent if needed */
                    542:                        };      /* else */
                    543: 
                    544:                        
                    545:                        /* If couldn't determine what type of fork, leave */
                    546:                        if (forkType == kUndefinedFork) {                               
                    547:                                retval = EISDIR;
                    548:                                goto Err_Exit;
                    549:                        };
                    550:                                
                    551:                        /* Get the vnode now that what type of fork is known */
                    552:                        DBG_ASSERT((forkType==kDirectory) || (forkType==kDataFork) || (forkType==kRsrcFork));
                    553:                        retval = hfs_vget_catinfo(tparent_vp, &catInfo, forkType, &target_vp);
                    554:                        if (retval != E_NONE)
                    555:                                goto Err_Exit;
                    556: 
                    557:                        if (!lockparent || !(flags & ISLASTCN))
                    558:                                VOP_UNLOCK(tparent_vp, 0, p);
                    559: 
                    560:                };      /* else found */
                    561: 
                    562: 
                    563:                /*
                    564:                * Insert name in cache if wanted.
                    565:                */
                    566:                if (cnp->cn_flags & MAKEENTRY)  {
                    567:                        /*
                    568:                         * XXX SER - Might be good idea to bcopy(catInfo.nodeData.fsspec.name, cnp->cn_nameptr)
                    569:                         * to "normalize" the name cache. This will avoid polluting the name cache with
                    570:                         * names that are different in case, and allow negative caching
                    571:                         */
                    572:                        cache_enter(parent_vp, target_vp, cnp);
                    573:                        }
                    574:        
                    575: 
                    576:        };      /* else found == TRUE */
                    577:        
                    578: Err_Exit:
                    579: 
                    580:        *ap->a_vpp = target_vp;
                    581: 
                    582:        DBG_VOP_UPDATE_VP(1, *ap->a_vpp);
                    583:        DBG_VOP_LOOKUP_TEST (funcname, cnp, parent_vp, target_vp);
                    584:        DBG_VOP_LOCKS_TEST(E_NONE);
                    585:        DBG_VOP_PRINT_FUNCNAME();
                    586:        if (retval == E_NONE) {
                    587:                DBG_VOP_CONT(("Success\n"));
                    588:        } else {
                    589:                DBG_VOP_CONT(("Fails\n"));
                    590:        }
                    591: 
                    592:        return (retval);
                    593: }
                    594: 
                    595: 
                    596: 
                    597: /*
                    598:  * Based on vn_cache_lookup (which is vfs_cache_lookup in FreeBSD 3.1)
                    599:  *
                    600:  * Name caching works as follows:
                    601:  *
                    602:  * Names found by directory scans are retained in a cache
                    603:  * for future reference.  It is managed LRU, so frequently
                    604:  * used names will hang around.         Cache is indexed by hash value
                    605:  * obtained from (vp, name) where vp refers to the directory
                    606:  * containing name.
                    607:  *
                    608:  * If it is a "negative" entry, (i.e. for a name that is known NOT to
                    609:  * exist) the vnode pointer will be NULL.
                    610:  *
                    611:  * Upon reaching the last segment of a path, if the reference
                    612:  * is for DELETE, or NOCACHE is set (rewrite), and the
                    613:  * name is located in the cache, it will be dropped.
                    614:  *
                    615:  * In hfs, since a name can represent multiple forks, it cannot
                    616:  * be known what fork the name matches, so further checks have to be done.
                    617:  * Currently a policy of first requested, is the one stored, is followed.
                    618:  *
                    619:  * SER XXX If this proves inadequate maybe we can munge the name to contain a fork reference
                    620:  * like foo -> foo.d for the data fork.
                    621:  */
                    622: 
                    623: int
                    624: hfs_cache_lookup(ap)
                    625:        struct vop_lookup_args /* {
                    626:                struct vnode *a_dvp;
                    627:                struct vnode **a_vpp;
                    628:                struct componentname *a_cnp;
                    629:        } */ *ap;
                    630: {
                    631:        struct vnode *vdp;
                    632:        struct vnode *pdp;
                    633:        int lockparent; 
                    634:        int error;
                    635:        struct vnode **vpp = ap->a_vpp;
                    636:        struct componentname *cnp = ap->a_cnp;
                    637:        struct ucred *cred = cnp->cn_cred;
                    638:        int flags = cnp->cn_flags;
                    639:        struct proc *p = cnp->cn_proc;
                    640:        struct hfsnode *hp;
                    641:        u_int32_t vpid; /* capability number of vnode */
                    642:        DBG_FUNC_NAME("cache_lookup");
                    643:        DBG_VOP_LOCKS_DECL(2);
                    644:        DBG_VOP_LOCKS_INIT(0,ap->a_dvp, VOPDBG_LOCKED, VOPDBG_IGNORE, VOPDBG_IGNORE, VOPDBG_POS);
                    645:        DBG_VOP_LOCKS_INIT(1,*ap->a_vpp, VOPDBG_IGNORE, VOPDBG_LOCKED, VOPDBG_IGNORE, VOPDBG_POS);
                    646:        DBG_VOP_PRINT_FUNCNAME();DBG_VOP_CONT(("\n"));
                    647:     DBG_VOP_CONT(("\tTarget: "));DBG_VOP_PRINT_CPN_INFO(ap->a_cnp);DBG_VOP_CONT(("\n"));
                    648:        DBG_HFS_NODE_CHECK(ap->a_dvp);
                    649: 
                    650:        *vpp = NULL;
                    651:        vdp = ap->a_dvp;
                    652:        lockparent = flags & LOCKPARENT;
                    653: 
                    654:        if (vdp->v_type != VDIR)
                    655:                                return (ENOTDIR);
                    656: 
                    657:        if ((flags & ISLASTCN) && (vdp->v_mount->mnt_flag & MNT_RDONLY) &&
                    658:                (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME))
                    659:                return (EROFS);
                    660: 
                    661:        error = VOP_ACCESS(vdp, VEXEC, cred, cnp->cn_proc);
                    662: 
                    663:        if (error)
                    664:                return (error);
                    665: 
                    666:        /*
                    667:         * Lookup an entry in the cache
                    668:         * If the lookup succeeds, the vnode is returned in *vpp, and a status of -1 is
                    669:         * returned. If the lookup determines that the name does not exist
                    670:         * (negative cacheing), a status of ENOENT is returned. If the lookup
                    671:         * fails, a status of zero is returned.
                    672:         */
                    673:        error = cache_lookup(vdp, vpp, cnp);
                    674: 
                    675:        if (error == 0)  {              /* Unsuccessfull */
                    676:                DBG_VOP(("\tWas not in name cache\n"));
                    677:                error = hfs_lookup(ap);
                    678: #if HFS_HARDLINKS
                    679:                if (error)
                    680:                        return (error);
                    681:                /*
                    682:                 * If this is a hard-link vnode then we need to update
                    683:                 * the name (of the link) and update the parent ID. This
                    684:                 * enables getattrlist calls to return correct link info.
                    685:                 */
                    686:                hp = VTOH(*ap->a_vpp);
                    687:                if ((flags & ISLASTCN) && (hp->h_meta->h_metaflags & IN_DATANODE)) {
                    688:                        H_DIRID(hp) = H_FILEID(VTOH(ap->a_dvp));
                    689:                        hfs_set_metaname(cnp->cn_nameptr, hp->h_meta);
                    690:                }
                    691: #endif
                    692:                return (error);
                    693:        };
                    694:        
                    695:        DBG_VOP(("\tName was found in the name cache"));
                    696:        if (error == ENOENT) {
                    697:                DBG_VOP_CONT((" though it was a NEGATIVE HIT\n"));
                    698:                return (error);
                    699:        };
                    700:        DBG_VOP_CONT(("\n"));
                    701:        
                    702: #if HFS_HARDLINKS
                    703:        /*
                    704:         * If this is a hard-link vnode then we need to update
                    705:         * the name (of the link) and update the parent ID. This
                    706:         * enables getattrlist calls to return correct link info.
                    707:         */
                    708:        hp = VTOH(*vpp);
                    709:        if ((flags & ISLASTCN) && (hp->h_meta->h_metaflags & IN_DATANODE)) {
                    710:                H_DIRID(hp) = H_FILEID(VTOH(vdp));
                    711:                hfs_set_metaname(cnp->cn_nameptr, hp->h_meta);
                    712:        }
                    713: #endif
                    714: 
                    715:        /* We have a name that matched */
                    716:        pdp = vdp;
                    717:        vdp = *vpp;
                    718:        vpid = vdp->v_id;
                    719:        if (pdp == vdp) {       /* lookup on "." */
                    720:                VREF(vdp);
                    721:                error = 0;
                    722:        } else if (flags & ISDOTDOT) {
                    723:                /* 
                    724:                 * Carefull on the locking policy,
                    725:                 * remember we always lock from parent to child, so have
                    726:                 * to release lock on child before trying to lock parent
                    727:                 * then regain lock if needed
                    728:                 */
                    729:                VOP_UNLOCK(pdp, 0, p);
                    730:                error = vget(vdp, LK_EXCLUSIVE, p);
                    731:                if (!error && lockparent && (flags & ISLASTCN))
                    732:                        error = vn_lock(pdp, LK_EXCLUSIVE, p);
                    733:        } else {
                    734:                /* 
                    735:                 * Check to see if a specific fork is not being requested.
                    736:                 *
                    737:                 * If it is a file and not the last path item
                    738:                 * then check if its a proper fork
                    739:                 *              If it is, check to see if the matched vnode is the same fork
                    740:                 *      else see if the proper fork exists.
                    741:                 *              If it does, return that one, else do VOP_CACHEDLOOKUP()
                    742:                 * Notice that nothing is done if an undefined fork is named. Just leave and let lookup()
                    743:                 * handle strange cases.
                    744:                 *
                    745:                 * XXX SER Notice that when the target is not what was in the name cache,
                    746:                 * it is locked, before trying to get its sibling. Could this be a problem since both 
                    747:                 * siblings can be locked, but not in a determinalistic order????
                    748:                 */
                    749:                u_int16_t       forkType;
                    750:                                 
                    751:                error = vget(vdp, LK_EXCLUSIVE, p);
                    752:                if ((! error) && (vdp->v_type == VREG) && (vpid == vdp->v_id)) {
                    753:                        if (!(flags & ISLASTCN)) {
                    754:                                forkType = GetForkFromName(cnp);
                    755:                                if (forkType != kUndefinedFork) {
                    756:                                        flags |= ISLASTCN;
                    757:                                        if (H_FORKTYPE(VTOH(vdp)) != forkType) {
                    758:                                                error = hfs_vget_sibling(vdp, forkType, vpp);
                    759:                                                vput(vdp);
                    760:                                                if (! error) {
                    761:                                                        vdp = *vpp;
                    762:                                                        vpid = vdp->v_id;
                    763:                                                }
                    764:                                        }
                    765:                                }
                    766:                        } 
                    767:                        else {
                    768:                                /* Its the last item, so we want the data fork */
                    769:                                if (H_FORKTYPE(VTOH(vdp)) != kDataFork) {
                    770:                                        error = hfs_vget_sibling(vdp, kDataFork, vpp);
                    771:                                        vput(vdp);
                    772:                                        if (! error) {
                    773:                                                vdp = *vpp;
                    774:                                                vpid = vdp->v_id;
                    775:                                        }
                    776:                                }
                    777:                        };
                    778:                };
                    779:                if (!lockparent || error || !(flags & ISLASTCN))
                    780:                        VOP_UNLOCK(pdp, 0, p);
                    781:        };
                    782:        /*
                    783:         * Check that the capability number did not change
                    784:         * while we were waiting for the lock.
                    785:         */
                    786:        if (!error) {
                    787:                if (vpid == vdp->v_id)
                    788:                        return (0);             /* HERE IS THE NORMAL EXIT FOR CACHE LOOKUP!!!! */
                    789:                /*
                    790:                 * The above is the NORMAL exit, after this point is an error
                    791:                 * condition.
                    792:                 */
                    793:                vput(vdp);
                    794:                if (lockparent && pdp != vdp && (flags & ISLASTCN))
                    795:                        VOP_UNLOCK(pdp, 0, p);
                    796:        }
                    797:        error = vn_lock(pdp, LK_EXCLUSIVE, p);
                    798:        if (error)
                    799:                return (error);
                    800:        return (hfs_lookup(ap));
                    801: }
                    802: 
                    803: /*
                    804:  *     Parses a componentname and sees if the remaining path
                    805:  *     contains a hfs named fork specifier. If it does set the
                    806:  *     componentname to consume the rest of the path, and
                    807:  *     return the forkType
                    808:  */
                    809: 
                    810: u_int16_t      GetForkFromName(struct componentname  *cnp)
                    811: {
                    812:        u_int16_t       forkType        = kUndefinedFork;
                    813:        char            *tcp            = cnp->cn_nameptr + cnp->cn_namelen;
                    814: 
                    815:        if (bcmp(tcp, _PATH_FORKSPECIFIER, sizeof(_PATH_FORKSPECIFIER) - 1) == 0) {             
                    816:                /* Its a HFS fork, so far */
                    817:                tcp += (sizeof(_PATH_FORKSPECIFIER) - 1);
                    818:                if (bcmp(tcp, _PATH_DATANAME, sizeof(_PATH_DATANAME)) == 0) {
                    819:                        forkType = kDataFork;
                    820:                        cnp->cn_consume = sizeof(_PATH_FORKSPECIFIER) + sizeof(_PATH_DATANAME) - 2;
                    821:                }
                    822:                else if (bcmp(tcp, _PATH_RSRCNAME, sizeof(_PATH_RSRCNAME)) == 0) {
                    823:                        forkType = kRsrcFork;
                    824:                        cnp->cn_consume = sizeof(_PATH_FORKSPECIFIER) + sizeof(_PATH_RSRCNAME) - 2;
                    825:                };      /* else if */
                    826:        };      /* if bcmp */   
                    827: 
                    828: 
                    829:        /* XXX SER For backwards compatability...keep it */
                    830:        if (forkType == kUndefinedFork) {
                    831:                tcp = cnp->cn_nameptr + cnp->cn_namelen;
                    832:        if (bcmp(tcp, gHFSForkIdentStr, sizeof(gHFSForkIdentStr) - 1) == 0) {           
                    833:                /* Its a HFS fork, so far */
                    834:                tcp += (sizeof(gHFSForkIdentStr) - 1);
                    835:                if (bcmp(tcp, gDataForkNameStr, sizeof(gDataForkNameStr)) == 0) {
                    836:                        forkType = kDataFork;
                    837:                        cnp->cn_consume = sizeof(gHFSForkIdentStr) + sizeof(gDataForkNameStr) - 2;
                    838:                }
                    839:                else if (bcmp(tcp, gRsrcForkNameStr, sizeof(gRsrcForkNameStr)) == 0) {
                    840:                        forkType = kRsrcFork;
                    841:                        cnp->cn_consume = sizeof(gHFSForkIdentStr) + sizeof(gRsrcForkNameStr) - 2;
                    842:                };      /* else if */
                    843:        };      /* if bcmp */                                                           
                    844:        };                                                      
                    845: 
                    846:        return forkType;        
                    847: }
                    848: 
                    849: #if DBG_VOP_TEST_LOCKS
                    850: 
                    851: void DbgLookupTest( char *funcname, struct componentname  *cnp, struct vnode *dvp, struct vnode *vp)
                    852: {
                    853:        if (! (hfs_dbg_lookup || hfs_dbg_all))
                    854:                return;
                    855:                
                    856:                
                    857:        if (dvp) {
                    858:                if (lockstatus(&VTOH(dvp)->h_lock)) {
                    859:                        DBG_LOOKUP (("%s: Parent vnode exited LOCKED", funcname));
                    860:                }
                    861:                else {
                    862:                        DBG_LOOKUP (("%s: Parent vnode exited UNLOCKED", funcname));
                    863:                }
                    864:        }
                    865: 
                    866:        if (vp) {
                    867:                if (vp==dvp)
                    868:                  {
                    869:                        DBG_LOOKUP (("%s: Target and Parent are the same", funcname));
                    870:                  }
                    871:                else {
                    872:                        if (lockstatus(&VTOH(vp)->h_lock)) {
                    873:                                DBG_LOOKUP (("%s: Found vnode exited LOCKED", funcname));
                    874:                        }
                    875:                        else {
                    876:                                DBG_LOOKUP (("%s: Found vnode exited LOCKED", funcname));
                    877:                        }
                    878:                }
                    879:                DBG_LOOKUP (("%s: Found vnode 0x%x has vtype of %d\n ", funcname, (u_int)vp, vp->v_type));
                    880:        }
                    881:        else
                    882:                DBG_LOOKUP (("%s: Found vnode exited NULL\n",  funcname));
                    883: 
                    884: 
                    885: }
                    886: 
                    887: #endif /* DBG_VOP_TEST_LOCKS */
                    888: 

unix.superglobalmegacorp.com

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