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