|
|
1.1 ! root 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: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.