home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / bsd_srcs / sys / kern / vfs_lookup.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-06-29  |  12.9 KB  |  457 lines

  1. /*
  2.  * Copyright (c) 1982, 1986, 1989 Regents of the University of California.
  3.  * All rights reserved.
  4.  *
  5.  * Redistribution and use in source and binary forms, with or without
  6.  * modification, are permitted provided that the following conditions
  7.  * are met:
  8.  * 1. Redistributions of source code must retain the above copyright
  9.  *    notice, this list of conditions and the following disclaimer.
  10.  * 2. Redistributions in binary form must reproduce the above copyright
  11.  *    notice, this list of conditions and the following disclaimer in the
  12.  *    documentation and/or other materials provided with the distribution.
  13.  * 3. All advertising materials mentioning features or use of this software
  14.  *    must display the following acknowledgement:
  15.  *    This product includes software developed by the University of
  16.  *    California, Berkeley and its contributors.
  17.  * 4. Neither the name of the University nor the names of its contributors
  18.  *    may be used to endorse or promote products derived from this software
  19.  *    without specific prior written permission.
  20.  *
  21.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  22.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  23.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  24.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  25.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  26.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  27.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  28.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  29.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  30.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  31.  * SUCH DAMAGE.
  32.  *
  33.  *    @(#)vfs_lookup.c    7.32 (Berkeley) 5/21/91
  34.  */
  35.  
  36. #include "param.h"
  37. #include "syslimits.h"
  38. #include "time.h"
  39. #include "namei.h"
  40. #include "vnode.h"
  41. #include "mount.h"
  42. #include "errno.h"
  43. #include "malloc.h"
  44. #include "filedesc.h"
  45. #include "proc.h"
  46.  
  47. #ifdef KTRACE
  48. #include "ktrace.h"
  49. #endif
  50.  
  51. /*
  52.  * Convert a pathname into a pointer to a locked inode.
  53.  *
  54.  * The FOLLOW flag is set when symbolic links are to be followed
  55.  * when they occur at the end of the name translation process.
  56.  * Symbolic links are always followed for all other pathname
  57.  * components other than the last.
  58.  *
  59.  * The segflg defines whether the name is to be copied from user
  60.  * space or kernel space.
  61.  *
  62.  * Overall outline of namei:
  63.  *
  64.  *    copy in name
  65.  *    get starting directory
  66.  *    while (!done && !error) {
  67.  *        call lookup to search path.
  68.  *        if symbolic link, massage name in buffer and continue
  69.  *    }
  70.  */
  71. namei(ndp, p)
  72.     register struct nameidata *ndp;
  73.     struct proc *p;
  74. {
  75.     register struct filedesc *fdp;    /* pointer to file descriptor state */
  76.     register char *cp;        /* pointer into pathname argument */
  77.     register struct vnode *dp;    /* the directory we are searching */
  78.     struct iovec aiov;        /* uio for reading symbolic links */
  79.     struct uio auio;
  80.     int error, linklen;
  81.  
  82.     ndp->ni_cred = p->p_ucred;
  83.     fdp = p->p_fd;
  84.  
  85.     /*
  86.      * Get a buffer for the name to be translated, and copy the
  87.      * name into the buffer.
  88.      */
  89.     if ((ndp->ni_nameiop & HASBUF) == 0)
  90.         MALLOC(ndp->ni_pnbuf, caddr_t, MAXPATHLEN, M_NAMEI, M_WAITOK);
  91.     if (ndp->ni_segflg == UIO_SYSSPACE)
  92.         error = copystr(ndp->ni_dirp, ndp->ni_pnbuf,
  93.                 MAXPATHLEN, &ndp->ni_pathlen);
  94.     else
  95.         error = copyinstr(ndp->ni_dirp, ndp->ni_pnbuf,
  96.                 MAXPATHLEN, &ndp->ni_pathlen);
  97.     if (error) {
  98.         free(ndp->ni_pnbuf, M_NAMEI);
  99.         ndp->ni_vp = NULL;
  100.         return (error);
  101.     }
  102.     ndp->ni_loopcnt = 0;
  103. #ifdef KTRACE
  104.     if (KTRPOINT(p, KTR_NAMEI))
  105.         ktrnamei(p->p_tracep, ndp->ni_pnbuf);
  106. #endif
  107.  
  108.     /*
  109.      * Get starting point for the translation.
  110.      */
  111.     if ((ndp->ni_rootdir = fdp->fd_rdir) == NULL)
  112.         ndp->ni_rootdir = rootdir;
  113.     dp = fdp->fd_cdir;
  114.     VREF(dp);
  115.     for (;;) {
  116.         /*
  117.          * Check if root directory should replace current directory.
  118.          * Done at start of translation and after symbolic link.
  119.          */
  120.         ndp->ni_ptr = ndp->ni_pnbuf;
  121.         if (*ndp->ni_ptr == '/') {
  122.             vrele(dp);
  123.             while (*ndp->ni_ptr == '/') {
  124.                 ndp->ni_ptr++;
  125.                 ndp->ni_pathlen--;
  126.             }
  127.             dp = ndp->ni_rootdir;
  128.             VREF(dp);
  129.         }
  130.         ndp->ni_startdir = dp;
  131.         if (error = lookup(ndp, p)) {
  132.             FREE(ndp->ni_pnbuf, M_NAMEI);
  133.             return (error);
  134.         }
  135.         /*
  136.          * Check for symbolic link
  137.          */
  138.         if (ndp->ni_more == 0) {
  139.             if ((ndp->ni_nameiop & (SAVENAME | SAVESTART)) == 0)
  140.                 FREE(ndp->ni_pnbuf, M_NAMEI);
  141.             else
  142.                 ndp->ni_nameiop |= HASBUF;
  143.             return (0);
  144.         }
  145.         if ((ndp->ni_nameiop & LOCKPARENT) && ndp->ni_pathlen == 1)
  146.             VOP_UNLOCK(ndp->ni_dvp);
  147.         if (ndp->ni_loopcnt++ >= MAXSYMLINKS) {
  148.             error = ELOOP;
  149.             break;
  150.         }
  151.         if (ndp->ni_pathlen > 1)
  152.             MALLOC(cp, char *, MAXPATHLEN, M_NAMEI, M_WAITOK);
  153.         else
  154.             cp = ndp->ni_pnbuf;
  155.         aiov.iov_base = cp;
  156.         aiov.iov_len = MAXPATHLEN;
  157.         auio.uio_iov = &aiov;
  158.         auio.uio_iovcnt = 1;
  159.         auio.uio_offset = 0;
  160.         auio.uio_rw = UIO_READ;
  161.         auio.uio_segflg = UIO_SYSSPACE;
  162.         auio.uio_procp = (struct proc *)0;
  163.         auio.uio_resid = MAXPATHLEN;
  164.         if (error = VOP_READLINK(ndp->ni_vp, &auio, p->p_ucred)) {
  165.             if (ndp->ni_pathlen > 1)
  166.                 free(cp, M_NAMEI);
  167.             break;
  168.         }
  169.         linklen = MAXPATHLEN - auio.uio_resid;
  170.         if (linklen + ndp->ni_pathlen >= MAXPATHLEN) {
  171.             if (ndp->ni_pathlen > 1)
  172.                 free(cp, M_NAMEI);
  173.             error = ENAMETOOLONG;
  174.             break;
  175.         }
  176.         if (ndp->ni_pathlen > 1) {
  177.             bcopy(ndp->ni_next, cp + linklen, ndp->ni_pathlen);
  178.             FREE(ndp->ni_pnbuf, M_NAMEI);
  179.             ndp->ni_pnbuf = cp;
  180.         } else
  181.             ndp->ni_pnbuf[linklen] = '\0';
  182.         ndp->ni_pathlen += linklen;
  183.         vput(ndp->ni_vp);
  184.         dp = ndp->ni_dvp;
  185.     }
  186.     FREE(ndp->ni_pnbuf, M_NAMEI);
  187.     vrele(ndp->ni_dvp);
  188.     vput(ndp->ni_vp);
  189.     ndp->ni_vp = NULL;
  190.     return (error);
  191. }
  192.  
  193. /*
  194.  * Search a pathname.
  195.  * This is a very central and rather complicated routine.
  196.  *
  197.  * The pathname is pointed to by ni_ptr and is of length ni_pathlen.
  198.  * The starting directory is taken from ni_startdir. The pathname is
  199.  * descended until done, or a symbolic link is encountered. The variable
  200.  * ni_more is clear if the path is completed; it is set to one if a
  201.  * symbolic link needing interpretation is encountered.
  202.  *
  203.  * The flag argument is LOOKUP, CREATE, RENAME, or DELETE depending on
  204.  * whether the name is to be looked up, created, renamed, or deleted.
  205.  * When CREATE, RENAME, or DELETE is specified, information usable in
  206.  * creating, renaming, or deleting a directory entry may be calculated.
  207.  * If flag has LOCKPARENT or'ed into it, the parent directory is returned
  208.  * locked. If flag has WANTPARENT or'ed into it, the parent directory is
  209.  * returned unlocked. Otherwise the parent directory is not returned. If
  210.  * the target of the pathname exists and LOCKLEAF is or'ed into the flag
  211.  * the target is returned locked, otherwise it is returned unlocked.
  212.  * When creating or renaming and LOCKPARENT is specified, the target may not
  213.  * be ".".  When deleting and LOCKPARENT is specified, the target may be ".".
  214.  * NOTE: (LOOKUP | LOCKPARENT) currently returns the parent vnode unlocked.
  215.  * 
  216.  * Overall outline of lookup:
  217.  *
  218.  * dirloop:
  219.  *    identify next component of name at ndp->ni_ptr
  220.  *    handle degenerate case where name is null string
  221.  *    if .. and crossing mount points and on mounted filesys, find parent
  222.  *    call VOP_LOOKUP routine for next component name
  223.  *        directory vnode returned in ni_dvp, unlocked unless LOCKPARENT set
  224.  *        component vnode returned in ni_vp (if it exists), locked.
  225.  *    if result vnode is mounted on and crossing mount points,
  226.  *        find mounted on vnode
  227.  *    if more components of name, do next level at dirloop
  228.  *    return the answer in ni_vp, locked if LOCKLEAF set
  229.  *        if LOCKPARENT set, return locked parent in ni_dvp
  230.  *        if WANTPARENT set, return unlocked parent in ni_dvp
  231.  */
  232. lookup(ndp, p)
  233.     register struct nameidata *ndp;
  234.     struct proc *p;
  235. {
  236.     register char *cp;        /* pointer into pathname argument */
  237.     register struct vnode *dp = 0;    /* the directory we are searching */
  238.     struct vnode *tdp;        /* saved dp */
  239.     struct mount *mp;        /* mount table entry */
  240.     int docache;            /* == 0 do not cache last component */
  241.     int flag;            /* LOOKUP, CREATE, RENAME or DELETE */
  242.     int wantparent;            /* 1 => wantparent or lockparent flag */
  243.     int rdonly;            /* mounted read-only flag bit(s) */
  244.     int error = 0;
  245.  
  246.     /*
  247.      * Setup: break out flag bits into variables.
  248.      */
  249.     flag = ndp->ni_nameiop & OPMASK;
  250.     wantparent = ndp->ni_nameiop & (LOCKPARENT|WANTPARENT);
  251.     docache = (ndp->ni_nameiop & NOCACHE) ^ NOCACHE;
  252.     if (flag == DELETE || (wantparent && flag != CREATE))
  253.         docache = 0;
  254.     rdonly = MNT_RDONLY;
  255.     if (ndp->ni_nameiop & REMOTE)
  256.         rdonly |= MNT_EXRDONLY;
  257.     ndp->ni_dvp = NULL;
  258.     ndp->ni_more = 0;
  259.     dp = ndp->ni_startdir;
  260.     ndp->ni_startdir = NULLVP;
  261.     VOP_LOCK(dp);
  262.  
  263. dirloop:
  264.     /*
  265.      * Search a new directory.
  266.      *
  267.      * The ni_hash value is for use by vfs_cache.
  268.      * The last component of the filename is left accessible via
  269.      * ndp->ptr for callers that need the name. Callers needing
  270.      * the name set the SAVENAME flag. When done, they assume
  271.      * responsibility for freeing the pathname buffer.
  272.      */
  273.     ndp->ni_hash = 0;
  274.     for (cp = ndp->ni_ptr; *cp != 0 && *cp != '/'; cp++)
  275.         ndp->ni_hash += (unsigned char)*cp;
  276.     ndp->ni_namelen = cp - ndp->ni_ptr;
  277.     if (ndp->ni_namelen >= NAME_MAX) {
  278.         error = ENAMETOOLONG;
  279.         goto bad;
  280.     }
  281. #ifdef NAMEI_DIAGNOSTIC
  282.     { char c = *cp;
  283.     *cp = '\0';
  284.     printf("{%s}: ", ndp->ni_ptr);
  285.     *cp = c; }
  286. #endif
  287.     ndp->ni_pathlen -= ndp->ni_namelen;
  288.     ndp->ni_next = cp;
  289.     ndp->ni_makeentry = 1;
  290.     if (*cp == '\0' && docache == 0)
  291.         ndp->ni_makeentry = 0;
  292.     ndp->ni_isdotdot = (ndp->ni_namelen == 2 &&
  293.         ndp->ni_ptr[1] == '.' && ndp->ni_ptr[0] == '.');
  294.  
  295.     /*
  296.      * Check for degenerate name (e.g. / or "")
  297.      * which is a way of talking about a directory,
  298.      * e.g. like "/." or ".".
  299.      */
  300.     if (ndp->ni_ptr[0] == '\0') {
  301.         if (flag != LOOKUP || wantparent) {
  302.             error = EISDIR;
  303.             goto bad;
  304.         }
  305.         if (dp->v_type != VDIR) {
  306.             error = ENOTDIR;
  307.             goto bad;
  308.         }
  309.         if (!(ndp->ni_nameiop & LOCKLEAF))
  310.             VOP_UNLOCK(dp);
  311.         ndp->ni_vp = dp;
  312.         if (ndp->ni_nameiop & SAVESTART)
  313.             panic("lookup: SAVESTART");
  314.         return (0);
  315.     }
  316.  
  317.     /*
  318.      * Handle "..": two special cases.
  319.      * 1. If at root directory (e.g. after chroot)
  320.      *    then ignore it so can't get out.
  321.      * 2. If this vnode is the root of a mounted
  322.      *    filesystem, then replace it with the
  323.      *    vnode which was mounted on so we take the
  324.      *    .. in the other file system.
  325.      */
  326.     if (ndp->ni_isdotdot) {
  327.         for (;;) {
  328.             if (dp == ndp->ni_rootdir) {
  329.                 ndp->ni_dvp = dp;
  330.                 ndp->ni_vp = dp;
  331.                 VREF(dp);
  332.                 goto nextname;
  333.             }
  334.             if ((dp->v_flag & VROOT) == 0 ||
  335.                 (ndp->ni_nameiop & NOCROSSMOUNT))
  336.                 break;
  337.             tdp = dp;
  338.             dp = dp->v_mount->mnt_vnodecovered;
  339.             vput(tdp);
  340.             VREF(dp);
  341.             VOP_LOCK(dp);
  342.         }
  343.     }
  344.  
  345.     /*
  346.      * We now have a segment name to search for, and a directory to search.
  347.      */
  348.     if (error = VOP_LOOKUP(dp, ndp, p)) {
  349. #ifdef DIAGNOSTIC
  350.         if (ndp->ni_vp != NULL)
  351.             panic("leaf should be empty");
  352. #endif
  353. #ifdef NAMEI_DIAGNOSTIC
  354.         printf("not found\n");
  355. #endif
  356.         if (flag == LOOKUP || flag == DELETE ||
  357.             error != ENOENT || *cp != 0)
  358.             goto bad;
  359.         /*
  360.          * If creating and at end of pathname, then can consider
  361.          * allowing file to be created.
  362.          */
  363.         if (ndp->ni_dvp->v_mount->mnt_flag & rdonly) {
  364.             error = EROFS;
  365.             goto bad;
  366.         }
  367.         /*
  368.          * We return with ni_vp NULL to indicate that the entry
  369.          * doesn't currently exist, leaving a pointer to the
  370.          * (possibly locked) directory inode in ndp->ni_dvp.
  371.          */
  372.         if (ndp->ni_nameiop & SAVESTART) {
  373.             ndp->ni_startdir = ndp->ni_dvp;
  374.             VREF(ndp->ni_startdir);
  375.         }
  376.         return (0);
  377.     }
  378. #ifdef NAMEI_DIAGNOSTIC
  379.     printf("found\n");
  380. #endif
  381.  
  382.     dp = ndp->ni_vp;
  383.     /*
  384.      * Check for symbolic link
  385.      */
  386.     if ((dp->v_type == VLNK) &&
  387.         ((ndp->ni_nameiop & FOLLOW) || *ndp->ni_next == '/')) {
  388.         ndp->ni_more = 1;
  389.         return (0);
  390.     }
  391.  
  392.     /*
  393.      * Check to see if the vnode has been mounted on;
  394.      * if so find the root of the mounted file system.
  395.      */
  396. mntloop:
  397.     while (dp->v_type == VDIR && (mp = dp->v_mountedhere) &&
  398.            (ndp->ni_nameiop & NOCROSSMOUNT) == 0) {
  399.         while(mp->mnt_flag & MNT_MLOCK) {
  400.             mp->mnt_flag |= MNT_MWAIT;
  401.             sleep((caddr_t)mp, PVFS);
  402.             goto mntloop;
  403.         }
  404.         if (error = VFS_ROOT(dp->v_mountedhere, &tdp))
  405.             goto bad2;
  406.         vput(dp);
  407.         ndp->ni_vp = dp = tdp;
  408.     }
  409.  
  410. nextname:
  411.     /*
  412.      * Not a symbolic link.  If more pathname,
  413.      * continue at next component, else return.
  414.      */
  415.     if (*ndp->ni_next == '/') {
  416.         ndp->ni_ptr = ndp->ni_next;
  417.         while (*ndp->ni_ptr == '/') {
  418.             ndp->ni_ptr++;
  419.             ndp->ni_pathlen--;
  420.         }
  421.         vrele(ndp->ni_dvp);
  422.         goto dirloop;
  423.     }
  424.     /*
  425.      * Check for read-only file systems.
  426.      */
  427.     if (flag == DELETE || flag == RENAME) {
  428.         /*
  429.          * Disallow directory write attempts on read-only
  430.          * file systems.
  431.          */
  432.         if ((dp->v_mount->mnt_flag & rdonly) ||
  433.             (wantparent && (ndp->ni_dvp->v_mount->mnt_flag & rdonly))) {
  434.             error = EROFS;
  435.             goto bad2;
  436.         }
  437.     }
  438.     if (ndp->ni_nameiop & SAVESTART) {
  439.         ndp->ni_startdir = ndp->ni_dvp;
  440.         VREF(ndp->ni_startdir);
  441.     }
  442.     if (!wantparent)
  443.         vrele(ndp->ni_dvp);
  444.     if ((ndp->ni_nameiop & LOCKLEAF) == 0)
  445.         VOP_UNLOCK(dp);
  446.     return (0);
  447.  
  448. bad2:
  449.     if ((ndp->ni_nameiop & LOCKPARENT) && *ndp->ni_next == '\0')
  450.         VOP_UNLOCK(ndp->ni_dvp);
  451.     vrele(ndp->ni_dvp);
  452. bad:
  453.     vput(dp);
  454.     ndp->ni_vp = NULL;
  455.     return (error);
  456. }
  457.