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