]> git.saurik.com Git - apple/xnu.git/blob - bsd/vfs/vfs_lookup.c
xnu-124.13.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 tdp = dp;
409 dp = dp->v_mount->mnt_vnodecovered;
410 vput(tdp);
411 VREF(dp);
412 vn_lock(dp, LK_EXCLUSIVE | LK_RETRY, p);
413 }
414 }
415
416 /*
417 * We now have a segment name to search for, and a directory to search.
418 */
419 unionlookup:
420 ndp->ni_dvp = dp;
421 ndp->ni_vp = NULL;
422 if (error = VOP_LOOKUP(dp, &ndp->ni_vp, cnp)) {
423 #if DIAGNOSTIC
424 if (ndp->ni_vp != NULL)
425 panic("leaf should be empty");
426 #endif
427 #ifdef NAMEI_DIAGNOSTIC
428 printf("not found\n");
429 #endif
430 if ((error == ENOENT) &&
431 (dp->v_flag & VROOT) &&
432 (dp->v_mount->mnt_flag & MNT_UNION)) {
433 tdp = dp;
434 dp = dp->v_mount->mnt_vnodecovered;
435 vput(tdp);
436 VREF(dp);
437 vn_lock(dp, LK_EXCLUSIVE | LK_RETRY, p);
438 goto unionlookup;
439 }
440
441 if (error != EJUSTRETURN)
442 goto bad;
443 /*
444 * If creating and at end of pathname, then can consider
445 * allowing file to be created.
446 */
447 if (rdonly) {
448 error = EROFS;
449 goto bad;
450 }
451 /*
452 * We return with ni_vp NULL to indicate that the entry
453 * doesn't currently exist, leaving a pointer to the
454 * (possibly locked) directory inode in ndp->ni_dvp.
455 */
456 if (cnp->cn_flags & SAVESTART) {
457 ndp->ni_startdir = ndp->ni_dvp;
458 VREF(ndp->ni_startdir);
459 }
460 if (kdebug_enable)
461 kdebug_lookup(ndp->ni_dvp, cnp);
462 return (0);
463 }
464 #ifdef NAMEI_DIAGNOSTIC
465 printf("found\n");
466 #endif
467
468 /*
469 * Take into account any additional components consumed by
470 * the underlying filesystem.
471 */
472 if (cnp->cn_consume > 0) {
473 cnp->cn_nameptr += cnp->cn_consume;
474 ndp->ni_next += cnp->cn_consume;
475 ndp->ni_pathlen -= cnp->cn_consume;
476 cnp->cn_consume = 0;
477 }
478
479 dp = ndp->ni_vp;
480 /*
481 * Check to see if the vnode has been mounted on;
482 * if so find the root of the mounted file system.
483 */
484 while (dp->v_type == VDIR && (mp = dp->v_mountedhere) &&
485 (cnp->cn_flags & NOCROSSMOUNT) == 0) {
486 if (vfs_busy(mp, 0, 0, p))
487 continue;
488 error = VFS_ROOT(mp, &tdp);
489 vfs_unbusy(mp, p);
490 if (error)
491 goto bad2;
492 vput(dp);
493 ndp->ni_vp = dp = tdp;
494 }
495
496 /*
497 * Check for symbolic link
498 */
499 if ((dp->v_type == VLNK) &&
500 ((cnp->cn_flags & FOLLOW) || *ndp->ni_next == '/')) {
501 cnp->cn_flags |= ISSYMLINK;
502 return (0);
503 }
504
505 nextname:
506 /*
507 * Not a symbolic link. If more pathname,
508 * continue at next component, else return.
509 */
510 if (*ndp->ni_next == '/') {
511 cnp->cn_nameptr = ndp->ni_next;
512 while (*cnp->cn_nameptr == '/') {
513 cnp->cn_nameptr++;
514 ndp->ni_pathlen--;
515 }
516 vrele(ndp->ni_dvp);
517 goto dirloop;
518 }
519
520 /*
521 * Disallow directory write attempts on read-only file systems.
522 */
523 if (rdonly &&
524 (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME)) {
525 error = EROFS;
526 goto bad2;
527 }
528 if (cnp->cn_flags & SAVESTART) {
529 ndp->ni_startdir = ndp->ni_dvp;
530 VREF(ndp->ni_startdir);
531 }
532 if (!wantparent)
533 vrele(ndp->ni_dvp);
534 if ((cnp->cn_flags & LOCKLEAF) == 0)
535 VOP_UNLOCK(dp, 0, p);
536 if (kdebug_enable)
537 kdebug_lookup(dp, cnp);
538 return (0);
539
540 bad2:
541 if ((cnp->cn_flags & LOCKPARENT) && *ndp->ni_next == '\0')
542 VOP_UNLOCK(ndp->ni_dvp, 0, p);
543 vrele(ndp->ni_dvp);
544 bad:
545 vput(dp);
546 ndp->ni_vp = NULL;
547 if (kdebug_enable)
548 kdebug_lookup(dp, cnp);
549 return (error);
550 }
551
552 /*
553 * relookup - lookup a path name component
554 * Used by lookup to re-aquire things.
555 */
556 int
557 relookup(dvp, vpp, cnp)
558 struct vnode *dvp, **vpp;
559 struct componentname *cnp;
560 {
561 struct proc *p = cnp->cn_proc;
562 struct vnode *dp = 0; /* the directory we are searching */
563 int docache; /* == 0 do not cache last component */
564 int wantparent; /* 1 => wantparent or lockparent flag */
565 int rdonly; /* lookup read-only flag bit */
566 int error = 0;
567 #ifdef NAMEI_DIAGNOSTIC
568 int newhash; /* DEBUG: check name hash */
569 char *cp; /* DEBUG: check name ptr/len */
570 #endif
571
572 /*
573 * Setup: break out flag bits into variables.
574 */
575 wantparent = cnp->cn_flags & (LOCKPARENT|WANTPARENT);
576 docache = (cnp->cn_flags & NOCACHE) ^ NOCACHE;
577 if (cnp->cn_nameiop == DELETE ||
578 (wantparent && cnp->cn_nameiop != CREATE))
579 docache = 0;
580 rdonly = cnp->cn_flags & RDONLY;
581 cnp->cn_flags &= ~ISSYMLINK;
582 dp = dvp;
583 vn_lock(dp, LK_EXCLUSIVE | LK_RETRY, p);
584
585 /* dirloop: */
586 /*
587 * Search a new directory.
588 *
589 * The cn_hash value is for use by vfs_cache.
590 * The last component of the filename is left accessible via
591 * cnp->cn_nameptr for callers that need the name. Callers needing
592 * the name set the SAVENAME flag. When done, they assume
593 * responsibility for freeing the pathname buffer.
594 */
595 #ifdef NAMEI_DIAGNOSTIC
596 for (newhash = 0, cp = cnp->cn_nameptr; *cp != 0 && *cp != '/'; cp++)
597 newhash += (unsigned char)*cp;
598 if (newhash != cnp->cn_hash)
599 panic("relookup: bad hash");
600 if (cnp->cn_namelen != cp - cnp->cn_nameptr)
601 panic ("relookup: bad len");
602 if (*cp != 0)
603 panic("relookup: not last component");
604 printf("{%s}: ", cnp->cn_nameptr);
605 #endif
606
607 /*
608 * Check for degenerate name (e.g. / or "")
609 * which is a way of talking about a directory,
610 * e.g. like "/." or ".".
611 */
612 if (cnp->cn_nameptr[0] == '\0') {
613 if (cnp->cn_nameiop != LOOKUP || wantparent) {
614 error = EISDIR;
615 goto bad;
616 }
617 if (dp->v_type != VDIR) {
618 error = ENOTDIR;
619 goto bad;
620 }
621 if (!(cnp->cn_flags & LOCKLEAF))
622 VOP_UNLOCK(dp, 0, p);
623 *vpp = dp;
624 if (cnp->cn_flags & SAVESTART)
625 panic("lookup: SAVESTART");
626 return (0);
627 }
628
629 if (cnp->cn_flags & ISDOTDOT)
630 panic ("relookup: lookup on dot-dot");
631
632 /*
633 * We now have a segment name to search for, and a directory to search.
634 */
635 if (error = VOP_LOOKUP(dp, vpp, cnp)) {
636 #if DIAGNOSTIC
637 if (*vpp != NULL)
638 panic("leaf should be empty");
639 #endif
640 if (error != EJUSTRETURN)
641 goto bad;
642 /*
643 * If creating and at end of pathname, then can consider
644 * allowing file to be created.
645 */
646 if (rdonly) {
647 error = EROFS;
648 goto bad;
649 }
650 /* ASSERT(dvp == ndp->ni_startdir) */
651 if (cnp->cn_flags & SAVESTART)
652 VREF(dvp);
653 /*
654 * We return with ni_vp NULL to indicate that the entry
655 * doesn't currently exist, leaving a pointer to the
656 * (possibly locked) directory inode in ndp->ni_dvp.
657 */
658 return (0);
659 }
660 dp = *vpp;
661
662 #if DIAGNOSTIC
663 /*
664 * Check for symbolic link
665 */
666 if (dp->v_type == VLNK && (cnp->cn_flags & FOLLOW))
667 panic ("relookup: symlink found.\n");
668 #endif
669
670 /*
671 * Disallow directory write attempts on read-only file systems.
672 */
673 if (rdonly &&
674 (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME)) {
675 error = EROFS;
676 goto bad2;
677 }
678 /* ASSERT(dvp == ndp->ni_startdir) */
679 if (cnp->cn_flags & SAVESTART)
680 VREF(dvp);
681
682 if (!wantparent)
683 vrele(dvp);
684 if ((cnp->cn_flags & LOCKLEAF) == 0)
685 VOP_UNLOCK(dp, 0, p);
686 return (0);
687
688 bad2:
689 if ((cnp->cn_flags & LOCKPARENT) && (cnp->cn_flags & ISLASTCN))
690 VOP_UNLOCK(dvp, 0, p);
691 vrele(dvp);
692 bad:
693 vput(dp);
694 *vpp = NULL;
695 return (error);
696 }
697
698
699 #define NUMPARMS 7
700
701 kdebug_lookup(dp, cnp)
702 struct vnode *dp;
703 struct componentname *cnp;
704 {
705 register int i, n;
706 register int dbg_namelen;
707 register char *dbg_nameptr;
708 long dbg_parms[NUMPARMS];
709 char dbg_buf[4];
710 static char *dbg_filler = ">>>>";
711
712 /* Collect the pathname for tracing */
713 dbg_namelen = (cnp->cn_nameptr - cnp->cn_pnbuf) + cnp->cn_namelen;
714 dbg_nameptr = cnp->cn_nameptr + cnp->cn_namelen;
715
716 if (dbg_namelen > sizeof(dbg_parms))
717 dbg_namelen = sizeof(dbg_parms);
718 dbg_nameptr -= dbg_namelen;
719
720 i = 0;
721
722 while (dbg_namelen > 0) {
723 if (dbg_namelen >= 4) {
724 dbg_parms[i++] = *(long *)dbg_nameptr;
725 dbg_nameptr += sizeof(long);
726 dbg_namelen -= sizeof(long);
727 } else {
728 for (n = 0; n < dbg_namelen; n++)
729 dbg_buf[n] = *dbg_nameptr++;
730 while (n <= 3) {
731 if (*dbg_nameptr)
732 dbg_buf[n++] = '>';
733 else
734 dbg_buf[n++] = 0;
735 }
736 dbg_parms[i++] = *(long *)&dbg_buf[0];
737
738 break;
739 }
740 }
741 while (i < NUMPARMS) {
742 if (*dbg_nameptr)
743 dbg_parms[i++] = *(long *)dbg_filler;
744 else
745 dbg_parms[i++] = 0;
746 }
747 KERNEL_DEBUG_CONSTANT((FSDBG_CODE(DBG_FSRW,36)) | DBG_FUNC_NONE,
748 dp, dbg_parms[0], dbg_parms[1], dbg_parms[2], 0);
749 KERNEL_DEBUG_CONSTANT((FSDBG_CODE(DBG_FSRW,36)) | DBG_FUNC_NONE,
750 dbg_parms[3], dbg_parms[4], dbg_parms[5], dbg_parms[6], 0);
751 }