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