]> git.saurik.com Git - apple/xnu.git/blob - bsd/vfs/vfs_lookup.c
xnu-344.12.2.tar.gz
[apple/xnu.git] / bsd / vfs / vfs_lookup.c
1 /*
2 * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
11 *
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
18 * under the License.
19 *
20 * @APPLE_LICENSE_HEADER_END@
21 */
22 /* Copyright (c) 1995 NeXT Computer, Inc. All Rights Reserved */
23 /*
24 * Copyright (c) 1982, 1986, 1989, 1993
25 * The Regents of the University of California. All rights reserved.
26 * (c) UNIX System Laboratories, Inc.
27 * All or some portions of this file are derived from material licensed
28 * to the University of California by American Telephone and Telegraph
29 * Co. or Unix System Laboratories, Inc. and are reproduced herein with
30 * the permission of UNIX System Laboratories, Inc.
31 *
32 * Redistribution and use in source and binary forms, with or without
33 * modification, are permitted provided that the following conditions
34 * are met:
35 * 1. Redistributions of source code must retain the above copyright
36 * notice, this list of conditions and the following disclaimer.
37 * 2. Redistributions in binary form must reproduce the above copyright
38 * notice, this list of conditions and the following disclaimer in the
39 * documentation and/or other materials provided with the distribution.
40 * 3. All advertising materials mentioning features or use of this software
41 * must display the following acknowledgement:
42 * This product includes software developed by the University of
43 * California, Berkeley and its contributors.
44 * 4. Neither the name of the University nor the names of its contributors
45 * may be used to endorse or promote products derived from this software
46 * without specific prior written permission.
47 *
48 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
49 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
50 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
51 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
52 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
53 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
54 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
55 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
56 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
57 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
58 * SUCH DAMAGE.
59 *
60 * @(#)vfs_lookup.c 8.10 (Berkeley) 5/27/95
61 */
62
63 #include <sys/param.h>
64 #include <sys/syslimits.h>
65 #include <sys/time.h>
66 #include <sys/namei.h>
67 #include <sys/vm.h>
68 #include <sys/vnode.h>
69 #include <sys/mount.h>
70 #include <sys/errno.h>
71 #include <sys/malloc.h>
72 #include <sys/filedesc.h>
73 #include <sys/proc.h>
74 #include <sys/kdebug.h>
75 #include <sys/unistd.h> /* For _PC_NAME_MAX */
76
77 #if KTRACE
78 #include <sys/ktrace.h>
79 #endif
80
81 /*
82 * Convert a pathname into a pointer to a locked inode.
83 *
84 * The FOLLOW flag is set when symbolic links are to be followed
85 * when they occur at the end of the name translation process.
86 * Symbolic links are always followed for all other pathname
87 * components other than the last.
88 *
89 * The segflg defines whether the name is to be copied from user
90 * space or kernel space.
91 *
92 * Overall outline of namei:
93 *
94 * copy in name
95 * get starting directory
96 * while (!done && !error) {
97 * call lookup to search path.
98 * if symbolic link, massage name in buffer and continue
99 * }
100 */
101 int
102 namei(ndp)
103 register struct nameidata *ndp;
104 {
105 register struct filedesc *fdp; /* pointer to file descriptor state */
106 register char *cp; /* pointer into pathname argument */
107 register struct vnode *dp; /* the directory we are searching */
108 struct iovec aiov; /* uio for reading symbolic links */
109 struct uio auio;
110 int error, linklen;
111 struct componentname *cnp = &ndp->ni_cnd;
112 struct proc *p = cnp->cn_proc;
113
114 ndp->ni_cnd.cn_cred = ndp->ni_cnd.cn_proc->p_ucred;
115 #if DIAGNOSTIC
116 if (!cnp->cn_cred || !cnp->cn_proc)
117 panic ("namei: bad cred/proc");
118 if (cnp->cn_nameiop & (~OPMASK))
119 panic ("namei: nameiop contaminated with flags");
120 if (cnp->cn_flags & OPMASK)
121 panic ("namei: flags contaminated with nameiops");
122 #endif
123 fdp = cnp->cn_proc->p_fd;
124
125 /*
126 * Get a buffer for the name to be translated, and copy the
127 * name into the buffer.
128 */
129 if ((cnp->cn_flags & HASBUF) == 0) {
130 MALLOC_ZONE(cnp->cn_pnbuf, caddr_t,
131 MAXPATHLEN, M_NAMEI, M_WAITOK);
132 cnp->cn_pnlen = MAXPATHLEN;
133 }
134 if (ndp->ni_segflg == UIO_SYSSPACE)
135 error = copystr(ndp->ni_dirp, cnp->cn_pnbuf,
136 MAXPATHLEN, &ndp->ni_pathlen);
137 else
138 error = copyinstr(ndp->ni_dirp, cnp->cn_pnbuf,
139 MAXPATHLEN, &ndp->ni_pathlen);
140 /*
141 * Do not allow empty pathnames
142 */
143 if (!error && *cnp->cn_pnbuf == '\0')
144 error = ENOENT;
145
146 if (error) {
147 _FREE_ZONE(cnp->cn_pnbuf, cnp->cn_pnlen, M_NAMEI);
148 ndp->ni_vp = NULL;
149 return (error);
150 }
151 ndp->ni_loopcnt = 0;
152 #if KTRACE
153 if (KTRPOINT(cnp->cn_proc, KTR_NAMEI))
154 ktrnamei(cnp->cn_proc->p_tracep, cnp->cn_pnbuf);
155 #endif
156
157 /*
158 * Get starting point for the translation.
159 */
160 if ((ndp->ni_rootdir = fdp->fd_rdir) == NULL)
161 ndp->ni_rootdir = rootvnode;
162 dp = fdp->fd_cdir;
163 VREF(dp);
164 for (;;) {
165 /*
166 * Check if root directory should replace current directory.
167 * Done at start of translation and after symbolic link.
168 */
169 cnp->cn_nameptr = cnp->cn_pnbuf;
170 if (*(cnp->cn_nameptr) == '/') {
171 vrele(dp);
172 while (*(cnp->cn_nameptr) == '/') {
173 cnp->cn_nameptr++;
174 ndp->ni_pathlen--;
175 }
176 dp = ndp->ni_rootdir;
177 VREF(dp);
178 }
179 ndp->ni_startdir = dp;
180 if (error = lookup(ndp)) {
181 FREE_ZONE(cnp->cn_pnbuf, cnp->cn_pnlen, M_NAMEI);
182 return (error);
183 }
184 /*
185 * Check for symbolic link
186 */
187 if ((cnp->cn_flags & ISSYMLINK) == 0) {
188 if ((cnp->cn_flags & (SAVENAME | SAVESTART)) == 0) {
189 FREE_ZONE(cnp->cn_pnbuf,
190 cnp->cn_pnlen, M_NAMEI);
191 } else {
192 cnp->cn_flags |= HASBUF;
193 }
194 return (0);
195 }
196 if ((cnp->cn_flags & LOCKPARENT) && ndp->ni_pathlen == 1)
197 VOP_UNLOCK(ndp->ni_dvp, 0, p);
198 if (ndp->ni_loopcnt++ >= MAXSYMLINKS) {
199 error = ELOOP;
200 break;
201 }
202 if (ndp->ni_pathlen > 1) {
203 MALLOC_ZONE(cp, char *, MAXPATHLEN, M_NAMEI, M_WAITOK);
204 } else {
205 cp = cnp->cn_pnbuf;
206 }
207 aiov.iov_base = cp;
208 aiov.iov_len = MAXPATHLEN;
209 auio.uio_iov = &aiov;
210 auio.uio_iovcnt = 1;
211 auio.uio_offset = 0;
212 auio.uio_rw = UIO_READ;
213 auio.uio_segflg = UIO_SYSSPACE;
214 auio.uio_procp = (struct proc *)0;
215 auio.uio_resid = MAXPATHLEN;
216 if (error = VOP_READLINK(ndp->ni_vp, &auio, cnp->cn_cred)) {
217 if (ndp->ni_pathlen > 1)
218 _FREE_ZONE(cp, MAXPATHLEN, M_NAMEI);
219 break;
220 }
221 linklen = MAXPATHLEN - auio.uio_resid;
222 if (linklen + ndp->ni_pathlen >= MAXPATHLEN) {
223 if (ndp->ni_pathlen > 1)
224 _FREE_ZONE(cp, MAXPATHLEN, M_NAMEI);
225 error = ENAMETOOLONG;
226 break;
227 }
228 if (ndp->ni_pathlen > 1) {
229 bcopy(ndp->ni_next, cp + linklen, ndp->ni_pathlen);
230 FREE_ZONE(cnp->cn_pnbuf, cnp->cn_pnlen, M_NAMEI);
231 cnp->cn_pnbuf = cp;
232 cnp->cn_pnlen = MAXPATHLEN;
233 } else
234 cnp->cn_pnbuf[linklen] = '\0';
235 ndp->ni_pathlen += linklen;
236 vput(ndp->ni_vp);
237 dp = ndp->ni_dvp;
238 }
239 FREE_ZONE(cnp->cn_pnbuf, cnp->cn_pnlen, M_NAMEI);
240 vrele(ndp->ni_dvp);
241 vput(ndp->ni_vp);
242 ndp->ni_vp = NULL;
243 return (error);
244 }
245
246 /*
247 * Search a pathname.
248 * This is a very central and rather complicated routine.
249 *
250 * The pathname is pointed to by ni_ptr and is of length ni_pathlen.
251 * The starting directory is taken from ni_startdir. The pathname is
252 * descended until done, or a symbolic link is encountered. The variable
253 * ni_more is clear if the path is completed; it is set to one if a
254 * symbolic link needing interpretation is encountered.
255 *
256 * The flag argument is LOOKUP, CREATE, RENAME, or DELETE depending on
257 * whether the name is to be looked up, created, renamed, or deleted.
258 * When CREATE, RENAME, or DELETE is specified, information usable in
259 * creating, renaming, or deleting a directory entry may be calculated.
260 * If flag has LOCKPARENT or'ed into it, the parent directory is returned
261 * locked. If flag has WANTPARENT or'ed into it, the parent directory is
262 * returned unlocked. Otherwise the parent directory is not returned. If
263 * the target of the pathname exists and LOCKLEAF is or'ed into the flag
264 * the target is returned locked, otherwise it is returned unlocked.
265 * When creating or renaming and LOCKPARENT is specified, the target may not
266 * be ".". When deleting and LOCKPARENT is specified, the target may be ".".
267 *
268 * Overall outline of lookup:
269 *
270 * dirloop:
271 * identify next component of name at ndp->ni_ptr
272 * handle degenerate case where name is null string
273 * if .. and crossing mount points and on mounted filesys, find parent
274 * call VOP_LOOKUP routine for next component name
275 * directory vnode returned in ni_dvp, unlocked unless LOCKPARENT set
276 * component vnode returned in ni_vp (if it exists), locked.
277 * if result vnode is mounted on and crossing mount points,
278 * find mounted on vnode
279 * if more components of name, do next level at dirloop
280 * return the answer in ni_vp, locked if LOCKLEAF set
281 * if LOCKPARENT set, return locked parent in ni_dvp
282 * if WANTPARENT set, return unlocked parent in ni_dvp
283 */
284 int
285 lookup(ndp)
286 register struct nameidata *ndp;
287 {
288 register char *cp; /* pointer into pathname argument */
289 register struct vnode *dp = 0; /* the directory we are searching */
290 struct vnode *tdp; /* saved dp */
291 struct mount *mp; /* mount table entry */
292 int namemax = 0; /* maximun number of bytes for filename returned by pathconf() */
293 int docache; /* == 0 do not cache last component */
294 int wantparent; /* 1 => wantparent or lockparent flag */
295 int dp_unlocked = 0; /* 1 => dp already VOP_UNLOCK()-ed */
296 int rdonly; /* lookup read-only flag bit */
297 int trailing_slash;
298 int error = 0;
299 struct componentname *cnp = &ndp->ni_cnd;
300 struct proc *p = cnp->cn_proc;
301 int i;
302
303 /*
304 * Setup: break out flag bits into variables.
305 */
306 wantparent = cnp->cn_flags & (LOCKPARENT | WANTPARENT);
307 docache = (cnp->cn_flags & NOCACHE) ^ NOCACHE;
308 if (cnp->cn_nameiop == DELETE ||
309 (wantparent && cnp->cn_nameiop != CREATE &&
310 cnp->cn_nameiop != LOOKUP))
311 docache = 0;
312 rdonly = cnp->cn_flags & RDONLY;
313 ndp->ni_dvp = NULL;
314 cnp->cn_flags &= ~ISSYMLINK;
315 dp = ndp->ni_startdir;
316 ndp->ni_startdir = NULLVP;
317 vn_lock(dp, LK_EXCLUSIVE | LK_RETRY, p);
318
319 dirloop:
320 /*
321 * Search a new directory.
322 *
323 * The cn_hash value is for use by vfs_cache.
324 * Check pathconf for maximun length of name
325 * The last component of the filename is left accessible via
326 * cnp->cn_nameptr for callers that need the name. Callers needing
327 * the name set the SAVENAME flag. When done, they assume
328 * responsibility for freeing the pathname buffer.
329 */
330 cnp->cn_consume = 0;
331 cnp->cn_hash = 0;
332 for (cp = cnp->cn_nameptr, i=1; *cp != 0 && *cp != '/'; i++, cp++)
333 cnp->cn_hash += (unsigned char)*cp * i;
334 cnp->cn_namelen = cp - cnp->cn_nameptr;
335 if (VOP_PATHCONF(dp, _PC_NAME_MAX, &namemax))
336 namemax = NAME_MAX;
337 if (cnp->cn_namelen > namemax) {
338 error = ENAMETOOLONG;
339 goto bad;
340 }
341 #ifdef NAMEI_DIAGNOSTIC
342 { char c = *cp;
343 *cp = '\0';
344 printf("{%s}: ", cnp->cn_nameptr);
345 *cp = c; }
346 #endif
347 ndp->ni_pathlen -= cnp->cn_namelen;
348 ndp->ni_next = cp;
349
350 /*
351 * Replace multiple slashes by a single slash and trailing slashes
352 * by a null. This must be done before VOP_LOOKUP() because some
353 * fs's don't know about trailing slashes. Remember if there were
354 * trailing slashes to handle symlinks, existing non-directories
355 * and non-existing files that won't be directories specially later.
356 */
357 trailing_slash = 0;
358 while (*cp == '/' && (cp[1] == '/' || cp[1] == '\0')) {
359 cp++;
360 ndp->ni_pathlen--;
361 if (*cp == '\0') {
362 trailing_slash = 1;
363 *ndp->ni_next = '\0';
364 }
365 }
366 ndp->ni_next = cp;
367
368 cnp->cn_flags |= MAKEENTRY;
369 if (*cp == '\0' && docache == 0)
370 cnp->cn_flags &= ~MAKEENTRY;
371 if (cnp->cn_namelen == 2 &&
372 cnp->cn_nameptr[1] == '.' && cnp->cn_nameptr[0] == '.')
373 cnp->cn_flags |= ISDOTDOT;
374 else
375 cnp->cn_flags &= ~ISDOTDOT;
376 if (*ndp->ni_next == 0)
377 cnp->cn_flags |= ISLASTCN;
378 else
379 cnp->cn_flags &= ~ISLASTCN;
380
381
382 /*
383 * Check for degenerate name (e.g. / or "")
384 * which is a way of talking about a directory,
385 * e.g. like "/." or ".".
386 */
387 if (cnp->cn_nameptr[0] == '\0') {
388 if (dp->v_type != VDIR) {
389 error = ENOTDIR;
390 goto bad;
391 }
392 if (cnp->cn_nameiop != LOOKUP) {
393 error = EISDIR;
394 goto bad;
395 }
396 if (wantparent) {
397 ndp->ni_dvp = dp;
398 VREF(dp);
399 }
400 ndp->ni_vp = dp;
401 if (!(cnp->cn_flags & (LOCKPARENT | LOCKLEAF)))
402 VOP_UNLOCK(dp, 0, p);
403 if (cnp->cn_flags & SAVESTART)
404 panic("lookup: SAVESTART");
405 return (0);
406 }
407
408 /*
409 * Handle "..": two special cases.
410 * 1. If at root directory (e.g. after chroot)
411 * or at absolute root directory
412 * then ignore it so can't get out.
413 * 2. If this vnode is the root of a mounted
414 * filesystem, then replace it with the
415 * vnode which was mounted on so we take the
416 * .. in the other file system.
417 */
418 if (cnp->cn_flags & ISDOTDOT) {
419 for (;;) {
420 if (dp == ndp->ni_rootdir || dp == rootvnode) {
421 ndp->ni_dvp = dp;
422 ndp->ni_vp = dp;
423 VREF(dp);
424 goto nextname;
425 }
426 if ((dp->v_flag & VROOT) == 0 ||
427 (cnp->cn_flags & NOCROSSMOUNT))
428 break;
429 if (dp->v_mount == NULL) { /* forced umount */
430 error = EBADF;
431 goto bad;
432 }
433
434 tdp = dp;
435 dp = dp->v_mount->mnt_vnodecovered;
436 vput(tdp);
437 VREF(dp);
438 vn_lock(dp, LK_EXCLUSIVE | LK_RETRY, p);
439 }
440 }
441
442 /*
443 * We now have a segment name to search for, and a directory to search.
444 */
445 unionlookup:
446 ndp->ni_dvp = dp;
447 ndp->ni_vp = NULL;
448 if (error = VOP_LOOKUP(dp, &ndp->ni_vp, cnp)) {
449 #if DIAGNOSTIC
450 if (ndp->ni_vp != NULL)
451 panic("leaf should be empty");
452 #endif
453 #ifdef NAMEI_DIAGNOSTIC
454 printf("not found\n");
455 #endif
456 if ((error == ENOENT) &&
457 (dp->v_flag & VROOT) && (dp->v_mount != NULL) &&
458 (dp->v_mount->mnt_flag & MNT_UNION)) {
459 tdp = dp;
460 dp = dp->v_mount->mnt_vnodecovered;
461 vput(tdp);
462 VREF(dp);
463 vn_lock(dp, LK_EXCLUSIVE | LK_RETRY, p);
464 goto unionlookup;
465 }
466
467 if (error != EJUSTRETURN)
468 goto bad;
469 /*
470 * If creating and at end of pathname, then can consider
471 * allowing file to be created.
472 */
473 if (rdonly) {
474 error = EROFS;
475 goto bad;
476 }
477 if (*cp == '\0' && trailing_slash &&
478 !(cnp->cn_flags & WILLBEDIR)) {
479 error = ENOENT;
480 goto bad;
481 }
482 /*
483 * We return with ni_vp NULL to indicate that the entry
484 * doesn't currently exist, leaving a pointer to the
485 * (possibly locked) directory inode in ndp->ni_dvp.
486 */
487 if (cnp->cn_flags & SAVESTART) {
488 ndp->ni_startdir = ndp->ni_dvp;
489 VREF(ndp->ni_startdir);
490 }
491 if (kdebug_enable)
492 kdebug_lookup(ndp->ni_dvp, cnp);
493 return (0);
494 }
495 #ifdef NAMEI_DIAGNOSTIC
496 printf("found\n");
497 #endif
498
499 /*
500 * Take into account any additional components consumed by
501 * the underlying filesystem.
502 */
503 if (cnp->cn_consume > 0) {
504 cnp->cn_nameptr += cnp->cn_consume;
505 ndp->ni_next += cnp->cn_consume;
506 ndp->ni_pathlen -= cnp->cn_consume;
507 cnp->cn_consume = 0;
508 }
509
510 dp = ndp->ni_vp;
511 /*
512 * Check to see if the vnode has been mounted on;
513 * if so find the root of the mounted file system.
514 */
515 while (dp->v_type == VDIR && (mp = dp->v_mountedhere) &&
516 (cnp->cn_flags & NOCROSSMOUNT) == 0) {
517 if (vfs_busy(mp, 0, 0, p))
518 continue;
519 VOP_UNLOCK(dp, 0, p);
520 error = VFS_ROOT(mp, &tdp);
521 vfs_unbusy(mp, p);
522 if (error) {
523 dp_unlocked = 1; /* Signal error path 'dp' has already been unlocked */
524 goto bad2;
525 };
526 vrele(dp);
527 ndp->ni_vp = dp = tdp;
528 }
529
530 /*
531 * Check for symbolic link
532 */
533 if ((dp->v_type == VLNK) &&
534 ((cnp->cn_flags & FOLLOW) || trailing_slash ||
535 *ndp->ni_next == '/')) {
536 cnp->cn_flags |= ISSYMLINK;
537 return (0);
538 }
539
540 /*
541 * Check for bogus trailing slashes.
542 */
543 if (trailing_slash && dp->v_type != VDIR) {
544 error = ENOTDIR;
545 goto bad2;
546 }
547
548 nextname:
549 /*
550 * Not a symbolic link. If more pathname,
551 * continue at next component, else return.
552 */
553 if (*ndp->ni_next == '/') {
554 cnp->cn_nameptr = ndp->ni_next;
555 while (*cnp->cn_nameptr == '/') {
556 cnp->cn_nameptr++;
557 ndp->ni_pathlen--;
558 }
559 vrele(ndp->ni_dvp);
560 goto dirloop;
561 }
562
563 /*
564 * Disallow directory write attempts on read-only file systems.
565 */
566 if (rdonly &&
567 (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME)) {
568 error = EROFS;
569 goto bad2;
570 }
571 if (cnp->cn_flags & SAVESTART) {
572 ndp->ni_startdir = ndp->ni_dvp;
573 VREF(ndp->ni_startdir);
574 }
575 if (!wantparent)
576 vrele(ndp->ni_dvp);
577 if ((cnp->cn_flags & LOCKLEAF) == 0)
578 VOP_UNLOCK(dp, 0, p);
579 if (kdebug_enable)
580 kdebug_lookup(dp, cnp);
581 return (0);
582
583 bad2:
584 if ((cnp->cn_flags & LOCKPARENT) && *ndp->ni_next == '\0')
585 VOP_UNLOCK(ndp->ni_dvp, 0, p);
586 vrele(ndp->ni_dvp);
587 bad:
588 if (dp_unlocked) {
589 vrele(dp);
590 } else {
591 vput(dp);
592 };
593 ndp->ni_vp = NULL;
594 if (kdebug_enable)
595 kdebug_lookup(dp, cnp);
596 return (error);
597 }
598
599 /*
600 * relookup - lookup a path name component
601 * Used by lookup to re-aquire things.
602 */
603 int
604 relookup(dvp, vpp, cnp)
605 struct vnode *dvp, **vpp;
606 struct componentname *cnp;
607 {
608 struct proc *p = cnp->cn_proc;
609 struct vnode *dp = 0; /* the directory we are searching */
610 int docache; /* == 0 do not cache last component */
611 int wantparent; /* 1 => wantparent or lockparent flag */
612 int rdonly; /* lookup read-only flag bit */
613 int error = 0;
614 #ifdef NAMEI_DIAGNOSTIC
615 int newhash; /* DEBUG: check name hash */
616 char *cp; /* DEBUG: check name ptr/len */
617 #endif
618
619 /*
620 * Setup: break out flag bits into variables.
621 */
622 wantparent = cnp->cn_flags & (LOCKPARENT|WANTPARENT);
623 docache = (cnp->cn_flags & NOCACHE) ^ NOCACHE;
624 if (cnp->cn_nameiop == DELETE ||
625 (wantparent && cnp->cn_nameiop != CREATE))
626 docache = 0;
627 rdonly = cnp->cn_flags & RDONLY;
628 cnp->cn_flags &= ~ISSYMLINK;
629 dp = dvp;
630 vn_lock(dp, LK_EXCLUSIVE | LK_RETRY, p);
631
632 /* dirloop: */
633 /*
634 * Search a new directory.
635 *
636 * The cn_hash value is for use by vfs_cache.
637 * The last component of the filename is left accessible via
638 * cnp->cn_nameptr for callers that need the name. Callers needing
639 * the name set the SAVENAME flag. When done, they assume
640 * responsibility for freeing the pathname buffer.
641 */
642 #ifdef NAMEI_DIAGNOSTIC
643 for (newhash = 0, cp = cnp->cn_nameptr; *cp != 0 && *cp != '/'; cp++)
644 newhash += (unsigned char)*cp;
645 if (newhash != cnp->cn_hash)
646 panic("relookup: bad hash");
647 if (cnp->cn_namelen != cp - cnp->cn_nameptr)
648 panic ("relookup: bad len");
649 if (*cp != 0)
650 panic("relookup: not last component");
651 printf("{%s}: ", cnp->cn_nameptr);
652 #endif
653
654 /*
655 * Check for degenerate name (e.g. / or "")
656 * which is a way of talking about a directory,
657 * e.g. like "/." or ".".
658 */
659 if (cnp->cn_nameptr[0] == '\0') {
660 if (cnp->cn_nameiop != LOOKUP || wantparent) {
661 error = EISDIR;
662 goto bad;
663 }
664 if (dp->v_type != VDIR) {
665 error = ENOTDIR;
666 goto bad;
667 }
668 if (!(cnp->cn_flags & LOCKLEAF))
669 VOP_UNLOCK(dp, 0, p);
670 *vpp = dp;
671 if (cnp->cn_flags & SAVESTART)
672 panic("lookup: SAVESTART");
673 return (0);
674 }
675
676 if (cnp->cn_flags & ISDOTDOT)
677 panic ("relookup: lookup on dot-dot");
678
679 /*
680 * We now have a segment name to search for, and a directory to search.
681 */
682 if (error = VOP_LOOKUP(dp, vpp, cnp)) {
683 #if DIAGNOSTIC
684 if (*vpp != NULL)
685 panic("leaf should be empty");
686 #endif
687 if (error != EJUSTRETURN)
688 goto bad;
689 /*
690 * If creating and at end of pathname, then can consider
691 * allowing file to be created.
692 */
693 if (rdonly) {
694 error = EROFS;
695 goto bad;
696 }
697 /* ASSERT(dvp == ndp->ni_startdir) */
698 if (cnp->cn_flags & SAVESTART)
699 VREF(dvp);
700 /*
701 * We return with ni_vp NULL to indicate that the entry
702 * doesn't currently exist, leaving a pointer to the
703 * (possibly locked) directory inode in ndp->ni_dvp.
704 */
705 return (0);
706 }
707 dp = *vpp;
708
709 #if DIAGNOSTIC
710 /*
711 * Check for symbolic link
712 */
713 if (dp->v_type == VLNK && (cnp->cn_flags & FOLLOW))
714 panic ("relookup: symlink found.\n");
715 #endif
716
717 /*
718 * Disallow directory write attempts on read-only file systems.
719 */
720 if (rdonly &&
721 (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME)) {
722 error = EROFS;
723 goto bad2;
724 }
725 /* ASSERT(dvp == ndp->ni_startdir) */
726 if (cnp->cn_flags & SAVESTART)
727 VREF(dvp);
728
729 if (!wantparent)
730 vrele(dvp);
731 if ((cnp->cn_flags & LOCKLEAF) == 0)
732 VOP_UNLOCK(dp, 0, p);
733 return (0);
734
735 bad2:
736 if ((cnp->cn_flags & LOCKPARENT) && (cnp->cn_flags & ISLASTCN))
737 VOP_UNLOCK(dvp, 0, p);
738 vrele(dvp);
739 bad:
740 vput(dp);
741 *vpp = NULL;
742 return (error);
743 }
744
745
746 #define NUMPARMS 23
747
748 kdebug_lookup(dp, cnp)
749 struct vnode *dp;
750 struct componentname *cnp;
751 {
752 register int i, n;
753 register int dbg_namelen;
754 register int save_dbg_namelen;
755 register char *dbg_nameptr;
756 long dbg_parms[NUMPARMS];
757 char dbg_buf[4];
758 static char *dbg_filler = ">>>>";
759
760 /* Collect the pathname for tracing */
761 dbg_namelen = (cnp->cn_nameptr - cnp->cn_pnbuf) + cnp->cn_namelen;
762 dbg_nameptr = cnp->cn_nameptr + cnp->cn_namelen;
763
764 if (dbg_namelen > sizeof(dbg_parms))
765 dbg_namelen = sizeof(dbg_parms);
766 dbg_nameptr -= dbg_namelen;
767 save_dbg_namelen = dbg_namelen;
768
769 i = 0;
770
771 while (dbg_namelen > 0) {
772 if (dbg_namelen >= 4) {
773 dbg_parms[i++] = *(long *)dbg_nameptr;
774 dbg_nameptr += sizeof(long);
775 dbg_namelen -= sizeof(long);
776 } else {
777 for (n = 0; n < dbg_namelen; n++)
778 dbg_buf[n] = *dbg_nameptr++;
779 while (n <= 3) {
780 if (*dbg_nameptr)
781 dbg_buf[n++] = '>';
782 else
783 dbg_buf[n++] = 0;
784 }
785 dbg_parms[i++] = *(long *)&dbg_buf[0];
786
787 break;
788 }
789 }
790 while (i < NUMPARMS) {
791 if (*dbg_nameptr)
792 dbg_parms[i++] = *(long *)dbg_filler;
793 else
794 dbg_parms[i++] = 0;
795 }
796
797 /*
798 In the event that we collect multiple, consecutive pathname
799 entries, we must mark the start of the path's string.
800 */
801 KERNEL_DEBUG_CONSTANT((FSDBG_CODE(DBG_FSRW,36)) | DBG_FUNC_START,
802 dp, dbg_parms[0], dbg_parms[1], dbg_parms[2], 0);
803
804 for (dbg_namelen = save_dbg_namelen-12, i=3;
805 dbg_namelen > 0;
806 dbg_namelen -=(4 * sizeof(long)), i+= 4)
807 {
808 KERNEL_DEBUG_CONSTANT((FSDBG_CODE(DBG_FSRW,36)) | DBG_FUNC_NONE,
809 dbg_parms[i], dbg_parms[i+1], dbg_parms[i+2], dbg_parms[i+3], 0);
810 }
811 }