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 }