FreeBSD/Linux Kernel Cross Reference
sys/kern/vfs_lookup.c
1 /* $OpenBSD: vfs_lookup.c,v 1.88 2023/01/06 19:08:36 miod 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/namei.h>
44 #include <sys/vnode.h>
45 #include <sys/lock.h>
46 #include <sys/mount.h>
47 #include <sys/errno.h>
48 #include <sys/pool.h>
49 #include <sys/filedesc.h>
50 #include <sys/proc.h>
51 #include <sys/pledge.h>
52 #include <sys/file.h>
53 #include <sys/fcntl.h>
54
55 #ifdef KTRACE
56 #include <sys/ktrace.h>
57 #endif
58
59 int
60 component_push(struct componentname *cnp, char *component, size_t len)
61 {
62 if (cnp->cn_rpi + len + 1 >= MAXPATHLEN)
63 return 0;
64 if (cnp->cn_rpi > 1)
65 cnp->cn_rpbuf[cnp->cn_rpi++] = '/';
66 memcpy(cnp->cn_rpbuf + cnp->cn_rpi, component, len);
67 cnp->cn_rpi+=len;
68 cnp->cn_rpbuf[cnp->cn_rpi] = '\0';
69 return 1;
70 }
71
72 void
73 component_pop(struct componentname *cnp)
74 {
75 while(cnp->cn_rpi && cnp->cn_rpbuf[cnp->cn_rpi] != '/' )
76 cnp->cn_rpi--;
77 if (cnp->cn_rpi == 0 && cnp->cn_rpbuf[0] == '/')
78 cnp->cn_rpi++;
79 cnp->cn_rpbuf[cnp->cn_rpi] = '\0';
80 }
81
82 void
83 ndinitat(struct nameidata *ndp, u_long op, u_long flags,
84 enum uio_seg segflg, int dirfd, const char *namep, struct proc *p)
85 {
86 memset(ndp, 0, sizeof(*ndp));
87 ndp->ni_cnd.cn_nameiop = op;
88 ndp->ni_cnd.cn_flags = flags;
89 ndp->ni_segflg = segflg;
90 ndp->ni_dirfd = dirfd;
91 ndp->ni_dirp = namep;
92 ndp->ni_cnd.cn_proc = p;
93 }
94
95 /*
96 * Convert a pathname into a pointer to a vnode.
97 *
98 * The FOLLOW flag is set when symbolic links are to be followed
99 * when they occur at the end of the name translation process.
100 * Symbolic links are always followed for all other pathname
101 * components other than the last.
102 *
103 * If the LOCKLEAF flag is set, a locked vnode is returned.
104 *
105 * The segflg defines whether the name is to be copied from user
106 * space or kernel space.
107 *
108 * Overall outline of namei:
109 *
110 * copy in name
111 * get starting directory
112 * while (!done && !error) {
113 * call lookup to search path.
114 * if symbolic link, massage name in buffer and continue
115 * }
116 */
117 int
118 namei(struct nameidata *ndp)
119 {
120 struct filedesc *fdp; /* pointer to file descriptor state */
121 char *cp; /* pointer into pathname argument */
122 struct vnode *dp; /* the directory we are searching */
123 struct iovec aiov; /* uio for reading symbolic links */
124 struct uio auio;
125 int error, linklen;
126 struct componentname *cnp = &ndp->ni_cnd;
127 struct proc *p = cnp->cn_proc;
128
129 ndp->ni_cnd.cn_cred = ndp->ni_cnd.cn_proc->p_ucred;
130 #ifdef DIAGNOSTIC
131 if (!cnp->cn_cred || !cnp->cn_proc)
132 panic ("namei: bad cred/proc");
133 if (cnp->cn_nameiop & (~OPMASK))
134 panic ("namei: nameiop contaminated with flags");
135 if (cnp->cn_flags & OPMASK)
136 panic ("namei: flags contaminated with nameiops");
137 #endif
138 fdp = cnp->cn_proc->p_fd;
139
140 /*
141 * Get a buffer for the name to be translated, and copy the
142 * name into the buffer.
143 */
144 if ((cnp->cn_flags & HASBUF) == 0)
145 cnp->cn_pnbuf = pool_get(&namei_pool, PR_WAITOK);
146 if (ndp->ni_segflg == UIO_SYSSPACE) {
147 ndp->ni_pathlen = strlcpy(cnp->cn_pnbuf, ndp->ni_dirp,
148 MAXPATHLEN);
149 if (ndp->ni_pathlen >= MAXPATHLEN) {
150 error = ENAMETOOLONG;
151 } else {
152 error = 0;
153 ndp->ni_pathlen++; /* ni_pathlen includes NUL */
154 }
155 } else
156 error = copyinstr(ndp->ni_dirp, cnp->cn_pnbuf,
157 MAXPATHLEN, &ndp->ni_pathlen);
158
159 /*
160 * Fail on null pathnames
161 */
162 if (error == 0 && ndp->ni_pathlen == 1)
163 error = ENOENT;
164
165 if (error)
166 goto fail;
167
168 #ifdef KTRACE
169 if (KTRPOINT(cnp->cn_proc, KTR_NAMEI))
170 ktrnamei(cnp->cn_proc, cnp->cn_pnbuf);
171 #endif
172
173 /*
174 * Strip trailing slashes, as requested
175 */
176 if (cnp->cn_flags & STRIPSLASHES) {
177 char *end = cnp->cn_pnbuf + ndp->ni_pathlen - 2;
178
179 cp = end;
180 while (cp >= cnp->cn_pnbuf && (*cp == '/'))
181 cp--;
182
183 /* Still some remaining characters in the buffer */
184 if (cp >= cnp->cn_pnbuf) {
185 ndp->ni_pathlen -= (end - cp);
186 *(cp + 1) = '\0';
187 }
188 }
189
190 ndp->ni_loopcnt = 0;
191
192 /*
193 * Get starting point for the translation.
194 */
195 if ((ndp->ni_rootdir = fdp->fd_rdir) == NULL ||
196 (ndp->ni_cnd.cn_flags & KERNELPATH))
197 ndp->ni_rootdir = rootvnode;
198
199 if (ndp->ni_cnd.cn_flags & KERNELPATH) {
200 ndp->ni_cnd.cn_flags |= BYPASSUNVEIL;
201 } else {
202 error = pledge_namei(p, ndp, cnp->cn_pnbuf);
203 if (error)
204 goto fail;
205 }
206
207 /*
208 * Check if starting from root directory or current directory.
209 */
210 if (cnp->cn_pnbuf[0] == '/') {
211 dp = ndp->ni_rootdir;
212 vref(dp);
213 if (cnp->cn_flags & REALPATH && cnp->cn_rpi == 0) {
214 cnp->cn_rpbuf[0] = '/';
215 cnp->cn_rpbuf[1] = '\0';
216 cnp->cn_rpi = 1;
217 }
218 } else if (ndp->ni_dirfd == AT_FDCWD) {
219 dp = fdp->fd_cdir;
220 vref(dp);
221 unveil_start_relative(p, ndp, dp);
222 unveil_check_component(p, ndp, dp);
223 } else {
224 struct file *fp = fd_getfile(fdp, ndp->ni_dirfd);
225 if (fp == NULL) {
226 error = EBADF;
227 goto fail;
228 }
229 dp = (struct vnode *)fp->f_data;
230 if (fp->f_type != DTYPE_VNODE || dp->v_type != VDIR) {
231 FRELE(fp, p);
232 error = ENOTDIR;
233 goto fail;
234 }
235 vref(dp);
236 unveil_start_relative(p, ndp, dp);
237 unveil_check_component(p, ndp, dp);
238 FRELE(fp, p);
239 }
240 for (;;) {
241 if (!dp->v_mount) {
242 /* Give up if the directory is no longer mounted */
243 vrele(dp);
244 error = ENOENT;
245 goto fail;
246 }
247
248 cnp->cn_nameptr = cnp->cn_pnbuf;
249 ndp->ni_startdir = dp;
250 if ((error = vfs_lookup(ndp)) != 0)
251 goto fail;
252
253 /*
254 * If not a symbolic link, return search result.
255 */
256 if ((cnp->cn_flags & ISSYMLINK) == 0) {
257 if ((error = unveil_check_final(p, ndp))) {
258 if ((cnp->cn_flags & LOCKPARENT) &&
259 (cnp->cn_flags & ISLASTCN) &&
260 (ndp->ni_vp != ndp->ni_dvp))
261 vput(ndp->ni_dvp);
262 if (ndp->ni_vp) {
263 if ((cnp->cn_flags & LOCKLEAF))
264 vput(ndp->ni_vp);
265 else
266 vrele(ndp->ni_vp);
267 }
268 goto fail;
269 }
270 if ((cnp->cn_flags & (SAVENAME | SAVESTART)) == 0)
271 pool_put(&namei_pool, cnp->cn_pnbuf);
272 else
273 cnp->cn_flags |= HASBUF;
274 return (0);
275 }
276 if ((cnp->cn_flags & LOCKPARENT) && (cnp->cn_flags & ISLASTCN))
277 VOP_UNLOCK(ndp->ni_dvp);
278 if (ndp->ni_loopcnt++ >= SYMLOOP_MAX) {
279 error = ELOOP;
280 break;
281 }
282 if (ndp->ni_pathlen > 1)
283 cp = pool_get(&namei_pool, PR_WAITOK);
284 else
285 cp = cnp->cn_pnbuf;
286 aiov.iov_base = cp;
287 aiov.iov_len = MAXPATHLEN;
288 auio.uio_iov = &aiov;
289 auio.uio_iovcnt = 1;
290 auio.uio_offset = 0;
291 auio.uio_rw = UIO_READ;
292 auio.uio_segflg = UIO_SYSSPACE;
293 auio.uio_procp = cnp->cn_proc;
294 auio.uio_resid = MAXPATHLEN;
295 error = VOP_READLINK(ndp->ni_vp, &auio, cnp->cn_cred);
296 if (error) {
297 badlink:
298 if (ndp->ni_pathlen > 1)
299 pool_put(&namei_pool, cp);
300 break;
301 }
302 linklen = MAXPATHLEN - auio.uio_resid;
303 if (linklen == 0) {
304 error = ENOENT;
305 goto badlink;
306 }
307 if (linklen + ndp->ni_pathlen >= MAXPATHLEN) {
308 error = ENAMETOOLONG;
309 goto badlink;
310 }
311 if (ndp->ni_pathlen > 1) {
312 memcpy(cp + linklen, ndp->ni_next, ndp->ni_pathlen);
313 pool_put(&namei_pool, cnp->cn_pnbuf);
314 cnp->cn_pnbuf = cp;
315 } else
316 cnp->cn_pnbuf[linklen] = '\0';
317 ndp->ni_pathlen += linklen;
318 vput(ndp->ni_vp);
319 dp = ndp->ni_dvp;
320 /*
321 * Check if root directory should replace current directory.
322 */
323 if (cnp->cn_pnbuf[0] == '/') {
324 vrele(dp);
325 dp = ndp->ni_rootdir;
326 vref(dp);
327 ndp->ni_unveil_match = NULL;
328 unveil_check_component(p, ndp, dp);
329 if (cnp->cn_flags & REALPATH) {
330 cnp->cn_rpbuf[0] = '/';
331 cnp->cn_rpbuf[1] = '\0';
332 cnp->cn_rpi = 1;
333 }
334 } else if (cnp->cn_flags & REALPATH) {
335 component_pop(cnp);
336 }
337 }
338 vrele(ndp->ni_dvp);
339 vput(ndp->ni_vp);
340 fail:
341 pool_put(&namei_pool, cnp->cn_pnbuf);
342 ndp->ni_vp = NULL;
343 return (error);
344 }
345
346 /*
347 * Search a pathname.
348 * This is a very central and rather complicated routine.
349 *
350 * The pathname is pointed to by ni_cnd.cn_nameptr and is of length
351 * ni_pathlen. The starting directory is taken from ni_startdir. The
352 * pathname is descended until done, or a symbolic link is encountered.
353 * If the path is completed the flag ISLASTCN is set in ni_cnd.cn_flags.
354 * If a symbolic link need interpretation is encountered, the flag ISSYMLINK
355 * is set in ni_cnd.cn_flags.
356 *
357 * The flag argument is LOOKUP, CREATE, RENAME, or DELETE depending on
358 * whether the name is to be looked up, created, renamed, or deleted.
359 * When CREATE, RENAME, or DELETE is specified, information usable in
360 * creating, renaming, or deleting a directory entry may be calculated.
361 * If flag has LOCKPARENT or'ed into it, the parent directory is returned
362 * locked. If flag has WANTPARENT or'ed into it, the parent directory is
363 * returned unlocked. Otherwise the parent directory is not returned. If
364 * the target of the pathname exists and LOCKLEAF is or'ed into the flag
365 * the target is returned locked, otherwise it is returned unlocked.
366 * When creating or renaming and LOCKPARENT is specified, the target may not
367 * be ".". When deleting and LOCKPARENT is specified, the target may be ".".
368 *
369 * Overall outline of lookup:
370 *
371 * dirloop:
372 * identify next component of name at ndp->ni_ptr
373 * handle degenerate case where name is null string
374 * if .. and crossing mount points and on mounted filesys, find parent
375 * call VOP_LOOKUP routine for next component name
376 * directory vnode returned in ni_dvp, unlocked unless LOCKPARENT set
377 * component vnode returned in ni_vp (if it exists), locked.
378 * if result vnode is mounted on and crossing mount points,
379 * find mounted on vnode
380 * if more components of name, do next level at dirloop
381 * return the answer in ni_vp, locked if LOCKLEAF set
382 * if LOCKPARENT set, return locked parent in ni_dvp
383 * if WANTPARENT set, return unlocked parent in ni_dvp
384 */
385 int
386 vfs_lookup(struct nameidata *ndp)
387 {
388 char *cp; /* pointer into pathname argument */
389 struct vnode *dp = NULL; /* the directory we are searching */
390 struct vnode *tdp; /* saved dp */
391 struct mount *mp; /* mount table entry */
392 int docache; /* == 0 do not cache last component */
393 int wantparent; /* 1 => wantparent or lockparent flag */
394 int rdonly; /* lookup read-only flag bit */
395 int error = 0;
396 int dpunlocked = 0; /* dp has already been unlocked */
397 int slashes;
398 struct componentname *cnp = &ndp->ni_cnd;
399 /*
400 * Setup: break out flag bits into variables.
401 */
402 wantparent = cnp->cn_flags & (LOCKPARENT | WANTPARENT);
403 docache = (cnp->cn_flags & NOCACHE) ^ NOCACHE;
404 if (cnp->cn_nameiop == DELETE ||
405 (wantparent && cnp->cn_nameiop != CREATE))
406 docache = 0;
407 rdonly = cnp->cn_flags & RDONLY;
408 ndp->ni_dvp = NULL;
409 cnp->cn_flags &= ~ISSYMLINK;
410 dp = ndp->ni_startdir;
411 ndp->ni_startdir = NULLVP;
412 vn_lock(dp, LK_EXCLUSIVE | LK_RETRY);
413
414 /*
415 * If we have a leading string of slashes, remove them, and just make
416 * sure the current node is a directory.
417 */
418 cp = cnp->cn_nameptr;
419 if (*cp == '/') {
420 do {
421 cp++;
422 } while (*cp == '/');
423 ndp->ni_pathlen -= cp - cnp->cn_nameptr;
424 cnp->cn_nameptr = cp;
425
426 if (dp->v_type != VDIR) {
427 error = ENOTDIR;
428 goto bad;
429 }
430
431 /*
432 * If we've exhausted the path name, then just return the
433 * current node. If the caller requested the parent node (i.e.
434 * it's a CREATE, DELETE, or RENAME), and we don't have one
435 * (because this is the root directory), then we must fail.
436 */
437 if (cnp->cn_nameptr[0] == '\0') {
438 if (ndp->ni_dvp == NULL && wantparent) {
439 error = EISDIR;
440 goto bad;
441 }
442 ndp->ni_vp = dp;
443 cnp->cn_flags |= ISLASTCN;
444 goto terminal;
445 }
446 }
447
448 dirloop:
449 /*
450 * Search a new directory.
451 *
452 * The last component of the filename is left accessible via
453 * cnp->cn_nameptr for callers that need the name. Callers needing
454 * the name set the SAVENAME flag. When done, they assume
455 * responsibility for freeing the pathname buffer.
456 */
457 cnp->cn_consume = 0;
458
459 /* XXX: Figure out the length of the last component. */
460 cp = cnp->cn_nameptr;
461 while (*cp && (*cp != '/'))
462 cp++;
463 cnp->cn_namelen = cp - cnp->cn_nameptr;
464 if (cnp->cn_namelen > NAME_MAX) {
465 error = ENAMETOOLONG;
466 goto bad;
467 }
468
469 #ifdef NAMEI_DIAGNOSTIC
470 { char c = *cp;
471 *cp = '\0';
472 printf("{%s}: ", cnp->cn_nameptr);
473 *cp = c; }
474 #endif
475 if (cnp->cn_flags & REALPATH) {
476 size_t len = cp - cnp->cn_nameptr;
477 if (len == 2 && cnp->cn_nameptr[0] == '.' &&
478 cnp->cn_nameptr[1] == '.')
479 component_pop(cnp);
480 else if (!(len == 1 && cnp->cn_nameptr[0] == '.')) {
481 if (!component_push(cnp, cnp->cn_nameptr, len)) {
482 error = ENAMETOOLONG;
483 goto bad;
484 }
485 }
486 }
487
488 ndp->ni_pathlen -= cnp->cn_namelen;
489 ndp->ni_next = cp;
490 /*
491 * If this component is followed by a slash, then move the pointer to
492 * the next component forward, and remember that this component must be
493 * a directory.
494 */
495 if (*cp == '/') {
496 do {
497 cp++;
498 } while (*cp == '/');
499 slashes = cp - ndp->ni_next;
500 ndp->ni_pathlen -= slashes;
501 ndp->ni_next = cp;
502 cnp->cn_flags |= REQUIREDIR;
503 } else {
504 slashes = 0;
505 cnp->cn_flags &= ~REQUIREDIR;
506 }
507 /*
508 * We do special processing on the last component, whether or not it's
509 * a directory. Cache all intervening lookups, but not the final one.
510 */
511 if (*cp == '\0') {
512 if (docache)
513 cnp->cn_flags |= MAKEENTRY;
514 else
515 cnp->cn_flags &= ~MAKEENTRY;
516 cnp->cn_flags |= ISLASTCN;
517 } else {
518 cnp->cn_flags |= MAKEENTRY;
519 cnp->cn_flags &= ~ISLASTCN;
520 }
521 if (cnp->cn_namelen == 2 &&
522 cnp->cn_nameptr[1] == '.' && cnp->cn_nameptr[0] == '.')
523 cnp->cn_flags |= ISDOTDOT;
524 else
525 cnp->cn_flags &= ~ISDOTDOT;
526
527 /*
528 * Handle "..": two special cases.
529 * 1. If at root directory (e.g. after chroot)
530 * or at absolute root directory
531 * then ignore it so can't get out.
532 * 2. If this vnode is the root of a mounted
533 * filesystem, then replace it with the
534 * vnode which was mounted on so we take the
535 * .. in the other file system.
536 */
537 if (cnp->cn_flags & ISDOTDOT) {
538 for (;;) {
539 if (dp == ndp->ni_rootdir || dp == rootvnode) {
540 ndp->ni_dvp = dp;
541 ndp->ni_vp = dp;
542 vref(dp);
543 ndp->ni_unveil_match = NULL;
544 goto nextname;
545 }
546 if ((dp->v_flag & VROOT) == 0 ||
547 (cnp->cn_flags & NOCROSSMOUNT))
548 break;
549 tdp = dp;
550 dp = dp->v_mount->mnt_vnodecovered;
551 vput(tdp);
552 vref(dp);
553 unveil_check_component(curproc, ndp, dp);
554 vn_lock(dp, LK_EXCLUSIVE | LK_RETRY);
555 }
556 }
557
558 /*
559 * We now have a segment name to search for, and a directory to search.
560 */
561 ndp->ni_dvp = dp;
562 ndp->ni_vp = NULL;
563 cnp->cn_flags &= ~PDIRUNLOCK;
564 unveil_check_component(curproc, ndp, dp);
565
566 if ((error = VOP_LOOKUP(dp, &ndp->ni_vp, cnp)) != 0) {
567 #ifdef DIAGNOSTIC
568 if (ndp->ni_vp != NULL)
569 panic("leaf should be empty");
570 #endif
571 #ifdef NAMEI_DIAGNOSTIC
572 printf("not found\n");
573 #endif
574 /*
575 * Allow for unveiling a file in a directory which we cannot
576 * create ourselves.
577 */
578 if (ndp->ni_pledge == PLEDGE_UNVEIL &&
579 (error == EPERM || error == EACCES || error == EROFS))
580 error = EJUSTRETURN;
581
582 if (error != EJUSTRETURN)
583 goto bad;
584 /*
585 * If this was not the last component, or there were trailing
586 * slashes, then the name must exist.
587 */
588 if (cnp->cn_flags & REQUIREDIR) {
589 error = ENOENT;
590 goto bad;
591 }
592 /*
593 * If creating and at end of pathname, then can consider
594 * allowing file to be created. Check for a read only
595 * filesystem and disallow this unless we are unveil'ing
596 */
597 if (ndp->ni_pledge != PLEDGE_UNVEIL && (rdonly ||
598 (ndp->ni_dvp->v_mount->mnt_flag & MNT_RDONLY))) {
599 error = EROFS;
600 goto bad;
601 }
602 /*
603 * We return with ni_vp NULL to indicate that the entry
604 * doesn't currently exist, leaving a pointer to the
605 * (possibly locked) directory inode in ndp->ni_dvp.
606 */
607 if (cnp->cn_flags & SAVESTART) {
608 ndp->ni_startdir = ndp->ni_dvp;
609 vref(ndp->ni_startdir);
610 }
611 return (0);
612 }
613 #ifdef NAMEI_DIAGNOSTIC
614 printf("found\n");
615 #endif
616
617 /*
618 * Take into account any additional components consumed by the
619 * underlying filesystem. This will include any trailing slashes after
620 * the last component consumed.
621 */
622 if (cnp->cn_consume > 0) {
623 if (cnp->cn_consume >= slashes) {
624 cnp->cn_flags &= ~REQUIREDIR;
625 }
626
627 ndp->ni_pathlen -= cnp->cn_consume - slashes;
628 ndp->ni_next += cnp->cn_consume - slashes;
629 cnp->cn_consume = 0;
630 if (ndp->ni_next[0] == '\0')
631 cnp->cn_flags |= ISLASTCN;
632 }
633
634 dp = ndp->ni_vp;
635 /*
636 * Check to see if the vnode has been mounted on;
637 * if so find the root of the mounted file system.
638 */
639 while (dp->v_type == VDIR && (mp = dp->v_mountedhere) &&
640 (cnp->cn_flags & NOCROSSMOUNT) == 0) {
641 if (vfs_busy(mp, VB_READ|VB_WAIT))
642 continue;
643 VOP_UNLOCK(dp);
644 error = VFS_ROOT(mp, &tdp);
645 vfs_unbusy(mp);
646 if (error) {
647 dpunlocked = 1;
648 goto bad2;
649 }
650 vrele(dp);
651 ndp->ni_vp = dp = tdp;
652 }
653
654 /*
655 * Check for symbolic link. Back up over any slashes that we skipped,
656 * as we will need them again.
657 */
658 if ((dp->v_type == VLNK) && (cnp->cn_flags & (FOLLOW|REQUIREDIR))) {
659 ndp->ni_pathlen += slashes;
660 ndp->ni_next -= slashes;
661 cnp->cn_flags |= ISSYMLINK;
662 return (0);
663 }
664
665 /*
666 * Check for directory, if the component was followed by a series of
667 * slashes.
668 */
669 if ((dp->v_type != VDIR) && (cnp->cn_flags & REQUIREDIR)) {
670 error = ENOTDIR;
671 goto bad2;
672 }
673
674 nextname:
675 /*
676 * Not a symbolic link. If this was not the last component, then
677 * continue at the next component, else return.
678 */
679 if (!(cnp->cn_flags & ISLASTCN)) {
680 cnp->cn_nameptr = ndp->ni_next;
681 vrele(ndp->ni_dvp);
682 goto dirloop;
683 }
684
685 terminal:
686 /*
687 * Check for read-only file systems.
688 */
689 if (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME) {
690 /*
691 * Disallow directory write attempts on read-only
692 * file systems.
693 */
694 if (rdonly || (dp->v_mount->mnt_flag & MNT_RDONLY) ||
695 (wantparent &&
696 (ndp->ni_dvp->v_mount->mnt_flag & MNT_RDONLY))) {
697 error = EROFS;
698 goto bad2;
699 }
700 }
701 if (ndp->ni_dvp != NULL) {
702 if (cnp->cn_flags & SAVESTART) {
703 ndp->ni_startdir = ndp->ni_dvp;
704 vref(ndp->ni_startdir);
705 }
706 if (!wantparent)
707 vrele(ndp->ni_dvp);
708 }
709 if ((cnp->cn_flags & LOCKLEAF) == 0)
710 VOP_UNLOCK(dp);
711 return (0);
712
713 bad2:
714 if ((cnp->cn_flags & LOCKPARENT) && (cnp->cn_flags & ISLASTCN) &&
715 ((cnp->cn_flags & PDIRUNLOCK) == 0))
716 VOP_UNLOCK(ndp->ni_dvp);
717 vrele(ndp->ni_dvp);
718 bad:
719 if (dpunlocked)
720 vrele(dp);
721 else
722 vput(dp);
723 ndp->ni_vp = NULL;
724 return (error);
725 }
726
727 /*
728 * Reacquire a path name component.
729 */
730 int
731 vfs_relookup(struct vnode *dvp, struct vnode **vpp, struct componentname *cnp)
732 {
733 struct vnode *dp = NULL; /* the directory we are searching */
734 int wantparent; /* 1 => wantparent or lockparent flag */
735 int rdonly; /* lookup read-only flag bit */
736 int error = 0;
737 #ifdef NAMEI_DIAGNOSTIC
738 char *cp; /* DEBUG: check name ptr/len */
739 #endif
740
741 /*
742 * Setup: break out flag bits into variables.
743 */
744 wantparent = cnp->cn_flags & (LOCKPARENT|WANTPARENT);
745 rdonly = cnp->cn_flags & RDONLY;
746 cnp->cn_flags &= ~ISSYMLINK;
747 dp = dvp;
748 vn_lock(dp, LK_EXCLUSIVE | LK_RETRY);
749
750 /* dirloop: */
751 /*
752 * Search a new directory.
753 *
754 * The last component of the filename is left accessible via
755 * cnp->cn_nameptr for callers that need the name. Callers needing
756 * the name set the SAVENAME flag. When done, they assume
757 * responsibility for freeing the pathname buffer.
758 */
759
760 #ifdef NAMEI_DIAGNOSTIC
761 /* XXX: Figure out the length of the last component. */
762 cp = cnp->cn_nameptr;
763 while (*cp && (*cp != '/')) {
764 cp++;
765 }
766 if (cnp->cn_namelen != cp - cnp->cn_nameptr)
767 panic("relookup: bad len");
768 if (*cp != 0)
769 panic("relookup: not last component");
770 printf("{%s}: ", cnp->cn_nameptr);
771 #endif
772
773 /*
774 * Check for degenerate name (e.g. / or "")
775 * which is a way of talking about a directory,
776 * e.g. like "/." or ".".
777 */
778 if (cnp->cn_nameptr[0] == '\0')
779 panic("relookup: null name");
780
781 if (cnp->cn_flags & ISDOTDOT)
782 panic ("relookup: lookup on dot-dot");
783
784 /*
785 * We now have a segment name to search for, and a directory to search.
786 */
787 if ((error = VOP_LOOKUP(dp, vpp, cnp)) != 0) {
788 #ifdef DIAGNOSTIC
789 if (*vpp != NULL)
790 panic("leaf should be empty");
791 #endif
792 if (error != EJUSTRETURN)
793 goto bad;
794 /*
795 * If creating and at end of pathname, then can consider
796 * allowing file to be created.
797 */
798 if (rdonly || (dvp->v_mount->mnt_flag & MNT_RDONLY)) {
799 error = EROFS;
800 goto bad;
801 }
802 /* ASSERT(dvp == ndp->ni_startdir) */
803 if (cnp->cn_flags & SAVESTART)
804 vref(dvp);
805 /*
806 * We return with ni_vp NULL to indicate that the entry
807 * doesn't currently exist, leaving a pointer to the
808 * (possibly locked) directory inode in ndp->ni_dvp.
809 */
810 return (0);
811 }
812 dp = *vpp;
813
814 #ifdef DIAGNOSTIC
815 /*
816 * Check for symbolic link
817 */
818 if (dp->v_type == VLNK && (cnp->cn_flags & FOLLOW))
819 panic ("relookup: symlink found.");
820 #endif
821
822 /*
823 * Check for read-only file systems.
824 */
825 if (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME) {
826 /*
827 * Disallow directory write attempts on read-only
828 * file systems.
829 */
830 if (rdonly || (dp->v_mount->mnt_flag & MNT_RDONLY) ||
831 (wantparent &&
832 (dvp->v_mount->mnt_flag & MNT_RDONLY))) {
833 error = EROFS;
834 goto bad2;
835 }
836 }
837 /* ASSERT(dvp == ndp->ni_startdir) */
838 if (cnp->cn_flags & SAVESTART)
839 vref(dvp);
840 if (!wantparent)
841 vrele(dvp);
842 if ((cnp->cn_flags & LOCKLEAF) == 0)
843 VOP_UNLOCK(dp);
844 return (0);
845
846 bad2:
847 if ((cnp->cn_flags & LOCKPARENT) && (cnp->cn_flags & ISLASTCN))
848 VOP_UNLOCK(dvp);
849 vrele(dvp);
850 bad:
851 vput(dp);
852 *vpp = NULL;
853 return (error);
854 }
855
856
Cache object: fe392ac221e9a4dbf8363398f2f4faa9
|