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.72.2.3 2007/02/17 23:27:47 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.72.2.3 2007/02/17 23:27:47 tron Exp $");
   41 
   42 #include "opt_ktrace.h"
   43 #include "opt_systrace.h"
   44 #include "opt_magiclinks.h"
   45 
   46 #include <sys/param.h>
   47 #include <sys/systm.h>
   48 #include <sys/kernel.h>
   49 #include <sys/syslimits.h>
   50 #include <sys/time.h>
   51 #include <sys/namei.h>
   52 #include <sys/vnode.h>
   53 #include <sys/mount.h>
   54 #include <sys/errno.h>
   55 #include <sys/filedesc.h>
   56 #include <sys/hash.h>
   57 #include <sys/malloc.h>
   58 #include <sys/proc.h>
   59 #include <sys/syslog.h>
   60 #include <sys/kauth.h>
   61 
   62 #ifdef KTRACE
   63 #include <sys/ktrace.h>
   64 #endif
   65 #ifdef SYSTRACE
   66 #include <sys/systrace.h>
   67 #endif
   68 
   69 #ifndef MAGICLINKS
   70 #define MAGICLINKS 0
   71 #endif
   72 
   73 struct pathname_internal {
   74         char *pathbuf;
   75         boolean_t needfree;
   76 };
   77 
   78 int vfs_magiclinks = MAGICLINKS;
   79 
   80 struct pool pnbuf_pool;         /* pathname buffer pool */
   81 struct pool_cache pnbuf_cache;  /* pathname buffer cache */
   82 
   83 /*
   84  * Substitute replacement text for 'magic' strings in symlinks.
   85  * Returns 0 if successful, and returns non-zero if an error
   86  * occurs.  (Currently, the only possible error is running out
   87  * of temporary pathname space.)
   88  *
   89  * Looks for "@<string>" and "@<string>/", where <string> is a
   90  * recognized 'magic' string.  Replaces the "@<string>" with the
   91  * appropriate replacement text.  (Note that in some cases the
   92  * replacement text may have zero length.)
   93  *
   94  * This would have been table driven, but the variance in
   95  * replacement strings (and replacement string lengths) made
   96  * that impractical.
   97  */
   98 #define VNL(x)                                                  \
   99         (sizeof(x) - 1)
  100 
  101 #define VO      '{'
  102 #define VC      '}'
  103 
  104 #define MATCH(str)                                              \
  105         ((termchar == '/' && i + VNL(str) == *len) ||           \
  106          (i + VNL(str) < *len &&                                \
  107           cp[i + VNL(str)] == termchar)) &&                     \
  108         !strncmp((str), &cp[i], VNL(str))
  109 
  110 #define SUBSTITUTE(m, s, sl)                                    \
  111         if ((newlen + (sl)) > MAXPATHLEN)                       \
  112                 return (1);                                     \
  113         i += VNL(m);                                            \
  114         if (termchar != '/')                                    \
  115                 i++;                                            \
  116         memcpy(&tmp[newlen], (s), (sl));                        \
  117         newlen += (sl);                                         \
  118         change = 1;                                             \
  119         termchar = '/';
  120 
  121 static int
  122 symlink_magic(struct proc *p, char *cp, int *len)
  123 {
  124         char *tmp;
  125         int change, i, newlen;
  126         int termchar = '/';
  127 
  128         tmp = PNBUF_GET();
  129         for (change = i = newlen = 0; i < *len; ) {
  130                 if (cp[i] != '@') {
  131                         tmp[newlen++] = cp[i++];
  132                         continue;
  133                 }
  134 
  135                 i++;
  136 
  137                 /* Check for @{var} syntax. */
  138                 if (cp[i] == VO) {
  139                         termchar = VC;
  140                         i++;
  141                 }
  142 
  143                 /*
  144                  * The following checks should be ordered according
  145                  * to frequency of use.
  146                  */
  147                 if (MATCH("machine_arch")) {
  148                         SUBSTITUTE("machine_arch", MACHINE_ARCH,
  149                             sizeof(MACHINE_ARCH) - 1);
  150                 } else if (MATCH("machine")) {
  151                         SUBSTITUTE("machine", MACHINE,
  152                             sizeof(MACHINE) - 1);
  153                 } else if (MATCH("hostname")) {
  154                         SUBSTITUTE("hostname", hostname,
  155                             hostnamelen);
  156                 } else if (MATCH("osrelease")) {
  157                         SUBSTITUTE("osrelease", osrelease,
  158                             strlen(osrelease));
  159                 } else if (MATCH("emul")) {
  160                         SUBSTITUTE("emul", p->p_emul->e_name,
  161                             strlen(p->p_emul->e_name));
  162                 } else if (MATCH("kernel_ident")) {
  163                         SUBSTITUTE("kernel_ident", kernel_ident,
  164                             strlen(kernel_ident));
  165                 } else if (MATCH("domainname")) {
  166                         SUBSTITUTE("domainname", domainname,
  167                             domainnamelen);
  168                 } else if (MATCH("ostype")) {
  169                         SUBSTITUTE("ostype", ostype,
  170                             strlen(ostype));
  171                 } else if (MATCH("uid")) {
  172                         char uidtmp[11]; /* XXX elad */
  173 
  174                         (void)snprintf(uidtmp, sizeof(uidtmp), "%u",
  175                             kauth_cred_geteuid(kauth_cred_get()));
  176                         SUBSTITUTE("uid", uidtmp, strlen(uidtmp));
  177                 } else {
  178                         tmp[newlen++] = '@';
  179                         if (termchar == VC)
  180                                 tmp[newlen++] = VO;
  181                 }
  182         }
  183 
  184         if (change) {
  185                 memcpy(cp, tmp, newlen);
  186                 *len = newlen;
  187         }
  188         PNBUF_PUT(tmp);
  189 
  190         return (0);
  191 }
  192 
  193 #undef VNL
  194 #undef VO
  195 #undef VC
  196 #undef MATCH
  197 #undef SUBSTITUTE
  198 
  199 int
  200 pathname_get(const char *dirp, enum uio_seg segflg, pathname_t *path)
  201 {
  202         int error;
  203 
  204         if (dirp == NULL)
  205                 return (EFAULT);
  206 
  207         *path = malloc(sizeof(struct pathname_internal), M_TEMP,
  208             M_ZERO|M_WAITOK);
  209 
  210         if (segflg == UIO_USERSPACE) {
  211                 (*path)->pathbuf = PNBUF_GET();
  212                 error = copyinstr(dirp, (*path)->pathbuf, MAXPATHLEN,
  213                     NULL);
  214                 if (error) {
  215                         PNBUF_PUT((*path)->pathbuf);
  216                         free(*path, M_TEMP);
  217                         *path = NULL;
  218                         return (error);
  219                 }
  220                 (*path)->needfree = TRUE;
  221         } else {
  222                 (*path)->pathbuf = __UNCONST(dirp);
  223                 (*path)->needfree = FALSE;
  224         }
  225 
  226         return (0);
  227 }
  228 
  229 const char *
  230 pathname_path(pathname_t path)
  231 {
  232         KASSERT(path != NULL);
  233         return (path->pathbuf);
  234 }
  235 
  236 void
  237 pathname_put(pathname_t path)
  238 {
  239         if (path != NULL) {
  240                 if (path->pathbuf != NULL && path->needfree)
  241                         PNBUF_PUT(path->pathbuf);
  242                 free(path, M_TEMP);
  243         }
  244 }
  245 
  246 /*
  247  * Convert a pathname into a pointer to a locked vnode.
  248  *
  249  * The FOLLOW flag is set when symbolic links are to be followed
  250  * when they occur at the end of the name translation process.
  251  * Symbolic links are always followed for all other pathname
  252  * components other than the last.
  253  *
  254  * The segflg defines whether the name is to be copied from user
  255  * space or kernel space.
  256  *
  257  * Overall outline of namei:
  258  *
  259  *      copy in name
  260  *      get starting directory
  261  *      while (!done && !error) {
  262  *              call lookup to search path.
  263  *              if symbolic link, massage name in buffer and continue
  264  *      }
  265  */
  266 int
  267 namei(struct nameidata *ndp)
  268 {
  269         struct cwdinfo *cwdi;           /* pointer to cwd state */
  270         char *cp;                       /* pointer into pathname argument */
  271         struct vnode *dp;               /* the directory we are searching */
  272         struct iovec aiov;              /* uio for reading symbolic links */
  273         struct uio auio;
  274         int error, linklen;
  275         struct componentname *cnp = &ndp->ni_cnd;
  276 
  277 #ifdef DIAGNOSTIC
  278         if (!cnp->cn_cred || !cnp->cn_lwp)
  279                 panic("namei: bad cred/proc");
  280         if (cnp->cn_nameiop & (~OPMASK))
  281                 panic("namei: nameiop contaminated with flags");
  282         if (cnp->cn_flags & OPMASK)
  283                 panic("namei: flags contaminated with nameiops");
  284 #endif
  285         cwdi = cnp->cn_lwp->l_proc->p_cwdi;
  286 
  287         /*
  288          * Get a buffer for the name to be translated, and copy the
  289          * name into the buffer.
  290          */
  291         if ((cnp->cn_flags & HASBUF) == 0)
  292                 cnp->cn_pnbuf = PNBUF_GET();
  293         if (ndp->ni_segflg == UIO_SYSSPACE)
  294                 error = copystr(ndp->ni_dirp, cnp->cn_pnbuf,
  295                             MAXPATHLEN, &ndp->ni_pathlen);
  296         else
  297                 error = copyinstr(ndp->ni_dirp, cnp->cn_pnbuf,
  298                             MAXPATHLEN, &ndp->ni_pathlen);
  299 
  300         /*
  301          * POSIX.1 requirement: "" is not a valid file name.
  302          */
  303         if (!error && ndp->ni_pathlen == 1)
  304                 error = ENOENT;
  305 
  306         if (error) {
  307                 PNBUF_PUT(cnp->cn_pnbuf);
  308                 ndp->ni_vp = NULL;
  309                 return (error);
  310         }
  311         ndp->ni_loopcnt = 0;
  312 
  313 #ifdef KTRACE
  314         if (KTRPOINT(cnp->cn_lwp->l_proc, KTR_NAMEI))
  315                 ktrnamei(cnp->cn_lwp, cnp->cn_pnbuf);
  316 #endif
  317 #ifdef SYSTRACE
  318         if (ISSET(cnp->cn_lwp->l_proc->p_flag, P_SYSTRACE))
  319                 systrace_namei(ndp);
  320 #endif
  321 
  322         /*
  323          * Get starting point for the translation.
  324          */
  325         if ((ndp->ni_rootdir = cwdi->cwdi_rdir) == NULL)
  326                 ndp->ni_rootdir = rootvnode;
  327         /*
  328          * Check if starting from root directory or current directory.
  329          */
  330         if (cnp->cn_pnbuf[0] == '/') {
  331                 dp = ndp->ni_rootdir;
  332                 VREF(dp);
  333         } else {
  334                 dp = cwdi->cwdi_cdir;
  335                 VREF(dp);
  336         }
  337         vn_lock(dp, LK_EXCLUSIVE | LK_RETRY);
  338         for (;;) {
  339                 if (!dp->v_mount) {
  340                         /* Give up if the directory is no longer mounted */
  341                         vput(dp);
  342                         PNBUF_PUT(cnp->cn_pnbuf);
  343                         return (ENOENT);
  344                 }
  345                 cnp->cn_nameptr = cnp->cn_pnbuf;
  346                 ndp->ni_startdir = dp;
  347                 error = lookup(ndp);
  348                 if (error != 0) {
  349                         if (ndp->ni_dvp) {
  350                                 vput(ndp->ni_dvp);
  351                         }
  352                         PNBUF_PUT(cnp->cn_pnbuf);
  353                         return (error);
  354                 }
  355 
  356                 /*
  357                  * Check for symbolic link
  358                  */
  359                 if ((cnp->cn_flags & ISSYMLINK) == 0) {
  360                         if ((cnp->cn_flags & LOCKPARENT) == 0 && ndp->ni_dvp) {
  361                                 if (ndp->ni_dvp == ndp->ni_vp) {
  362                                         vrele(ndp->ni_dvp);
  363                                 } else {
  364                                         vput(ndp->ni_dvp);
  365                                 }
  366                         }
  367                         if ((cnp->cn_flags & (SAVENAME | SAVESTART)) == 0)
  368                                 PNBUF_PUT(cnp->cn_pnbuf);
  369                         else
  370                                 cnp->cn_flags |= HASBUF;
  371                         return (0);
  372                 }
  373 
  374                 if (ndp->ni_loopcnt++ >= MAXSYMLINKS) {
  375                         error = ELOOP;
  376                         break;
  377                 }
  378                 if (ndp->ni_vp->v_mount->mnt_flag & MNT_SYMPERM) {
  379                         error = VOP_ACCESS(ndp->ni_vp, VEXEC, cnp->cn_cred,
  380                             cnp->cn_lwp);
  381                         if (error != 0)
  382                                 break;
  383                 }
  384                 if (ndp->ni_pathlen > 1)
  385                         cp = PNBUF_GET();
  386                 else
  387                         cp = cnp->cn_pnbuf;
  388                 aiov.iov_base = cp;
  389                 aiov.iov_len = MAXPATHLEN;
  390                 auio.uio_iov = &aiov;
  391                 auio.uio_iovcnt = 1;
  392                 auio.uio_offset = 0;
  393                 auio.uio_rw = UIO_READ;
  394                 auio.uio_resid = MAXPATHLEN;
  395                 UIO_SETUP_SYSSPACE(&auio);
  396                 error = VOP_READLINK(ndp->ni_vp, &auio, cnp->cn_cred);
  397                 if (error) {
  398 badlink:
  399                         if (ndp->ni_pathlen > 1)
  400                                 PNBUF_PUT(cp);
  401                         break;
  402                 }
  403                 linklen = MAXPATHLEN - auio.uio_resid;
  404                 if (linklen == 0) {
  405                         error = ENOENT;
  406                         goto badlink;
  407                 }
  408 
  409                 /*
  410                  * Do symlink substitution, if appropriate, and
  411                  * check length for potential overflow.
  412                  */
  413                 if ((vfs_magiclinks &&
  414                      symlink_magic(cnp->cn_lwp->l_proc, cp, &linklen)) ||
  415                     (linklen + ndp->ni_pathlen >= MAXPATHLEN)) {
  416                         error = ENAMETOOLONG;
  417                         goto badlink;
  418                 }
  419                 if (ndp->ni_pathlen > 1) {
  420                         memcpy(cp + linklen, ndp->ni_next, ndp->ni_pathlen);
  421                         PNBUF_PUT(cnp->cn_pnbuf);
  422                         cnp->cn_pnbuf = cp;
  423                 } else
  424                         cnp->cn_pnbuf[linklen] = '\0';
  425                 ndp->ni_pathlen += linklen;
  426                 vput(ndp->ni_vp);
  427                 dp = ndp->ni_dvp;
  428 
  429                 /*
  430                  * Check if root directory should replace current directory.
  431                  */
  432                 if (cnp->cn_pnbuf[0] == '/') {
  433                         vput(dp);
  434                         dp = ndp->ni_rootdir;
  435                         VREF(dp);
  436                         vn_lock(dp, LK_EXCLUSIVE | LK_RETRY);
  437                 }
  438         }
  439         KASSERT(ndp->ni_dvp != ndp->ni_vp);
  440         vput(ndp->ni_dvp);
  441         vput(ndp->ni_vp);
  442         ndp->ni_vp = NULL;
  443         PNBUF_PUT(cnp->cn_pnbuf);
  444         return (error);
  445 }
  446 
  447 /*
  448  * Determine the namei hash (for cn_hash) for name.
  449  * If *ep != NULL, hash from name to ep-1.
  450  * If *ep == NULL, hash from name until the first NUL or '/', and
  451  * return the location of this termination character in *ep.
  452  *
  453  * This function returns an equivalent hash to the MI hash32_strn().
  454  * The latter isn't used because in the *ep == NULL case, determining
  455  * the length of the string to the first NUL or `/' and then calling
  456  * hash32_strn() involves unnecessary double-handling of the data.
  457  */
  458 uint32_t
  459 namei_hash(const char *name, const char **ep)
  460 {
  461         uint32_t        hash;
  462 
  463         hash = HASH32_STR_INIT;
  464         if (*ep != NULL) {
  465                 for (; name < *ep; name++)
  466                         hash = hash * 33 + *(const uint8_t *)name;
  467         } else {
  468                 for (; *name != '\0' && *name != '/'; name++)
  469                         hash = hash * 33 + *(const uint8_t *)name;
  470                 *ep = name;
  471         }
  472         return (hash + (hash >> 5));
  473 }
  474 
  475 /*
  476  * Search a pathname.
  477  * This is a very central and rather complicated routine.
  478  *
  479  * The pathname is pointed to by ni_ptr and is of length ni_pathlen.
  480  * The starting directory is taken from ni_startdir. The pathname is
  481  * descended until done, or a symbolic link is encountered. The variable
  482  * ni_more is clear if the path is completed; it is set to one if a
  483  * symbolic link needing interpretation is encountered.
  484  *
  485  * The flag argument is LOOKUP, CREATE, RENAME, or DELETE depending on
  486  * whether the name is to be looked up, created, renamed, or deleted.
  487  * When CREATE, RENAME, or DELETE is specified, information usable in
  488  * creating, renaming, or deleting a directory entry may be calculated.
  489  * If flag has LOCKPARENT or'ed into it, the parent directory is returned
  490  * locked.  Otherwise the parent directory is not returned. If the target
  491  * of the pathname exists and LOCKLEAF is or'ed into the flag the target
  492  * is returned locked, otherwise it is returned unlocked.  When creating
  493  * or renaming and LOCKPARENT is specified, the target may not be ".".
  494  * When deleting and LOCKPARENT is specified, the target may be ".".
  495  *
  496  * Overall outline of lookup:
  497  *
  498  * dirloop:
  499  *      identify next component of name at ndp->ni_ptr
  500  *      handle degenerate case where name is null string
  501  *      if .. and crossing mount points and on mounted filesys, find parent
  502  *      call VOP_LOOKUP routine for next component name
  503  *          directory vnode returned in ni_dvp, locked.
  504  *          component vnode returned in ni_vp (if it exists), locked.
  505  *      if result vnode is mounted on and crossing mount points,
  506  *          find mounted on vnode
  507  *      if more components of name, do next level at dirloop
  508  *      return the answer in ni_vp, locked if LOCKLEAF set
  509  *          if LOCKPARENT set, return locked parent in ni_dvp
  510  */
  511 int
  512 lookup(struct nameidata *ndp)
  513 {
  514         const char *cp;                 /* pointer into pathname argument */
  515         struct vnode *dp = 0;           /* the directory we are searching */
  516         struct vnode *tdp;              /* saved dp */
  517         struct mount *mp;               /* mount table entry */
  518         int docache;                    /* == 0 do not cache last component */
  519         int rdonly;                     /* lookup read-only flag bit */
  520         int error = 0;
  521         int slashes;
  522         struct componentname *cnp = &ndp->ni_cnd;
  523         struct lwp *l = cnp->cn_lwp;
  524 
  525         /*
  526          * Setup: break out flag bits into variables.
  527          */
  528         docache = (cnp->cn_flags & NOCACHE) ^ NOCACHE;
  529         if (cnp->cn_nameiop == DELETE)
  530                 docache = 0;
  531         rdonly = cnp->cn_flags & RDONLY;
  532         ndp->ni_dvp = NULL;
  533         cnp->cn_flags &= ~ISSYMLINK;
  534         dp = ndp->ni_startdir;
  535         ndp->ni_startdir = NULLVP;
  536 
  537         /*
  538          * If we have a leading string of slashes, remove them, and just make
  539          * sure the current node is a directory.
  540          */
  541         cp = cnp->cn_nameptr;
  542         if (*cp == '/') {
  543                 do {
  544                         cp++;
  545                 } while (*cp == '/');
  546                 ndp->ni_pathlen -= cp - cnp->cn_nameptr;
  547                 cnp->cn_nameptr = cp;
  548 
  549                 if (dp->v_type != VDIR) {
  550                         error = ENOTDIR;
  551                         vput(dp);
  552                         goto bad;
  553                 }
  554 
  555                 /*
  556                  * If we've exhausted the path name, then just return the
  557                  * current node.  If the caller requested the parent node (i.e.
  558                  * it's a CREATE, DELETE, or RENAME), and we don't have one
  559                  * (because this is the root directory), then we must fail.
  560                  */
  561                 if (cnp->cn_nameptr[0] == '\0') {
  562                         if (ndp->ni_dvp == NULL && cnp->cn_nameiop != LOOKUP) {
  563                                 switch (cnp->cn_nameiop) {
  564                                 case CREATE:
  565                                         error = EEXIST;
  566                                         break;
  567                                 case DELETE:
  568                                 case RENAME:
  569                                         error = EBUSY;
  570                                         break;
  571                                 default:
  572                                         KASSERT(0);
  573                                 }
  574                                 vput(dp);
  575                                 goto bad;
  576                         }
  577                         ndp->ni_vp = dp;
  578                         cnp->cn_flags |= ISLASTCN;
  579                         goto terminal;
  580                 }
  581         }
  582 
  583 dirloop:
  584         /*
  585          * Search a new directory.
  586          *
  587          * The cn_hash value is for use by vfs_cache.
  588          * The last component of the filename is left accessible via
  589          * cnp->cn_nameptr for callers that need the name. Callers needing
  590          * the name set the SAVENAME flag. When done, they assume
  591          * responsibility for freeing the pathname buffer.
  592          *
  593          * At this point, our only vnode state is that "dp" is held and locked.
  594          */
  595         cnp->cn_consume = 0;
  596         cp = NULL;
  597         cnp->cn_hash = namei_hash(cnp->cn_nameptr, &cp);
  598         cnp->cn_namelen = cp - cnp->cn_nameptr;
  599         if (cnp->cn_namelen > NAME_MAX) {
  600                 vput(dp);
  601                 error = ENAMETOOLONG;
  602                 ndp->ni_dvp = NULL;
  603                 goto bad;
  604         }
  605 #ifdef NAMEI_DIAGNOSTIC
  606         { char c = *cp;
  607         *(char *)cp = '\0';
  608         printf("{%s}: ", cnp->cn_nameptr);
  609         *(char *)cp = c; }
  610 #endif /* NAMEI_DIAGNOSTIC */
  611         ndp->ni_pathlen -= cnp->cn_namelen;
  612         ndp->ni_next = cp;
  613         /*
  614          * If this component is followed by a slash, then move the pointer to
  615          * the next component forward, and remember that this component must be
  616          * a directory.
  617          */
  618         if (*cp == '/') {
  619                 do {
  620                         cp++;
  621                 } while (*cp == '/');
  622                 slashes = cp - ndp->ni_next;
  623                 ndp->ni_pathlen -= slashes;
  624                 ndp->ni_next = cp;
  625                 cnp->cn_flags |= REQUIREDIR;
  626         } else {
  627                 slashes = 0;
  628                 cnp->cn_flags &= ~REQUIREDIR;
  629         }
  630         /*
  631          * We do special processing on the last component, whether or not it's
  632          * a directory.  Cache all intervening lookups, but not the final one.
  633          */
  634         if (*cp == '\0') {
  635                 if (docache)
  636                         cnp->cn_flags |= MAKEENTRY;
  637                 else
  638                         cnp->cn_flags &= ~MAKEENTRY;
  639                 cnp->cn_flags |= ISLASTCN;
  640         } else {
  641                 cnp->cn_flags |= MAKEENTRY;
  642                 cnp->cn_flags &= ~ISLASTCN;
  643         }
  644         if (cnp->cn_namelen == 2 &&
  645             cnp->cn_nameptr[1] == '.' && cnp->cn_nameptr[0] == '.')
  646                 cnp->cn_flags |= ISDOTDOT;
  647         else
  648                 cnp->cn_flags &= ~ISDOTDOT;
  649 
  650         /*
  651          * Handle "..": two special cases.
  652          * 1. If at root directory (e.g. after chroot)
  653          *    or at absolute root directory
  654          *    then ignore it so can't get out.
  655          * 1a. If we have somehow gotten out of a jail, warn
  656          *    and also ignore it so we can't get farther out.
  657          * 2. If this vnode is the root of a mounted
  658          *    filesystem, then replace it with the
  659          *    vnode which was mounted on so we take the
  660          *    .. in the other file system.
  661          */
  662         if (cnp->cn_flags & ISDOTDOT) {
  663                 struct proc *p = l->l_proc;
  664 
  665                 for (;;) {
  666                         if (dp == ndp->ni_rootdir || dp == rootvnode) {
  667                                 ndp->ni_dvp = dp;
  668                                 ndp->ni_vp = dp;
  669                                 VREF(dp);
  670                                 goto nextname;
  671                         }
  672                         if (ndp->ni_rootdir != rootvnode) {
  673                                 int retval;
  674 
  675                                 VOP_UNLOCK(dp, 0);
  676                                 retval = vn_isunder(dp, ndp->ni_rootdir, l);
  677                                 vn_lock(dp, LK_EXCLUSIVE | LK_RETRY);
  678                                 if (!retval) {
  679                                     /* Oops! We got out of jail! */
  680                                     log(LOG_WARNING,
  681                                         "chrooted pid %d uid %d (%s) "
  682                                         "detected outside of its chroot\n",
  683                                         p->p_pid, kauth_cred_geteuid(l->l_cred),
  684                                         p->p_comm);
  685                                     /* Put us at the jail root. */
  686                                     vput(dp);
  687                                     dp = ndp->ni_rootdir;
  688                                     ndp->ni_dvp = dp;
  689                                     ndp->ni_vp = dp;
  690                                     VREF(dp);
  691                                     VREF(dp);
  692                                     vn_lock(dp, LK_EXCLUSIVE | LK_RETRY);
  693                                     goto nextname;
  694                                 }
  695                         }
  696                         if ((dp->v_flag & VROOT) == 0 ||
  697                             (cnp->cn_flags & NOCROSSMOUNT))
  698                                 break;
  699                         tdp = dp;
  700                         dp = dp->v_mount->mnt_vnodecovered;
  701                         vput(tdp);
  702                         VREF(dp);
  703                         vn_lock(dp, LK_EXCLUSIVE | LK_RETRY);
  704                 }
  705         }
  706 
  707         /*
  708          * We now have a segment name to search for, and a directory to search.
  709          * Again, our only vnode state is that "dp" is held and locked.
  710          */
  711 unionlookup:
  712         ndp->ni_dvp = dp;
  713         ndp->ni_vp = NULL;
  714         error = VOP_LOOKUP(dp, &ndp->ni_vp, cnp);
  715         if (error != 0) {
  716 #ifdef DIAGNOSTIC
  717                 if (ndp->ni_vp != NULL)
  718                         panic("leaf `%s' should be empty", cnp->cn_nameptr);
  719 #endif /* DIAGNOSTIC */
  720 #ifdef NAMEI_DIAGNOSTIC
  721                 printf("not found\n");
  722 #endif /* NAMEI_DIAGNOSTIC */
  723                 if ((error == ENOENT) &&
  724                     (dp->v_flag & VROOT) &&
  725                     (dp->v_mount->mnt_flag & MNT_UNION)) {
  726                         tdp = dp;
  727                         dp = dp->v_mount->mnt_vnodecovered;
  728                         vput(tdp);
  729                         VREF(dp);
  730                         vn_lock(dp, LK_EXCLUSIVE | LK_RETRY);
  731                         goto unionlookup;
  732                 }
  733 
  734                 if (error != EJUSTRETURN)
  735                         goto bad;
  736 
  737                 /*
  738                  * If this was not the last component, or there were trailing
  739                  * slashes, and we are not going to create a directory,
  740                  * then the name must exist.
  741                  */
  742                 if ((cnp->cn_flags & (REQUIREDIR | CREATEDIR)) == REQUIREDIR) {
  743                         error = ENOENT;
  744                         goto bad;
  745                 }
  746 
  747                 /*
  748                  * If creating and at end of pathname, then can consider
  749                  * allowing file to be created.
  750                  */
  751                 if (rdonly) {
  752                         error = EROFS;
  753                         goto bad;
  754                 }
  755 
  756                 /*
  757                  * We return with ni_vp NULL to indicate that the entry
  758                  * doesn't currently exist, leaving a pointer to the
  759                  * (possibly locked) directory vnode in ndp->ni_dvp.
  760                  */
  761                 if (cnp->cn_flags & SAVESTART) {
  762                         ndp->ni_startdir = ndp->ni_dvp;
  763                         VREF(ndp->ni_startdir);
  764                 }
  765                 return (0);
  766         }
  767 #ifdef NAMEI_DIAGNOSTIC
  768         printf("found\n");
  769 #endif /* NAMEI_DIAGNOSTIC */
  770 
  771         /*
  772          * Take into account any additional components consumed by the
  773          * underlying filesystem.  This will include any trailing slashes after
  774          * the last component consumed.
  775          */
  776         if (cnp->cn_consume > 0) {
  777                 ndp->ni_pathlen -= cnp->cn_consume - slashes;
  778                 ndp->ni_next += cnp->cn_consume - slashes;
  779                 cnp->cn_consume = 0;
  780                 if (ndp->ni_next[0] == '\0')
  781                         cnp->cn_flags |= ISLASTCN;
  782         }
  783 
  784         dp = ndp->ni_vp;
  785 
  786         /*
  787          * "dp" and "ndp->ni_dvp" are both locked and held,
  788          * and may be the same vnode.
  789          */
  790 
  791         /*
  792          * Check to see if the vnode has been mounted on;
  793          * if so find the root of the mounted file system.
  794          */
  795         while (dp->v_type == VDIR && (mp = dp->v_mountedhere) &&
  796                (cnp->cn_flags & NOCROSSMOUNT) == 0) {
  797                 if (vfs_busy(mp, 0, 0))
  798                         continue;
  799 
  800                 KASSERT(ndp->ni_dvp != dp);
  801                 VOP_UNLOCK(ndp->ni_dvp, 0);
  802                 vput(dp);
  803                 error = VFS_ROOT(mp, &tdp);
  804                 vfs_unbusy(mp);
  805                 if (error) {
  806                         vn_lock(ndp->ni_dvp, LK_EXCLUSIVE | LK_RETRY);
  807                         goto bad;
  808                 }
  809                 VOP_UNLOCK(tdp, 0);
  810                 ndp->ni_vp = dp = tdp;
  811                 vn_lock(ndp->ni_dvp, LK_EXCLUSIVE | LK_RETRY);
  812                 vn_lock(ndp->ni_vp, LK_EXCLUSIVE | LK_RETRY);
  813         }
  814 
  815         /*
  816          * Check for symbolic link.  Back up over any slashes that we skipped,
  817          * as we will need them again.
  818          */
  819         if ((dp->v_type == VLNK) && (cnp->cn_flags & (FOLLOW|REQUIREDIR))) {
  820                 ndp->ni_pathlen += slashes;
  821                 ndp->ni_next -= slashes;
  822                 cnp->cn_flags |= ISSYMLINK;
  823                 return (0);
  824         }
  825 
  826         /*
  827          * Check for directory, if the component was followed by a series of
  828          * slashes.
  829          */
  830         if ((dp->v_type != VDIR) && (cnp->cn_flags & REQUIREDIR)) {
  831                 error = ENOTDIR;
  832                 KASSERT(dp != ndp->ni_dvp);
  833                 vput(dp);
  834                 goto bad;
  835         }
  836 
  837 nextname:
  838 
  839         /*
  840          * Not a symbolic link.  If this was not the last component, then
  841          * continue at the next component, else return.
  842          */
  843         if (!(cnp->cn_flags & ISLASTCN)) {
  844                 cnp->cn_nameptr = ndp->ni_next;
  845                 if (ndp->ni_dvp == dp) {
  846                         vrele(ndp->ni_dvp);
  847                 } else {
  848                         vput(ndp->ni_dvp);
  849                 }
  850                 goto dirloop;
  851         }
  852 
  853 terminal:
  854 
  855         /*
  856          * Disallow directory write attempts on read-only file systems.
  857          */
  858         if (rdonly &&
  859             (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME)) {
  860 
  861                 /*
  862                  * Disallow directory write attempts on read-only
  863                  * file systems.
  864                  */
  865                 error = EROFS;
  866                 if (dp != ndp->ni_dvp) {
  867                         vput(dp);
  868                 }
  869                 goto bad;
  870         }
  871         if (ndp->ni_dvp != NULL) {
  872                 if (cnp->cn_flags & SAVESTART) {
  873                         ndp->ni_startdir = ndp->ni_dvp;
  874                         VREF(ndp->ni_startdir);
  875                 }
  876         }
  877         if ((cnp->cn_flags & LOCKLEAF) == 0) {
  878                 VOP_UNLOCK(dp, 0);
  879         }
  880         return (0);
  881 
  882 bad:
  883         ndp->ni_vp = NULL;
  884         return (error);
  885 }
  886 
  887 /*
  888  * Reacquire a path name component.
  889  * dvp is locked on entry and exit.
  890  * *vpp is locked on exit unless it's NULL.
  891  */
  892 int
  893 relookup(struct vnode *dvp, struct vnode **vpp, struct componentname *cnp)
  894 {
  895         int rdonly;                     /* lookup read-only flag bit */
  896         int error = 0;
  897 #ifdef DEBUG
  898         uint32_t newhash;               /* DEBUG: check name hash */
  899         const char *cp;                 /* DEBUG: check name ptr/len */
  900 #endif /* DEBUG */
  901 
  902         /*
  903          * Setup: break out flag bits into variables.
  904          */
  905         rdonly = cnp->cn_flags & RDONLY;
  906         cnp->cn_flags &= ~ISSYMLINK;
  907 
  908         /*
  909          * Search a new directory.
  910          *
  911          * The cn_hash value is for use by vfs_cache.
  912          * The last component of the filename is left accessible via
  913          * cnp->cn_nameptr for callers that need the name. Callers needing
  914          * the name set the SAVENAME flag. When done, they assume
  915          * responsibility for freeing the pathname buffer.
  916          */
  917 #ifdef DEBUG
  918         cp = NULL;
  919         newhash = namei_hash(cnp->cn_nameptr, &cp);
  920         if ((uint32_t)newhash != (uint32_t)cnp->cn_hash)
  921                 panic("relookup: bad hash");
  922         if (cnp->cn_namelen != cp - cnp->cn_nameptr)
  923                 panic("relookup: bad len");
  924         while (*cp == '/')
  925                 cp++;
  926         if (*cp != 0)
  927                 panic("relookup: not last component");
  928 #endif /* DEBUG */
  929 
  930         /*
  931          * Check for degenerate name (e.g. / or "")
  932          * which is a way of talking about a directory,
  933          * e.g. like "/." or ".".
  934          */
  935         if (cnp->cn_nameptr[0] == '\0')
  936                 panic("relookup: null name");
  937 
  938         if (cnp->cn_flags & ISDOTDOT)
  939                 panic("relookup: lookup on dot-dot");
  940 
  941         /*
  942          * We now have a segment name to search for, and a directory to search.
  943          */
  944         if ((error = VOP_LOOKUP(dvp, vpp, cnp)) != 0) {
  945 #ifdef DIAGNOSTIC
  946                 if (*vpp != NULL)
  947                         panic("leaf `%s' should be empty", cnp->cn_nameptr);
  948 #endif
  949                 if (error != EJUSTRETURN)
  950                         goto bad;
  951         }
  952 
  953 #ifdef DIAGNOSTIC
  954         /*
  955          * Check for symbolic link
  956          */
  957         if (*vpp && (*vpp)->v_type == VLNK && (cnp->cn_flags & FOLLOW))
  958                 panic("relookup: symlink found");
  959 #endif
  960 
  961         /*
  962          * Check for read-only file systems.
  963          */
  964         if (rdonly && cnp->cn_nameiop != LOOKUP) {
  965                 error = EROFS;
  966                 if (*vpp) {
  967                         vput(*vpp);
  968                 }
  969                 goto bad;
  970         }
  971         if (cnp->cn_flags & SAVESTART)
  972                 VREF(dvp);
  973         return (0);
  974 
  975 bad:
  976         *vpp = NULL;
  977         return (error);
  978 }

Cache object: 281b0146150ed9bc34499e203e0e654b


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