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