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