root/kern/vfs_lookup.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. namei
  2. lookup
  3. relookup

    1 /*      $OpenBSD: vfs_lookup.c,v 1.36 2007/08/07 07:41:59 thib 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/time.h>
   44 #include <sys/namei.h>
   45 #include <sys/vnode.h>
   46 #include <sys/mount.h>
   47 #include <sys/errno.h>
   48 #include <sys/malloc.h>
   49 #include <sys/pool.h>
   50 #include <sys/filedesc.h>
   51 #include <sys/proc.h>
   52 #include <sys/hash.h>
   53 
   54 #ifdef KTRACE
   55 #include <sys/ktrace.h>
   56 #endif
   57 
   58 #include <dev/systrace.h>
   59 #include "systrace.h"
   60 
   61 /*
   62  * Convert a pathname into a pointer to a vnode.
   63  *
   64  * The FOLLOW flag is set when symbolic links are to be followed
   65  * when they occur at the end of the name translation process.
   66  * Symbolic links are always followed for all other pathname
   67  * components other than the last.
   68  *
   69  * If the LOCKLEAF flag is set, a locked vnode is returned.
   70  *
   71  * The segflg defines whether the name is to be copied from user
   72  * space or kernel space.
   73  *
   74  * Overall outline of namei:
   75  *
   76  *      copy in name
   77  *      get starting directory
   78  *      while (!done && !error) {
   79  *              call lookup to search path.
   80  *              if symbolic link, massage name in buffer and continue
   81  *      }
   82  */
   83 int
   84 namei(struct nameidata *ndp)
   85 {
   86         struct filedesc *fdp;           /* pointer to file descriptor state */
   87         char *cp;                       /* pointer into pathname argument */
   88         struct vnode *dp;               /* the directory we are searching */
   89         struct iovec aiov;              /* uio for reading symbolic links */
   90         struct uio auio;
   91         int error, linklen;
   92         struct componentname *cnp = &ndp->ni_cnd;
   93         struct proc *p = cnp->cn_proc;
   94 
   95         ndp->ni_cnd.cn_cred = ndp->ni_cnd.cn_proc->p_ucred;
   96 #ifdef DIAGNOSTIC
   97         if (!cnp->cn_cred || !cnp->cn_proc)
   98                 panic ("namei: bad cred/proc");
   99         if (cnp->cn_nameiop & (~OPMASK))
  100                 panic ("namei: nameiop contaminated with flags");
  101         if (cnp->cn_flags & OPMASK)
  102                 panic ("namei: flags contaminated with nameiops");
  103 #endif
  104         fdp = cnp->cn_proc->p_fd;
  105 
  106         /*
  107          * Get a buffer for the name to be translated, and copy the
  108          * name into the buffer.
  109          */
  110         if ((cnp->cn_flags & HASBUF) == 0)
  111                 cnp->cn_pnbuf = pool_get(&namei_pool, PR_WAITOK);
  112         if (ndp->ni_segflg == UIO_SYSSPACE)
  113                 error = copystr(ndp->ni_dirp, cnp->cn_pnbuf,
  114                             MAXPATHLEN, &ndp->ni_pathlen);
  115         else
  116                 error = copyinstr(ndp->ni_dirp, cnp->cn_pnbuf,
  117                             MAXPATHLEN, &ndp->ni_pathlen);
  118 
  119         /*
  120          * Fail on null pathnames
  121          */
  122         if (error == 0 && ndp->ni_pathlen == 1)
  123                 error = ENOENT;
  124 
  125         if (error) {
  126                 pool_put(&namei_pool, cnp->cn_pnbuf);
  127                 ndp->ni_vp = NULL;
  128                 return (error);
  129         }
  130 
  131 #ifdef KTRACE
  132         if (KTRPOINT(cnp->cn_proc, KTR_NAMEI))
  133                 ktrnamei(cnp->cn_proc, cnp->cn_pnbuf);
  134 #endif
  135 #if NSYSTRACE > 0
  136         if (ISSET(cnp->cn_proc->p_flag, P_SYSTRACE))
  137                 systrace_namei(ndp);
  138 #endif
  139 
  140         /*
  141          *  Strip trailing slashes, as requested
  142          */
  143         if (cnp->cn_flags & STRIPSLASHES) {
  144                 char *end = cnp->cn_pnbuf + ndp->ni_pathlen - 2;
  145 
  146                 cp = end;
  147                 while (cp >= cnp->cn_pnbuf && (*cp == '/'))
  148                         cp--;
  149 
  150                 /* Still some remaining characters in the buffer */
  151                 if (cp >= cnp->cn_pnbuf) {
  152                         ndp->ni_pathlen -= (end - cp);
  153                         *(cp + 1) = '\0';
  154                 }
  155         }
  156 
  157         ndp->ni_loopcnt = 0;
  158 
  159         /*
  160          * Get starting point for the translation.
  161          */
  162         if ((ndp->ni_rootdir = fdp->fd_rdir) == NULL)
  163                 ndp->ni_rootdir = rootvnode;
  164         /*
  165          * Check if starting from root directory or current directory.
  166          */
  167         if (cnp->cn_pnbuf[0] == '/') {
  168                 dp = ndp->ni_rootdir;
  169                 VREF(dp);
  170         } else {
  171                 dp = fdp->fd_cdir;
  172                 VREF(dp);
  173         }
  174         for (;;) {
  175                 if (!dp->v_mount) {
  176                         /* Give up if the directory is no longer mounted */
  177                         pool_put(&namei_pool, cnp->cn_pnbuf);
  178                         return (ENOENT);
  179                 }
  180                 cnp->cn_nameptr = cnp->cn_pnbuf;
  181                 ndp->ni_startdir = dp;
  182                 if ((error = lookup(ndp)) != 0) {
  183                         pool_put(&namei_pool, cnp->cn_pnbuf);
  184                         return (error);
  185                 }
  186                 /*
  187                  * Check for symbolic link
  188                  */
  189                 if ((cnp->cn_flags & ISSYMLINK) == 0) {
  190                         if ((cnp->cn_flags & (SAVENAME | SAVESTART)) == 0)
  191                                 pool_put(&namei_pool, cnp->cn_pnbuf);
  192                         else
  193                                 cnp->cn_flags |= HASBUF;
  194                         return (0);
  195                 }
  196                 if ((cnp->cn_flags & LOCKPARENT) && (cnp->cn_flags & ISLASTCN))
  197                         VOP_UNLOCK(ndp->ni_dvp, 0, p);
  198                 if (ndp->ni_loopcnt++ >= MAXSYMLINKS) {
  199                         error = ELOOP;
  200                         break;
  201                 }
  202                 if (ndp->ni_pathlen > 1)
  203                         cp = pool_get(&namei_pool, PR_WAITOK);
  204                 else
  205                         cp = cnp->cn_pnbuf;
  206                 aiov.iov_base = cp;
  207                 aiov.iov_len = MAXPATHLEN;
  208                 auio.uio_iov = &aiov;
  209                 auio.uio_iovcnt = 1;
  210                 auio.uio_offset = 0;
  211                 auio.uio_rw = UIO_READ;
  212                 auio.uio_segflg = UIO_SYSSPACE;
  213                 auio.uio_procp = cnp->cn_proc;
  214                 auio.uio_resid = MAXPATHLEN;
  215                 error = VOP_READLINK(ndp->ni_vp, &auio, cnp->cn_cred);
  216                 if (error) {
  217 badlink:
  218                         if (ndp->ni_pathlen > 1)
  219                                 pool_put(&namei_pool, cp);
  220                         break;
  221                 }
  222                 linklen = MAXPATHLEN - auio.uio_resid;
  223                 if (linklen + ndp->ni_pathlen >= MAXPATHLEN) {
  224                         error = ENAMETOOLONG;
  225                         goto badlink;
  226                 }
  227                 if (ndp->ni_pathlen > 1) {
  228                         bcopy(ndp->ni_next, cp + linklen, ndp->ni_pathlen);
  229                         pool_put(&namei_pool, cnp->cn_pnbuf);
  230                         cnp->cn_pnbuf = cp;
  231                 } else
  232                         cnp->cn_pnbuf[linklen] = '\0';
  233                 ndp->ni_pathlen += linklen;
  234                 vput(ndp->ni_vp);
  235                 dp = ndp->ni_dvp;
  236                 /*
  237                  * Check if root directory should replace current directory.
  238                  */
  239                 if (cnp->cn_pnbuf[0] == '/') {
  240                         vrele(dp);
  241                         dp = ndp->ni_rootdir;
  242                         VREF(dp);
  243                 }
  244         }
  245         pool_put(&namei_pool, cnp->cn_pnbuf);
  246         vrele(ndp->ni_dvp);
  247         vput(ndp->ni_vp);
  248         ndp->ni_vp = NULL;
  249         return (error);
  250 }
  251 
  252 /*
  253  * Search a pathname.
  254  * This is a very central and rather complicated routine.
  255  *
  256  * The pathname is pointed to by ni_ptr and is of length ni_pathlen.
  257  * The starting directory is taken from ni_startdir. The pathname is
  258  * descended until done, or a symbolic link is encountered. The variable
  259  * ni_more is clear if the path is completed; it is set to one if a
  260  * symbolic link needing interpretation is encountered.
  261  *
  262  * The flag argument is LOOKUP, CREATE, RENAME, or DELETE depending on
  263  * whether the name is to be looked up, created, renamed, or deleted.
  264  * When CREATE, RENAME, or DELETE is specified, information usable in
  265  * creating, renaming, or deleting a directory entry may be calculated.
  266  * If flag has LOCKPARENT or'ed into it, the parent directory is returned
  267  * locked. If flag has WANTPARENT or'ed into it, the parent directory is
  268  * returned unlocked. Otherwise the parent directory is not returned. If
  269  * the target of the pathname exists and LOCKLEAF is or'ed into the flag
  270  * the target is returned locked, otherwise it is returned unlocked.
  271  * When creating or renaming and LOCKPARENT is specified, the target may not
  272  * be ".".  When deleting and LOCKPARENT is specified, the target may be ".".
  273  *
  274  * Overall outline of lookup:
  275  *
  276  * dirloop:
  277  *      identify next component of name at ndp->ni_ptr
  278  *      handle degenerate case where name is null string
  279  *      if .. and crossing mount points and on mounted filesys, find parent
  280  *      call VOP_LOOKUP routine for next component name
  281  *          directory vnode returned in ni_dvp, unlocked unless LOCKPARENT set
  282  *          component vnode returned in ni_vp (if it exists), locked.
  283  *      if result vnode is mounted on and crossing mount points,
  284  *          find mounted on vnode
  285  *      if more components of name, do next level at dirloop
  286  *      return the answer in ni_vp, locked if LOCKLEAF set
  287  *          if LOCKPARENT set, return locked parent in ni_dvp
  288  *          if WANTPARENT set, return unlocked parent in ni_dvp
  289  */
  290 int
  291 lookup(struct nameidata *ndp)
  292 {
  293         char *cp;                       /* pointer into pathname argument */
  294         struct vnode *dp = 0;           /* the directory we are searching */
  295         struct vnode *tdp;              /* saved dp */
  296         struct mount *mp;               /* mount table entry */
  297         int docache;                    /* == 0 do not cache last component */
  298         int wantparent;                 /* 1 => wantparent or lockparent flag */
  299         int rdonly;                     /* lookup read-only flag bit */
  300         int error = 0;
  301         int dpunlocked = 0;             /* dp has already been unlocked */
  302         int slashes;
  303         struct componentname *cnp = &ndp->ni_cnd;
  304         struct proc *p = cnp->cn_proc;
  305         /*
  306          * Setup: break out flag bits into variables.
  307          */
  308         wantparent = cnp->cn_flags & (LOCKPARENT | WANTPARENT);
  309         docache = (cnp->cn_flags & NOCACHE) ^ NOCACHE;
  310         if (cnp->cn_nameiop == DELETE ||
  311             (wantparent && cnp->cn_nameiop != CREATE))
  312                 docache = 0;
  313         rdonly = cnp->cn_flags & RDONLY;
  314         ndp->ni_dvp = NULL;
  315         cnp->cn_flags &= ~ISSYMLINK;
  316         dp = ndp->ni_startdir;
  317         ndp->ni_startdir = NULLVP;
  318         vn_lock(dp, LK_EXCLUSIVE | LK_RETRY, p);
  319 
  320         /*
  321          * If we have a leading string of slashes, remove them, and just make
  322          * sure the current node is a directory.
  323          */
  324         cp = cnp->cn_nameptr;
  325         if (*cp == '/') {
  326                 do {
  327                         cp++;
  328                 } while (*cp == '/');
  329                 ndp->ni_pathlen -= cp - cnp->cn_nameptr;
  330                 cnp->cn_nameptr = cp;
  331 
  332                 if (dp->v_type != VDIR) {
  333                         error = ENOTDIR;
  334                         goto bad;
  335                 }
  336 
  337                 /*
  338                  * If we've exhausted the path name, then just return the
  339                  * current node.  If the caller requested the parent node (i.e.
  340                  * it's a CREATE, DELETE, or RENAME), and we don't have one
  341                  * (because this is the root directory), then we must fail.
  342                  */
  343                 if (cnp->cn_nameptr[0] == '\0') {
  344                         if (ndp->ni_dvp == NULL && wantparent) {
  345                                 error = EISDIR;
  346                                 goto bad;
  347                         }
  348                         ndp->ni_vp = dp;
  349                         cnp->cn_flags |= ISLASTCN;
  350                         goto terminal;
  351                 }
  352         }
  353 
  354 dirloop:
  355         /*
  356          * Search a new directory.
  357          *
  358          * The cn_hash value is for use by vfs_cache.
  359          * The last component of the filename is left accessible via
  360          * cnp->cn_nameptr for callers that need the name. Callers needing
  361          * the name set the SAVENAME flag. When done, they assume
  362          * responsibility for freeing the pathname buffer.
  363          */
  364         cp = NULL;
  365         cnp->cn_consume = 0;
  366         cnp->cn_hash = hash32_stre(cnp->cn_nameptr, '/', &cp, HASHINIT);
  367         cnp->cn_namelen = cp - cnp->cn_nameptr;
  368         if (cnp->cn_namelen > NAME_MAX) {
  369                 error = ENAMETOOLONG;
  370                 goto bad;
  371         }
  372 #ifdef NAMEI_DIAGNOSTIC
  373         { char c = *cp;
  374         *cp = '\0';
  375         printf("{%s}: ", cnp->cn_nameptr);
  376         *cp = c; }
  377 #endif
  378         ndp->ni_pathlen -= cnp->cn_namelen;
  379         ndp->ni_next = cp;
  380         /*
  381          * If this component is followed by a slash, then move the pointer to
  382          * the next component forward, and remember that this component must be
  383          * a directory.
  384          */
  385         if (*cp == '/') {
  386                 do {
  387                         cp++;
  388                 } while (*cp == '/');
  389                 slashes = cp - ndp->ni_next;
  390                 ndp->ni_pathlen -= slashes;
  391                 ndp->ni_next = cp;
  392                 cnp->cn_flags |= REQUIREDIR;
  393         } else {
  394                 slashes = 0;
  395                 cnp->cn_flags &= ~REQUIREDIR;
  396         }
  397         /*
  398          * We do special processing on the last component, whether or not it's
  399          * a directory.  Cache all intervening lookups, but not the final one.
  400          */
  401         if (*cp == '\0') {
  402                 if (docache)
  403                         cnp->cn_flags |= MAKEENTRY;
  404                 else
  405                         cnp->cn_flags &= ~MAKEENTRY;
  406                 cnp->cn_flags |= ISLASTCN;
  407         } else {
  408                 cnp->cn_flags |= MAKEENTRY;
  409                 cnp->cn_flags &= ~ISLASTCN;
  410         }
  411         if (cnp->cn_namelen == 2 &&
  412             cnp->cn_nameptr[1] == '.' && cnp->cn_nameptr[0] == '.')
  413                 cnp->cn_flags |= ISDOTDOT;
  414         else
  415                 cnp->cn_flags &= ~ISDOTDOT;
  416 
  417         /*
  418          * Handle "..": two special cases.
  419          * 1. If at root directory (e.g. after chroot)
  420          *    or at absolute root directory
  421          *    then ignore it so can't get out.
  422          * 2. If this vnode is the root of a mounted
  423          *    filesystem, then replace it with the
  424          *    vnode which was mounted on so we take the
  425          *    .. in the other file system.
  426          */
  427         if (cnp->cn_flags & ISDOTDOT) {
  428                 for (;;) {
  429                         if (dp == ndp->ni_rootdir || dp == rootvnode) {
  430                                 ndp->ni_dvp = dp;
  431                                 ndp->ni_vp = dp;
  432                                 VREF(dp);
  433                                 goto nextname;
  434                         }
  435                         if ((dp->v_flag & VROOT) == 0 ||
  436                             (cnp->cn_flags & NOCROSSMOUNT))
  437                                 break;
  438                         tdp = dp;
  439                         dp = dp->v_mount->mnt_vnodecovered;
  440                         vput(tdp);
  441                         VREF(dp);
  442                         vn_lock(dp, LK_EXCLUSIVE | LK_RETRY, p);
  443                 }
  444         }
  445 
  446         /*
  447          * We now have a segment name to search for, and a directory to search.
  448          */
  449         ndp->ni_dvp = dp;
  450         ndp->ni_vp = NULL;
  451         cnp->cn_flags &= ~PDIRUNLOCK;
  452 
  453         if ((error = VOP_LOOKUP(dp, &ndp->ni_vp, cnp)) != 0) {
  454 #ifdef DIAGNOSTIC
  455                 if (ndp->ni_vp != NULL)
  456                         panic("leaf should be empty");
  457 #endif
  458 #ifdef NAMEI_DIAGNOSTIC
  459                 printf("not found\n");
  460 #endif
  461                 if (error != EJUSTRETURN)
  462                         goto bad;
  463                 /*
  464                  * If this was not the last component, or there were trailing
  465                  * slashes, then the name must exist.
  466                  */
  467                 if (cnp->cn_flags & REQUIREDIR) {
  468                         error = ENOENT;
  469                         goto bad;
  470                 }
  471                 /*
  472                  * If creating and at end of pathname, then can consider
  473                  * allowing file to be created.
  474                  */
  475                 if (rdonly || (ndp->ni_dvp->v_mount->mnt_flag & MNT_RDONLY)) {
  476                         error = EROFS;
  477                         goto bad;
  478                 }
  479                 /*
  480                  * We return with ni_vp NULL to indicate that the entry
  481                  * doesn't currently exist, leaving a pointer to the
  482                  * (possibly locked) directory inode in ndp->ni_dvp.
  483                  */
  484                 if (cnp->cn_flags & SAVESTART) {
  485                         ndp->ni_startdir = ndp->ni_dvp;
  486                         VREF(ndp->ni_startdir);
  487                 }
  488                 return (0);
  489         }
  490 #ifdef NAMEI_DIAGNOSTIC
  491         printf("found\n");
  492 #endif
  493 
  494         /*
  495          * Take into account any additional components consumed by the
  496          * underlying filesystem.  This will include any trailing slashes after
  497          * the last component consumed.
  498          */
  499         if (cnp->cn_consume > 0) {
  500                 if (cnp->cn_consume >= slashes) {
  501                         cnp->cn_flags &= ~REQUIREDIR;
  502                 }
  503 
  504                 ndp->ni_pathlen -= cnp->cn_consume - slashes;
  505                 ndp->ni_next += cnp->cn_consume - slashes;
  506                 cnp->cn_consume = 0;
  507                 if (ndp->ni_next[0] == '\0')
  508                         cnp->cn_flags |= ISLASTCN;
  509         }
  510 
  511         dp = ndp->ni_vp;
  512         /*
  513          * Check to see if the vnode has been mounted on;
  514          * if so find the root of the mounted file system.
  515          */
  516         while (dp->v_type == VDIR && (mp = dp->v_mountedhere) &&
  517             (cnp->cn_flags & NOCROSSMOUNT) == 0) {
  518                 if (vfs_busy(mp, VB_READ|VB_WAIT))
  519                         continue;
  520                 VOP_UNLOCK(dp, 0, p);
  521                 error = VFS_ROOT(mp, &tdp);
  522                 vfs_unbusy(mp);
  523                 if (error) {
  524                         dpunlocked = 1;
  525                         goto bad2;
  526                 }
  527                 vrele(dp);
  528                 ndp->ni_vp = dp = tdp;
  529         }
  530 
  531         /*
  532          * Check for symbolic link.  Back up over any slashes that we skipped,
  533          * as we will need them again.
  534          */
  535         if ((dp->v_type == VLNK) && (cnp->cn_flags & (FOLLOW|REQUIREDIR))) {
  536                 ndp->ni_pathlen += slashes;
  537                 ndp->ni_next -= slashes;
  538                 cnp->cn_flags |= ISSYMLINK;
  539                 return (0);
  540         }
  541 
  542         /*
  543          * Check for directory, if the component was followed by a series of
  544          * slashes.
  545          */
  546         if ((dp->v_type != VDIR) && (cnp->cn_flags & REQUIREDIR)) {
  547                 error = ENOTDIR;
  548                 goto bad2;
  549         }
  550 
  551 nextname:
  552         /*
  553          * Not a symbolic link.  If this was not the last component, then
  554          * continue at the next component, else return.
  555          */
  556         if (!(cnp->cn_flags & ISLASTCN)) {
  557                 cnp->cn_nameptr = ndp->ni_next;
  558                 vrele(ndp->ni_dvp);
  559                 goto dirloop;
  560         }
  561 
  562 terminal:
  563         /*
  564          * Check for read-only file systems.
  565          */
  566         if (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME) {
  567                 /*
  568                  * Disallow directory write attempts on read-only
  569                  * file systems.
  570                  */
  571                 if (rdonly || (dp->v_mount->mnt_flag & MNT_RDONLY) ||
  572                     (wantparent &&
  573                     (ndp->ni_dvp->v_mount->mnt_flag & MNT_RDONLY))) {
  574                         error = EROFS;
  575                         goto bad2;
  576                 }
  577         }
  578         if (ndp->ni_dvp != NULL) {
  579                 if (cnp->cn_flags & SAVESTART) {
  580                         ndp->ni_startdir = ndp->ni_dvp;
  581                         VREF(ndp->ni_startdir);
  582                 }
  583                 if (!wantparent)
  584                         vrele(ndp->ni_dvp);
  585         }
  586         if ((cnp->cn_flags & LOCKLEAF) == 0)
  587                 VOP_UNLOCK(dp, 0, p);
  588         return (0);
  589 
  590 bad2:
  591         if ((cnp->cn_flags & LOCKPARENT) && (cnp->cn_flags & ISLASTCN) &&
  592             ((cnp->cn_flags & PDIRUNLOCK) == 0))
  593                 VOP_UNLOCK(ndp->ni_dvp, 0, p);
  594         vrele(ndp->ni_dvp);
  595 bad:
  596         if (dpunlocked)
  597                 vrele(dp);
  598         else
  599                 vput(dp);
  600         ndp->ni_vp = NULL;
  601         return (error);
  602 }
  603 
  604 /*
  605  * Reacquire a path name component.
  606  */
  607 int
  608 relookup(struct vnode *dvp, struct vnode **vpp, struct componentname *cnp)
  609 {
  610         struct proc *p = cnp->cn_proc;
  611         struct vnode *dp = 0;           /* the directory we are searching */
  612         int wantparent;                 /* 1 => wantparent or lockparent flag */
  613         int rdonly;                     /* lookup read-only flag bit */
  614         int error = 0;
  615 #ifdef NAMEI_DIAGNOSTIC
  616         u_int32_t newhash;              /* DEBUG: check name hash */
  617         char *cp;                       /* DEBUG: check name ptr/len */
  618 #endif
  619 
  620         /*
  621          * Setup: break out flag bits into variables.
  622          */
  623         wantparent = cnp->cn_flags & (LOCKPARENT|WANTPARENT);
  624         rdonly = cnp->cn_flags & RDONLY;
  625         cnp->cn_flags &= ~ISSYMLINK;
  626         dp = dvp;
  627         vn_lock(dp, LK_EXCLUSIVE | LK_RETRY, p);
  628 
  629 /* dirloop: */
  630         /*
  631          * Search a new directory.
  632          *
  633          * The cn_hash value is for use by vfs_cache.
  634          * The last component of the filename is left accessible via
  635          * cnp->cn_nameptr for callers that need the name. Callers needing
  636          * the name set the SAVENAME flag. When done, they assume
  637          * responsibility for freeing the pathname buffer.
  638          */
  639 #ifdef NAMEI_DIAGNOSTIC
  640         cp = NULL;
  641         newhash = hash32_stre(cnp->cn_nameptr, '/', &cp, HASHINIT);
  642         if (newhash != cnp->cn_hash)
  643                 panic("relookup: bad hash");
  644         if (cnp->cn_namelen != cp - cnp->cn_nameptr)
  645                 panic ("relookup: bad len");
  646         if (*cp != 0)
  647                 panic("relookup: not last component");
  648         printf("{%s}: ", cnp->cn_nameptr);
  649 #endif
  650 
  651         /*
  652          * Check for degenerate name (e.g. / or "")
  653          * which is a way of talking about a directory,
  654          * e.g. like "/." or ".".
  655          */
  656         if (cnp->cn_nameptr[0] == '\0')
  657                 panic("relookup: null name");
  658 
  659         if (cnp->cn_flags & ISDOTDOT)
  660                 panic ("relookup: lookup on dot-dot");
  661 
  662         /*
  663          * We now have a segment name to search for, and a directory to search.
  664          */
  665         if ((error = VOP_LOOKUP(dp, vpp, cnp)) != 0) {
  666 #ifdef DIAGNOSTIC
  667                 if (*vpp != NULL)
  668                         panic("leaf should be empty");
  669 #endif
  670                 if (error != EJUSTRETURN)
  671                         goto bad;
  672                 /*
  673                  * If creating and at end of pathname, then can consider
  674                  * allowing file to be created.
  675                  */
  676                 if (rdonly || (dvp->v_mount->mnt_flag & MNT_RDONLY)) {
  677                         error = EROFS;
  678                         goto bad;
  679                 }
  680                 /* ASSERT(dvp == ndp->ni_startdir) */
  681                 if (cnp->cn_flags & SAVESTART)
  682                         VREF(dvp);
  683                 /*
  684                  * We return with ni_vp NULL to indicate that the entry
  685                  * doesn't currently exist, leaving a pointer to the
  686                  * (possibly locked) directory inode in ndp->ni_dvp.
  687                  */
  688                 return (0);
  689         }
  690         dp = *vpp;
  691 
  692 #ifdef DIAGNOSTIC
  693         /*
  694          * Check for symbolic link
  695          */
  696         if (dp->v_type == VLNK && (cnp->cn_flags & FOLLOW))
  697                 panic ("relookup: symlink found.");
  698 #endif
  699 
  700         /*
  701          * Check for read-only file systems.
  702          */
  703         if (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME) {
  704                 /*
  705                  * Disallow directory write attempts on read-only
  706                  * file systems.
  707                  */
  708                 if (rdonly || (dp->v_mount->mnt_flag & MNT_RDONLY) ||
  709                     (wantparent &&
  710                     (dvp->v_mount->mnt_flag & MNT_RDONLY))) {
  711                         error = EROFS;
  712                         goto bad2;
  713                 }
  714         }
  715         /* ASSERT(dvp == ndp->ni_startdir) */
  716         if (cnp->cn_flags & SAVESTART)
  717                 VREF(dvp);
  718         if (!wantparent)
  719                 vrele(dvp);
  720         if ((cnp->cn_flags & LOCKLEAF) == 0)
  721                 VOP_UNLOCK(dp, 0, p);
  722         return (0);
  723 
  724 bad2:
  725         if ((cnp->cn_flags & LOCKPARENT) && (cnp->cn_flags & ISLASTCN))
  726                 VOP_UNLOCK(dvp, 0, p);
  727         vrele(dvp);
  728 bad:
  729         vput(dp);
  730         *vpp = NULL;
  731         return (error);
  732 }

/* [<][>][^][v][top][bottom][index][help] */