123401Smckusick /*
263180Sbostic * Copyright (c) 1982, 1986, 1989, 1993
363180Sbostic * The Regents of the University of California. All rights reserved.
465771Sbostic * (c) UNIX System Laboratories, Inc.
565771Sbostic * All or some portions of this file are derived from material licensed
665771Sbostic * to the University of California by American Telephone and Telegraph
765771Sbostic * Co. or Unix System Laboratories, Inc. and are reproduced herein with
865771Sbostic * the permission of UNIX System Laboratories, Inc.
923401Smckusick *
1044457Sbostic * %sccs.include.redist.c%
1137715Smckusick *
12*69736Smckusick * @(#)vfs_lookup.c 8.10 (Berkeley) 05/27/95
1323401Smckusick */
1430Sbill
1556517Sbostic #include <sys/param.h>
1656517Sbostic #include <sys/syslimits.h>
1756517Sbostic #include <sys/time.h>
1856517Sbostic #include <sys/namei.h>
1956517Sbostic #include <sys/vnode.h>
2056517Sbostic #include <sys/mount.h>
2156517Sbostic #include <sys/errno.h>
2256517Sbostic #include <sys/malloc.h>
2356517Sbostic #include <sys/filedesc.h>
2456517Sbostic #include <sys/proc.h>
2537715Smckusick
2637582Smarc #ifdef KTRACE
2756517Sbostic #include <sys/ktrace.h>
2837582Smarc #endif
2930Sbill
3030Sbill /*
3127268Smckusick * Convert a pathname into a pointer to a locked inode.
3230Sbill *
3316688Smckusick * The FOLLOW flag is set when symbolic links are to be followed
349166Ssam * when they occur at the end of the name translation process.
3527268Smckusick * Symbolic links are always followed for all other pathname
3627268Smckusick * components other than the last.
379166Ssam *
3827268Smckusick * The segflg defines whether the name is to be copied from user
3927268Smckusick * space or kernel space.
4027268Smckusick *
4115798Smckusick * Overall outline of namei:
4215798Smckusick *
437534Sroot * copy in name
447534Sroot * get starting directory
4549736Smckusick * while (!done && !error) {
4649736Smckusick * call lookup to search path.
4749736Smckusick * if symbolic link, massage name in buffer and continue
4849736Smckusick * }
4949736Smckusick */
5052633Sheideman int
namei(ndp)5152633Sheideman namei(ndp)
5249736Smckusick register struct nameidata *ndp;
5349736Smckusick {
5449736Smckusick register struct filedesc *fdp; /* pointer to file descriptor state */
5549736Smckusick register char *cp; /* pointer into pathname argument */
5649736Smckusick register struct vnode *dp; /* the directory we are searching */
5749736Smckusick struct iovec aiov; /* uio for reading symbolic links */
5849736Smckusick struct uio auio;
5949736Smckusick int error, linklen;
6052633Sheideman struct componentname *cnp = &ndp->ni_cnd;
6169409Smckusick struct proc *p = cnp->cn_proc;
6249736Smckusick
6352633Sheideman ndp->ni_cnd.cn_cred = ndp->ni_cnd.cn_proc->p_ucred;
6452633Sheideman #ifdef DIAGNOSTIC
6552633Sheideman if (!cnp->cn_cred || !cnp->cn_proc)
6652633Sheideman panic ("namei: bad cred/proc");
6752633Sheideman if (cnp->cn_nameiop & (~OPMASK))
6852633Sheideman panic ("namei: nameiop contaminated with flags");
6952633Sheideman if (cnp->cn_flags & OPMASK)
7052633Sheideman panic ("namei: flags contaminated with nameiops");
7152633Sheideman #endif
7252633Sheideman fdp = cnp->cn_proc->p_fd;
7349736Smckusick
7449736Smckusick /*
7549736Smckusick * Get a buffer for the name to be translated, and copy the
7649736Smckusick * name into the buffer.
7749736Smckusick */
7852633Sheideman if ((cnp->cn_flags & HASBUF) == 0)
7952633Sheideman MALLOC(cnp->cn_pnbuf, caddr_t, MAXPATHLEN, M_NAMEI, M_WAITOK);
8049736Smckusick if (ndp->ni_segflg == UIO_SYSSPACE)
8152633Sheideman error = copystr(ndp->ni_dirp, cnp->cn_pnbuf,
8249736Smckusick MAXPATHLEN, &ndp->ni_pathlen);
8349736Smckusick else
8452633Sheideman error = copyinstr(ndp->ni_dirp, cnp->cn_pnbuf,
8549736Smckusick MAXPATHLEN, &ndp->ni_pathlen);
8649736Smckusick if (error) {
8752633Sheideman free(cnp->cn_pnbuf, M_NAMEI);
8849736Smckusick ndp->ni_vp = NULL;
8949736Smckusick return (error);
9049736Smckusick }
9149736Smckusick ndp->ni_loopcnt = 0;
9249736Smckusick #ifdef KTRACE
9352633Sheideman if (KTRPOINT(cnp->cn_proc, KTR_NAMEI))
9452633Sheideman ktrnamei(cnp->cn_proc->p_tracep, cnp->cn_pnbuf);
9549736Smckusick #endif
9649736Smckusick
9749736Smckusick /*
9849736Smckusick * Get starting point for the translation.
9949736Smckusick */
10049736Smckusick if ((ndp->ni_rootdir = fdp->fd_rdir) == NULL)
10164414Sbostic ndp->ni_rootdir = rootvnode;
10249736Smckusick dp = fdp->fd_cdir;
10349736Smckusick VREF(dp);
10449736Smckusick for (;;) {
10549736Smckusick /*
10649736Smckusick * Check if root directory should replace current directory.
10749736Smckusick * Done at start of translation and after symbolic link.
10849736Smckusick */
10952633Sheideman cnp->cn_nameptr = cnp->cn_pnbuf;
11052633Sheideman if (*(cnp->cn_nameptr) == '/') {
11149736Smckusick vrele(dp);
11252633Sheideman while (*(cnp->cn_nameptr) == '/') {
11352633Sheideman cnp->cn_nameptr++;
11449736Smckusick ndp->ni_pathlen--;
11549736Smckusick }
11649736Smckusick dp = ndp->ni_rootdir;
11749736Smckusick VREF(dp);
11849736Smckusick }
11949736Smckusick ndp->ni_startdir = dp;
12052633Sheideman if (error = lookup(ndp)) {
12152633Sheideman FREE(cnp->cn_pnbuf, M_NAMEI);
12249736Smckusick return (error);
12349736Smckusick }
12449736Smckusick /*
12549736Smckusick * Check for symbolic link
12649736Smckusick */
12752633Sheideman if ((cnp->cn_flags & ISSYMLINK) == 0) {
12852633Sheideman if ((cnp->cn_flags & (SAVENAME | SAVESTART)) == 0)
12952633Sheideman FREE(cnp->cn_pnbuf, M_NAMEI);
13049736Smckusick else
13152633Sheideman cnp->cn_flags |= HASBUF;
13249736Smckusick return (0);
13349736Smckusick }
13452633Sheideman if ((cnp->cn_flags & LOCKPARENT) && ndp->ni_pathlen == 1)
13569409Smckusick VOP_UNLOCK(ndp->ni_dvp, 0, p);
13649736Smckusick if (ndp->ni_loopcnt++ >= MAXSYMLINKS) {
13749736Smckusick error = ELOOP;
13849736Smckusick break;
13949736Smckusick }
14049736Smckusick if (ndp->ni_pathlen > 1)
14149736Smckusick MALLOC(cp, char *, MAXPATHLEN, M_NAMEI, M_WAITOK);
14249736Smckusick else
14352633Sheideman cp = cnp->cn_pnbuf;
14449736Smckusick aiov.iov_base = cp;
14549736Smckusick aiov.iov_len = MAXPATHLEN;
14649736Smckusick auio.uio_iov = &aiov;
14749736Smckusick auio.uio_iovcnt = 1;
14849736Smckusick auio.uio_offset = 0;
14949736Smckusick auio.uio_rw = UIO_READ;
15049736Smckusick auio.uio_segflg = UIO_SYSSPACE;
15149736Smckusick auio.uio_procp = (struct proc *)0;
15249736Smckusick auio.uio_resid = MAXPATHLEN;
15352633Sheideman if (error = VOP_READLINK(ndp->ni_vp, &auio, cnp->cn_cred)) {
15449736Smckusick if (ndp->ni_pathlen > 1)
15549736Smckusick free(cp, M_NAMEI);
15649736Smckusick break;
15749736Smckusick }
15849736Smckusick linklen = MAXPATHLEN - auio.uio_resid;
15949736Smckusick if (linklen + ndp->ni_pathlen >= MAXPATHLEN) {
16049736Smckusick if (ndp->ni_pathlen > 1)
16149736Smckusick free(cp, M_NAMEI);
16249736Smckusick error = ENAMETOOLONG;
16349736Smckusick break;
16449736Smckusick }
16549736Smckusick if (ndp->ni_pathlen > 1) {
16649736Smckusick bcopy(ndp->ni_next, cp + linklen, ndp->ni_pathlen);
16752633Sheideman FREE(cnp->cn_pnbuf, M_NAMEI);
16852633Sheideman cnp->cn_pnbuf = cp;
16949736Smckusick } else
17052633Sheideman cnp->cn_pnbuf[linklen] = '\0';
17149736Smckusick ndp->ni_pathlen += linklen;
17249736Smckusick vput(ndp->ni_vp);
17349736Smckusick dp = ndp->ni_dvp;
17449736Smckusick }
17552633Sheideman FREE(cnp->cn_pnbuf, M_NAMEI);
17649736Smckusick vrele(ndp->ni_dvp);
17749736Smckusick vput(ndp->ni_vp);
17849736Smckusick ndp->ni_vp = NULL;
17949736Smckusick return (error);
18049736Smckusick }
18149736Smckusick
18249736Smckusick /*
18349736Smckusick * Search a pathname.
18449736Smckusick * This is a very central and rather complicated routine.
18549736Smckusick *
18649736Smckusick * The pathname is pointed to by ni_ptr and is of length ni_pathlen.
18749736Smckusick * The starting directory is taken from ni_startdir. The pathname is
18849736Smckusick * descended until done, or a symbolic link is encountered. The variable
18949736Smckusick * ni_more is clear if the path is completed; it is set to one if a
19049736Smckusick * symbolic link needing interpretation is encountered.
19149736Smckusick *
19249736Smckusick * The flag argument is LOOKUP, CREATE, RENAME, or DELETE depending on
19349736Smckusick * whether the name is to be looked up, created, renamed, or deleted.
19449736Smckusick * When CREATE, RENAME, or DELETE is specified, information usable in
19549736Smckusick * creating, renaming, or deleting a directory entry may be calculated.
19649736Smckusick * If flag has LOCKPARENT or'ed into it, the parent directory is returned
19749736Smckusick * locked. If flag has WANTPARENT or'ed into it, the parent directory is
19849736Smckusick * returned unlocked. Otherwise the parent directory is not returned. If
19949736Smckusick * the target of the pathname exists and LOCKLEAF is or'ed into the flag
20049736Smckusick * the target is returned locked, otherwise it is returned unlocked.
20149736Smckusick * When creating or renaming and LOCKPARENT is specified, the target may not
20249736Smckusick * be ".". When deleting and LOCKPARENT is specified, the target may be ".".
20349736Smckusick *
20449736Smckusick * Overall outline of lookup:
20549736Smckusick *
2067534Sroot * dirloop:
20749736Smckusick * identify next component of name at ndp->ni_ptr
2087534Sroot * handle degenerate case where name is null string
20949736Smckusick * if .. and crossing mount points and on mounted filesys, find parent
21049736Smckusick * call VOP_LOOKUP routine for next component name
21149736Smckusick * directory vnode returned in ni_dvp, unlocked unless LOCKPARENT set
21249736Smckusick * component vnode returned in ni_vp (if it exists), locked.
21349736Smckusick * if result vnode is mounted on and crossing mount points,
21449736Smckusick * find mounted on vnode
2157534Sroot * if more components of name, do next level at dirloop
21649736Smckusick * return the answer in ni_vp, locked if LOCKLEAF set
21749736Smckusick * if LOCKPARENT set, return locked parent in ni_dvp
21849736Smckusick * if WANTPARENT set, return unlocked parent in ni_dvp
21930Sbill */
22052633Sheideman int
lookup(ndp)22152633Sheideman lookup(ndp)
22216688Smckusick register struct nameidata *ndp;
22330Sbill {
2247534Sroot register char *cp; /* pointer into pathname argument */
22537715Smckusick register struct vnode *dp = 0; /* the directory we are searching */
22637715Smckusick struct vnode *tdp; /* saved dp */
22737715Smckusick struct mount *mp; /* mount table entry */
22818109Smckusick int docache; /* == 0 do not cache last component */
22937715Smckusick int wantparent; /* 1 => wantparent or lockparent flag */
23052181Smckusick int rdonly; /* lookup read-only flag bit */
23137715Smckusick int error = 0;
23252230Sheideman struct componentname *cnp = &ndp->ni_cnd;
23369409Smckusick struct proc *p = cnp->cn_proc;
23430Sbill
23541337Smckusick /*
23641337Smckusick * Setup: break out flag bits into variables.
23741337Smckusick */
23852633Sheideman wantparent = cnp->cn_flags & (LOCKPARENT | WANTPARENT);
23952230Sheideman docache = (cnp->cn_flags & NOCACHE) ^ NOCACHE;
24052633Sheideman if (cnp->cn_nameiop == DELETE ||
24152633Sheideman (wantparent && cnp->cn_nameiop != CREATE))
24215798Smckusick docache = 0;
24352230Sheideman rdonly = cnp->cn_flags & RDONLY;
24449736Smckusick ndp->ni_dvp = NULL;
24552230Sheideman cnp->cn_flags &= ~ISSYMLINK;
24649736Smckusick dp = ndp->ni_startdir;
24749736Smckusick ndp->ni_startdir = NULLVP;
24869409Smckusick vn_lock(dp, LK_EXCLUSIVE | LK_RETRY, p);
2497534Sroot
2506571Smckusic dirloop:
25130Sbill /*
25249736Smckusick * Search a new directory.
25349736Smckusick *
25452230Sheideman * The cn_hash value is for use by vfs_cache.
25549736Smckusick * The last component of the filename is left accessible via
25652230Sheideman * cnp->cn_nameptr for callers that need the name. Callers needing
25749736Smckusick * the name set the SAVENAME flag. When done, they assume
25849736Smckusick * responsibility for freeing the pathname buffer.
2597534Sroot */
26055091Spendry cnp->cn_consume = 0;
26152230Sheideman cnp->cn_hash = 0;
26252230Sheideman for (cp = cnp->cn_nameptr; *cp != 0 && *cp != '/'; cp++)
26352230Sheideman cnp->cn_hash += (unsigned char)*cp;
26452230Sheideman cnp->cn_namelen = cp - cnp->cn_nameptr;
26557653Smckusick if (cnp->cn_namelen > NAME_MAX) {
26649736Smckusick error = ENAMETOOLONG;
26749736Smckusick goto bad;
26849736Smckusick }
26937743Smckusick #ifdef NAMEI_DIAGNOSTIC
27049736Smckusick { char c = *cp;
27149736Smckusick *cp = '\0';
27252230Sheideman printf("{%s}: ", cnp->cn_nameptr);
27349736Smckusick *cp = c; }
27437743Smckusick #endif
27552230Sheideman ndp->ni_pathlen -= cnp->cn_namelen;
27649736Smckusick ndp->ni_next = cp;
27752230Sheideman cnp->cn_flags |= MAKEENTRY;
27818109Smckusick if (*cp == '\0' && docache == 0)
27952230Sheideman cnp->cn_flags &= ~MAKEENTRY;
28052230Sheideman if (cnp->cn_namelen == 2 &&
28155181Smckusick cnp->cn_nameptr[1] == '.' && cnp->cn_nameptr[0] == '.')
28252230Sheideman cnp->cn_flags |= ISDOTDOT;
28355181Smckusick else
28455181Smckusick cnp->cn_flags &= ~ISDOTDOT;
28552230Sheideman if (*ndp->ni_next == 0)
28652230Sheideman cnp->cn_flags |= ISLASTCN;
28755181Smckusick else
28855181Smckusick cnp->cn_flags &= ~ISLASTCN;
2897534Sroot
29052230Sheideman
2917534Sroot /*
2927534Sroot * Check for degenerate name (e.g. / or "")
2937534Sroot * which is a way of talking about a directory,
2947534Sroot * e.g. like "/." or ".".
2957534Sroot */
29652230Sheideman if (cnp->cn_nameptr[0] == '\0') {
29767207Smckusick if (dp->v_type != VDIR) {
29867207Smckusick error = ENOTDIR;
29967207Smckusick goto bad;
30067207Smckusick }
30159371Smckusick if (cnp->cn_nameiop != LOOKUP) {
30237715Smckusick error = EISDIR;
3037534Sroot goto bad;
3045972Swnj }
30559371Smckusick if (wantparent) {
30659371Smckusick ndp->ni_dvp = dp;
30766128Spendry VREF(dp);
30859371Smckusick }
30959371Smckusick ndp->ni_vp = dp;
31059371Smckusick if (!(cnp->cn_flags & (LOCKPARENT | LOCKLEAF)))
31169409Smckusick VOP_UNLOCK(dp, 0, p);
31252230Sheideman if (cnp->cn_flags & SAVESTART)
31349736Smckusick panic("lookup: SAVESTART");
31452633Sheideman return (0);
3155972Swnj }
3167534Sroot
3176571Smckusic /*
31837715Smckusick * Handle "..": two special cases.
31937715Smckusick * 1. If at root directory (e.g. after chroot)
32056313Shibler * or at absolute root directory
32137715Smckusick * then ignore it so can't get out.
32237715Smckusick * 2. If this vnode is the root of a mounted
32349736Smckusick * filesystem, then replace it with the
32437715Smckusick * vnode which was mounted on so we take the
32537715Smckusick * .. in the other file system.
32636547Smckusick */
32752230Sheideman if (cnp->cn_flags & ISDOTDOT) {
32836547Smckusick for (;;) {
32964414Sbostic if (dp == ndp->ni_rootdir || dp == rootvnode) {
33037715Smckusick ndp->ni_dvp = dp;
33138390Smckusick ndp->ni_vp = dp;
33238347Smckusick VREF(dp);
33337715Smckusick goto nextname;
33436547Smckusick }
33541337Smckusick if ((dp->v_flag & VROOT) == 0 ||
33652230Sheideman (cnp->cn_flags & NOCROSSMOUNT))
33736547Smckusick break;
33837715Smckusick tdp = dp;
33941400Smckusick dp = dp->v_mount->mnt_vnodecovered;
34037715Smckusick vput(tdp);
34138390Smckusick VREF(dp);
34269409Smckusick vn_lock(dp, LK_EXCLUSIVE | LK_RETRY, p);
34336547Smckusick }
34436547Smckusick }
34536547Smckusick
34636547Smckusick /*
34715798Smckusick * We now have a segment name to search for, and a directory to search.
34815798Smckusick */
34955451Spendry unionlookup:
35052230Sheideman ndp->ni_dvp = dp;
351*69736Smckusick ndp->ni_vp = NULL;
35252230Sheideman if (error = VOP_LOOKUP(dp, &ndp->ni_vp, cnp)) {
35349736Smckusick #ifdef DIAGNOSTIC
35437715Smckusick if (ndp->ni_vp != NULL)
35537715Smckusick panic("leaf should be empty");
35649736Smckusick #endif
35737582Smarc #ifdef NAMEI_DIAGNOSTIC
35837715Smckusick printf("not found\n");
35937582Smarc #endif
36055451Spendry if ((error == ENOENT) &&
36155451Spendry (dp->v_flag & VROOT) &&
36255451Spendry (dp->v_mount->mnt_flag & MNT_UNION)) {
36355451Spendry tdp = dp;
36455451Spendry dp = dp->v_mount->mnt_vnodecovered;
36555451Spendry vput(tdp);
36655451Spendry VREF(dp);
36769409Smckusick vn_lock(dp, LK_EXCLUSIVE | LK_RETRY, p);
36855451Spendry goto unionlookup;
36955451Spendry }
37055451Spendry
37152798Smckusick if (error != EJUSTRETURN)
37238581Smckusick goto bad;
3735972Swnj /*
37437715Smckusick * If creating and at end of pathname, then can consider
37537715Smckusick * allowing file to be created.
3765972Swnj */
377*69736Smckusick if (rdonly) {
37837715Smckusick error = EROFS;
3797534Sroot goto bad;
38038581Smckusick }
3815972Swnj /*
38237715Smckusick * We return with ni_vp NULL to indicate that the entry
38337715Smckusick * doesn't currently exist, leaving a pointer to the
38437715Smckusick * (possibly locked) directory inode in ndp->ni_dvp.
3855972Swnj */
38652230Sheideman if (cnp->cn_flags & SAVESTART) {
38749736Smckusick ndp->ni_startdir = ndp->ni_dvp;
38849736Smckusick VREF(ndp->ni_startdir);
38949736Smckusick }
39052633Sheideman return (0);
3917534Sroot }
39237582Smarc #ifdef NAMEI_DIAGNOSTIC
39337715Smckusick printf("found\n");
39437582Smarc #endif
3957534Sroot
39655091Spendry /*
39755091Spendry * Take into account any additional components consumed by
39855091Spendry * the underlying filesystem.
39955091Spendry */
40055091Spendry if (cnp->cn_consume > 0) {
40155091Spendry cnp->cn_nameptr += cnp->cn_consume;
40255091Spendry ndp->ni_next += cnp->cn_consume;
40355091Spendry ndp->ni_pathlen -= cnp->cn_consume;
40455091Spendry cnp->cn_consume = 0;
40555091Spendry }
40655091Spendry
40749736Smckusick dp = ndp->ni_vp;
4087534Sroot /*
40937715Smckusick * Check to see if the vnode has been mounted on;
41037715Smckusick * if so find the root of the mounted file system.
4117534Sroot */
41241337Smckusick while (dp->v_type == VDIR && (mp = dp->v_mountedhere) &&
41352230Sheideman (cnp->cn_flags & NOCROSSMOUNT) == 0) {
41469578Smckusick if (vfs_busy(mp, 0, 0, p))
41552634Smckusick continue;
41669578Smckusick error = VFS_ROOT(mp, &tdp);
41769578Smckusick vfs_unbusy(mp, p);
41869578Smckusick if (error)
4197534Sroot goto bad2;
42037715Smckusick vput(dp);
42137715Smckusick ndp->ni_vp = dp = tdp;
42230Sbill }
4237534Sroot
42467959Smckusick /*
42567959Smckusick * Check for symbolic link
42667959Smckusick */
42767959Smckusick if ((dp->v_type == VLNK) &&
42867959Smckusick ((cnp->cn_flags & FOLLOW) || *ndp->ni_next == '/')) {
42967959Smckusick cnp->cn_flags |= ISSYMLINK;
43067959Smckusick return (0);
43167959Smckusick }
43267959Smckusick
43337715Smckusick nextname:
43430Sbill /*
4357534Sroot * Not a symbolic link. If more pathname,
4367534Sroot * continue at next component, else return.
43730Sbill */
43849736Smckusick if (*ndp->ni_next == '/') {
43952230Sheideman cnp->cn_nameptr = ndp->ni_next;
44052230Sheideman while (*cnp->cn_nameptr == '/') {
44152230Sheideman cnp->cn_nameptr++;
44237715Smckusick ndp->ni_pathlen--;
44337715Smckusick }
44437715Smckusick vrele(ndp->ni_dvp);
4457534Sroot goto dirloop;
44630Sbill }
4477534Sroot /*
448*69736Smckusick * Disallow directory write attempts on read-only file systems.
4497534Sroot */
450*69736Smckusick if (rdonly &&
451*69736Smckusick (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME)) {
452*69736Smckusick error = EROFS;
453*69736Smckusick goto bad2;
45438267Smckusick }
45552230Sheideman if (cnp->cn_flags & SAVESTART) {
45649736Smckusick ndp->ni_startdir = ndp->ni_dvp;
45749736Smckusick VREF(ndp->ni_startdir);
45849736Smckusick }
45937715Smckusick if (!wantparent)
46037715Smckusick vrele(ndp->ni_dvp);
46152230Sheideman if ((cnp->cn_flags & LOCKLEAF) == 0)
46269409Smckusick VOP_UNLOCK(dp, 0, p);
46352633Sheideman return (0);
4647534Sroot
46537715Smckusick bad2:
46652230Sheideman if ((cnp->cn_flags & LOCKPARENT) && *ndp->ni_next == '\0')
46769409Smckusick VOP_UNLOCK(ndp->ni_dvp, 0, p);
46837715Smckusick vrele(ndp->ni_dvp);
46937715Smckusick bad:
47037715Smckusick vput(dp);
47137715Smckusick ndp->ni_vp = NULL;
47252633Sheideman return (error);
4735972Swnj }
47452230Sheideman
47569083Smckusick /*
47669083Smckusick * relookup - lookup a path name component
47769083Smckusick * Used by lookup to re-aquire things.
47869083Smckusick */
47969083Smckusick int
relookup(dvp,vpp,cnp)48069083Smckusick relookup(dvp, vpp, cnp)
48169083Smckusick struct vnode *dvp, **vpp;
48269083Smckusick struct componentname *cnp;
48369083Smckusick {
48469409Smckusick struct proc *p = cnp->cn_proc;
48569409Smckusick struct vnode *dp = 0; /* the directory we are searching */
48669083Smckusick int docache; /* == 0 do not cache last component */
48769083Smckusick int wantparent; /* 1 => wantparent or lockparent flag */
48869083Smckusick int rdonly; /* lookup read-only flag bit */
48969083Smckusick int error = 0;
49069083Smckusick #ifdef NAMEI_DIAGNOSTIC
49169083Smckusick int newhash; /* DEBUG: check name hash */
49269083Smckusick char *cp; /* DEBUG: check name ptr/len */
49369083Smckusick #endif
49452230Sheideman
49569083Smckusick /*
49669083Smckusick * Setup: break out flag bits into variables.
49769083Smckusick */
49869083Smckusick wantparent = cnp->cn_flags & (LOCKPARENT|WANTPARENT);
49969083Smckusick docache = (cnp->cn_flags & NOCACHE) ^ NOCACHE;
50069083Smckusick if (cnp->cn_nameiop == DELETE ||
50169083Smckusick (wantparent && cnp->cn_nameiop != CREATE))
50269083Smckusick docache = 0;
50369083Smckusick rdonly = cnp->cn_flags & RDONLY;
50469083Smckusick cnp->cn_flags &= ~ISSYMLINK;
50569083Smckusick dp = dvp;
50669409Smckusick vn_lock(dp, LK_EXCLUSIVE | LK_RETRY, p);
50769083Smckusick
50869083Smckusick /* dirloop: */
50969083Smckusick /*
51069083Smckusick * Search a new directory.
51169083Smckusick *
51269083Smckusick * The cn_hash value is for use by vfs_cache.
51369083Smckusick * The last component of the filename is left accessible via
51469083Smckusick * cnp->cn_nameptr for callers that need the name. Callers needing
51569083Smckusick * the name set the SAVENAME flag. When done, they assume
51669083Smckusick * responsibility for freeing the pathname buffer.
51769083Smckusick */
51869083Smckusick #ifdef NAMEI_DIAGNOSTIC
51969083Smckusick for (newhash = 0, cp = cnp->cn_nameptr; *cp != 0 && *cp != '/'; cp++)
52069083Smckusick newhash += (unsigned char)*cp;
52169083Smckusick if (newhash != cnp->cn_hash)
52269083Smckusick panic("relookup: bad hash");
52369083Smckusick if (cnp->cn_namelen != cp - cnp->cn_nameptr)
52469083Smckusick panic ("relookup: bad len");
52569083Smckusick if (*cp != 0)
52669083Smckusick panic("relookup: not last component");
52769083Smckusick printf("{%s}: ", cnp->cn_nameptr);
52869083Smckusick #endif
52969083Smckusick
53069083Smckusick /*
53169083Smckusick * Check for degenerate name (e.g. / or "")
53269083Smckusick * which is a way of talking about a directory,
53369083Smckusick * e.g. like "/." or ".".
53469083Smckusick */
53569083Smckusick if (cnp->cn_nameptr[0] == '\0') {
53669083Smckusick if (cnp->cn_nameiop != LOOKUP || wantparent) {
53769083Smckusick error = EISDIR;
53869083Smckusick goto bad;
53969083Smckusick }
54069083Smckusick if (dp->v_type != VDIR) {
54169083Smckusick error = ENOTDIR;
54269083Smckusick goto bad;
54369083Smckusick }
54469083Smckusick if (!(cnp->cn_flags & LOCKLEAF))
54569409Smckusick VOP_UNLOCK(dp, 0, p);
54669083Smckusick *vpp = dp;
54769083Smckusick if (cnp->cn_flags & SAVESTART)
54869083Smckusick panic("lookup: SAVESTART");
54969083Smckusick return (0);
55069083Smckusick }
55169083Smckusick
55269083Smckusick if (cnp->cn_flags & ISDOTDOT)
55369083Smckusick panic ("relookup: lookup on dot-dot");
55469083Smckusick
55569083Smckusick /*
55669083Smckusick * We now have a segment name to search for, and a directory to search.
55769083Smckusick */
55869083Smckusick if (error = VOP_LOOKUP(dp, vpp, cnp)) {
55969083Smckusick #ifdef DIAGNOSTIC
56069083Smckusick if (*vpp != NULL)
56169083Smckusick panic("leaf should be empty");
56269083Smckusick #endif
56369083Smckusick if (error != EJUSTRETURN)
56469083Smckusick goto bad;
56569083Smckusick /*
56669083Smckusick * If creating and at end of pathname, then can consider
56769083Smckusick * allowing file to be created.
56869083Smckusick */
569*69736Smckusick if (rdonly) {
57069083Smckusick error = EROFS;
57169083Smckusick goto bad;
57269083Smckusick }
57369083Smckusick /* ASSERT(dvp == ndp->ni_startdir) */
57469083Smckusick if (cnp->cn_flags & SAVESTART)
57569083Smckusick VREF(dvp);
57669083Smckusick /*
57769083Smckusick * We return with ni_vp NULL to indicate that the entry
57869083Smckusick * doesn't currently exist, leaving a pointer to the
57969083Smckusick * (possibly locked) directory inode in ndp->ni_dvp.
58069083Smckusick */
58169083Smckusick return (0);
58269083Smckusick }
58369083Smckusick dp = *vpp;
58469083Smckusick
58569083Smckusick #ifdef DIAGNOSTIC
58669083Smckusick /*
58769083Smckusick * Check for symbolic link
58869083Smckusick */
58969083Smckusick if (dp->v_type == VLNK && (cnp->cn_flags & FOLLOW))
59069083Smckusick panic ("relookup: symlink found.\n");
59169083Smckusick #endif
59269083Smckusick
59369083Smckusick /*
594*69736Smckusick * Disallow directory write attempts on read-only file systems.
59569083Smckusick */
596*69736Smckusick if (rdonly &&
597*69736Smckusick (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME)) {
598*69736Smckusick error = EROFS;
599*69736Smckusick goto bad2;
60069083Smckusick }
60169083Smckusick /* ASSERT(dvp == ndp->ni_startdir) */
60269083Smckusick if (cnp->cn_flags & SAVESTART)
60369083Smckusick VREF(dvp);
60469083Smckusick
60569083Smckusick if (!wantparent)
60669083Smckusick vrele(dvp);
60769083Smckusick if ((cnp->cn_flags & LOCKLEAF) == 0)
60869409Smckusick VOP_UNLOCK(dp, 0, p);
60969083Smckusick return (0);
61069083Smckusick
61169083Smckusick bad2:
61269083Smckusick if ((cnp->cn_flags & LOCKPARENT) && (cnp->cn_flags & ISLASTCN))
61369409Smckusick VOP_UNLOCK(dvp, 0, p);
61469083Smckusick vrele(dvp);
61569083Smckusick bad:
61669083Smckusick vput(dp);
61769083Smckusick *vpp = NULL;
61869083Smckusick return (error);
61969083Smckusick }
620