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