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

Cache object: fe392ac221e9a4dbf8363398f2f4faa9


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