123401Smckusick /* 237715Smckusick * Copyright (c) 1982, 1986, 1989 Regents of the University of California. 337715Smckusick * All rights reserved. 423401Smckusick * 544457Sbostic * %sccs.include.redist.c% 637715Smckusick * 7*56517Sbostic * @(#)vfs_lookup.c 7.45 (Berkeley) 10/11/92 823401Smckusick */ 930Sbill 10*56517Sbostic #include <sys/param.h> 11*56517Sbostic #include <sys/syslimits.h> 12*56517Sbostic #include <sys/time.h> 13*56517Sbostic #include <sys/namei.h> 14*56517Sbostic #include <sys/vnode.h> 15*56517Sbostic #include <sys/mount.h> 16*56517Sbostic #include <sys/errno.h> 17*56517Sbostic #include <sys/malloc.h> 18*56517Sbostic #include <sys/filedesc.h> 19*56517Sbostic #include <sys/proc.h> 2037715Smckusick 2137582Smarc #ifdef KTRACE 22*56517Sbostic #include <sys/ktrace.h> 2337582Smarc #endif 2430Sbill 2530Sbill /* 2627268Smckusick * Convert a pathname into a pointer to a locked inode. 2730Sbill * 2816688Smckusick * The FOLLOW flag is set when symbolic links are to be followed 299166Ssam * when they occur at the end of the name translation process. 3027268Smckusick * Symbolic links are always followed for all other pathname 3127268Smckusick * components other than the last. 329166Ssam * 3327268Smckusick * The segflg defines whether the name is to be copied from user 3427268Smckusick * space or kernel space. 3527268Smckusick * 3615798Smckusick * Overall outline of namei: 3715798Smckusick * 387534Sroot * copy in name 397534Sroot * get starting directory 4049736Smckusick * while (!done && !error) { 4149736Smckusick * call lookup to search path. 4249736Smckusick * if symbolic link, massage name in buffer and continue 4349736Smckusick * } 4449736Smckusick */ 4552633Sheideman int 4652633Sheideman namei(ndp) 4749736Smckusick register struct nameidata *ndp; 4849736Smckusick { 4949736Smckusick register struct filedesc *fdp; /* pointer to file descriptor state */ 5049736Smckusick register char *cp; /* pointer into pathname argument */ 5149736Smckusick register struct vnode *dp; /* the directory we are searching */ 5249736Smckusick struct iovec aiov; /* uio for reading symbolic links */ 5349736Smckusick struct uio auio; 5449736Smckusick int error, linklen; 5552633Sheideman struct componentname *cnp = &ndp->ni_cnd; 5649736Smckusick 5752633Sheideman ndp->ni_cnd.cn_cred = ndp->ni_cnd.cn_proc->p_ucred; 5852633Sheideman #ifdef DIAGNOSTIC 5952633Sheideman if (!cnp->cn_cred || !cnp->cn_proc) 6052633Sheideman panic ("namei: bad cred/proc"); 6152633Sheideman if (cnp->cn_nameiop & (~OPMASK)) 6252633Sheideman panic ("namei: nameiop contaminated with flags"); 6352633Sheideman if (cnp->cn_flags & OPMASK) 6452633Sheideman panic ("namei: flags contaminated with nameiops"); 6552633Sheideman #endif 6652633Sheideman fdp = cnp->cn_proc->p_fd; 6749736Smckusick 6849736Smckusick /* 6949736Smckusick * Get a buffer for the name to be translated, and copy the 7049736Smckusick * name into the buffer. 7149736Smckusick */ 7252633Sheideman if ((cnp->cn_flags & HASBUF) == 0) 7352633Sheideman MALLOC(cnp->cn_pnbuf, caddr_t, MAXPATHLEN, M_NAMEI, M_WAITOK); 7449736Smckusick if (ndp->ni_segflg == UIO_SYSSPACE) 7552633Sheideman error = copystr(ndp->ni_dirp, cnp->cn_pnbuf, 7649736Smckusick MAXPATHLEN, &ndp->ni_pathlen); 7749736Smckusick else 7852633Sheideman error = copyinstr(ndp->ni_dirp, cnp->cn_pnbuf, 7949736Smckusick MAXPATHLEN, &ndp->ni_pathlen); 8049736Smckusick if (error) { 8152633Sheideman free(cnp->cn_pnbuf, M_NAMEI); 8249736Smckusick ndp->ni_vp = NULL; 8349736Smckusick return (error); 8449736Smckusick } 8549736Smckusick ndp->ni_loopcnt = 0; 8649736Smckusick #ifdef KTRACE 8752633Sheideman if (KTRPOINT(cnp->cn_proc, KTR_NAMEI)) 8852633Sheideman ktrnamei(cnp->cn_proc->p_tracep, cnp->cn_pnbuf); 8949736Smckusick #endif 9049736Smckusick 9149736Smckusick /* 9249736Smckusick * Get starting point for the translation. 9349736Smckusick */ 9449736Smckusick if ((ndp->ni_rootdir = fdp->fd_rdir) == NULL) 9549736Smckusick ndp->ni_rootdir = rootdir; 9649736Smckusick dp = fdp->fd_cdir; 9749736Smckusick VREF(dp); 9849736Smckusick for (;;) { 9949736Smckusick /* 10049736Smckusick * Check if root directory should replace current directory. 10149736Smckusick * Done at start of translation and after symbolic link. 10249736Smckusick */ 10352633Sheideman cnp->cn_nameptr = cnp->cn_pnbuf; 10452633Sheideman if (*(cnp->cn_nameptr) == '/') { 10549736Smckusick vrele(dp); 10652633Sheideman while (*(cnp->cn_nameptr) == '/') { 10752633Sheideman cnp->cn_nameptr++; 10849736Smckusick ndp->ni_pathlen--; 10949736Smckusick } 11049736Smckusick dp = ndp->ni_rootdir; 11149736Smckusick VREF(dp); 11249736Smckusick } 11349736Smckusick ndp->ni_startdir = dp; 11452633Sheideman if (error = lookup(ndp)) { 11552633Sheideman FREE(cnp->cn_pnbuf, M_NAMEI); 11649736Smckusick return (error); 11749736Smckusick } 11849736Smckusick /* 11949736Smckusick * Check for symbolic link 12049736Smckusick */ 12152633Sheideman if ((cnp->cn_flags & ISSYMLINK) == 0) { 12252633Sheideman if ((cnp->cn_flags & (SAVENAME | SAVESTART)) == 0) 12352633Sheideman FREE(cnp->cn_pnbuf, M_NAMEI); 12449736Smckusick else 12552633Sheideman cnp->cn_flags |= HASBUF; 12649736Smckusick return (0); 12749736Smckusick } 12852633Sheideman if ((cnp->cn_flags & LOCKPARENT) && ndp->ni_pathlen == 1) 12949736Smckusick VOP_UNLOCK(ndp->ni_dvp); 13049736Smckusick if (ndp->ni_loopcnt++ >= MAXSYMLINKS) { 13149736Smckusick error = ELOOP; 13249736Smckusick break; 13349736Smckusick } 13449736Smckusick if (ndp->ni_pathlen > 1) 13549736Smckusick MALLOC(cp, char *, MAXPATHLEN, M_NAMEI, M_WAITOK); 13649736Smckusick else 13752633Sheideman cp = cnp->cn_pnbuf; 13849736Smckusick aiov.iov_base = cp; 13949736Smckusick aiov.iov_len = MAXPATHLEN; 14049736Smckusick auio.uio_iov = &aiov; 14149736Smckusick auio.uio_iovcnt = 1; 14249736Smckusick auio.uio_offset = 0; 14349736Smckusick auio.uio_rw = UIO_READ; 14449736Smckusick auio.uio_segflg = UIO_SYSSPACE; 14549736Smckusick auio.uio_procp = (struct proc *)0; 14649736Smckusick auio.uio_resid = MAXPATHLEN; 14752633Sheideman if (error = VOP_READLINK(ndp->ni_vp, &auio, cnp->cn_cred)) { 14849736Smckusick if (ndp->ni_pathlen > 1) 14949736Smckusick free(cp, M_NAMEI); 15049736Smckusick break; 15149736Smckusick } 15249736Smckusick linklen = MAXPATHLEN - auio.uio_resid; 15349736Smckusick if (linklen + ndp->ni_pathlen >= MAXPATHLEN) { 15449736Smckusick if (ndp->ni_pathlen > 1) 15549736Smckusick free(cp, M_NAMEI); 15649736Smckusick error = ENAMETOOLONG; 15749736Smckusick break; 15849736Smckusick } 15949736Smckusick if (ndp->ni_pathlen > 1) { 16049736Smckusick bcopy(ndp->ni_next, cp + linklen, ndp->ni_pathlen); 16152633Sheideman FREE(cnp->cn_pnbuf, M_NAMEI); 16252633Sheideman cnp->cn_pnbuf = cp; 16349736Smckusick } else 16452633Sheideman cnp->cn_pnbuf[linklen] = '\0'; 16549736Smckusick ndp->ni_pathlen += linklen; 16649736Smckusick vput(ndp->ni_vp); 16749736Smckusick dp = ndp->ni_dvp; 16849736Smckusick } 16952633Sheideman FREE(cnp->cn_pnbuf, M_NAMEI); 17049736Smckusick vrele(ndp->ni_dvp); 17149736Smckusick vput(ndp->ni_vp); 17249736Smckusick ndp->ni_vp = NULL; 17349736Smckusick return (error); 17449736Smckusick } 17549736Smckusick 17649736Smckusick /* 17749736Smckusick * Search a pathname. 17849736Smckusick * This is a very central and rather complicated routine. 17949736Smckusick * 18049736Smckusick * The pathname is pointed to by ni_ptr and is of length ni_pathlen. 18149736Smckusick * The starting directory is taken from ni_startdir. The pathname is 18249736Smckusick * descended until done, or a symbolic link is encountered. The variable 18349736Smckusick * ni_more is clear if the path is completed; it is set to one if a 18449736Smckusick * symbolic link needing interpretation is encountered. 18549736Smckusick * 18649736Smckusick * The flag argument is LOOKUP, CREATE, RENAME, or DELETE depending on 18749736Smckusick * whether the name is to be looked up, created, renamed, or deleted. 18849736Smckusick * When CREATE, RENAME, or DELETE is specified, information usable in 18949736Smckusick * creating, renaming, or deleting a directory entry may be calculated. 19049736Smckusick * If flag has LOCKPARENT or'ed into it, the parent directory is returned 19149736Smckusick * locked. If flag has WANTPARENT or'ed into it, the parent directory is 19249736Smckusick * returned unlocked. Otherwise the parent directory is not returned. If 19349736Smckusick * the target of the pathname exists and LOCKLEAF is or'ed into the flag 19449736Smckusick * the target is returned locked, otherwise it is returned unlocked. 19549736Smckusick * When creating or renaming and LOCKPARENT is specified, the target may not 19649736Smckusick * be ".". When deleting and LOCKPARENT is specified, the target may be ".". 19749736Smckusick * NOTE: (LOOKUP | LOCKPARENT) currently returns the parent vnode unlocked. 19849736Smckusick * 19949736Smckusick * Overall outline of lookup: 20049736Smckusick * 2017534Sroot * dirloop: 20249736Smckusick * identify next component of name at ndp->ni_ptr 2037534Sroot * handle degenerate case where name is null string 20449736Smckusick * if .. and crossing mount points and on mounted filesys, find parent 20549736Smckusick * call VOP_LOOKUP routine for next component name 20649736Smckusick * directory vnode returned in ni_dvp, unlocked unless LOCKPARENT set 20749736Smckusick * component vnode returned in ni_vp (if it exists), locked. 20849736Smckusick * if result vnode is mounted on and crossing mount points, 20949736Smckusick * find mounted on vnode 2107534Sroot * if more components of name, do next level at dirloop 21149736Smckusick * return the answer in ni_vp, locked if LOCKLEAF set 21249736Smckusick * if LOCKPARENT set, return locked parent in ni_dvp 21349736Smckusick * if WANTPARENT set, return unlocked parent in ni_dvp 21430Sbill */ 21552633Sheideman int 21652633Sheideman lookup(ndp) 21716688Smckusick register struct nameidata *ndp; 21830Sbill { 2197534Sroot register char *cp; /* pointer into pathname argument */ 22037715Smckusick register struct vnode *dp = 0; /* the directory we are searching */ 22137715Smckusick struct vnode *tdp; /* saved dp */ 22237715Smckusick struct mount *mp; /* mount table entry */ 22318109Smckusick int docache; /* == 0 do not cache last component */ 22437715Smckusick int wantparent; /* 1 => wantparent or lockparent flag */ 22552181Smckusick int rdonly; /* lookup read-only flag bit */ 22637715Smckusick int error = 0; 22752230Sheideman struct componentname *cnp = &ndp->ni_cnd; 22830Sbill 22941337Smckusick /* 23041337Smckusick * Setup: break out flag bits into variables. 23141337Smckusick */ 23252633Sheideman wantparent = cnp->cn_flags & (LOCKPARENT | WANTPARENT); 23352230Sheideman docache = (cnp->cn_flags & NOCACHE) ^ NOCACHE; 23452633Sheideman if (cnp->cn_nameiop == DELETE || 23552633Sheideman (wantparent && cnp->cn_nameiop != CREATE)) 23615798Smckusick docache = 0; 23752230Sheideman rdonly = cnp->cn_flags & RDONLY; 23849736Smckusick ndp->ni_dvp = NULL; 23952230Sheideman cnp->cn_flags &= ~ISSYMLINK; 24049736Smckusick dp = ndp->ni_startdir; 24149736Smckusick ndp->ni_startdir = NULLVP; 24237715Smckusick VOP_LOCK(dp); 2437534Sroot 2446571Smckusic dirloop: 24530Sbill /* 24649736Smckusick * Search a new directory. 24749736Smckusick * 24852230Sheideman * The cn_hash value is for use by vfs_cache. 24949736Smckusick * The last component of the filename is left accessible via 25052230Sheideman * cnp->cn_nameptr for callers that need the name. Callers needing 25149736Smckusick * the name set the SAVENAME flag. When done, they assume 25249736Smckusick * responsibility for freeing the pathname buffer. 2537534Sroot */ 25455091Spendry cnp->cn_consume = 0; 25552230Sheideman cnp->cn_hash = 0; 25652230Sheideman for (cp = cnp->cn_nameptr; *cp != 0 && *cp != '/'; cp++) 25752230Sheideman cnp->cn_hash += (unsigned char)*cp; 25852230Sheideman cnp->cn_namelen = cp - cnp->cn_nameptr; 25952230Sheideman if (cnp->cn_namelen >= NAME_MAX) { 26049736Smckusick error = ENAMETOOLONG; 26149736Smckusick goto bad; 26249736Smckusick } 26337743Smckusick #ifdef NAMEI_DIAGNOSTIC 26449736Smckusick { char c = *cp; 26549736Smckusick *cp = '\0'; 26652230Sheideman printf("{%s}: ", cnp->cn_nameptr); 26749736Smckusick *cp = c; } 26837743Smckusick #endif 26952230Sheideman ndp->ni_pathlen -= cnp->cn_namelen; 27049736Smckusick ndp->ni_next = cp; 27152230Sheideman cnp->cn_flags |= MAKEENTRY; 27218109Smckusick if (*cp == '\0' && docache == 0) 27352230Sheideman cnp->cn_flags &= ~MAKEENTRY; 27452230Sheideman if (cnp->cn_namelen == 2 && 27555181Smckusick cnp->cn_nameptr[1] == '.' && cnp->cn_nameptr[0] == '.') 27652230Sheideman cnp->cn_flags |= ISDOTDOT; 27755181Smckusick else 27855181Smckusick cnp->cn_flags &= ~ISDOTDOT; 27952230Sheideman if (*ndp->ni_next == 0) 28052230Sheideman cnp->cn_flags |= ISLASTCN; 28155181Smckusick else 28255181Smckusick cnp->cn_flags &= ~ISLASTCN; 2837534Sroot 28452230Sheideman 2857534Sroot /* 2867534Sroot * Check for degenerate name (e.g. / or "") 2877534Sroot * which is a way of talking about a directory, 2887534Sroot * e.g. like "/." or ".". 2897534Sroot */ 29052230Sheideman if (cnp->cn_nameptr[0] == '\0') { 29152230Sheideman if (cnp->cn_nameiop != LOOKUP || wantparent) { 29237715Smckusick error = EISDIR; 2937534Sroot goto bad; 2945972Swnj } 29549736Smckusick if (dp->v_type != VDIR) { 29649736Smckusick error = ENOTDIR; 29749736Smckusick goto bad; 29849736Smckusick } 29952230Sheideman if (!(cnp->cn_flags & LOCKLEAF)) 30037715Smckusick VOP_UNLOCK(dp); 30137715Smckusick ndp->ni_vp = dp; 30252230Sheideman if (cnp->cn_flags & SAVESTART) 30349736Smckusick panic("lookup: SAVESTART"); 30452633Sheideman return (0); 3055972Swnj } 3067534Sroot 3076571Smckusic /* 30837715Smckusick * Handle "..": two special cases. 30937715Smckusick * 1. If at root directory (e.g. after chroot) 31056313Shibler * or at absolute root directory 31137715Smckusick * then ignore it so can't get out. 31237715Smckusick * 2. If this vnode is the root of a mounted 31349736Smckusick * filesystem, then replace it with the 31437715Smckusick * vnode which was mounted on so we take the 31537715Smckusick * .. in the other file system. 31636547Smckusick */ 31752230Sheideman if (cnp->cn_flags & ISDOTDOT) { 31836547Smckusick for (;;) { 31956313Shibler if (dp == ndp->ni_rootdir || dp == rootdir) { 32037715Smckusick ndp->ni_dvp = dp; 32138390Smckusick ndp->ni_vp = dp; 32238347Smckusick VREF(dp); 32337715Smckusick goto nextname; 32436547Smckusick } 32541337Smckusick if ((dp->v_flag & VROOT) == 0 || 32652230Sheideman (cnp->cn_flags & NOCROSSMOUNT)) 32736547Smckusick break; 32837715Smckusick tdp = dp; 32941400Smckusick dp = dp->v_mount->mnt_vnodecovered; 33037715Smckusick vput(tdp); 33138390Smckusick VREF(dp); 33237715Smckusick VOP_LOCK(dp); 33336547Smckusick } 33436547Smckusick } 33536547Smckusick 33636547Smckusick /* 33715798Smckusick * We now have a segment name to search for, and a directory to search. 33815798Smckusick */ 33955451Spendry unionlookup: 34052230Sheideman ndp->ni_dvp = dp; 34152230Sheideman if (error = VOP_LOOKUP(dp, &ndp->ni_vp, cnp)) { 34249736Smckusick #ifdef DIAGNOSTIC 34337715Smckusick if (ndp->ni_vp != NULL) 34437715Smckusick panic("leaf should be empty"); 34549736Smckusick #endif 34637582Smarc #ifdef NAMEI_DIAGNOSTIC 34737715Smckusick printf("not found\n"); 34837582Smarc #endif 34955451Spendry if ((error == ENOENT) && 35055451Spendry (dp->v_flag & VROOT) && 35155451Spendry (dp->v_mount->mnt_flag & MNT_UNION)) { 35255451Spendry tdp = dp; 35355451Spendry dp = dp->v_mount->mnt_vnodecovered; 35455451Spendry vput(tdp); 35555451Spendry VREF(dp); 35655451Spendry VOP_LOCK(dp); 35755451Spendry goto unionlookup; 35855451Spendry } 35955451Spendry 36052798Smckusick if (error != EJUSTRETURN) 36138581Smckusick goto bad; 3625972Swnj /* 36337715Smckusick * If creating and at end of pathname, then can consider 36437715Smckusick * allowing file to be created. 3655972Swnj */ 36652181Smckusick if (rdonly || (ndp->ni_dvp->v_mount->mnt_flag & MNT_RDONLY)) { 36737715Smckusick error = EROFS; 3687534Sroot goto bad; 36938581Smckusick } 3705972Swnj /* 37137715Smckusick * We return with ni_vp NULL to indicate that the entry 37237715Smckusick * doesn't currently exist, leaving a pointer to the 37337715Smckusick * (possibly locked) directory inode in ndp->ni_dvp. 3745972Swnj */ 37552230Sheideman if (cnp->cn_flags & SAVESTART) { 37649736Smckusick ndp->ni_startdir = ndp->ni_dvp; 37749736Smckusick VREF(ndp->ni_startdir); 37849736Smckusick } 37952633Sheideman return (0); 3807534Sroot } 38137582Smarc #ifdef NAMEI_DIAGNOSTIC 38237715Smckusick printf("found\n"); 38337582Smarc #endif 3847534Sroot 38555091Spendry /* 38655091Spendry * Take into account any additional components consumed by 38755091Spendry * the underlying filesystem. 38855091Spendry */ 38955091Spendry if (cnp->cn_consume > 0) { 39055091Spendry cnp->cn_nameptr += cnp->cn_consume; 39155091Spendry ndp->ni_next += cnp->cn_consume; 39255091Spendry ndp->ni_pathlen -= cnp->cn_consume; 39355091Spendry cnp->cn_consume = 0; 39455091Spendry } 39555091Spendry 39649736Smckusick dp = ndp->ni_vp; 3977534Sroot /* 39837715Smckusick * Check for symbolic link 3997534Sroot */ 40037715Smckusick if ((dp->v_type == VLNK) && 40152230Sheideman ((cnp->cn_flags & FOLLOW) || *ndp->ni_next == '/')) { 40252230Sheideman cnp->cn_flags |= ISSYMLINK; 40352633Sheideman return (0); 40415798Smckusick } 40515798Smckusick 4067534Sroot /* 40737715Smckusick * Check to see if the vnode has been mounted on; 40837715Smckusick * if so find the root of the mounted file system. 4097534Sroot */ 41041337Smckusick while (dp->v_type == VDIR && (mp = dp->v_mountedhere) && 41152230Sheideman (cnp->cn_flags & NOCROSSMOUNT) == 0) { 41252116Smarc if (mp->mnt_flag & MNT_MLOCK) { 41341400Smckusick mp->mnt_flag |= MNT_MWAIT; 41437715Smckusick sleep((caddr_t)mp, PVFS); 41552634Smckusick continue; 41621014Smckusick } 41749736Smckusick if (error = VFS_ROOT(dp->v_mountedhere, &tdp)) 4187534Sroot goto bad2; 41937715Smckusick vput(dp); 42037715Smckusick ndp->ni_vp = dp = tdp; 42130Sbill } 4227534Sroot 42337715Smckusick nextname: 42430Sbill /* 4257534Sroot * Not a symbolic link. If more pathname, 4267534Sroot * continue at next component, else return. 42730Sbill */ 42849736Smckusick if (*ndp->ni_next == '/') { 42952230Sheideman cnp->cn_nameptr = ndp->ni_next; 43052230Sheideman while (*cnp->cn_nameptr == '/') { 43152230Sheideman cnp->cn_nameptr++; 43237715Smckusick ndp->ni_pathlen--; 43337715Smckusick } 43437715Smckusick vrele(ndp->ni_dvp); 4357534Sroot goto dirloop; 43630Sbill } 4377534Sroot /* 43838400Smckusick * Check for read-only file systems. 4397534Sroot */ 44052230Sheideman if (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME) { 44138267Smckusick /* 44238400Smckusick * Disallow directory write attempts on read-only 44338400Smckusick * file systems. 44438267Smckusick */ 44552181Smckusick if (rdonly || (dp->v_mount->mnt_flag & MNT_RDONLY) || 44652181Smckusick (wantparent && 44752181Smckusick (ndp->ni_dvp->v_mount->mnt_flag & MNT_RDONLY))) { 44838267Smckusick error = EROFS; 44938267Smckusick goto bad2; 45038267Smckusick } 45138267Smckusick } 45252230Sheideman if (cnp->cn_flags & SAVESTART) { 45349736Smckusick ndp->ni_startdir = ndp->ni_dvp; 45449736Smckusick VREF(ndp->ni_startdir); 45549736Smckusick } 45637715Smckusick if (!wantparent) 45737715Smckusick vrele(ndp->ni_dvp); 45852230Sheideman if ((cnp->cn_flags & LOCKLEAF) == 0) 45937715Smckusick VOP_UNLOCK(dp); 46052633Sheideman return (0); 4617534Sroot 46237715Smckusick bad2: 46352230Sheideman if ((cnp->cn_flags & LOCKPARENT) && *ndp->ni_next == '\0') 46438001Smckusick VOP_UNLOCK(ndp->ni_dvp); 46537715Smckusick vrele(ndp->ni_dvp); 46637715Smckusick bad: 46737715Smckusick vput(dp); 46837715Smckusick ndp->ni_vp = NULL; 46952633Sheideman return (error); 4705972Swnj } 47152230Sheideman 47252230Sheideman 473