add USL's copyright notice
[unix-history] / usr / src / sys / kern / vfs_lookup.c
CommitLineData
da7c5cc6 1/*
ec54f0cc
KB
2 * Copyright (c) 1982, 1986, 1989, 1993
3 * The Regents of the University of California. All rights reserved.
adb35f79
KB
4 * (c) UNIX System Laboratories, Inc.
5 * All or some portions of this file are derived from material licensed
6 * to the University of California by American Telephone and Telegraph
7 * Co. or Unix System Laboratories, Inc. and are reproduced herein with
8 * the permission of UNIX System Laboratories, Inc.
da7c5cc6 9 *
dbf0c423 10 * %sccs.include.redist.c%
6d0f0ece 11 *
adb35f79 12 * @(#)vfs_lookup.c 8.3 (Berkeley) %G%
da7c5cc6 13 */
10873320 14
38a01dbe
KB
15#include <sys/param.h>
16#include <sys/syslimits.h>
17#include <sys/time.h>
18#include <sys/namei.h>
19#include <sys/vnode.h>
20#include <sys/mount.h>
21#include <sys/errno.h>
22#include <sys/malloc.h>
23#include <sys/filedesc.h>
24#include <sys/proc.h>
0caff0ad
KM
25
26#ifdef KTRACE
38a01dbe 27#include <sys/ktrace.h>
658f5fdc 28#endif
10873320
BJ
29
30/*
7f69b0e6 31 * Convert a pathname into a pointer to a locked inode.
4f083fd7 32 *
d870be74 33 * The FOLLOW flag is set when symbolic links are to be followed
4f083fd7 34 * when they occur at the end of the name translation process.
7f69b0e6
KM
35 * Symbolic links are always followed for all other pathname
36 * components other than the last.
37 *
38 * The segflg defines whether the name is to be copied from user
39 * space or kernel space.
10873320 40 *
f93197fc 41 * Overall outline of namei:
6bd0bb92
BJ
42 *
43 * copy in name
44 * get starting directory
955e7a55
KM
45 * while (!done && !error) {
46 * call lookup to search path.
47 * if symbolic link, massage name in buffer and continue
48 * }
10873320 49 */
743467cb
JH
50int
51namei(ndp)
d870be74 52 register struct nameidata *ndp;
10873320 53{
5e00df3b 54 register struct filedesc *fdp; /* pointer to file descriptor state */
6bd0bb92 55 register char *cp; /* pointer into pathname argument */
955e7a55
KM
56 register struct vnode *dp; /* the directory we are searching */
57 struct iovec aiov; /* uio for reading symbolic links */
58 struct uio auio;
59 int error, linklen;
743467cb 60 struct componentname *cnp = &ndp->ni_cnd;
10873320 61
743467cb
JH
62 ndp->ni_cnd.cn_cred = ndp->ni_cnd.cn_proc->p_ucred;
63#ifdef DIAGNOSTIC
64 if (!cnp->cn_cred || !cnp->cn_proc)
65 panic ("namei: bad cred/proc");
66 if (cnp->cn_nameiop & (~OPMASK))
67 panic ("namei: nameiop contaminated with flags");
68 if (cnp->cn_flags & OPMASK)
69 panic ("namei: flags contaminated with nameiops");
70#endif
71 fdp = cnp->cn_proc->p_fd;
955e7a55 72
f5039631 73 /*
6bd0bb92
BJ
74 * Get a buffer for the name to be translated, and copy the
75 * name into the buffer.
f5039631 76 */
743467cb
JH
77 if ((cnp->cn_flags & HASBUF) == 0)
78 MALLOC(cnp->cn_pnbuf, caddr_t, MAXPATHLEN, M_NAMEI, M_WAITOK);
955e7a55 79 if (ndp->ni_segflg == UIO_SYSSPACE)
743467cb 80 error = copystr(ndp->ni_dirp, cnp->cn_pnbuf,
955e7a55
KM
81 MAXPATHLEN, &ndp->ni_pathlen);
82 else
743467cb 83 error = copyinstr(ndp->ni_dirp, cnp->cn_pnbuf,
955e7a55
KM
84 MAXPATHLEN, &ndp->ni_pathlen);
85 if (error) {
743467cb 86 free(cnp->cn_pnbuf, M_NAMEI);
955e7a55
KM
87 ndp->ni_vp = NULL;
88 return (error);
d870be74 89 }
6d0f0ece 90 ndp->ni_loopcnt = 0;
658f5fdc 91#ifdef KTRACE
743467cb
JH
92 if (KTRPOINT(cnp->cn_proc, KTR_NAMEI))
93 ktrnamei(cnp->cn_proc->p_tracep, cnp->cn_pnbuf);
658f5fdc 94#endif
6bd0bb92 95
5f9e231a
KM
96 /*
97 * Get starting point for the translation.
98 */
955e7a55 99 if ((ndp->ni_rootdir = fdp->fd_rdir) == NULL)
6c1c42d5 100 ndp->ni_rootdir = rootvnode;
955e7a55 101 dp = fdp->fd_cdir;
5f9e231a 102 VREF(dp);
955e7a55
KM
103 for (;;) {
104 /*
105 * Check if root directory should replace current directory.
106 * Done at start of translation and after symbolic link.
107 */
743467cb
JH
108 cnp->cn_nameptr = cnp->cn_pnbuf;
109 if (*(cnp->cn_nameptr) == '/') {
955e7a55 110 vrele(dp);
743467cb
JH
111 while (*(cnp->cn_nameptr) == '/') {
112 cnp->cn_nameptr++;
955e7a55
KM
113 ndp->ni_pathlen--;
114 }
115 dp = ndp->ni_rootdir;
116 VREF(dp);
117 }
118 ndp->ni_startdir = dp;
743467cb
JH
119 if (error = lookup(ndp)) {
120 FREE(cnp->cn_pnbuf, M_NAMEI);
955e7a55
KM
121 return (error);
122 }
123 /*
124 * Check for symbolic link
125 */
743467cb
JH
126 if ((cnp->cn_flags & ISSYMLINK) == 0) {
127 if ((cnp->cn_flags & (SAVENAME | SAVESTART)) == 0)
128 FREE(cnp->cn_pnbuf, M_NAMEI);
955e7a55 129 else
743467cb 130 cnp->cn_flags |= HASBUF;
955e7a55
KM
131 return (0);
132 }
743467cb 133 if ((cnp->cn_flags & LOCKPARENT) && ndp->ni_pathlen == 1)
955e7a55
KM
134 VOP_UNLOCK(ndp->ni_dvp);
135 if (ndp->ni_loopcnt++ >= MAXSYMLINKS) {
136 error = ELOOP;
137 break;
138 }
139 if (ndp->ni_pathlen > 1)
140 MALLOC(cp, char *, MAXPATHLEN, M_NAMEI, M_WAITOK);
141 else
743467cb 142 cp = cnp->cn_pnbuf;
955e7a55
KM
143 aiov.iov_base = cp;
144 aiov.iov_len = MAXPATHLEN;
145 auio.uio_iov = &aiov;
146 auio.uio_iovcnt = 1;
147 auio.uio_offset = 0;
148 auio.uio_rw = UIO_READ;
149 auio.uio_segflg = UIO_SYSSPACE;
150 auio.uio_procp = (struct proc *)0;
151 auio.uio_resid = MAXPATHLEN;
743467cb 152 if (error = VOP_READLINK(ndp->ni_vp, &auio, cnp->cn_cred)) {
955e7a55
KM
153 if (ndp->ni_pathlen > 1)
154 free(cp, M_NAMEI);
155 break;
156 }
157 linklen = MAXPATHLEN - auio.uio_resid;
158 if (linklen + ndp->ni_pathlen >= MAXPATHLEN) {
159 if (ndp->ni_pathlen > 1)
160 free(cp, M_NAMEI);
161 error = ENAMETOOLONG;
162 break;
6d0f0ece 163 }
955e7a55
KM
164 if (ndp->ni_pathlen > 1) {
165 bcopy(ndp->ni_next, cp + linklen, ndp->ni_pathlen);
743467cb
JH
166 FREE(cnp->cn_pnbuf, M_NAMEI);
167 cnp->cn_pnbuf = cp;
955e7a55 168 } else
743467cb 169 cnp->cn_pnbuf[linklen] = '\0';
955e7a55
KM
170 ndp->ni_pathlen += linklen;
171 vput(ndp->ni_vp);
172 dp = ndp->ni_dvp;
6d0f0ece 173 }
743467cb 174 FREE(cnp->cn_pnbuf, M_NAMEI);
955e7a55
KM
175 vrele(ndp->ni_dvp);
176 vput(ndp->ni_vp);
177 ndp->ni_vp = NULL;
178 return (error);
179}
180
181/*
182 * Search a pathname.
183 * This is a very central and rather complicated routine.
184 *
185 * The pathname is pointed to by ni_ptr and is of length ni_pathlen.
186 * The starting directory is taken from ni_startdir. The pathname is
187 * descended until done, or a symbolic link is encountered. The variable
188 * ni_more is clear if the path is completed; it is set to one if a
189 * symbolic link needing interpretation is encountered.
190 *
191 * The flag argument is LOOKUP, CREATE, RENAME, or DELETE depending on
192 * whether the name is to be looked up, created, renamed, or deleted.
193 * When CREATE, RENAME, or DELETE is specified, information usable in
194 * creating, renaming, or deleting a directory entry may be calculated.
195 * If flag has LOCKPARENT or'ed into it, the parent directory is returned
196 * locked. If flag has WANTPARENT or'ed into it, the parent directory is
197 * returned unlocked. Otherwise the parent directory is not returned. If
198 * the target of the pathname exists and LOCKLEAF is or'ed into the flag
199 * the target is returned locked, otherwise it is returned unlocked.
200 * When creating or renaming and LOCKPARENT is specified, the target may not
201 * be ".". When deleting and LOCKPARENT is specified, the target may be ".".
955e7a55
KM
202 *
203 * Overall outline of lookup:
204 *
205 * dirloop:
206 * identify next component of name at ndp->ni_ptr
207 * handle degenerate case where name is null string
208 * if .. and crossing mount points and on mounted filesys, find parent
209 * call VOP_LOOKUP routine for next component name
210 * directory vnode returned in ni_dvp, unlocked unless LOCKPARENT set
211 * component vnode returned in ni_vp (if it exists), locked.
212 * if result vnode is mounted on and crossing mount points,
213 * find mounted on vnode
214 * if more components of name, do next level at dirloop
215 * return the answer in ni_vp, locked if LOCKLEAF set
216 * if LOCKPARENT set, return locked parent in ni_dvp
217 * if WANTPARENT set, return unlocked parent in ni_dvp
218 */
743467cb
JH
219int
220lookup(ndp)
955e7a55 221 register struct nameidata *ndp;
955e7a55
KM
222{
223 register char *cp; /* pointer into pathname argument */
224 register struct vnode *dp = 0; /* the directory we are searching */
225 struct vnode *tdp; /* saved dp */
226 struct mount *mp; /* mount table entry */
227 int docache; /* == 0 do not cache last component */
955e7a55 228 int wantparent; /* 1 => wantparent or lockparent flag */
6c235bc4 229 int rdonly; /* lookup read-only flag bit */
955e7a55 230 int error = 0;
cfef4373 231 struct componentname *cnp = &ndp->ni_cnd;
6bd0bb92 232
10873320 233 /*
955e7a55 234 * Setup: break out flag bits into variables.
10873320 235 */
743467cb 236 wantparent = cnp->cn_flags & (LOCKPARENT | WANTPARENT);
cfef4373 237 docache = (cnp->cn_flags & NOCACHE) ^ NOCACHE;
743467cb
JH
238 if (cnp->cn_nameiop == DELETE ||
239 (wantparent && cnp->cn_nameiop != CREATE))
955e7a55 240 docache = 0;
cfef4373 241 rdonly = cnp->cn_flags & RDONLY;
955e7a55 242 ndp->ni_dvp = NULL;
cfef4373 243 cnp->cn_flags &= ~ISSYMLINK;
955e7a55
KM
244 dp = ndp->ni_startdir;
245 ndp->ni_startdir = NULLVP;
246 VOP_LOCK(dp);
247
6bd0bb92 248dirloop:
6bd0bb92 249 /*
955e7a55
KM
250 * Search a new directory.
251 *
cfef4373 252 * The cn_hash value is for use by vfs_cache.
955e7a55 253 * The last component of the filename is left accessible via
cfef4373 254 * cnp->cn_nameptr for callers that need the name. Callers needing
955e7a55
KM
255 * the name set the SAVENAME flag. When done, they assume
256 * responsibility for freeing the pathname buffer.
6bd0bb92 257 */
7530700b 258 cnp->cn_consume = 0;
cfef4373
JH
259 cnp->cn_hash = 0;
260 for (cp = cnp->cn_nameptr; *cp != 0 && *cp != '/'; cp++)
261 cnp->cn_hash += (unsigned char)*cp;
262 cnp->cn_namelen = cp - cnp->cn_nameptr;
67d5a373 263 if (cnp->cn_namelen > NAME_MAX) {
955e7a55
KM
264 error = ENAMETOOLONG;
265 goto bad;
266 }
6d0f0ece 267#ifdef NAMEI_DIAGNOSTIC
955e7a55
KM
268 { char c = *cp;
269 *cp = '\0';
cfef4373 270 printf("{%s}: ", cnp->cn_nameptr);
955e7a55 271 *cp = c; }
6d0f0ece 272#endif
cfef4373 273 ndp->ni_pathlen -= cnp->cn_namelen;
955e7a55 274 ndp->ni_next = cp;
cfef4373 275 cnp->cn_flags |= MAKEENTRY;
87c05e6e 276 if (*cp == '\0' && docache == 0)
cfef4373
JH
277 cnp->cn_flags &= ~MAKEENTRY;
278 if (cnp->cn_namelen == 2 &&
0dc4f94d 279 cnp->cn_nameptr[1] == '.' && cnp->cn_nameptr[0] == '.')
cfef4373 280 cnp->cn_flags |= ISDOTDOT;
0dc4f94d
KM
281 else
282 cnp->cn_flags &= ~ISDOTDOT;
cfef4373
JH
283 if (*ndp->ni_next == 0)
284 cnp->cn_flags |= ISLASTCN;
0dc4f94d
KM
285 else
286 cnp->cn_flags &= ~ISLASTCN;
cfef4373 287
6bd0bb92
BJ
288
289 /*
290 * Check for degenerate name (e.g. / or "")
291 * which is a way of talking about a directory,
292 * e.g. like "/." or ".".
293 */
cfef4373 294 if (cnp->cn_nameptr[0] == '\0') {
c118ffcb 295 if (cnp->cn_nameiop != LOOKUP) {
6d0f0ece 296 error = EISDIR;
6bd0bb92 297 goto bad;
f5039631 298 }
955e7a55
KM
299 if (dp->v_type != VDIR) {
300 error = ENOTDIR;
301 goto bad;
302 }
c118ffcb
KM
303 if (wantparent) {
304 ndp->ni_dvp = dp;
305 vref(dp);
306 }
6d0f0ece 307 ndp->ni_vp = dp;
c118ffcb
KM
308 if (!(cnp->cn_flags & (LOCKPARENT | LOCKLEAF)))
309 VOP_UNLOCK(dp);
cfef4373 310 if (cnp->cn_flags & SAVESTART)
955e7a55 311 panic("lookup: SAVESTART");
743467cb 312 return (0);
f5039631 313 }
6bd0bb92 314
e47da406 315 /*
6d0f0ece
KM
316 * Handle "..": two special cases.
317 * 1. If at root directory (e.g. after chroot)
138a4aec 318 * or at absolute root directory
6d0f0ece
KM
319 * then ignore it so can't get out.
320 * 2. If this vnode is the root of a mounted
955e7a55 321 * filesystem, then replace it with the
6d0f0ece
KM
322 * vnode which was mounted on so we take the
323 * .. in the other file system.
e47da406 324 */
cfef4373 325 if (cnp->cn_flags & ISDOTDOT) {
e47da406 326 for (;;) {
6c1c42d5 327 if (dp == ndp->ni_rootdir || dp == rootvnode) {
6d0f0ece 328 ndp->ni_dvp = dp;
7655c64a 329 ndp->ni_vp = dp;
8fe1c702 330 VREF(dp);
6d0f0ece 331 goto nextname;
e47da406 332 }
d5cea2aa 333 if ((dp->v_flag & VROOT) == 0 ||
cfef4373 334 (cnp->cn_flags & NOCROSSMOUNT))
e47da406 335 break;
6d0f0ece 336 tdp = dp;
54fb9dc2 337 dp = dp->v_mount->mnt_vnodecovered;
6d0f0ece 338 vput(tdp);
8fe1c702 339 VREF(dp);
7655c64a 340 VOP_LOCK(dp);
e47da406
KM
341 }
342 }
343
f93197fc
KM
344 /*
345 * We now have a segment name to search for, and a directory to search.
6459ebe0 346 */
95a9cadb 347unionlookup:
cfef4373
JH
348 ndp->ni_dvp = dp;
349 if (error = VOP_LOOKUP(dp, &ndp->ni_vp, cnp)) {
955e7a55 350#ifdef DIAGNOSTIC
6d0f0ece
KM
351 if (ndp->ni_vp != NULL)
352 panic("leaf should be empty");
955e7a55 353#endif
658f5fdc 354#ifdef NAMEI_DIAGNOSTIC
6d0f0ece 355 printf("not found\n");
658f5fdc 356#endif
95a9cadb
JSP
357 if ((error == ENOENT) &&
358 (dp->v_flag & VROOT) &&
359 (dp->v_mount->mnt_flag & MNT_UNION)) {
360 tdp = dp;
361 dp = dp->v_mount->mnt_vnodecovered;
362 vput(tdp);
363 VREF(dp);
364 VOP_LOCK(dp);
365 goto unionlookup;
366 }
367
39a892ba 368 if (error != EJUSTRETURN)
1f6ef9f5 369 goto bad;
f5039631 370 /*
6d0f0ece
KM
371 * If creating and at end of pathname, then can consider
372 * allowing file to be created.
f5039631 373 */
6c235bc4 374 if (rdonly || (ndp->ni_dvp->v_mount->mnt_flag & MNT_RDONLY)) {
6d0f0ece 375 error = EROFS;
6bd0bb92 376 goto bad;
1f6ef9f5 377 }
f5039631 378 /*
6d0f0ece
KM
379 * We return with ni_vp NULL to indicate that the entry
380 * doesn't currently exist, leaving a pointer to the
381 * (possibly locked) directory inode in ndp->ni_dvp.
f5039631 382 */
cfef4373 383 if (cnp->cn_flags & SAVESTART) {
955e7a55
KM
384 ndp->ni_startdir = ndp->ni_dvp;
385 VREF(ndp->ni_startdir);
b8c8091e 386 p->p_spare[1]++;
955e7a55 387 }
743467cb 388 return (0);
6bd0bb92 389 }
658f5fdc 390#ifdef NAMEI_DIAGNOSTIC
6d0f0ece 391 printf("found\n");
658f5fdc 392#endif
6bd0bb92 393
7530700b
JSP
394 /*
395 * Take into account any additional components consumed by
396 * the underlying filesystem.
397 */
398 if (cnp->cn_consume > 0) {
399 cnp->cn_nameptr += cnp->cn_consume;
400 ndp->ni_next += cnp->cn_consume;
401 ndp->ni_pathlen -= cnp->cn_consume;
402 cnp->cn_consume = 0;
403 }
404
955e7a55 405 dp = ndp->ni_vp;
6bd0bb92 406 /*
6d0f0ece 407 * Check for symbolic link
4f083fd7 408 */
6d0f0ece 409 if ((dp->v_type == VLNK) &&
cfef4373
JH
410 ((cnp->cn_flags & FOLLOW) || *ndp->ni_next == '/')) {
411 cnp->cn_flags |= ISSYMLINK;
743467cb 412 return (0);
f93197fc
KM
413 }
414
6bd0bb92 415 /*
6d0f0ece
KM
416 * Check to see if the vnode has been mounted on;
417 * if so find the root of the mounted file system.
6bd0bb92 418 */
d5cea2aa 419 while (dp->v_type == VDIR && (mp = dp->v_mountedhere) &&
cfef4373 420 (cnp->cn_flags & NOCROSSMOUNT) == 0) {
17c70d83 421 if (mp->mnt_flag & MNT_MLOCK) {
54fb9dc2 422 mp->mnt_flag |= MNT_MWAIT;
6d0f0ece 423 sleep((caddr_t)mp, PVFS);
74f8a498 424 continue;
6bd0bb92 425 }
955e7a55 426 if (error = VFS_ROOT(dp->v_mountedhere, &tdp))
6bd0bb92 427 goto bad2;
6d0f0ece
KM
428 vput(dp);
429 ndp->ni_vp = dp = tdp;
10873320 430 }
6bd0bb92 431
6d0f0ece 432nextname:
10873320 433 /*
6bd0bb92
BJ
434 * Not a symbolic link. If more pathname,
435 * continue at next component, else return.
10873320 436 */
955e7a55 437 if (*ndp->ni_next == '/') {
cfef4373
JH
438 cnp->cn_nameptr = ndp->ni_next;
439 while (*cnp->cn_nameptr == '/') {
440 cnp->cn_nameptr++;
6d0f0ece 441 ndp->ni_pathlen--;
6bd0bb92 442 }
6d0f0ece
KM
443 vrele(ndp->ni_dvp);
444 goto dirloop;
6bd0bb92
BJ
445 }
446 /*
01633fea 447 * Check for read-only file systems.
6bd0bb92 448 */
cfef4373 449 if (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME) {
dfc0e8dd 450 /*
01633fea
KM
451 * Disallow directory write attempts on read-only
452 * file systems.
dfc0e8dd 453 */
6c235bc4
KM
454 if (rdonly || (dp->v_mount->mnt_flag & MNT_RDONLY) ||
455 (wantparent &&
456 (ndp->ni_dvp->v_mount->mnt_flag & MNT_RDONLY))) {
dfc0e8dd
KM
457 error = EROFS;
458 goto bad2;
459 }
460 }
cfef4373 461 if (cnp->cn_flags & SAVESTART) {
955e7a55 462 ndp->ni_startdir = ndp->ni_dvp;
b8c8091e 463 p->p_spare[1]++;
955e7a55
KM
464 VREF(ndp->ni_startdir);
465 }
6d0f0ece
KM
466 if (!wantparent)
467 vrele(ndp->ni_dvp);
cfef4373 468 if ((cnp->cn_flags & LOCKLEAF) == 0)
6d0f0ece 469 VOP_UNLOCK(dp);
743467cb 470 return (0);
4f083fd7 471
6d0f0ece 472bad2:
cfef4373 473 if ((cnp->cn_flags & LOCKPARENT) && *ndp->ni_next == '\0')
206be3f9 474 VOP_UNLOCK(ndp->ni_dvp);
6d0f0ece
KM
475 vrele(ndp->ni_dvp);
476bad:
477 vput(dp);
478 ndp->ni_vp = NULL;
743467cb 479 return (error);
b1aa93b9 480}
cfef4373
JH
481
482