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