]> git.saurik.com Git - apple/xnu.git/blob - bsd/vfs/vfs_lookup.c
xnu-201.5.tar.gz
[apple/xnu.git] / bsd / vfs / vfs_lookup.c
1 /*
2 * Copyright (c) 2000 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 rdonly; /* lookup read-only flag bit */
296 int error = 0;
297 struct componentname *cnp = &ndp->ni_cnd;
298 struct proc *p = cnp->cn_proc;
299 int i;
300
301 /*
302 * Setup: break out flag bits into variables.
303 */
304 wantparent = cnp->cn_flags & (LOCKPARENT | WANTPARENT);
305 docache = (cnp->cn_flags & NOCACHE) ^ NOCACHE;
306 if (cnp->cn_nameiop == DELETE ||
307 (wantparent && cnp->cn_nameiop != CREATE &&
308 cnp->cn_nameiop != LOOKUP))
309 docache = 0;
310 rdonly = cnp->cn_flags & RDONLY;
311 ndp->ni_dvp = NULL;
312 cnp->cn_flags &= ~ISSYMLINK;
313 dp = ndp->ni_startdir;
314 ndp->ni_startdir = NULLVP;
315 vn_lock(dp, LK_EXCLUSIVE | LK_RETRY, p);
316
317 dirloop:
318 /*
319 * Search a new directory.
320 *
321 * The cn_hash value is for use by vfs_cache.
322 * Check pathconf for maximun length of name
323 * The last component of the filename is left accessible via
324 * cnp->cn_nameptr for callers that need the name. Callers needing
325 * the name set the SAVENAME flag. When done, they assume
326 * responsibility for freeing the pathname buffer.
327 */
328 cnp->cn_consume = 0;
329 cnp->cn_hash = 0;
330 for (cp = cnp->cn_nameptr, i=1; *cp != 0 && *cp != '/'; i++, cp++)
331 cnp->cn_hash += (unsigned char)*cp * i;
332 cnp->cn_namelen = cp - cnp->cn_nameptr;
333 if (VOP_PATHCONF(dp, _PC_NAME_MAX, &namemax))
334 namemax = NAME_MAX;
335 if (cnp->cn_namelen > namemax) {
336 error = ENAMETOOLONG;
337 goto bad;
338 }
339 #ifdef NAMEI_DIAGNOSTIC
340 { char c = *cp;
341 *cp = '\0';
342 printf("{%s}: ", cnp->cn_nameptr);
343 *cp = c; }
344 #endif
345 ndp->ni_pathlen -= cnp->cn_namelen;
346 ndp->ni_next = cp;
347 cnp->cn_flags |= MAKEENTRY;
348 if (*cp == '\0' && docache == 0)
349 cnp->cn_flags &= ~MAKEENTRY;
350 if (cnp->cn_namelen == 2 &&
351 cnp->cn_nameptr[1] == '.' && cnp->cn_nameptr[0] == '.')
352 cnp->cn_flags |= ISDOTDOT;
353 else
354 cnp->cn_flags &= ~ISDOTDOT;
355 if (*ndp->ni_next == 0)
356 cnp->cn_flags |= ISLASTCN;
357 else
358 cnp->cn_flags &= ~ISLASTCN;
359
360
361 /*
362 * Check for degenerate name (e.g. / or "")
363 * which is a way of talking about a directory,
364 * e.g. like "/." or ".".
365 */
366 if (cnp->cn_nameptr[0] == '\0') {
367 if (dp->v_type != VDIR) {
368 error = ENOTDIR;
369 goto bad;
370 }
371 if (cnp->cn_nameiop != LOOKUP) {
372 error = EISDIR;
373 goto bad;
374 }
375 if (wantparent) {
376 ndp->ni_dvp = dp;
377 VREF(dp);
378 }
379 ndp->ni_vp = dp;
380 if (!(cnp->cn_flags & (LOCKPARENT | LOCKLEAF)))
381 VOP_UNLOCK(dp, 0, p);
382 if (cnp->cn_flags & SAVESTART)
383 panic("lookup: SAVESTART");
384 return (0);
385 }
386
387 /*
388 * Handle "..": two special cases.
389 * 1. If at root directory (e.g. after chroot)
390 * or at absolute root directory
391 * then ignore it so can't get out.
392 * 2. If this vnode is the root of a mounted
393 * filesystem, then replace it with the
394 * vnode which was mounted on so we take the
395 * .. in the other file system.
396 */
397 if (cnp->cn_flags & ISDOTDOT) {
398 for (;;) {
399 if (dp == ndp->ni_rootdir || dp == rootvnode) {
400 ndp->ni_dvp = dp;
401 ndp->ni_vp = dp;
402 VREF(dp);
403 goto nextname;
404 }
405 if ((dp->v_flag & VROOT) == 0 ||
406 (cnp->cn_flags & NOCROSSMOUNT))
407 break;
408 if (dp->v_mount == NULL) { /* forced umount */
409 error = EBADF;
410 goto bad;
411 }
412
413 tdp = dp;
414 dp = dp->v_mount->mnt_vnodecovered;
415 vput(tdp);
416 VREF(dp);
417 vn_lock(dp, LK_EXCLUSIVE | LK_RETRY, p);
418 }
419 }
420
421 /*
422 * We now have a segment name to search for, and a directory to search.
423 */
424 unionlookup:
425 ndp->ni_dvp = dp;
426 ndp->ni_vp = NULL;
427 if (error = VOP_LOOKUP(dp, &ndp->ni_vp, cnp)) {
428 #if DIAGNOSTIC
429 if (ndp->ni_vp != NULL)
430 panic("leaf should be empty");
431 #endif
432 #ifdef NAMEI_DIAGNOSTIC
433 printf("not found\n");
434 #endif
435 if ((error == ENOENT) &&
436 (dp->v_flag & VROOT) && (dp->v_mount != NULL) &&
437 (dp->v_mount->mnt_flag & MNT_UNION)) {
438 tdp = dp;
439 dp = dp->v_mount->mnt_vnodecovered;
440 vput(tdp);
441 VREF(dp);
442 vn_lock(dp, LK_EXCLUSIVE | LK_RETRY, p);
443 goto unionlookup;
444 }
445
446 if (error != EJUSTRETURN)
447 goto bad;
448 /*
449 * If creating and at end of pathname, then can consider
450 * allowing file to be created.
451 */
452 if (rdonly) {
453 error = EROFS;
454 goto bad;
455 }
456 /*
457 * We return with ni_vp NULL to indicate that the entry
458 * doesn't currently exist, leaving a pointer to the
459 * (possibly locked) directory inode in ndp->ni_dvp.
460 */
461 if (cnp->cn_flags & SAVESTART) {
462 ndp->ni_startdir = ndp->ni_dvp;
463 VREF(ndp->ni_startdir);
464 }
465 if (kdebug_enable)
466 kdebug_lookup(ndp->ni_dvp, cnp);
467 return (0);
468 }
469 #ifdef NAMEI_DIAGNOSTIC
470 printf("found\n");
471 #endif
472
473 /*
474 * Take into account any additional components consumed by
475 * the underlying filesystem.
476 */
477 if (cnp->cn_consume > 0) {
478 cnp->cn_nameptr += cnp->cn_consume;
479 ndp->ni_next += cnp->cn_consume;
480 ndp->ni_pathlen -= cnp->cn_consume;
481 cnp->cn_consume = 0;
482 }
483
484 dp = ndp->ni_vp;
485 /*
486 * Check to see if the vnode has been mounted on;
487 * if so find the root of the mounted file system.
488 */
489 while (dp->v_type == VDIR && (mp = dp->v_mountedhere) &&
490 (cnp->cn_flags & NOCROSSMOUNT) == 0) {
491 if (vfs_busy(mp, 0, 0, p))
492 continue;
493 error = VFS_ROOT(mp, &tdp);
494 vfs_unbusy(mp, p);
495 if (error)
496 goto bad2;
497 vput(dp);
498 ndp->ni_vp = dp = tdp;
499 }
500
501 /*
502 * Check for symbolic link
503 */
504 if ((dp->v_type == VLNK) &&
505 ((cnp->cn_flags & FOLLOW) || *ndp->ni_next == '/')) {
506 cnp->cn_flags |= ISSYMLINK;
507 return (0);
508 }
509
510 nextname:
511 /*
512 * Not a symbolic link. If more pathname,
513 * continue at next component, else return.
514 */
515 if (*ndp->ni_next == '/') {
516 cnp->cn_nameptr = ndp->ni_next;
517 while (*cnp->cn_nameptr == '/') {
518 cnp->cn_nameptr++;
519 ndp->ni_pathlen--;
520 }
521 vrele(ndp->ni_dvp);
522 goto dirloop;
523 }
524
525 /*
526 * Disallow directory write attempts on read-only file systems.
527 */
528 if (rdonly &&
529 (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME)) {
530 error = EROFS;
531 goto bad2;
532 }
533 if (cnp->cn_flags & SAVESTART) {
534 ndp->ni_startdir = ndp->ni_dvp;
535 VREF(ndp->ni_startdir);
536 }
537 if (!wantparent)
538 vrele(ndp->ni_dvp);
539 if ((cnp->cn_flags & LOCKLEAF) == 0)
540 VOP_UNLOCK(dp, 0, p);
541 if (kdebug_enable)
542 kdebug_lookup(dp, cnp);
543 return (0);
544
545 bad2:
546 if ((cnp->cn_flags & LOCKPARENT) && *ndp->ni_next == '\0')
547 VOP_UNLOCK(ndp->ni_dvp, 0, p);
548 vrele(ndp->ni_dvp);
549 bad:
550 vput(dp);
551 ndp->ni_vp = NULL;
552 if (kdebug_enable)
553 kdebug_lookup(dp, cnp);
554 return (error);
555 }
556
557 /*
558 * relookup - lookup a path name component
559 * Used by lookup to re-aquire things.
560 */
561 int
562 relookup(dvp, vpp, cnp)
563 struct vnode *dvp, **vpp;
564 struct componentname *cnp;
565 {
566 struct proc *p = cnp->cn_proc;
567 struct vnode *dp = 0; /* the directory we are searching */
568 int docache; /* == 0 do not cache last component */
569 int wantparent; /* 1 => wantparent or lockparent flag */
570 int rdonly; /* lookup read-only flag bit */
571 int error = 0;
572 #ifdef NAMEI_DIAGNOSTIC
573 int newhash; /* DEBUG: check name hash */
574 char *cp; /* DEBUG: check name ptr/len */
575 #endif
576
577 /*
578 * Setup: break out flag bits into variables.
579 */
580 wantparent = cnp->cn_flags & (LOCKPARENT|WANTPARENT);
581 docache = (cnp->cn_flags & NOCACHE) ^ NOCACHE;
582 if (cnp->cn_nameiop == DELETE ||
583 (wantparent && cnp->cn_nameiop != CREATE))
584 docache = 0;
585 rdonly = cnp->cn_flags & RDONLY;
586 cnp->cn_flags &= ~ISSYMLINK;
587 dp = dvp;
588 vn_lock(dp, LK_EXCLUSIVE | LK_RETRY, p);
589
590 /* dirloop: */
591 /*
592 * Search a new directory.
593 *
594 * The cn_hash value is for use by vfs_cache.
595 * The last component of the filename is left accessible via
596 * cnp->cn_nameptr for callers that need the name. Callers needing
597 * the name set the SAVENAME flag. When done, they assume
598 * responsibility for freeing the pathname buffer.
599 */
600 #ifdef NAMEI_DIAGNOSTIC
601 for (newhash = 0, cp = cnp->cn_nameptr; *cp != 0 && *cp != '/'; cp++)
602 newhash += (unsigned char)*cp;
603 if (newhash != cnp->cn_hash)
604 panic("relookup: bad hash");
605 if (cnp->cn_namelen != cp - cnp->cn_nameptr)
606 panic ("relookup: bad len");
607 if (*cp != 0)
608 panic("relookup: not last component");
609 printf("{%s}: ", cnp->cn_nameptr);
610 #endif
611
612 /*
613 * Check for degenerate name (e.g. / or "")
614 * which is a way of talking about a directory,
615 * e.g. like "/." or ".".
616 */
617 if (cnp->cn_nameptr[0] == '\0') {
618 if (cnp->cn_nameiop != LOOKUP || wantparent) {
619 error = EISDIR;
620 goto bad;
621 }
622 if (dp->v_type != VDIR) {
623 error = ENOTDIR;
624 goto bad;
625 }
626 if (!(cnp->cn_flags & LOCKLEAF))
627 VOP_UNLOCK(dp, 0, p);
628 *vpp = dp;
629 if (cnp->cn_flags & SAVESTART)
630 panic("lookup: SAVESTART");
631 return (0);
632 }
633
634 if (cnp->cn_flags & ISDOTDOT)
635 panic ("relookup: lookup on dot-dot");
636
637 /*
638 * We now have a segment name to search for, and a directory to search.
639 */
640 if (error = VOP_LOOKUP(dp, vpp, cnp)) {
641 #if DIAGNOSTIC
642 if (*vpp != NULL)
643 panic("leaf should be empty");
644 #endif
645 if (error != EJUSTRETURN)
646 goto bad;
647 /*
648 * If creating and at end of pathname, then can consider
649 * allowing file to be created.
650 */
651 if (rdonly) {
652 error = EROFS;
653 goto bad;
654 }
655 /* ASSERT(dvp == ndp->ni_startdir) */
656 if (cnp->cn_flags & SAVESTART)
657 VREF(dvp);
658 /*
659 * We return with ni_vp NULL to indicate that the entry
660 * doesn't currently exist, leaving a pointer to the
661 * (possibly locked) directory inode in ndp->ni_dvp.
662 */
663 return (0);
664 }
665 dp = *vpp;
666
667 #if DIAGNOSTIC
668 /*
669 * Check for symbolic link
670 */
671 if (dp->v_type == VLNK && (cnp->cn_flags & FOLLOW))
672 panic ("relookup: symlink found.\n");
673 #endif
674
675 /*
676 * Disallow directory write attempts on read-only file systems.
677 */
678 if (rdonly &&
679 (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME)) {
680 error = EROFS;
681 goto bad2;
682 }
683 /* ASSERT(dvp == ndp->ni_startdir) */
684 if (cnp->cn_flags & SAVESTART)
685 VREF(dvp);
686
687 if (!wantparent)
688 vrele(dvp);
689 if ((cnp->cn_flags & LOCKLEAF) == 0)
690 VOP_UNLOCK(dp, 0, p);
691 return (0);
692
693 bad2:
694 if ((cnp->cn_flags & LOCKPARENT) && (cnp->cn_flags & ISLASTCN))
695 VOP_UNLOCK(dvp, 0, p);
696 vrele(dvp);
697 bad:
698 vput(dp);
699 *vpp = NULL;
700 return (error);
701 }
702
703
704 #define NUMPARMS 23
705
706 kdebug_lookup(dp, cnp)
707 struct vnode *dp;
708 struct componentname *cnp;
709 {
710 register int i, n;
711 register int dbg_namelen;
712 register int save_dbg_namelen;
713 register char *dbg_nameptr;
714 long dbg_parms[NUMPARMS];
715 char dbg_buf[4];
716 static char *dbg_filler = ">>>>";
717
718 /* Collect the pathname for tracing */
719 dbg_namelen = (cnp->cn_nameptr - cnp->cn_pnbuf) + cnp->cn_namelen;
720 dbg_nameptr = cnp->cn_nameptr + cnp->cn_namelen;
721
722 if (dbg_namelen > sizeof(dbg_parms))
723 dbg_namelen = sizeof(dbg_parms);
724 dbg_nameptr -= dbg_namelen;
725 save_dbg_namelen = dbg_namelen;
726
727 i = 0;
728
729 while (dbg_namelen > 0) {
730 if (dbg_namelen >= 4) {
731 dbg_parms[i++] = *(long *)dbg_nameptr;
732 dbg_nameptr += sizeof(long);
733 dbg_namelen -= sizeof(long);
734 } else {
735 for (n = 0; n < dbg_namelen; n++)
736 dbg_buf[n] = *dbg_nameptr++;
737 while (n <= 3) {
738 if (*dbg_nameptr)
739 dbg_buf[n++] = '>';
740 else
741 dbg_buf[n++] = 0;
742 }
743 dbg_parms[i++] = *(long *)&dbg_buf[0];
744
745 break;
746 }
747 }
748 while (i < NUMPARMS) {
749 if (*dbg_nameptr)
750 dbg_parms[i++] = *(long *)dbg_filler;
751 else
752 dbg_parms[i++] = 0;
753 }
754
755 KERNEL_DEBUG_CONSTANT((FSDBG_CODE(DBG_FSRW,36)) | DBG_FUNC_NONE,
756 dp, dbg_parms[0], dbg_parms[1], dbg_parms[2], 0);
757
758 for (dbg_namelen = save_dbg_namelen-12, i=3;
759 dbg_namelen > 0;
760 dbg_namelen -=(4 * sizeof(long)))
761 {
762 KERNEL_DEBUG_CONSTANT((FSDBG_CODE(DBG_FSRW,36)) | DBG_FUNC_NONE,
763 dbg_parms[i++], dbg_parms[i++], dbg_parms[i++], dbg_parms[i++], 0);
764 }
765 }