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