Make it compile in the presence of MACHVMCOMPAT (&p->p_vmspace->vm_map, not
[unix-history] / sys / kern / vfs_lookup.c
CommitLineData
15637ed4
RG
1/*
2 * Copyright (c) 1982, 1986, 1989 Regents of the University of California.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by the University of
16 * California, Berkeley and its contributors.
17 * 4. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 *
600f7f07 33 * from: @(#)vfs_lookup.c 7.32 (Berkeley) 5/21/91
bbc3f849 34 * $Id: vfs_lookup.c,v 1.2 1993/10/16 15:25:23 rgrimes Exp $
15637ed4
RG
35 */
36
37#include "param.h"
38#include "syslimits.h"
39#include "time.h"
40#include "namei.h"
41#include "vnode.h"
42#include "mount.h"
43#include "errno.h"
44#include "malloc.h"
45#include "filedesc.h"
46#include "proc.h"
47
48#ifdef KTRACE
49#include "ktrace.h"
50#endif
51
bbc3f849
GW
52u_long nextvnodeid;
53
15637ed4
RG
54/*
55 * Convert a pathname into a pointer to a locked inode.
56 *
57 * The FOLLOW flag is set when symbolic links are to be followed
58 * when they occur at the end of the name translation process.
59 * Symbolic links are always followed for all other pathname
60 * components other than the last.
61 *
62 * The segflg defines whether the name is to be copied from user
63 * space or kernel space.
64 *
65 * Overall outline of namei:
66 *
67 * copy in name
68 * get starting directory
69 * while (!done && !error) {
70 * call lookup to search path.
71 * if symbolic link, massage name in buffer and continue
72 * }
73 */
74namei(ndp, p)
75 register struct nameidata *ndp;
76 struct proc *p;
77{
78 register struct filedesc *fdp; /* pointer to file descriptor state */
79 register char *cp; /* pointer into pathname argument */
80 register struct vnode *dp; /* the directory we are searching */
81 struct iovec aiov; /* uio for reading symbolic links */
82 struct uio auio;
83 int error, linklen;
84
85 ndp->ni_cred = p->p_ucred;
86 fdp = p->p_fd;
87
88 /*
89 * Get a buffer for the name to be translated, and copy the
90 * name into the buffer.
91 */
92 if ((ndp->ni_nameiop & HASBUF) == 0)
93 MALLOC(ndp->ni_pnbuf, caddr_t, MAXPATHLEN, M_NAMEI, M_WAITOK);
94 if (ndp->ni_segflg == UIO_SYSSPACE)
95 error = copystr(ndp->ni_dirp, ndp->ni_pnbuf,
96 MAXPATHLEN, &ndp->ni_pathlen);
97 else
98 error = copyinstr(ndp->ni_dirp, ndp->ni_pnbuf,
99 MAXPATHLEN, &ndp->ni_pathlen);
100 if (error) {
101 free(ndp->ni_pnbuf, M_NAMEI);
102 ndp->ni_vp = NULL;
103 return (error);
104 }
105 ndp->ni_loopcnt = 0;
106#ifdef KTRACE
107 if (KTRPOINT(p, KTR_NAMEI))
108 ktrnamei(p->p_tracep, ndp->ni_pnbuf);
109#endif
110
111 /*
112 * Get starting point for the translation.
113 */
114 if ((ndp->ni_rootdir = fdp->fd_rdir) == NULL)
115 ndp->ni_rootdir = rootdir;
116 dp = fdp->fd_cdir;
117 VREF(dp);
118 for (;;) {
119 /*
120 * Check if root directory should replace current directory.
121 * Done at start of translation and after symbolic link.
122 */
123 ndp->ni_ptr = ndp->ni_pnbuf;
124 if (*ndp->ni_ptr == '/') {
125 vrele(dp);
126 while (*ndp->ni_ptr == '/') {
127 ndp->ni_ptr++;
128 ndp->ni_pathlen--;
129 }
130 dp = ndp->ni_rootdir;
131 VREF(dp);
132 }
133 ndp->ni_startdir = dp;
134 if (error = lookup(ndp, p)) {
135 FREE(ndp->ni_pnbuf, M_NAMEI);
136 return (error);
137 }
138 /*
139 * Check for symbolic link
140 */
141 if (ndp->ni_more == 0) {
142 if ((ndp->ni_nameiop & (SAVENAME | SAVESTART)) == 0)
143 FREE(ndp->ni_pnbuf, M_NAMEI);
144 else
145 ndp->ni_nameiop |= HASBUF;
146 return (0);
147 }
148 if ((ndp->ni_nameiop & LOCKPARENT) && ndp->ni_pathlen == 1)
149 VOP_UNLOCK(ndp->ni_dvp);
150 if (ndp->ni_loopcnt++ >= MAXSYMLINKS) {
151 error = ELOOP;
152 break;
153 }
154 if (ndp->ni_pathlen > 1)
155 MALLOC(cp, char *, MAXPATHLEN, M_NAMEI, M_WAITOK);
156 else
157 cp = ndp->ni_pnbuf;
158 aiov.iov_base = cp;
159 aiov.iov_len = MAXPATHLEN;
160 auio.uio_iov = &aiov;
161 auio.uio_iovcnt = 1;
162 auio.uio_offset = 0;
163 auio.uio_rw = UIO_READ;
164 auio.uio_segflg = UIO_SYSSPACE;
165 auio.uio_procp = (struct proc *)0;
166 auio.uio_resid = MAXPATHLEN;
167 if (error = VOP_READLINK(ndp->ni_vp, &auio, p->p_ucred)) {
168 if (ndp->ni_pathlen > 1)
169 free(cp, M_NAMEI);
170 break;
171 }
172 linklen = MAXPATHLEN - auio.uio_resid;
173 if (linklen + ndp->ni_pathlen >= MAXPATHLEN) {
174 if (ndp->ni_pathlen > 1)
175 free(cp, M_NAMEI);
176 error = ENAMETOOLONG;
177 break;
178 }
179 if (ndp->ni_pathlen > 1) {
180 bcopy(ndp->ni_next, cp + linklen, ndp->ni_pathlen);
181 FREE(ndp->ni_pnbuf, M_NAMEI);
182 ndp->ni_pnbuf = cp;
183 } else
184 ndp->ni_pnbuf[linklen] = '\0';
185 ndp->ni_pathlen += linklen;
186 vput(ndp->ni_vp);
187 dp = ndp->ni_dvp;
188 }
189 FREE(ndp->ni_pnbuf, M_NAMEI);
190 vrele(ndp->ni_dvp);
191 vput(ndp->ni_vp);
192 ndp->ni_vp = NULL;
193 return (error);
194}
195
196/*
197 * Search a pathname.
198 * This is a very central and rather complicated routine.
199 *
200 * The pathname is pointed to by ni_ptr and is of length ni_pathlen.
201 * The starting directory is taken from ni_startdir. The pathname is
202 * descended until done, or a symbolic link is encountered. The variable
203 * ni_more is clear if the path is completed; it is set to one if a
204 * symbolic link needing interpretation is encountered.
205 *
206 * The flag argument is LOOKUP, CREATE, RENAME, or DELETE depending on
207 * whether the name is to be looked up, created, renamed, or deleted.
208 * When CREATE, RENAME, or DELETE is specified, information usable in
209 * creating, renaming, or deleting a directory entry may be calculated.
210 * If flag has LOCKPARENT or'ed into it, the parent directory is returned
211 * locked. If flag has WANTPARENT or'ed into it, the parent directory is
212 * returned unlocked. Otherwise the parent directory is not returned. If
213 * the target of the pathname exists and LOCKLEAF is or'ed into the flag
214 * the target is returned locked, otherwise it is returned unlocked.
215 * When creating or renaming and LOCKPARENT is specified, the target may not
216 * be ".". When deleting and LOCKPARENT is specified, the target may be ".".
217 * NOTE: (LOOKUP | LOCKPARENT) currently returns the parent vnode unlocked.
218 *
219 * Overall outline of lookup:
220 *
221 * dirloop:
222 * identify next component of name at ndp->ni_ptr
223 * handle degenerate case where name is null string
224 * if .. and crossing mount points and on mounted filesys, find parent
225 * call VOP_LOOKUP routine for next component name
226 * directory vnode returned in ni_dvp, unlocked unless LOCKPARENT set
227 * component vnode returned in ni_vp (if it exists), locked.
228 * if result vnode is mounted on and crossing mount points,
229 * find mounted on vnode
230 * if more components of name, do next level at dirloop
231 * return the answer in ni_vp, locked if LOCKLEAF set
232 * if LOCKPARENT set, return locked parent in ni_dvp
233 * if WANTPARENT set, return unlocked parent in ni_dvp
234 */
235lookup(ndp, p)
236 register struct nameidata *ndp;
237 struct proc *p;
238{
239 register char *cp; /* pointer into pathname argument */
240 register struct vnode *dp = 0; /* the directory we are searching */
241 struct vnode *tdp; /* saved dp */
242 struct mount *mp; /* mount table entry */
243 int docache; /* == 0 do not cache last component */
244 int flag; /* LOOKUP, CREATE, RENAME or DELETE */
245 int wantparent; /* 1 => wantparent or lockparent flag */
246 int rdonly; /* mounted read-only flag bit(s) */
247 int error = 0;
248
249 /*
250 * Setup: break out flag bits into variables.
251 */
252 flag = ndp->ni_nameiop & OPMASK;
253 wantparent = ndp->ni_nameiop & (LOCKPARENT|WANTPARENT);
254 docache = (ndp->ni_nameiop & NOCACHE) ^ NOCACHE;
255 if (flag == DELETE || (wantparent && flag != CREATE))
256 docache = 0;
257 rdonly = MNT_RDONLY;
258 if (ndp->ni_nameiop & REMOTE)
259 rdonly |= MNT_EXRDONLY;
260 ndp->ni_dvp = NULL;
261 ndp->ni_more = 0;
262 dp = ndp->ni_startdir;
263 ndp->ni_startdir = NULLVP;
264 VOP_LOCK(dp);
265
266dirloop:
267 /*
268 * Search a new directory.
269 *
270 * The ni_hash value is for use by vfs_cache.
271 * The last component of the filename is left accessible via
272 * ndp->ptr for callers that need the name. Callers needing
273 * the name set the SAVENAME flag. When done, they assume
274 * responsibility for freeing the pathname buffer.
275 */
276 ndp->ni_hash = 0;
277 for (cp = ndp->ni_ptr; *cp != 0 && *cp != '/'; cp++)
278 ndp->ni_hash += (unsigned char)*cp;
279 ndp->ni_namelen = cp - ndp->ni_ptr;
280 if (ndp->ni_namelen >= NAME_MAX) {
281 error = ENAMETOOLONG;
282 goto bad;
283 }
284#ifdef NAMEI_DIAGNOSTIC
285 { char c = *cp;
286 *cp = '\0';
287 printf("{%s}: ", ndp->ni_ptr);
288 *cp = c; }
289#endif
290 ndp->ni_pathlen -= ndp->ni_namelen;
291 ndp->ni_next = cp;
292 ndp->ni_makeentry = 1;
293 if (*cp == '\0' && docache == 0)
294 ndp->ni_makeentry = 0;
295 ndp->ni_isdotdot = (ndp->ni_namelen == 2 &&
296 ndp->ni_ptr[1] == '.' && ndp->ni_ptr[0] == '.');
297
298 /*
299 * Check for degenerate name (e.g. / or "")
300 * which is a way of talking about a directory,
301 * e.g. like "/." or ".".
302 */
303 if (ndp->ni_ptr[0] == '\0') {
304 if (flag != LOOKUP || wantparent) {
305 error = EISDIR;
306 goto bad;
307 }
308 if (dp->v_type != VDIR) {
309 error = ENOTDIR;
310 goto bad;
311 }
312 if (!(ndp->ni_nameiop & LOCKLEAF))
313 VOP_UNLOCK(dp);
314 ndp->ni_vp = dp;
315 if (ndp->ni_nameiop & SAVESTART)
316 panic("lookup: SAVESTART");
317 return (0);
318 }
319
320 /*
321 * Handle "..": two special cases.
322 * 1. If at root directory (e.g. after chroot)
323 * then ignore it so can't get out.
324 * 2. If this vnode is the root of a mounted
325 * filesystem, then replace it with the
326 * vnode which was mounted on so we take the
327 * .. in the other file system.
328 */
329 if (ndp->ni_isdotdot) {
330 for (;;) {
331/* 17 Aug 92*/ if ((dp == ndp->ni_rootdir) || (dp == rootdir)) {
332 ndp->ni_dvp = dp;
333 ndp->ni_vp = dp;
334 VREF(dp);
335 goto nextname;
336 }
337 if ((dp->v_flag & VROOT) == 0 ||
338 (ndp->ni_nameiop & NOCROSSMOUNT))
339 break;
340 tdp = dp;
341 dp = dp->v_mount->mnt_vnodecovered;
342 vput(tdp);
343 VREF(dp);
344 VOP_LOCK(dp);
345 }
346 }
347
348 /*
349 * We now have a segment name to search for, and a directory to search.
350 */
351 if (error = VOP_LOOKUP(dp, ndp, p)) {
352#ifdef DIAGNOSTIC
353 if (ndp->ni_vp != NULL)
354 panic("leaf should be empty");
355#endif
356#ifdef NAMEI_DIAGNOSTIC
357 printf("not found\n");
358#endif
359 if (flag == LOOKUP || flag == DELETE ||
360 error != ENOENT || *cp != 0)
361 goto bad;
362 /*
363 * If creating and at end of pathname, then can consider
364 * allowing file to be created.
365 */
366 if (ndp->ni_dvp->v_mount->mnt_flag & rdonly) {
367 error = EROFS;
368 goto bad;
369 }
370 /*
371 * We return with ni_vp NULL to indicate that the entry
372 * doesn't currently exist, leaving a pointer to the
373 * (possibly locked) directory inode in ndp->ni_dvp.
374 */
375 if (ndp->ni_nameiop & SAVESTART) {
376 ndp->ni_startdir = ndp->ni_dvp;
377 VREF(ndp->ni_startdir);
378 }
379 return (0);
380 }
381#ifdef NAMEI_DIAGNOSTIC
382 printf("found\n");
383#endif
384
385 dp = ndp->ni_vp;
386 /*
387 * Check for symbolic link
388 */
389 if ((dp->v_type == VLNK) &&
390 ((ndp->ni_nameiop & FOLLOW) || *ndp->ni_next == '/')) {
391 ndp->ni_more = 1;
392 return (0);
393 }
394
395 /*
396 * Check to see if the vnode has been mounted on;
397 * if so find the root of the mounted file system.
398 */
399mntloop:
400 while (dp->v_type == VDIR && (mp = dp->v_mountedhere) &&
401 (ndp->ni_nameiop & NOCROSSMOUNT) == 0) {
402 while(mp->mnt_flag & MNT_MLOCK) {
403 mp->mnt_flag |= MNT_MWAIT;
404 sleep((caddr_t)mp, PVFS);
405 goto mntloop;
406 }
407 if (error = VFS_ROOT(dp->v_mountedhere, &tdp))
408 goto bad2;
409 vput(dp);
410 ndp->ni_vp = dp = tdp;
411 }
412
413nextname:
414 /*
415 * Not a symbolic link. If more pathname,
416 * continue at next component, else return.
417 */
418 if (*ndp->ni_next == '/') {
419 ndp->ni_ptr = ndp->ni_next;
420 while (*ndp->ni_ptr == '/') {
421 ndp->ni_ptr++;
422 ndp->ni_pathlen--;
423 }
424 vrele(ndp->ni_dvp);
425 goto dirloop;
426 }
427 /*
428 * Check for read-only file systems.
429 */
430 if (flag == DELETE || flag == RENAME) {
431 /*
432 * Disallow directory write attempts on read-only
433 * file systems.
434 */
435 if ((dp->v_mount->mnt_flag & rdonly) ||
436 (wantparent && (ndp->ni_dvp->v_mount->mnt_flag & rdonly))) {
437 error = EROFS;
438 goto bad2;
439 }
440 }
441 if (ndp->ni_nameiop & SAVESTART) {
442 ndp->ni_startdir = ndp->ni_dvp;
443 VREF(ndp->ni_startdir);
444 }
445 if (!wantparent)
446 vrele(ndp->ni_dvp);
447 if ((ndp->ni_nameiop & LOCKLEAF) == 0)
448 VOP_UNLOCK(dp);
449 return (0);
450
451bad2:
452 if ((ndp->ni_nameiop & LOCKPARENT) && *ndp->ni_next == '\0')
453 VOP_UNLOCK(ndp->ni_dvp);
454 vrele(ndp->ni_dvp);
455bad:
456 vput(dp);
457 ndp->ni_vp = NULL;
458 return (error);
459}