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

Cache object: f5061216793e277c8aefdd7a24c02979


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