The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/bsd/hfs/hfs_lookup.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*
    2  * Copyright (c) 1999-2003 Apple Computer, Inc. All rights reserved.
    3  *
    4  * @APPLE_LICENSE_HEADER_START@
    5  * 
    6  * Copyright (c) 1999-2003 Apple Computer, Inc.  All Rights Reserved.
    7  * 
    8  * This file contains Original Code and/or Modifications of Original Code
    9  * as defined in and that are subject to the Apple Public Source License
   10  * Version 2.0 (the 'License'). You may not use this file except in
   11  * compliance with the License. Please obtain a copy of the License at
   12  * http://www.opensource.apple.com/apsl/ and read it before using this
   13  * file.
   14  * 
   15  * The Original Code and all software distributed under the License are
   16  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
   17  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
   18  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
   19  * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
   20  * Please see the License for the specific language governing rights and
   21  * limitations under the License.
   22  * 
   23  * @APPLE_LICENSE_HEADER_END@
   24  */
   25 /*
   26  * Copyright (c) 1989, 1993
   27  *      The Regents of the University of California.  All rights reserved.
   28  * (c) UNIX System Laboratories, Inc.
   29  * All or some portions of this file are derived from material licensed
   30  * to the University of California by American Telephone and Telegraph
   31  * Co. or Unix System Laboratories, Inc. and are reproduced herein with
   32  * the permission of UNIX System Laboratories, Inc.
   33  *
   34  * Redistribution and use in source and binary forms, with or without
   35  * modification, are permitted provided that the following conditions
   36  * are met:
   37  * 1. Redistributions of source code must retain the above copyright
   38  *        notice, this list of conditions and the following disclaimer.
   39  * 2. Redistributions in binary form must reproduce the above copyright
   40  *        notice, this list of conditions and the following disclaimer in the
   41  *        documentation and/or other materials provided with the distribution.
   42  * 3. All advertising materials mentioning features or use of this software
   43  *        must display the following acknowledgement:
   44  *      This product includes software developed by the University of
   45  *      California, Berkeley and its contributors.
   46  * 4. Neither the name of the University nor the names of its contributors
   47  *        may be used to endorse or promote products derived from this software
   48  *        without specific prior written permission.
   49  *
   50  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
   51  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   52  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   53  * ARE DISCLAIMED.      IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   54  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   55  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   56  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   57  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   58  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   59  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   60  * SUCH DAMAGE.
   61  *
   62  *      @(#)hfs_lookup.c        1.0
   63  *      derived from @(#)ufs_lookup.c   8.15 (Berkeley) 6/16/95
   64  *
   65  *      (c) 1998-1999   Apple Computer, Inc.     All Rights Reserved
   66  *      (c) 1990, 1992  NeXT Computer, Inc.     All Rights Reserved
   67  *      
   68  *
   69  *      hfs_lookup.c -- code to handle directory traversal on HFS/HFS+ volume
   70  */
   71 #define LEGACY_FORK_NAMES       0
   72 
   73 #include <sys/param.h>
   74 #include <sys/buf.h>
   75 #include <sys/file.h>
   76 #include <sys/mount.h>
   77 #include <sys/vnode.h>
   78 #include <sys/namei.h>
   79 #include <sys/malloc.h>
   80 #include <sys/paths.h>
   81 
   82 #include "hfs.h"
   83 #include "hfs_catalog.h"
   84 #include "hfs_cnode.h"
   85 
   86 
   87 static int forkcomponent(struct componentname *cnp, int *rsrcfork);
   88 
   89 #define _PATH_DATAFORKSPEC      "/..namedfork/data"
   90 
   91 #ifdef LEGACY_FORK_NAMES
   92 #define LEGACY_RSRCFORKSPEC     "/rsrc"
   93 #endif
   94 
   95 /*      
   96  * FROM FREEBSD 3.1
   97  * Convert a component of a pathname into a pointer to a locked cnode.
   98  * This is a very central and rather complicated routine.
   99  * If the file system is not maintained in a strict tree hierarchy,
  100  * this can result in a deadlock situation (see comments in code below).
  101  *
  102  * The cnp->cn_nameiop argument is LOOKUP, CREATE, RENAME, or DELETE depending
  103  * on whether the name is to be looked up, created, renamed, or deleted.
  104  * When CREATE, RENAME, or DELETE is specified, information usable in
  105  * creating, renaming, or deleting a directory entry may be calculated.
  106  * Notice that these are the only operations that can affect the directory of the target.
  107  *
  108  * If flag has LOCKPARENT or'ed into it and the target of the pathname
  109  * exists, lookup returns both the target and its parent directory locked.
  110  * When creating or renaming and LOCKPARENT is specified, the target may
  111  * not be ".".  When deleting and LOCKPARENT is specified, the target may
  112  * be "."., but the caller must check to ensure it does an vrele and vput
  113  * instead of two vputs.
  114  *
  115  * LOCKPARENT and WANTPARENT actually refer to the parent of the last item,
  116  * so if ISLASTCN is not set, they should be ignored. Also they are mutually exclusive, or
  117  * WANTPARENT really implies DONTLOCKPARENT. Either of them set means that the calling
  118  * routine wants to access the parent of the target, locked or unlocked.
  119  *
  120  * Keeping the parent locked as long as possible protects from other processes
  121  * looking up the same item, so it has to be locked until the cnode is totally finished
  122  *
  123  * This routine is actually used as VOP_CACHEDLOOKUP method, and the
  124  * filesystem employs the generic hfs_cache_lookup() as VOP_LOOKUP
  125  * method.
  126  *
  127  * hfs_cache_lookup() performs the following for us:
  128  *      check that it is a directory
  129  *      check accessibility of directory
  130  *      check for modification attempts on read-only mounts
  131  *      if name found in cache
  132  *              if at end of path and deleting or creating
  133  *              drop it
  134  *               else
  135  *              return name.
  136  *      return VOP_CACHEDLOOKUP()
  137  *
  138  * Overall outline of hfs_lookup:
  139  *
  140  *      handle simple cases of . and ..
  141  *      search for name in directory, to found or notfound
  142  * notfound:
  143  *      if creating, return locked directory, leaving info on available slots
  144  *      else return error
  145  * found:
  146  *      if at end of path and deleting, return information to allow delete
  147  *      if at end of path and rewriting (RENAME and LOCKPARENT), lock target
  148  *        cnode and return info to allow rewrite
  149  *      if not at end, add name to cache; if at end and neither creating
  150  *        nor deleting, add name to cache
  151  */
  152 
  153 /*      
  154  *      Lookup *nm in directory *pvp, return it in *a_vpp.
  155  *      **a_vpp is held on exit.
  156  *      We create a cnode for the file, but we do NOT open the file here.
  157 
  158 #% lookup       dvp L ? ?
  159 #% lookup       vpp - L -
  160 
  161         IN struct vnode *dvp - Parent node of file;
  162         INOUT struct vnode **vpp - node of target file, its a new node if
  163                 the target vnode did not exist;
  164         IN struct componentname *cnp - Name of file;
  165 
  166  *      When should we lock parent_hp in here ??
  167  */
  168 
  169 __private_extern__
  170 int
  171 hfs_lookup(ap)
  172         struct vop_cachedlookup_args /* {
  173                 struct vnode *a_dvp;
  174                 struct vnode **a_vpp;
  175                 struct componentname *a_cnp;
  176         } */ *ap;
  177 {
  178         struct vnode *dvp;      /* vnode for directory being searched */
  179         struct cnode *dcp;      /* cnode for directory being searched */
  180         struct vnode *tvp;      /* target vnode */
  181         struct hfsmount *hfsmp;
  182         struct componentname *cnp;      
  183         struct ucred *cred;
  184         struct proc *p;
  185         int wantrsrc = 0;
  186         int forknamelen = 0;
  187         int flags;
  188         int wantparent;
  189         int nameiop;
  190         int retval = 0;
  191         int isDot;
  192         struct cat_desc desc = {0};
  193         struct cat_desc cndesc;
  194         struct cat_attr attr;
  195         struct cat_fork fork;
  196         struct vnode **vpp;
  197 
  198         vpp = ap->a_vpp;
  199         cnp = ap->a_cnp;
  200         dvp = ap->a_dvp;
  201         dcp = VTOC(dvp);
  202         hfsmp = VTOHFS(dvp);
  203         *vpp = NULL;
  204         isDot = FALSE;
  205         tvp = NULL;
  206         nameiop = cnp->cn_nameiop;
  207         cred = cnp->cn_cred;
  208         p = cnp->cn_proc;
  209         flags = cnp->cn_flags;
  210         wantparent = flags & (LOCKPARENT|WANTPARENT);
  211 
  212         /*
  213          * First check to see if it is a . or .., else look it up.
  214          */
  215         if (flags & ISDOTDOT) {         /* Wanting the parent */
  216                 goto found;     /* .. is always defined */
  217         } else if ((cnp->cn_nameptr[0] == '.') && (cnp->cn_namelen == 1)) {
  218                 isDot = TRUE;
  219                 goto found;     /* We always know who we are */
  220         } else {
  221                 /* Check fork suffix to see if we want the resource fork */
  222                 forknamelen = forkcomponent(cnp, &wantrsrc);
  223 
  224                 /* No need to go to catalog if there are no children */
  225                 if (dcp->c_entries == 0)
  226                         goto notfound;
  227 
  228                 bzero(&cndesc, sizeof(cndesc));
  229                 cndesc.cd_nameptr = cnp->cn_nameptr;
  230                 cndesc.cd_namelen = cnp->cn_namelen;
  231                 cndesc.cd_parentcnid = dcp->c_cnid;
  232                 cndesc.cd_hint = dcp->c_childhint;
  233 
  234                 /* Lock catalog b-tree */
  235                 retval = hfs_metafilelocking(hfsmp, kHFSCatalogFileID, LK_SHARED, p);
  236                 if (retval)
  237                            goto exit;
  238                 retval = cat_lookup(hfsmp, &cndesc, wantrsrc, &desc, &attr, &fork);
  239                 
  240                 if (retval == 0 && S_ISREG(attr.ca_mode) && attr.ca_blocks < fork.cf_blocks)
  241                         panic("hfs_lookup: bad ca_blocks (too small)");
  242         
  243                 /* Unlock catalog b-tree */
  244                 (void) hfs_metafilelocking(hfsmp, kHFSCatalogFileID, LK_RELEASE, p);
  245                 if (retval == 0) {
  246                         dcp->c_childhint = desc.cd_hint;
  247                         goto found;
  248                 }
  249 notfound:
  250                 /*
  251                  * This is a non-existing entry
  252                  *
  253                  * If creating, and at end of pathname and current
  254                  * directory has not been removed, then can consider
  255                  * allowing file to be created.
  256                  */
  257                 if ((nameiop == CREATE || nameiop == RENAME ||
  258                     (nameiop == DELETE &&
  259                     (ap->a_cnp->cn_flags & DOWHITEOUT) &&
  260                     (ap->a_cnp->cn_flags & ISWHITEOUT))) &&
  261                     (flags & ISLASTCN)) {
  262                         /*
  263                          * Access for write is interpreted as allowing
  264                          * creation of files in the directory.
  265                          */
  266                         retval = VOP_ACCESS(dvp, VWRITE, cred, cnp->cn_proc);
  267                         if (retval) {
  268                                 goto exit;
  269                         }
  270                 
  271                         cnp->cn_flags |= SAVENAME;
  272                         if (!(flags & LOCKPARENT))
  273                                 VOP_UNLOCK(dvp, 0, p);
  274                         retval = EJUSTRETURN;
  275                         goto exit;
  276                 }
  277 
  278                 /*
  279                  * Insert name into cache (as non-existent) if appropriate.
  280                  *
  281                  * Only done for case-sensitive HFS+ volumes.
  282                  */
  283                 if ((hfsmp->hfs_flags & HFS_CASE_SENSITIVE) &&
  284                     (cnp->cn_flags & MAKEENTRY) && nameiop != CREATE)
  285                         cache_enter(dvp, *vpp, cnp);
  286                 retval = ENOENT;
  287                 goto exit;
  288         }
  289 
  290 found:
  291         /*
  292          * Process any fork specifiers
  293          */
  294         if (forknamelen && S_ISREG(attr.ca_mode)) {
  295                 /* fork names are only for lookups */
  296                 if ((nameiop != LOOKUP) && (nameiop != CREATE)) {
  297                         retval = EPERM;  
  298                         goto exit;
  299                 }
  300                 cnp->cn_consume = forknamelen;
  301                 flags |= ISLASTCN;
  302         } else {
  303                 wantrsrc = 0;
  304                 forknamelen = 0;
  305         }
  306 
  307         /*
  308          * If deleting, and at end of pathname, return
  309          * parameters which can be used to remove file.
  310          */
  311         if (nameiop == DELETE && (flags & ISLASTCN)) {
  312                 /*
  313                 * Write access to directory required to delete files.
  314                 */
  315                 if ((retval = VOP_ACCESS(dvp, VWRITE, cred, cnp->cn_proc)))
  316                         goto exit;
  317                 
  318                 if (isDot) {    /* Want to return ourselves */
  319                         VREF(dvp);
  320                         *vpp = dvp;
  321                         goto exit;
  322                 } else if (flags & ISDOTDOT) {
  323                         retval = hfs_getcnode(hfsmp, dcp->c_parentcnid,
  324                                 NULL, 0, NULL, NULL, &tvp);
  325                         if (retval)
  326                                 goto exit;
  327                 } else {
  328                         retval = hfs_getcnode(hfsmp, attr.ca_fileid,
  329                                 &desc, wantrsrc, &attr, &fork, &tvp);
  330                         if (retval)
  331                                 goto exit;
  332                 }
  333 
  334                 /*
  335                  * If directory is "sticky", then user must own
  336                  * the directory, or the file in it, else she
  337                  * may not delete it (unless she's root). This
  338                  * implements append-only directories.
  339                  */
  340                 if ((dcp->c_mode & S_ISTXT) &&
  341                         (cred->cr_uid != 0) &&
  342                         (cred->cr_uid != dcp->c_uid) &&
  343                         (tvp->v_type != VLNK) &&
  344                         (hfs_owner_rights(hfsmp, VTOC(tvp)->c_uid, cred, p, false))) {
  345                         vput(tvp);
  346                         retval = EPERM;
  347                         goto exit;
  348                 }
  349 
  350                 /*
  351                  * If this is a link node then we need to save the name
  352                  * (of the link) so we can delete it from the catalog b-tree.
  353                  * In this case, hfs_remove will then free the component name.
  354                  *
  355                  * DJB - IS THIS STILL NEEDED????
  356                  */
  357                 if (tvp && (VTOC(tvp)->c_flag & C_HARDLINK))
  358                         cnp->cn_flags |= SAVENAME;
  359   
  360                 if (!(flags & LOCKPARENT))
  361                         VOP_UNLOCK(dvp, 0, p);
  362                 *vpp = tvp;
  363                 goto exit;
  364          }
  365 
  366         /*
  367          * If renaming, return the cnode and save the current name.
  368          */
  369         if (nameiop == RENAME && wantparent && (flags & ISLASTCN)) {
  370                 if ((retval = VOP_ACCESS(dvp, VWRITE, cred, cnp->cn_proc)) != 0)
  371                         goto exit;
  372                 /*
  373                  * Careful about locking second cnode.
  374                  */
  375                 if (isDot) {
  376                         retval = EISDIR;
  377                         goto exit;
  378                 } else if (flags & ISDOTDOT) {
  379                         retval = hfs_getcnode(hfsmp, dcp->c_parentcnid,
  380                                 NULL, 0, NULL, NULL, &tvp);
  381                         if (retval)
  382                                 goto exit;
  383                 } else {
  384                         retval = hfs_getcnode(hfsmp, attr.ca_fileid,
  385                                 &desc, wantrsrc, &attr, &fork, &tvp);
  386                         if (retval)
  387                                 goto exit;
  388                 }
  389                 cnp->cn_flags |= SAVENAME;
  390                 if (!(flags & LOCKPARENT))
  391                         VOP_UNLOCK(dvp, 0, p);
  392                 *vpp = tvp;
  393                 goto exit;
  394          }
  395 
  396         /*
  397          * We must get the target cnode before unlocking
  398          * the directory to insure that the cnode will not be removed
  399          * before we get it.  We prevent deadlock by always fetching
  400          * cnodes from the root, moving down the directory tree. Thus
  401          * when following backward pointers ".." we must unlock the
  402          * parent directory before getting the requested directory.
  403          * There is a potential race condition here if both the current
  404          * and parent directories are removed before the VFS_VGET for the
  405          * cnode associated with ".." returns.  We hope that this occurs
  406          * infrequently since we cannot avoid this race condition without
  407          * implementing a sophisticated deadlock detection algorithm.
  408          */
  409         if (flags & ISDOTDOT) {
  410                 VOP_UNLOCK(dvp, 0, p);  /* race to get the cnode */
  411                 retval = hfs_getcnode(hfsmp, dcp->c_parentcnid,
  412                         NULL, 0, NULL, NULL, &tvp);
  413                 if (retval) {
  414                         vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY, p);
  415                         goto exit;
  416                 }
  417                 if ((flags & LOCKPARENT) && (flags & ISLASTCN) && (dvp != tvp) && 
  418                     (retval = vn_lock(dvp, LK_EXCLUSIVE, p))) {
  419                         vput(tvp);
  420                         goto exit;
  421                 }
  422                 *vpp = tvp;
  423         } else if (isDot) {
  424                 VREF(dvp);      /* we want ourself, ie "." */
  425                 *vpp = dvp;
  426         } else {
  427                 int type = (attr.ca_mode & S_IFMT);
  428 
  429                 if (!(flags & ISLASTCN) && type != S_IFDIR && type != S_IFLNK) {
  430                         retval = ENOTDIR;
  431                         goto exit;
  432                 }
  433 
  434                 retval = hfs_getcnode(hfsmp, attr.ca_fileid,
  435                         &desc, wantrsrc, &attr, &fork, &tvp);
  436                 if (retval)
  437                         goto exit;
  438 
  439                 if (!(flags & LOCKPARENT) || !(flags & ISLASTCN))
  440                         VOP_UNLOCK(dvp, 0, p);
  441                 *vpp = tvp;
  442         }
  443 
  444         /*
  445          * Insert name in cache if appropriate.
  446          *  - "." and ".." are not cached.
  447          *  - Resource fork names are not cached.
  448          *  - Names with composed chars are not cached.
  449          */
  450         if ((cnp->cn_flags & MAKEENTRY)
  451             && !isDot
  452             && !(flags & ISDOTDOT)
  453             && !wantrsrc
  454             && (cnp->cn_namelen == VTOC(*vpp)->c_desc.cd_namelen)) {
  455                 cache_enter(dvp, *vpp, cnp);
  456         }
  457 
  458 
  459         //
  460         // have to patch up the resource fork name because
  461         // it won't happen properly in the layers above us.
  462         //
  463         if (wantrsrc) {
  464             if (VTOC(*vpp)->c_vp == NULL) {
  465                 if (VNAME(*vpp) == NULL) {
  466                     VNAME(*vpp) = add_name(cnp->cn_nameptr, cnp->cn_namelen, cnp->cn_hash, 0);
  467                 }
  468                 if (VPARENT(*vpp) == NULL) {
  469                     vget(dvp, 0, p);
  470                     VPARENT(*vpp) = dvp;
  471                 }
  472             } else {
  473                 if (VNAME(*vpp) == NULL) {
  474                     // the +1/-2 thing is to skip the leading "/" on the rsrc fork spec
  475                     // and to not count the trailing null byte at the end of the string.
  476                     VNAME(*vpp) = add_name(_PATH_RSRCFORKSPEC+1, sizeof(_PATH_RSRCFORKSPEC)-2, 0, 0);
  477                 }
  478                 if (VPARENT(*vpp) == NULL && *vpp != VTOC(*vpp)->c_vp) {
  479                     VPARENT(*vpp) = VTOC(*vpp)->c_vp;
  480                     VTOC(*vpp)->c_flag |= C_VPREFHELD;
  481                     vget(VTOC(*vpp)->c_vp, 0, p);
  482                 }
  483             }
  484         }
  485 
  486 exit:
  487         cat_releasedesc(&desc);
  488         return (retval);
  489 }
  490 
  491 
  492 
  493 /*
  494  * Based on vn_cache_lookup (which is vfs_cache_lookup in FreeBSD 3.1)
  495  *
  496  * Name caching works as follows:
  497  *
  498  * Names found by directory scans are retained in a cache
  499  * for future reference.  It is managed LRU, so frequently
  500  * used names will hang around.  Cache is indexed by hash value
  501  * obtained from (vp, name) where vp refers to the directory
  502  * containing name.
  503  *
  504  * If it is a "negative" entry, (i.e. for a name that is known NOT to
  505  * exist) the vnode pointer will be NULL.
  506  *
  507  * Upon reaching the last segment of a path, if the reference
  508  * is for DELETE, or NOCACHE is set (rewrite), and the
  509  * name is located in the cache, it will be dropped.
  510  *
  511  */
  512 
  513 #define S_IXALL 0000111
  514 
  515 __private_extern__
  516 int
  517 hfs_cache_lookup(ap)
  518         struct vop_lookup_args /* {
  519                 struct vnode *a_dvp;
  520                 struct vnode **a_vpp;
  521                 struct componentname *a_cnp;
  522         } */ *ap;
  523 {
  524         struct vnode *dvp;
  525         struct vnode *vp;
  526         struct cnode *cp;
  527         struct cnode *dcp;
  528         int lockparent; 
  529         int error;
  530         struct vnode **vpp = ap->a_vpp;
  531         struct componentname *cnp = ap->a_cnp;
  532         int flags = cnp->cn_flags;
  533         struct proc *p = cnp->cn_proc;
  534         u_long vpid;    /* capability number of vnode */
  535 
  536         dvp = ap->a_dvp;
  537         lockparent = flags & LOCKPARENT;
  538 
  539         /*
  540          * Check accessiblity of directory.
  541          */
  542         if (dvp->v_type != VDIR)
  543                 return (ENOTDIR);
  544         if ((flags & ISLASTCN) && (dvp->v_mount->mnt_flag & MNT_RDONLY) &&
  545             (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME)) {
  546                 error = EROFS;
  547                 goto err_exit;
  548         }
  549         dcp = VTOC(dvp);
  550 
  551         if (((dcp->c_mode & S_IXALL) != S_IXALL) && (cnp->cn_cred->cr_uid != 0)) {
  552                 if ((error = VOP_ACCESS(dvp, VEXEC, cnp->cn_cred, p))) {
  553                         goto err_exit;
  554                 }
  555         }
  556         /*
  557          * Lookup an entry in the cache
  558          * If the lookup succeeds, the vnode is returned in *vpp, and a status of -1 is
  559          * returned. If the lookup determines that the name does not exist
  560          * (negative cacheing), a status of ENOENT is returned. If the lookup
  561          * fails, a status of zero is returned.
  562          */
  563         error = cache_lookup(dvp, vpp, cnp);
  564         if (error != -1) {
  565                 if (error == 0)  {              /* Unsuccessfull */
  566                         goto lookup;
  567                 }
  568                 
  569                 if (error == ENOENT) {
  570                         goto err_exit;
  571                 }
  572         }
  573         /* We have a name that matched */
  574         vp = *vpp;
  575         vpid = vp->v_id;
  576 
  577         /*
  578          * If this is a hard-link vnode then we need to update
  579          * the name (of the link), the parent ID, the cnid, the
  580          * text encoding and the catalog hint.  This enables
  581          * getattrlist calls to return the correct link info.
  582          */
  583         cp = VTOC(vp);
  584         if ((flags & ISLASTCN) && (cp->c_flag & C_HARDLINK) &&
  585              ((cp->c_parentcnid != VTOC(ap->a_dvp)->c_cnid) ||
  586               (bcmp(cnp->cn_nameptr, cp->c_desc.cd_nameptr, cp->c_desc.cd_namelen) != 0))) {
  587               
  588                 struct cat_desc desc;
  589 
  590                 /*
  591                  * Get an updated descriptor
  592                  */
  593                 bzero(&desc, sizeof(desc));
  594                 desc.cd_nameptr = cnp->cn_nameptr;
  595                 desc.cd_namelen = cnp->cn_namelen;
  596                 desc.cd_parentcnid = VTOC(ap->a_dvp)->c_cnid;
  597                 desc.cd_hint = VTOC(ap->a_dvp)->c_childhint;
  598                 if (cat_lookup(VTOHFS(vp), &desc, 0, &desc, NULL, NULL) == 0)
  599                         replace_desc(cp, &desc);
  600         }
  601 
  602         if (dvp == vp) {        /* lookup on "." */
  603                 VREF(vp);
  604                 error = 0;
  605         } else if (flags & ISDOTDOT) {
  606                 /* 
  607                  * Carefull on the locking policy,
  608                  * remember we always lock from parent to child, so have
  609                  * to release lock on child before trying to lock parent
  610                  * then regain lock if needed
  611                  */
  612                 VOP_UNLOCK(dvp, 0, p);
  613                 error = vget(vp, LK_EXCLUSIVE, p);
  614                 if (!error && lockparent && (flags & ISLASTCN))
  615                         error = vn_lock(dvp, LK_EXCLUSIVE, p);
  616         } else {
  617                 if ((flags & ISLASTCN) == 0 && vp->v_type == VREG) {
  618                         int wantrsrc = 0;
  619 
  620                         cnp->cn_consume = forkcomponent(cnp, &wantrsrc);
  621                         if (cnp->cn_consume) {
  622                                 flags |= ISLASTCN;
  623                                 /* Fork names are only for lookups */
  624                                 if (cnp->cn_nameiop != LOOKUP &&
  625                                     cnp->cn_nameiop != CREATE) {
  626                                         error = EPERM;
  627 
  628                                         goto err_exit;
  629                                 }
  630                         }
  631 
  632                         if (wantrsrc) {
  633                                 /* Use cnode's rsrcfork vnode (if available) */
  634                                 if (cp->c_rsrc_vp != NULL) {
  635                                         *vpp = vp = cp->c_rsrc_vp;
  636                                         if (VNAME(vp) == NULL) {
  637                                             // the +1/-2 thing is to skip the leading "/" on the rsrc fork spec
  638                                             // and to not count the trailing null byte at the end of the string.
  639                                             VNAME(vp) = add_name(_PATH_RSRCFORKSPEC+1, sizeof(_PATH_RSRCFORKSPEC)-2, 0, 0);
  640                                         }
  641                                         if (VPARENT(vp) == NULL) {
  642                                             vget(cp->c_vp, 0, p);
  643                                             VPARENT(vp) = cp->c_vp;
  644                                         }
  645                                         vpid = vp->v_id;
  646                                 } else {
  647                                         goto lookup;
  648                                 }
  649                         }
  650                 }
  651                 error = vget(vp, 0, p);
  652                 if (error == 0) {
  653                         if (VTOC(vp) == NULL || vp->v_data != (void *)cp) {
  654                                 panic("hfs: cache lookup: my cnode disappeared/went bad! vp 0x%x 0x%x 0x%x\n",
  655                                           vp, vp->v_data, cp);
  656                         }
  657                         if (cnp->cn_nameiop == LOOKUP &&
  658                             (!(flags & ISLASTCN) || (flags & SHAREDLEAF)))
  659                                 error = lockmgr(&VTOC(vp)->c_lock, LK_SHARED, NULL, p);
  660                         else
  661                                 error = lockmgr(&VTOC(vp)->c_lock, LK_EXCLUSIVE, NULL, p);
  662                 }
  663                 if (!lockparent || error || !(flags & ISLASTCN)) {
  664                         (void) lockmgr(&dcp->c_lock, LK_RELEASE, NULL, p);
  665                 }
  666         }
  667         /*
  668          * Check that the capability number did not change
  669          * while we were waiting for the lock.
  670          */
  671         if (!error) {
  672                 if (vpid == vp->v_id)
  673                         return (0);
  674                 /*
  675                  * The above is the NORMAL exit, after this point is an error
  676                  * condition.
  677                  */
  678                 vput(vp);
  679                 if (lockparent && (dvp != vp) && (flags & ISLASTCN))
  680                         VOP_UNLOCK(dvp, 0, p);
  681         }
  682 
  683         if ((error = vn_lock(dvp, LK_EXCLUSIVE, p)))
  684                 return (error);
  685 lookup:
  686         return (hfs_lookup(ap));
  687 
  688 err_exit:
  689         *vpp = NULL;
  690         return (error);
  691 }
  692 
  693 
  694 /*
  695  * forkcomponent - look for a fork suffix in the component name
  696  *
  697  */
  698 static int
  699 forkcomponent(struct componentname *cnp, int *rsrcfork)
  700 {
  701         char *suffix = cnp->cn_nameptr + cnp->cn_namelen;
  702         int consume = 0;
  703 
  704         *rsrcfork = 0;
  705         if (*suffix == '\0')
  706                 return (0);
  707         /*
  708          * There are only 3 valid fork suffixes:
  709          *      "/..namedfork/rsrc"
  710          *      "/..namedfork/data"
  711          *      "/rsrc"  (legacy)
  712          */
  713         if (bcmp(suffix, _PATH_RSRCFORKSPEC, sizeof(_PATH_RSRCFORKSPEC)) == 0) {
  714                 consume = sizeof(_PATH_RSRCFORKSPEC) - 1;
  715                 *rsrcfork = 1;
  716         } else if (bcmp(suffix, _PATH_DATAFORKSPEC, sizeof(_PATH_DATAFORKSPEC)) == 0) {
  717                 consume = sizeof(_PATH_DATAFORKSPEC) - 1;
  718         }
  719 
  720 #ifdef LEGACY_FORK_NAMES
  721         else if (bcmp(suffix, LEGACY_RSRCFORKSPEC, sizeof(LEGACY_RSRCFORKSPEC)) == 0) {
  722                 consume = sizeof(LEGACY_RSRCFORKSPEC) - 1;
  723                 *rsrcfork = 1;
  724         }
  725 #endif
  726         return (consume);
  727 }
  728 

Cache object: 01cfb2e0f99031f5b530d42a5d5c7254


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.