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