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

Cache object: d8726138df8ba2758c383b10737429ea


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