Annotation of sys/kern/vfs_lookup.c, Revision 1.1.1.1
1.1 nbrk 1: /* $OpenBSD: vfs_lookup.c,v 1.36 2007/08/07 07:41:59 thib Exp $ */
2: /* $NetBSD: vfs_lookup.c,v 1.17 1996/02/09 19:00:59 christos Exp $ */
3:
4: /*
5: * Copyright (c) 1982, 1986, 1989, 1993
6: * The Regents of the University of California. All rights reserved.
7: * (c) UNIX System Laboratories, Inc.
8: * All or some portions of this file are derived from material licensed
9: * to the University of California by American Telephone and Telegraph
10: * Co. or Unix System Laboratories, Inc. and are reproduced herein with
11: * the permission of UNIX System Laboratories, Inc.
12: *
13: * Redistribution and use in source and binary forms, with or without
14: * modification, are permitted provided that the following conditions
15: * are met:
16: * 1. Redistributions of source code must retain the above copyright
17: * notice, this list of conditions and the following disclaimer.
18: * 2. Redistributions in binary form must reproduce the above copyright
19: * notice, this list of conditions and the following disclaimer in the
20: * documentation and/or other materials provided with the distribution.
21: * 3. Neither the name of the University nor the names of its contributors
22: * may be used to endorse or promote products derived from this software
23: * without specific prior written permission.
24: *
25: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
26: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
29: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
31: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
34: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35: * SUCH DAMAGE.
36: *
37: * @(#)vfs_lookup.c 8.6 (Berkeley) 11/21/94
38: */
39:
40: #include <sys/param.h>
41: #include <sys/systm.h>
42: #include <sys/syslimits.h>
43: #include <sys/time.h>
44: #include <sys/namei.h>
45: #include <sys/vnode.h>
46: #include <sys/mount.h>
47: #include <sys/errno.h>
48: #include <sys/malloc.h>
49: #include <sys/pool.h>
50: #include <sys/filedesc.h>
51: #include <sys/proc.h>
52: #include <sys/hash.h>
53:
54: #ifdef KTRACE
55: #include <sys/ktrace.h>
56: #endif
57:
58: #include <dev/systrace.h>
59: #include "systrace.h"
60:
61: /*
62: * Convert a pathname into a pointer to a vnode.
63: *
64: * The FOLLOW flag is set when symbolic links are to be followed
65: * when they occur at the end of the name translation process.
66: * Symbolic links are always followed for all other pathname
67: * components other than the last.
68: *
69: * If the LOCKLEAF flag is set, a locked vnode is returned.
70: *
71: * The segflg defines whether the name is to be copied from user
72: * space or kernel space.
73: *
74: * Overall outline of namei:
75: *
76: * copy in name
77: * get starting directory
78: * while (!done && !error) {
79: * call lookup to search path.
80: * if symbolic link, massage name in buffer and continue
81: * }
82: */
83: int
84: namei(struct nameidata *ndp)
85: {
86: struct filedesc *fdp; /* pointer to file descriptor state */
87: char *cp; /* pointer into pathname argument */
88: struct vnode *dp; /* the directory we are searching */
89: struct iovec aiov; /* uio for reading symbolic links */
90: struct uio auio;
91: int error, linklen;
92: struct componentname *cnp = &ndp->ni_cnd;
93: struct proc *p = cnp->cn_proc;
94:
95: ndp->ni_cnd.cn_cred = ndp->ni_cnd.cn_proc->p_ucred;
96: #ifdef DIAGNOSTIC
97: if (!cnp->cn_cred || !cnp->cn_proc)
98: panic ("namei: bad cred/proc");
99: if (cnp->cn_nameiop & (~OPMASK))
100: panic ("namei: nameiop contaminated with flags");
101: if (cnp->cn_flags & OPMASK)
102: panic ("namei: flags contaminated with nameiops");
103: #endif
104: fdp = cnp->cn_proc->p_fd;
105:
106: /*
107: * Get a buffer for the name to be translated, and copy the
108: * name into the buffer.
109: */
110: if ((cnp->cn_flags & HASBUF) == 0)
111: cnp->cn_pnbuf = pool_get(&namei_pool, PR_WAITOK);
112: if (ndp->ni_segflg == UIO_SYSSPACE)
113: error = copystr(ndp->ni_dirp, cnp->cn_pnbuf,
114: MAXPATHLEN, &ndp->ni_pathlen);
115: else
116: error = copyinstr(ndp->ni_dirp, cnp->cn_pnbuf,
117: MAXPATHLEN, &ndp->ni_pathlen);
118:
119: /*
120: * Fail on null pathnames
121: */
122: if (error == 0 && ndp->ni_pathlen == 1)
123: error = ENOENT;
124:
125: if (error) {
126: pool_put(&namei_pool, cnp->cn_pnbuf);
127: ndp->ni_vp = NULL;
128: return (error);
129: }
130:
131: #ifdef KTRACE
132: if (KTRPOINT(cnp->cn_proc, KTR_NAMEI))
133: ktrnamei(cnp->cn_proc, cnp->cn_pnbuf);
134: #endif
135: #if NSYSTRACE > 0
136: if (ISSET(cnp->cn_proc->p_flag, P_SYSTRACE))
137: systrace_namei(ndp);
138: #endif
139:
140: /*
141: * Strip trailing slashes, as requested
142: */
143: if (cnp->cn_flags & STRIPSLASHES) {
144: char *end = cnp->cn_pnbuf + ndp->ni_pathlen - 2;
145:
146: cp = end;
147: while (cp >= cnp->cn_pnbuf && (*cp == '/'))
148: cp--;
149:
150: /* Still some remaining characters in the buffer */
151: if (cp >= cnp->cn_pnbuf) {
152: ndp->ni_pathlen -= (end - cp);
153: *(cp + 1) = '\0';
154: }
155: }
156:
157: ndp->ni_loopcnt = 0;
158:
159: /*
160: * Get starting point for the translation.
161: */
162: if ((ndp->ni_rootdir = fdp->fd_rdir) == NULL)
163: ndp->ni_rootdir = rootvnode;
164: /*
165: * Check if starting from root directory or current directory.
166: */
167: if (cnp->cn_pnbuf[0] == '/') {
168: dp = ndp->ni_rootdir;
169: VREF(dp);
170: } else {
171: dp = fdp->fd_cdir;
172: VREF(dp);
173: }
174: for (;;) {
175: if (!dp->v_mount) {
176: /* Give up if the directory is no longer mounted */
177: pool_put(&namei_pool, cnp->cn_pnbuf);
178: return (ENOENT);
179: }
180: cnp->cn_nameptr = cnp->cn_pnbuf;
181: ndp->ni_startdir = dp;
182: if ((error = lookup(ndp)) != 0) {
183: pool_put(&namei_pool, cnp->cn_pnbuf);
184: return (error);
185: }
186: /*
187: * Check for symbolic link
188: */
189: if ((cnp->cn_flags & ISSYMLINK) == 0) {
190: if ((cnp->cn_flags & (SAVENAME | SAVESTART)) == 0)
191: pool_put(&namei_pool, cnp->cn_pnbuf);
192: else
193: cnp->cn_flags |= HASBUF;
194: return (0);
195: }
196: if ((cnp->cn_flags & LOCKPARENT) && (cnp->cn_flags & ISLASTCN))
197: VOP_UNLOCK(ndp->ni_dvp, 0, p);
198: if (ndp->ni_loopcnt++ >= MAXSYMLINKS) {
199: error = ELOOP;
200: break;
201: }
202: if (ndp->ni_pathlen > 1)
203: cp = pool_get(&namei_pool, PR_WAITOK);
204: else
205: cp = cnp->cn_pnbuf;
206: aiov.iov_base = cp;
207: aiov.iov_len = MAXPATHLEN;
208: auio.uio_iov = &aiov;
209: auio.uio_iovcnt = 1;
210: auio.uio_offset = 0;
211: auio.uio_rw = UIO_READ;
212: auio.uio_segflg = UIO_SYSSPACE;
213: auio.uio_procp = cnp->cn_proc;
214: auio.uio_resid = MAXPATHLEN;
215: error = VOP_READLINK(ndp->ni_vp, &auio, cnp->cn_cred);
216: if (error) {
217: badlink:
218: if (ndp->ni_pathlen > 1)
219: pool_put(&namei_pool, cp);
220: break;
221: }
222: linklen = MAXPATHLEN - auio.uio_resid;
223: if (linklen + ndp->ni_pathlen >= MAXPATHLEN) {
224: error = ENAMETOOLONG;
225: goto badlink;
226: }
227: if (ndp->ni_pathlen > 1) {
228: bcopy(ndp->ni_next, cp + linklen, ndp->ni_pathlen);
229: pool_put(&namei_pool, cnp->cn_pnbuf);
230: cnp->cn_pnbuf = cp;
231: } else
232: cnp->cn_pnbuf[linklen] = '\0';
233: ndp->ni_pathlen += linklen;
234: vput(ndp->ni_vp);
235: dp = ndp->ni_dvp;
236: /*
237: * Check if root directory should replace current directory.
238: */
239: if (cnp->cn_pnbuf[0] == '/') {
240: vrele(dp);
241: dp = ndp->ni_rootdir;
242: VREF(dp);
243: }
244: }
245: pool_put(&namei_pool, cnp->cn_pnbuf);
246: vrele(ndp->ni_dvp);
247: vput(ndp->ni_vp);
248: ndp->ni_vp = NULL;
249: return (error);
250: }
251:
252: /*
253: * Search a pathname.
254: * This is a very central and rather complicated routine.
255: *
256: * The pathname is pointed to by ni_ptr and is of length ni_pathlen.
257: * The starting directory is taken from ni_startdir. The pathname is
258: * descended until done, or a symbolic link is encountered. The variable
259: * ni_more is clear if the path is completed; it is set to one if a
260: * symbolic link needing interpretation is encountered.
261: *
262: * The flag argument is LOOKUP, CREATE, RENAME, or DELETE depending on
263: * whether the name is to be looked up, created, renamed, or deleted.
264: * When CREATE, RENAME, or DELETE is specified, information usable in
265: * creating, renaming, or deleting a directory entry may be calculated.
266: * If flag has LOCKPARENT or'ed into it, the parent directory is returned
267: * locked. If flag has WANTPARENT or'ed into it, the parent directory is
268: * returned unlocked. Otherwise the parent directory is not returned. If
269: * the target of the pathname exists and LOCKLEAF is or'ed into the flag
270: * the target is returned locked, otherwise it is returned unlocked.
271: * When creating or renaming and LOCKPARENT is specified, the target may not
272: * be ".". When deleting and LOCKPARENT is specified, the target may be ".".
273: *
274: * Overall outline of lookup:
275: *
276: * dirloop:
277: * identify next component of name at ndp->ni_ptr
278: * handle degenerate case where name is null string
279: * if .. and crossing mount points and on mounted filesys, find parent
280: * call VOP_LOOKUP routine for next component name
281: * directory vnode returned in ni_dvp, unlocked unless LOCKPARENT set
282: * component vnode returned in ni_vp (if it exists), locked.
283: * if result vnode is mounted on and crossing mount points,
284: * find mounted on vnode
285: * if more components of name, do next level at dirloop
286: * return the answer in ni_vp, locked if LOCKLEAF set
287: * if LOCKPARENT set, return locked parent in ni_dvp
288: * if WANTPARENT set, return unlocked parent in ni_dvp
289: */
290: int
291: lookup(struct nameidata *ndp)
292: {
293: char *cp; /* pointer into pathname argument */
294: struct vnode *dp = 0; /* the directory we are searching */
295: struct vnode *tdp; /* saved dp */
296: struct mount *mp; /* mount table entry */
297: int docache; /* == 0 do not cache last component */
298: int wantparent; /* 1 => wantparent or lockparent flag */
299: int rdonly; /* lookup read-only flag bit */
300: int error = 0;
301: int dpunlocked = 0; /* dp has already been unlocked */
302: int slashes;
303: struct componentname *cnp = &ndp->ni_cnd;
304: struct proc *p = cnp->cn_proc;
305: /*
306: * Setup: break out flag bits into variables.
307: */
308: wantparent = cnp->cn_flags & (LOCKPARENT | WANTPARENT);
309: docache = (cnp->cn_flags & NOCACHE) ^ NOCACHE;
310: if (cnp->cn_nameiop == DELETE ||
311: (wantparent && cnp->cn_nameiop != CREATE))
312: docache = 0;
313: rdonly = cnp->cn_flags & RDONLY;
314: ndp->ni_dvp = NULL;
315: cnp->cn_flags &= ~ISSYMLINK;
316: dp = ndp->ni_startdir;
317: ndp->ni_startdir = NULLVP;
318: vn_lock(dp, LK_EXCLUSIVE | LK_RETRY, p);
319:
320: /*
321: * If we have a leading string of slashes, remove them, and just make
322: * sure the current node is a directory.
323: */
324: cp = cnp->cn_nameptr;
325: if (*cp == '/') {
326: do {
327: cp++;
328: } while (*cp == '/');
329: ndp->ni_pathlen -= cp - cnp->cn_nameptr;
330: cnp->cn_nameptr = cp;
331:
332: if (dp->v_type != VDIR) {
333: error = ENOTDIR;
334: goto bad;
335: }
336:
337: /*
338: * If we've exhausted the path name, then just return the
339: * current node. If the caller requested the parent node (i.e.
340: * it's a CREATE, DELETE, or RENAME), and we don't have one
341: * (because this is the root directory), then we must fail.
342: */
343: if (cnp->cn_nameptr[0] == '\0') {
344: if (ndp->ni_dvp == NULL && wantparent) {
345: error = EISDIR;
346: goto bad;
347: }
348: ndp->ni_vp = dp;
349: cnp->cn_flags |= ISLASTCN;
350: goto terminal;
351: }
352: }
353:
354: dirloop:
355: /*
356: * Search a new directory.
357: *
358: * The cn_hash value is for use by vfs_cache.
359: * The last component of the filename is left accessible via
360: * cnp->cn_nameptr for callers that need the name. Callers needing
361: * the name set the SAVENAME flag. When done, they assume
362: * responsibility for freeing the pathname buffer.
363: */
364: cp = NULL;
365: cnp->cn_consume = 0;
366: cnp->cn_hash = hash32_stre(cnp->cn_nameptr, '/', &cp, HASHINIT);
367: cnp->cn_namelen = cp - cnp->cn_nameptr;
368: if (cnp->cn_namelen > NAME_MAX) {
369: error = ENAMETOOLONG;
370: goto bad;
371: }
372: #ifdef NAMEI_DIAGNOSTIC
373: { char c = *cp;
374: *cp = '\0';
375: printf("{%s}: ", cnp->cn_nameptr);
376: *cp = c; }
377: #endif
378: ndp->ni_pathlen -= cnp->cn_namelen;
379: ndp->ni_next = cp;
380: /*
381: * If this component is followed by a slash, then move the pointer to
382: * the next component forward, and remember that this component must be
383: * a directory.
384: */
385: if (*cp == '/') {
386: do {
387: cp++;
388: } while (*cp == '/');
389: slashes = cp - ndp->ni_next;
390: ndp->ni_pathlen -= slashes;
391: ndp->ni_next = cp;
392: cnp->cn_flags |= REQUIREDIR;
393: } else {
394: slashes = 0;
395: cnp->cn_flags &= ~REQUIREDIR;
396: }
397: /*
398: * We do special processing on the last component, whether or not it's
399: * a directory. Cache all intervening lookups, but not the final one.
400: */
401: if (*cp == '\0') {
402: if (docache)
403: cnp->cn_flags |= MAKEENTRY;
404: else
405: cnp->cn_flags &= ~MAKEENTRY;
406: cnp->cn_flags |= ISLASTCN;
407: } else {
408: cnp->cn_flags |= MAKEENTRY;
409: cnp->cn_flags &= ~ISLASTCN;
410: }
411: if (cnp->cn_namelen == 2 &&
412: cnp->cn_nameptr[1] == '.' && cnp->cn_nameptr[0] == '.')
413: cnp->cn_flags |= ISDOTDOT;
414: else
415: cnp->cn_flags &= ~ISDOTDOT;
416:
417: /*
418: * Handle "..": two special cases.
419: * 1. If at root directory (e.g. after chroot)
420: * or at absolute root directory
421: * then ignore it so can't get out.
422: * 2. If this vnode is the root of a mounted
423: * filesystem, then replace it with the
424: * vnode which was mounted on so we take the
425: * .. in the other file system.
426: */
427: if (cnp->cn_flags & ISDOTDOT) {
428: for (;;) {
429: if (dp == ndp->ni_rootdir || dp == rootvnode) {
430: ndp->ni_dvp = dp;
431: ndp->ni_vp = dp;
432: VREF(dp);
433: goto nextname;
434: }
435: if ((dp->v_flag & VROOT) == 0 ||
436: (cnp->cn_flags & NOCROSSMOUNT))
437: break;
438: tdp = dp;
439: dp = dp->v_mount->mnt_vnodecovered;
440: vput(tdp);
441: VREF(dp);
442: vn_lock(dp, LK_EXCLUSIVE | LK_RETRY, p);
443: }
444: }
445:
446: /*
447: * We now have a segment name to search for, and a directory to search.
448: */
449: ndp->ni_dvp = dp;
450: ndp->ni_vp = NULL;
451: cnp->cn_flags &= ~PDIRUNLOCK;
452:
453: if ((error = VOP_LOOKUP(dp, &ndp->ni_vp, cnp)) != 0) {
454: #ifdef DIAGNOSTIC
455: if (ndp->ni_vp != NULL)
456: panic("leaf should be empty");
457: #endif
458: #ifdef NAMEI_DIAGNOSTIC
459: printf("not found\n");
460: #endif
461: if (error != EJUSTRETURN)
462: goto bad;
463: /*
464: * If this was not the last component, or there were trailing
465: * slashes, then the name must exist.
466: */
467: if (cnp->cn_flags & REQUIREDIR) {
468: error = ENOENT;
469: goto bad;
470: }
471: /*
472: * If creating and at end of pathname, then can consider
473: * allowing file to be created.
474: */
475: if (rdonly || (ndp->ni_dvp->v_mount->mnt_flag & MNT_RDONLY)) {
476: error = EROFS;
477: goto bad;
478: }
479: /*
480: * We return with ni_vp NULL to indicate that the entry
481: * doesn't currently exist, leaving a pointer to the
482: * (possibly locked) directory inode in ndp->ni_dvp.
483: */
484: if (cnp->cn_flags & SAVESTART) {
485: ndp->ni_startdir = ndp->ni_dvp;
486: VREF(ndp->ni_startdir);
487: }
488: return (0);
489: }
490: #ifdef NAMEI_DIAGNOSTIC
491: printf("found\n");
492: #endif
493:
494: /*
495: * Take into account any additional components consumed by the
496: * underlying filesystem. This will include any trailing slashes after
497: * the last component consumed.
498: */
499: if (cnp->cn_consume > 0) {
500: if (cnp->cn_consume >= slashes) {
501: cnp->cn_flags &= ~REQUIREDIR;
502: }
503:
504: ndp->ni_pathlen -= cnp->cn_consume - slashes;
505: ndp->ni_next += cnp->cn_consume - slashes;
506: cnp->cn_consume = 0;
507: if (ndp->ni_next[0] == '\0')
508: cnp->cn_flags |= ISLASTCN;
509: }
510:
511: dp = ndp->ni_vp;
512: /*
513: * Check to see if the vnode has been mounted on;
514: * if so find the root of the mounted file system.
515: */
516: while (dp->v_type == VDIR && (mp = dp->v_mountedhere) &&
517: (cnp->cn_flags & NOCROSSMOUNT) == 0) {
518: if (vfs_busy(mp, VB_READ|VB_WAIT))
519: continue;
520: VOP_UNLOCK(dp, 0, p);
521: error = VFS_ROOT(mp, &tdp);
522: vfs_unbusy(mp);
523: if (error) {
524: dpunlocked = 1;
525: goto bad2;
526: }
527: vrele(dp);
528: ndp->ni_vp = dp = tdp;
529: }
530:
531: /*
532: * Check for symbolic link. Back up over any slashes that we skipped,
533: * as we will need them again.
534: */
535: if ((dp->v_type == VLNK) && (cnp->cn_flags & (FOLLOW|REQUIREDIR))) {
536: ndp->ni_pathlen += slashes;
537: ndp->ni_next -= slashes;
538: cnp->cn_flags |= ISSYMLINK;
539: return (0);
540: }
541:
542: /*
543: * Check for directory, if the component was followed by a series of
544: * slashes.
545: */
546: if ((dp->v_type != VDIR) && (cnp->cn_flags & REQUIREDIR)) {
547: error = ENOTDIR;
548: goto bad2;
549: }
550:
551: nextname:
552: /*
553: * Not a symbolic link. If this was not the last component, then
554: * continue at the next component, else return.
555: */
556: if (!(cnp->cn_flags & ISLASTCN)) {
557: cnp->cn_nameptr = ndp->ni_next;
558: vrele(ndp->ni_dvp);
559: goto dirloop;
560: }
561:
562: terminal:
563: /*
564: * Check for read-only file systems.
565: */
566: if (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME) {
567: /*
568: * Disallow directory write attempts on read-only
569: * file systems.
570: */
571: if (rdonly || (dp->v_mount->mnt_flag & MNT_RDONLY) ||
572: (wantparent &&
573: (ndp->ni_dvp->v_mount->mnt_flag & MNT_RDONLY))) {
574: error = EROFS;
575: goto bad2;
576: }
577: }
578: if (ndp->ni_dvp != NULL) {
579: if (cnp->cn_flags & SAVESTART) {
580: ndp->ni_startdir = ndp->ni_dvp;
581: VREF(ndp->ni_startdir);
582: }
583: if (!wantparent)
584: vrele(ndp->ni_dvp);
585: }
586: if ((cnp->cn_flags & LOCKLEAF) == 0)
587: VOP_UNLOCK(dp, 0, p);
588: return (0);
589:
590: bad2:
591: if ((cnp->cn_flags & LOCKPARENT) && (cnp->cn_flags & ISLASTCN) &&
592: ((cnp->cn_flags & PDIRUNLOCK) == 0))
593: VOP_UNLOCK(ndp->ni_dvp, 0, p);
594: vrele(ndp->ni_dvp);
595: bad:
596: if (dpunlocked)
597: vrele(dp);
598: else
599: vput(dp);
600: ndp->ni_vp = NULL;
601: return (error);
602: }
603:
604: /*
605: * Reacquire a path name component.
606: */
607: int
608: relookup(struct vnode *dvp, struct vnode **vpp, struct componentname *cnp)
609: {
610: struct proc *p = cnp->cn_proc;
611: struct vnode *dp = 0; /* the directory we are searching */
612: int wantparent; /* 1 => wantparent or lockparent flag */
613: int rdonly; /* lookup read-only flag bit */
614: int error = 0;
615: #ifdef NAMEI_DIAGNOSTIC
616: u_int32_t newhash; /* DEBUG: check name hash */
617: char *cp; /* DEBUG: check name ptr/len */
618: #endif
619:
620: /*
621: * Setup: break out flag bits into variables.
622: */
623: wantparent = cnp->cn_flags & (LOCKPARENT|WANTPARENT);
624: rdonly = cnp->cn_flags & RDONLY;
625: cnp->cn_flags &= ~ISSYMLINK;
626: dp = dvp;
627: vn_lock(dp, LK_EXCLUSIVE | LK_RETRY, p);
628:
629: /* dirloop: */
630: /*
631: * Search a new directory.
632: *
633: * The cn_hash value is for use by vfs_cache.
634: * The last component of the filename is left accessible via
635: * cnp->cn_nameptr for callers that need the name. Callers needing
636: * the name set the SAVENAME flag. When done, they assume
637: * responsibility for freeing the pathname buffer.
638: */
639: #ifdef NAMEI_DIAGNOSTIC
640: cp = NULL;
641: newhash = hash32_stre(cnp->cn_nameptr, '/', &cp, HASHINIT);
642: if (newhash != cnp->cn_hash)
643: panic("relookup: bad hash");
644: if (cnp->cn_namelen != cp - cnp->cn_nameptr)
645: panic ("relookup: bad len");
646: if (*cp != 0)
647: panic("relookup: not last component");
648: printf("{%s}: ", cnp->cn_nameptr);
649: #endif
650:
651: /*
652: * Check for degenerate name (e.g. / or "")
653: * which is a way of talking about a directory,
654: * e.g. like "/." or ".".
655: */
656: if (cnp->cn_nameptr[0] == '\0')
657: panic("relookup: null name");
658:
659: if (cnp->cn_flags & ISDOTDOT)
660: panic ("relookup: lookup on dot-dot");
661:
662: /*
663: * We now have a segment name to search for, and a directory to search.
664: */
665: if ((error = VOP_LOOKUP(dp, vpp, cnp)) != 0) {
666: #ifdef DIAGNOSTIC
667: if (*vpp != NULL)
668: panic("leaf should be empty");
669: #endif
670: if (error != EJUSTRETURN)
671: goto bad;
672: /*
673: * If creating and at end of pathname, then can consider
674: * allowing file to be created.
675: */
676: if (rdonly || (dvp->v_mount->mnt_flag & MNT_RDONLY)) {
677: error = EROFS;
678: goto bad;
679: }
680: /* ASSERT(dvp == ndp->ni_startdir) */
681: if (cnp->cn_flags & SAVESTART)
682: VREF(dvp);
683: /*
684: * We return with ni_vp NULL to indicate that the entry
685: * doesn't currently exist, leaving a pointer to the
686: * (possibly locked) directory inode in ndp->ni_dvp.
687: */
688: return (0);
689: }
690: dp = *vpp;
691:
692: #ifdef DIAGNOSTIC
693: /*
694: * Check for symbolic link
695: */
696: if (dp->v_type == VLNK && (cnp->cn_flags & FOLLOW))
697: panic ("relookup: symlink found.");
698: #endif
699:
700: /*
701: * Check for read-only file systems.
702: */
703: if (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME) {
704: /*
705: * Disallow directory write attempts on read-only
706: * file systems.
707: */
708: if (rdonly || (dp->v_mount->mnt_flag & MNT_RDONLY) ||
709: (wantparent &&
710: (dvp->v_mount->mnt_flag & MNT_RDONLY))) {
711: error = EROFS;
712: goto bad2;
713: }
714: }
715: /* ASSERT(dvp == ndp->ni_startdir) */
716: if (cnp->cn_flags & SAVESTART)
717: VREF(dvp);
718: if (!wantparent)
719: vrele(dvp);
720: if ((cnp->cn_flags & LOCKLEAF) == 0)
721: VOP_UNLOCK(dp, 0, p);
722: return (0);
723:
724: bad2:
725: if ((cnp->cn_flags & LOCKPARENT) && (cnp->cn_flags & ISLASTCN))
726: VOP_UNLOCK(dvp, 0, p);
727: vrele(dvp);
728: bad:
729: vput(dp);
730: *vpp = NULL;
731: return (error);
732: }
CVSweb