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/kern/vfs_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 /*      $NetBSD: vfs_lookup.c,v 1.54.2.1 2005/03/16 12:59:03 tron Exp $ */
    2 
    3 /*
    4  * Copyright (c) 1982, 1986, 1989, 1993
    5  *      The Regents of the University of California.  All rights reserved.
    6  * (c) UNIX System Laboratories, Inc.
    7  * All or some portions of this file are derived from material licensed
    8  * to the University of California by American Telephone and Telegraph
    9  * Co. or Unix System Laboratories, Inc. and are reproduced herein with
   10  * the permission of UNIX System Laboratories, Inc.
   11  *
   12  * Redistribution and use in source and binary forms, with or without
   13  * modification, are permitted provided that the following conditions
   14  * are met:
   15  * 1. Redistributions of source code must retain the above copyright
   16  *    notice, this list of conditions and the following disclaimer.
   17  * 2. Redistributions in binary form must reproduce the above copyright
   18  *    notice, this list of conditions and the following disclaimer in the
   19  *    documentation and/or other materials provided with the distribution.
   20  * 3. Neither the name of the University nor the names of its contributors
   21  *    may be used to endorse or promote products derived from this software
   22  *    without specific prior written permission.
   23  *
   24  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
   25  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   26  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   27  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   28  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   29  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   30  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   31  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   32  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   33  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   34  * SUCH DAMAGE.
   35  *
   36  *      @(#)vfs_lookup.c        8.10 (Berkeley) 5/27/95
   37  */
   38 
   39 #include <sys/cdefs.h>
   40 __KERNEL_RCSID(0, "$NetBSD: vfs_lookup.c,v 1.54.2.1 2005/03/16 12:59:03 tron Exp $");
   41 
   42 #include "opt_ktrace.h"
   43 #include "opt_systrace.h"
   44 
   45 #include <sys/param.h>
   46 #include <sys/systm.h>
   47 #include <sys/syslimits.h>
   48 #include <sys/time.h>
   49 #include <sys/namei.h>
   50 #include <sys/vnode.h>
   51 #include <sys/mount.h>
   52 #include <sys/errno.h>
   53 #include <sys/filedesc.h>
   54 #include <sys/hash.h>
   55 #include <sys/malloc.h>
   56 #include <sys/proc.h>
   57 #include <sys/syslog.h>
   58 
   59 #ifdef KTRACE
   60 #include <sys/ktrace.h>
   61 #endif
   62 #ifdef SYSTRACE
   63 #include <sys/systrace.h>
   64 #endif
   65 
   66 struct pool pnbuf_pool;         /* pathname buffer pool */
   67 struct pool_cache pnbuf_cache;  /* pathname buffer cache */
   68 
   69 MALLOC_DEFINE(M_NAMEI, "namei", "namei path buffer");
   70 
   71 /*
   72  * Convert a pathname into a pointer to a locked inode.
   73  *
   74  * The FOLLOW flag is set when symbolic links are to be followed
   75  * when they occur at the end of the name translation process.
   76  * Symbolic links are always followed for all other pathname
   77  * components other than the last.
   78  *
   79  * The segflg defines whether the name is to be copied from user
   80  * space or kernel space.
   81  *
   82  * Overall outline of namei:
   83  *
   84  *      copy in name
   85  *      get starting directory
   86  *      while (!done && !error) {
   87  *              call lookup to search path.
   88  *              if symbolic link, massage name in buffer and continue
   89  *      }
   90  */
   91 int
   92 namei(ndp)
   93         struct nameidata *ndp;
   94 {
   95         struct cwdinfo *cwdi;           /* pointer to cwd state */
   96         char *cp;                       /* pointer into pathname argument */
   97         struct vnode *dp;               /* the directory we are searching */
   98         struct iovec aiov;              /* uio for reading symbolic links */
   99         struct uio auio;
  100         int error, linklen;
  101         struct componentname *cnp = &ndp->ni_cnd;
  102 
  103 #ifdef DIAGNOSTIC
  104         if (!cnp->cn_cred || !cnp->cn_proc)
  105                 panic ("namei: bad cred/proc");
  106         if (cnp->cn_nameiop & (~OPMASK))
  107                 panic ("namei: nameiop contaminated with flags");
  108         if (cnp->cn_flags & OPMASK)
  109                 panic ("namei: flags contaminated with nameiops");
  110 #endif
  111         cwdi = cnp->cn_proc->p_cwdi;
  112 
  113         /*
  114          * Get a buffer for the name to be translated, and copy the
  115          * name into the buffer.
  116          */
  117         if ((cnp->cn_flags & HASBUF) == 0)
  118                 cnp->cn_pnbuf = PNBUF_GET();
  119         if (ndp->ni_segflg == UIO_SYSSPACE)
  120                 error = copystr(ndp->ni_dirp, cnp->cn_pnbuf,
  121                             MAXPATHLEN, &ndp->ni_pathlen);
  122         else
  123                 error = copyinstr(ndp->ni_dirp, cnp->cn_pnbuf,
  124                             MAXPATHLEN, &ndp->ni_pathlen);
  125 
  126         /*
  127          * POSIX.1 requirement: "" is not a valid file name.
  128          */      
  129         if (!error && ndp->ni_pathlen == 1)
  130                 error = ENOENT;
  131 
  132         if (error) {
  133                 PNBUF_PUT(cnp->cn_pnbuf);
  134                 ndp->ni_vp = NULL;
  135                 return (error);
  136         }
  137         ndp->ni_loopcnt = 0;
  138 
  139 #ifdef KTRACE
  140         if (KTRPOINT(cnp->cn_proc, KTR_NAMEI))
  141                 ktrnamei(cnp->cn_proc, cnp->cn_pnbuf);
  142 #endif
  143 #ifdef SYSTRACE
  144         if (ISSET(cnp->cn_proc->p_flag, P_SYSTRACE))
  145                 systrace_namei(ndp);
  146 #endif
  147 
  148         /*
  149          * Get starting point for the translation.
  150          */
  151         if ((ndp->ni_rootdir = cwdi->cwdi_rdir) == NULL)
  152                 ndp->ni_rootdir = rootvnode;
  153         /*
  154          * Check if starting from root directory or current directory.
  155          */
  156         if (cnp->cn_pnbuf[0] == '/') {
  157                 dp = ndp->ni_rootdir;
  158                 VREF(dp);
  159         } else {
  160                 dp = cwdi->cwdi_cdir;
  161                 VREF(dp);
  162         }
  163         for (;;) {
  164                 if (!dp->v_mount)
  165                 {
  166                         /* Give up if the directory is no longer mounted */
  167                         PNBUF_PUT(cnp->cn_pnbuf);
  168                         return (ENOENT);
  169                 }
  170                 cnp->cn_nameptr = cnp->cn_pnbuf;
  171                 ndp->ni_startdir = dp;
  172                 if ((error = lookup(ndp)) != 0) {
  173                         PNBUF_PUT(cnp->cn_pnbuf);
  174                         return (error);
  175                 }
  176                 /*
  177                  * Check for symbolic link
  178                  */
  179                 if ((cnp->cn_flags & ISSYMLINK) == 0) {
  180                         if ((cnp->cn_flags & (SAVENAME | SAVESTART)) == 0)
  181                                 PNBUF_PUT(cnp->cn_pnbuf);
  182                         else
  183                                 cnp->cn_flags |= HASBUF;
  184                         return (0);
  185                 }
  186                 if ((cnp->cn_flags & LOCKPARENT) && (cnp->cn_flags & ISLASTCN))
  187                         VOP_UNLOCK(ndp->ni_dvp, 0);
  188                 if (ndp->ni_loopcnt++ >= MAXSYMLINKS) {
  189                         error = ELOOP;
  190                         break;
  191                 }
  192                 if (ndp->ni_vp->v_mount->mnt_flag & MNT_SYMPERM) {
  193                         error = VOP_ACCESS(ndp->ni_vp, VEXEC, cnp->cn_cred,
  194                             cnp->cn_proc);
  195                         if (error != 0)
  196                                 break;
  197                 }
  198                 if (ndp->ni_pathlen > 1)
  199                         cp = PNBUF_GET();
  200                 else
  201                         cp = cnp->cn_pnbuf;
  202                 aiov.iov_base = cp;
  203                 aiov.iov_len = MAXPATHLEN;
  204                 auio.uio_iov = &aiov;
  205                 auio.uio_iovcnt = 1;
  206                 auio.uio_offset = 0;
  207                 auio.uio_rw = UIO_READ;
  208                 auio.uio_segflg = UIO_SYSSPACE;
  209                 auio.uio_procp = (struct proc *)0;
  210                 auio.uio_resid = MAXPATHLEN;
  211                 error = VOP_READLINK(ndp->ni_vp, &auio, cnp->cn_cred);
  212                 if (error) {
  213                 badlink:
  214                         if (ndp->ni_pathlen > 1)
  215                                 PNBUF_PUT(cp);
  216                         break;
  217                 }
  218                 linklen = MAXPATHLEN - auio.uio_resid;
  219                 if (linklen == 0) {
  220                         error = ENOENT;
  221                         goto badlink;
  222                 }
  223                 if (linklen + ndp->ni_pathlen >= MAXPATHLEN) {
  224                         error = ENAMETOOLONG;
  225                         goto badlink;
  226                 }
  227                 if (ndp->ni_pathlen > 1) {
  228                         memcpy(cp + linklen, ndp->ni_next, ndp->ni_pathlen);
  229                         PNBUF_PUT(cnp->cn_pnbuf);
  230                         cnp->cn_pnbuf = cp;
  231                 } else
  232                         cnp->cn_pnbuf[linklen] = '\0';
  233                 ndp->ni_pathlen += linklen;
  234                 vput(ndp->ni_vp);
  235                 dp = ndp->ni_dvp;
  236                 /*
  237                  * Check if root directory should replace current directory.
  238                  */
  239                 if (cnp->cn_pnbuf[0] == '/') {
  240                         vrele(dp);
  241                         dp = ndp->ni_rootdir;
  242                         VREF(dp);
  243                 }
  244         }
  245         PNBUF_PUT(cnp->cn_pnbuf);
  246         vrele(ndp->ni_dvp);
  247         vput(ndp->ni_vp);
  248         ndp->ni_vp = NULL;
  249         return (error);
  250 }
  251 
  252 /*
  253  * Determine the namei hash (for cn_hash) for name.
  254  * If *ep != NULL, hash from name to ep-1.
  255  * If *ep == NULL, hash from name until the first NUL or '/', and
  256  * return the location of this termination character in *ep.
  257  *
  258  * This function returns an equivalent hash to the MI hash32_strn().
  259  * The latter isn't used because in the *ep == NULL case, determining
  260  * the length of the string to the first NUL or `/' and then calling
  261  * hash32_strn() involves unnecessary double-handling of the data.
  262  */
  263 uint32_t
  264 namei_hash(const char *name, const char **ep)
  265 {
  266         uint32_t        hash;
  267 
  268         hash = HASH32_STR_INIT;
  269         if (*ep != NULL) {
  270                 for (; name < *ep; name++)
  271                         hash = hash * 33 + *(uint8_t *)name;
  272         } else {
  273                 for (; *name != '\0' && *name != '/'; name++)
  274                         hash = hash * 33 + *(uint8_t *)name;
  275                 *ep = name;
  276         }
  277         return (hash + (hash >> 5));
  278 }
  279 
  280 /*
  281  * Search a pathname.
  282  * This is a very central and rather complicated routine.
  283  *
  284  * The pathname is pointed to by ni_ptr and is of length ni_pathlen.
  285  * The starting directory is taken from ni_startdir. The pathname is
  286  * descended until done, or a symbolic link is encountered. The variable
  287  * ni_more is clear if the path is completed; it is set to one if a
  288  * symbolic link needing interpretation is encountered.
  289  *
  290  * The flag argument is LOOKUP, CREATE, RENAME, or DELETE depending on
  291  * whether the name is to be looked up, created, renamed, or deleted.
  292  * When CREATE, RENAME, or DELETE is specified, information usable in
  293  * creating, renaming, or deleting a directory entry may be calculated.
  294  * If flag has LOCKPARENT or'ed into it, the parent directory is returned
  295  * locked. If flag has WANTPARENT or'ed into it, the parent directory is
  296  * returned unlocked. Otherwise the parent directory is not returned. If
  297  * the target of the pathname exists and LOCKLEAF is or'ed into the flag
  298  * the target is returned locked, otherwise it is returned unlocked.
  299  * When creating or renaming and LOCKPARENT is specified, the target may not
  300  * be ".".  When deleting and LOCKPARENT is specified, the target may be ".".
  301  * 
  302  * Overall outline of lookup:
  303  *
  304  * dirloop:
  305  *      identify next component of name at ndp->ni_ptr
  306  *      handle degenerate case where name is null string
  307  *      if .. and crossing mount points and on mounted filesys, find parent
  308  *      call VOP_LOOKUP routine for next component name
  309  *          directory vnode returned in ni_dvp, unlocked unless LOCKPARENT set
  310  *          component vnode returned in ni_vp (if it exists), locked.
  311  *      if result vnode is mounted on and crossing mount points,
  312  *          find mounted on vnode
  313  *      if more components of name, do next level at dirloop
  314  *      return the answer in ni_vp, locked if LOCKLEAF set
  315  *          if LOCKPARENT set, return locked parent in ni_dvp
  316  *          if WANTPARENT set, return unlocked parent in ni_dvp
  317  */
  318 int
  319 lookup(ndp)
  320         struct nameidata *ndp;
  321 {
  322         const char *cp;                 /* pointer into pathname argument */
  323         struct vnode *dp = 0;           /* the directory we are searching */
  324         struct vnode *tdp;              /* saved dp */
  325         struct mount *mp;               /* mount table entry */
  326         int docache;                    /* == 0 do not cache last component */
  327         int wantparent;                 /* 1 => wantparent or lockparent flag */
  328         int rdonly;                     /* lookup read-only flag bit */
  329         int error = 0;
  330         int slashes;
  331         int dpunlocked = 0;             /* dp has already been unlocked */
  332         struct componentname *cnp = &ndp->ni_cnd;
  333 
  334         /*
  335          * Setup: break out flag bits into variables.
  336          */
  337         wantparent = cnp->cn_flags & (LOCKPARENT | WANTPARENT);
  338         docache = (cnp->cn_flags & NOCACHE) ^ NOCACHE;
  339         if (cnp->cn_nameiop == DELETE ||
  340             (wantparent && cnp->cn_nameiop != CREATE))
  341                 docache = 0;
  342         rdonly = cnp->cn_flags & RDONLY;
  343         ndp->ni_dvp = NULL;
  344         cnp->cn_flags &= ~ISSYMLINK;
  345         dp = ndp->ni_startdir;
  346         ndp->ni_startdir = NULLVP;
  347         vn_lock(dp, LK_EXCLUSIVE | LK_RETRY);
  348 
  349         /*
  350          * If we have a leading string of slashes, remove them, and just make
  351          * sure the current node is a directory.
  352          */
  353         cp = cnp->cn_nameptr;
  354         if (*cp == '/') {
  355                 do {
  356                         cp++;
  357                 } while (*cp == '/');
  358                 ndp->ni_pathlen -= cp - cnp->cn_nameptr;
  359                 cnp->cn_nameptr = cp;
  360 
  361                 if (dp->v_type != VDIR) {
  362                         error = ENOTDIR;
  363                         goto bad;
  364                 }
  365 
  366                 /*
  367                  * If we've exhausted the path name, then just return the
  368                  * current node.  If the caller requested the parent node (i.e.
  369                  * it's a CREATE, DELETE, or RENAME), and we don't have one
  370                  * (because this is the root directory), then we must fail.
  371                  */
  372                 if (cnp->cn_nameptr[0] == '\0') {
  373                         if (ndp->ni_dvp == NULL && wantparent) {
  374                                 error = EISDIR;
  375                                 goto bad;
  376                         }
  377                         ndp->ni_vp = dp;
  378                         cnp->cn_flags |= ISLASTCN;
  379                         goto terminal;
  380                 }
  381         }
  382 
  383 dirloop:
  384         /*
  385          * Search a new directory.
  386          *
  387          * The cn_hash value is for use by vfs_cache.
  388          * The last component of the filename is left accessible via
  389          * cnp->cn_nameptr for callers that need the name. Callers needing
  390          * the name set the SAVENAME flag. When done, they assume
  391          * responsibility for freeing the pathname buffer.
  392          */
  393         cnp->cn_consume = 0;
  394         cp = NULL;
  395         cnp->cn_hash = namei_hash(cnp->cn_nameptr, &cp);
  396         cnp->cn_namelen = cp - cnp->cn_nameptr;
  397         if (cnp->cn_namelen > NAME_MAX) {
  398                 error = ENAMETOOLONG;
  399                 goto bad;
  400         }
  401 #ifdef NAMEI_DIAGNOSTIC
  402         { char c = *cp;
  403         *(char *)cp = '\0';
  404         printf("{%s}: ", cnp->cn_nameptr);
  405         *(char *)cp = c; }
  406 #endif /* NAMEI_DIAGNOSTIC */
  407         ndp->ni_pathlen -= cnp->cn_namelen;
  408         ndp->ni_next = cp;
  409         /*
  410          * If this component is followed by a slash, then move the pointer to
  411          * the next component forward, and remember that this component must be
  412          * a directory.
  413          */
  414         if (*cp == '/') {
  415                 do {
  416                         cp++;
  417                 } while (*cp == '/');
  418                 slashes = cp - ndp->ni_next;
  419                 ndp->ni_pathlen -= slashes;
  420                 ndp->ni_next = cp;
  421                 cnp->cn_flags |= REQUIREDIR;
  422         } else {
  423                 slashes = 0;
  424                 cnp->cn_flags &= ~REQUIREDIR;
  425         }
  426         /*
  427          * We do special processing on the last component, whether or not it's
  428          * a directory.  Cache all intervening lookups, but not the final one.
  429          */
  430         if (*cp == '\0') {
  431                 if (docache)
  432                         cnp->cn_flags |= MAKEENTRY;
  433                 else
  434                         cnp->cn_flags &= ~MAKEENTRY;
  435                 cnp->cn_flags |= ISLASTCN;
  436         } else {
  437                 cnp->cn_flags |= MAKEENTRY;
  438                 cnp->cn_flags &= ~ISLASTCN;
  439         }
  440         if (cnp->cn_namelen == 2 &&
  441             cnp->cn_nameptr[1] == '.' && cnp->cn_nameptr[0] == '.')
  442                 cnp->cn_flags |= ISDOTDOT;
  443         else
  444                 cnp->cn_flags &= ~ISDOTDOT;
  445 
  446         /*
  447          * Handle "..": two special cases.
  448          * 1. If at root directory (e.g. after chroot)
  449          *    or at absolute root directory
  450          *    then ignore it so can't get out.
  451          * 1a. If we have somehow gotten out of a jail, warn
  452          *    and also ignore it so we can't get farther out.
  453          * 2. If this vnode is the root of a mounted
  454          *    filesystem, then replace it with the
  455          *    vnode which was mounted on so we take the
  456          *    .. in the other file system.
  457          */
  458         if (cnp->cn_flags & ISDOTDOT) {
  459                 for (;;) {
  460                         if (dp == ndp->ni_rootdir || dp == rootvnode) {
  461                                 ndp->ni_dvp = dp;
  462                                 ndp->ni_vp = dp;
  463                                 VREF(dp);
  464                                 goto nextname;
  465                         }
  466                         if (ndp->ni_rootdir != rootvnode) {
  467                                 int retval;
  468                                 VOP_UNLOCK(dp, 0);
  469                                 retval = vn_isunder(dp, ndp->ni_rootdir,
  470                                     cnp->cn_proc);
  471                                 vn_lock(dp, LK_EXCLUSIVE | LK_RETRY);
  472                                 if (!retval) {
  473                                     /* Oops! We got out of jail! */
  474                                     log(LOG_WARNING,
  475                                         "chrooted pid %d uid %d (%s) "
  476                                         "detected outside of its chroot\n",
  477                                         cnp->cn_proc->p_pid,
  478                                         cnp->cn_proc->p_ucred->cr_uid,
  479                                         cnp->cn_proc->p_comm);
  480                                     /* Put us at the jail root. */
  481                                     vput(dp);
  482                                     dp = ndp->ni_rootdir;
  483                                     ndp->ni_dvp = dp;
  484                                     ndp->ni_vp = dp;
  485                                     VREF(dp);
  486                                     VREF(dp);
  487                                     vn_lock(dp, LK_EXCLUSIVE | LK_RETRY);
  488                                     goto nextname;
  489                                 }
  490                         }
  491                         if ((dp->v_flag & VROOT) == 0 ||
  492                             (cnp->cn_flags & NOCROSSMOUNT))
  493                                 break;
  494                         tdp = dp;
  495                         dp = dp->v_mount->mnt_vnodecovered;
  496                         vput(tdp);
  497                         VREF(dp);
  498                         vn_lock(dp, LK_EXCLUSIVE | LK_RETRY);
  499                 }
  500         }
  501 
  502         /*
  503          * We now have a segment name to search for, and a directory to search.
  504          */
  505 unionlookup:
  506         ndp->ni_dvp = dp;
  507         ndp->ni_vp = NULL;
  508         cnp->cn_flags &= ~PDIRUNLOCK;
  509         if ((error = VOP_LOOKUP(dp, &ndp->ni_vp, cnp)) != 0) {
  510 #ifdef DIAGNOSTIC
  511                 if (ndp->ni_vp != NULL)
  512                         panic("leaf `%s' should be empty", cnp->cn_nameptr);
  513 #endif /* DIAGNOSTIC */
  514 #ifdef NAMEI_DIAGNOSTIC
  515                 printf("not found\n");
  516 #endif /* NAMEI_DIAGNOSTIC */
  517                 if ((error == ENOENT) &&
  518                     (dp->v_flag & VROOT) &&
  519                     (dp->v_mount->mnt_flag & MNT_UNION)) {
  520                         tdp = dp;
  521                         dp = dp->v_mount->mnt_vnodecovered;
  522                         if (cnp->cn_flags & PDIRUNLOCK)
  523                                 vrele(tdp);
  524                         else
  525                                 vput(tdp);
  526                         VREF(dp);
  527                         vn_lock(dp, LK_EXCLUSIVE | LK_RETRY);
  528                         goto unionlookup;
  529                 }
  530 
  531                 if (cnp->cn_flags & PDIRUNLOCK)
  532                         dpunlocked = 1;
  533 
  534                 if (error != EJUSTRETURN)
  535                         goto bad;
  536                 /*
  537                  * If this was not the last component, or there were trailing
  538                  * slashes, and we are not going to create a directory,
  539                  * then the name must exist.
  540                  */
  541                 if ((cnp->cn_flags & (REQUIREDIR | CREATEDIR)) == REQUIREDIR) {
  542                         error = ENOENT;
  543                         goto bad;
  544                 }
  545                 /*
  546                  * If creating and at end of pathname, then can consider
  547                  * allowing file to be created.
  548                  */
  549                 if (rdonly) {
  550                         error = EROFS;
  551                         goto bad;
  552                 }
  553                 /*
  554                  * We return with ni_vp NULL to indicate that the entry
  555                  * doesn't currently exist, leaving a pointer to the
  556                  * (possibly locked) directory inode in ndp->ni_dvp.
  557                  */
  558                 if (cnp->cn_flags & SAVESTART) {
  559                         ndp->ni_startdir = ndp->ni_dvp;
  560                         VREF(ndp->ni_startdir);
  561                 }
  562                 return (0);
  563         }
  564 #ifdef NAMEI_DIAGNOSTIC
  565         printf("found\n");
  566 #endif /* NAMEI_DIAGNOSTIC */
  567 
  568         /*
  569          * Take into account any additional components consumed by the
  570          * underlying filesystem.  This will include any trailing slashes after
  571          * the last component consumed.
  572          */
  573         if (cnp->cn_consume > 0) {
  574                 ndp->ni_pathlen -= cnp->cn_consume - slashes;
  575                 ndp->ni_next += cnp->cn_consume - slashes;
  576                 cnp->cn_consume = 0;
  577                 if (ndp->ni_next[0] == '\0')
  578                         cnp->cn_flags |= ISLASTCN;
  579         }
  580 
  581         dp = ndp->ni_vp;
  582         /*
  583          * Check to see if the vnode has been mounted on;
  584          * if so find the root of the mounted file system.
  585          */
  586         while (dp->v_type == VDIR && (mp = dp->v_mountedhere) &&
  587                (cnp->cn_flags & NOCROSSMOUNT) == 0) {
  588                 if (vfs_busy(mp, 0, 0))
  589                         continue;
  590                 VOP_UNLOCK(dp, 0);
  591                 error = VFS_ROOT(mp, &tdp);
  592                 vfs_unbusy(mp);
  593                 if (error) {
  594                         dpunlocked = 1;
  595                         goto bad2;
  596                 }
  597                 vrele(dp);
  598                 ndp->ni_vp = dp = tdp;
  599         }
  600 
  601         /*
  602          * Check for symbolic link.  Back up over any slashes that we skipped,
  603          * as we will need them again.
  604          */
  605         if ((dp->v_type == VLNK) && (cnp->cn_flags & (FOLLOW|REQUIREDIR))) {
  606                 ndp->ni_pathlen += slashes;
  607                 ndp->ni_next -= slashes;
  608                 cnp->cn_flags |= ISSYMLINK;
  609                 return (0);
  610         }
  611 
  612         /*
  613          * Check for directory, if the component was followed by a series of
  614          * slashes.
  615          */
  616         if ((dp->v_type != VDIR) && (cnp->cn_flags & REQUIREDIR)) {
  617                 error = ENOTDIR;
  618                 goto bad2;
  619         }
  620 
  621 nextname:
  622         /*
  623          * Not a symbolic link.  If this was not the last component, then
  624          * continue at the next component, else return.
  625          */
  626         if (!(cnp->cn_flags & ISLASTCN)) {
  627                 cnp->cn_nameptr = ndp->ni_next;
  628                 vrele(ndp->ni_dvp);
  629                 goto dirloop;
  630         }
  631 
  632 terminal:
  633         /*
  634          * Disallow directory write attempts on read-only file systems.
  635          */
  636         if (rdonly &&
  637             (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME)) {
  638                 /*
  639                  * Disallow directory write attempts on read-only
  640                  * file systems.
  641                  */
  642                 error = EROFS;
  643                 goto bad2;
  644         }
  645         if (ndp->ni_dvp != NULL) {
  646                 if (cnp->cn_flags & SAVESTART) {
  647                         ndp->ni_startdir = ndp->ni_dvp;
  648                         VREF(ndp->ni_startdir);
  649                 }
  650                 if (!wantparent)
  651                         vrele(ndp->ni_dvp);
  652         }
  653         if ((cnp->cn_flags & LOCKLEAF) == 0)
  654                 VOP_UNLOCK(dp, 0);
  655         return (0);
  656 
  657 bad2:
  658         if ((cnp->cn_flags & LOCKPARENT) && (cnp->cn_flags & ISLASTCN) &&
  659                         ((cnp->cn_flags & PDIRUNLOCK) == 0))
  660                 VOP_UNLOCK(ndp->ni_dvp, 0);
  661         vrele(ndp->ni_dvp);
  662 bad:
  663         if (dpunlocked)
  664                 vrele(dp);
  665         else
  666                 vput(dp);
  667         ndp->ni_vp = NULL;
  668         return (error);
  669 }
  670 
  671 /*
  672  * Reacquire a path name component.
  673  */
  674 int
  675 relookup(dvp, vpp, cnp)
  676         struct vnode *dvp, **vpp;
  677         struct componentname *cnp;
  678 {
  679         struct vnode *dp = 0;           /* the directory we are searching */
  680         int wantparent;                 /* 1 => wantparent or lockparent flag */
  681         int rdonly;                     /* lookup read-only flag bit */
  682         int error = 0;
  683 #ifdef DEBUG
  684         u_long newhash;                 /* DEBUG: check name hash */
  685         const char *cp;                 /* DEBUG: check name ptr/len */
  686 #endif /* DEBUG */
  687 
  688         /*
  689          * Setup: break out flag bits into variables.
  690          */
  691         wantparent = cnp->cn_flags & (LOCKPARENT|WANTPARENT);
  692         rdonly = cnp->cn_flags & RDONLY;
  693         cnp->cn_flags &= ~ISSYMLINK;
  694         dp = dvp;
  695         vn_lock(dp, LK_EXCLUSIVE | LK_RETRY);
  696 
  697 /* dirloop: */
  698         /*
  699          * Search a new directory.
  700          *
  701          * The cn_hash value is for use by vfs_cache.
  702          * The last component of the filename is left accessible via
  703          * cnp->cn_nameptr for callers that need the name. Callers needing
  704          * the name set the SAVENAME flag. When done, they assume
  705          * responsibility for freeing the pathname buffer.
  706          */
  707 #ifdef DEBUG
  708         cp = NULL;
  709         newhash = namei_hash(cnp->cn_nameptr, &cp);
  710         if (newhash != cnp->cn_hash)
  711                 panic("relookup: bad hash");
  712         if (cnp->cn_namelen != cp - cnp->cn_nameptr)
  713                 panic ("relookup: bad len");
  714         while (*cp == '/')
  715                 cp++;
  716         if (*cp != 0)
  717                 panic("relookup: not last component");
  718 #endif /* DEBUG */
  719 #ifdef NAMEI_DIAGNOSTIC
  720         printf("{%s}: ", cnp->cn_nameptr);
  721 #endif /* NAMEI_DIAGNOSTIC */
  722 
  723         /*
  724          * Check for degenerate name (e.g. / or "")
  725          * which is a way of talking about a directory,
  726          * e.g. like "/." or ".".
  727          */
  728         if (cnp->cn_nameptr[0] == '\0')
  729                 panic("relookup: null name");
  730 
  731         if (cnp->cn_flags & ISDOTDOT)
  732                 panic ("relookup: lookup on dot-dot");
  733 
  734         /*
  735          * We now have a segment name to search for, and a directory to search.
  736          */
  737         if ((error = VOP_LOOKUP(dp, vpp, cnp)) != 0) {
  738 #ifdef DIAGNOSTIC
  739                 if (*vpp != NULL)
  740                         panic("leaf `%s' should be empty", cnp->cn_nameptr);
  741 #endif
  742                 if (error != EJUSTRETURN)
  743                         goto bad;
  744                 /*
  745                  * If creating and at end of pathname, then can consider
  746                  * allowing file to be created.
  747                  */
  748                 if (rdonly) {
  749                         error = EROFS;
  750                         goto bad;
  751                 }
  752                 /* ASSERT(dvp == ndp->ni_startdir) */
  753                 if (cnp->cn_flags & SAVESTART)
  754                         VREF(dvp);
  755                 /*
  756                  * We return with ni_vp NULL to indicate that the entry
  757                  * doesn't currently exist, leaving a pointer to the
  758                  * (possibly locked) directory inode in ndp->ni_dvp.
  759                  */
  760                 return (0);
  761         }
  762         dp = *vpp;
  763 
  764 #ifdef DIAGNOSTIC
  765         /*
  766          * Check for symbolic link
  767          */
  768         if (dp->v_type == VLNK && (cnp->cn_flags & FOLLOW))
  769                 panic ("relookup: symlink found.\n");
  770 #endif
  771 
  772         /*
  773          * Check for read-only file systems.
  774          */
  775         if (rdonly &&
  776             (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME)) {
  777                 error = EROFS;
  778                 goto bad2;
  779         }
  780         /* ASSERT(dvp == ndp->ni_startdir) */
  781         if (cnp->cn_flags & SAVESTART)
  782                 VREF(dvp);
  783         if (!wantparent)
  784                 vrele(dvp);
  785         if ((cnp->cn_flags & LOCKLEAF) == 0)
  786                 VOP_UNLOCK(dp, 0);
  787         return (0);
  788 
  789 bad2:
  790         if ((cnp->cn_flags & LOCKPARENT) && (cnp->cn_flags & ISLASTCN))
  791                 VOP_UNLOCK(dvp, 0);
  792         vrele(dvp);
  793 bad:
  794         vput(dp);
  795         *vpp = NULL;
  796         return (error);
  797 }

Cache object: 8c9da6f53181988c76311ee3a362da71


[ 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.