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*52634Smckusick * @(#)vfs_lookup.c 7.37 (Berkeley) 02/21/92 823401Smckusick */ 930Sbill 1017100Sbloom #include "param.h" 1149736Smckusick #include "syslimits.h" 1237715Smckusick #include "time.h" 1337715Smckusick #include "namei.h" 1437715Smckusick #include "vnode.h" 1517100Sbloom #include "mount.h" 1637715Smckusick #include "errno.h" 1731650Smckusick #include "malloc.h" 1845914Smckusick #include "filedesc.h" 1945924Smckusick #include "proc.h" 2037715Smckusick 2137582Smarc #ifdef KTRACE 2237582Smarc #include "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 */ 25452230Sheideman cnp->cn_hash = 0; 25552230Sheideman for (cp = cnp->cn_nameptr; *cp != 0 && *cp != '/'; cp++) 25652230Sheideman cnp->cn_hash += (unsigned char)*cp; 25752230Sheideman cnp->cn_namelen = cp - cnp->cn_nameptr; 25852230Sheideman if (cnp->cn_namelen >= NAME_MAX) { 25949736Smckusick error = ENAMETOOLONG; 26049736Smckusick goto bad; 26149736Smckusick } 26237743Smckusick #ifdef NAMEI_DIAGNOSTIC 26349736Smckusick { char c = *cp; 26449736Smckusick *cp = '\0'; 26552230Sheideman printf("{%s}: ", cnp->cn_nameptr); 26649736Smckusick *cp = c; } 26737743Smckusick #endif 26852230Sheideman ndp->ni_pathlen -= cnp->cn_namelen; 26949736Smckusick ndp->ni_next = cp; 27052230Sheideman cnp->cn_flags |= MAKEENTRY; 27118109Smckusick if (*cp == '\0' && docache == 0) 27252230Sheideman cnp->cn_flags &= ~MAKEENTRY; 27352230Sheideman if (cnp->cn_namelen == 2 && 27452230Sheideman cnp->cn_nameptr[1] == '.' && cnp->cn_nameptr[0] == '.') 27552230Sheideman cnp->cn_flags |= ISDOTDOT; 27652230Sheideman else cnp->cn_flags &= ~ISDOTDOT; 27752230Sheideman if (*ndp->ni_next == 0) 27852230Sheideman cnp->cn_flags |= ISLASTCN; 27952230Sheideman else cnp->cn_flags &= ~ISLASTCN; 2807534Sroot 28152230Sheideman 2827534Sroot /* 2837534Sroot * Check for degenerate name (e.g. / or "") 2847534Sroot * which is a way of talking about a directory, 2857534Sroot * e.g. like "/." or ".". 2867534Sroot */ 28752230Sheideman if (cnp->cn_nameptr[0] == '\0') { 28852230Sheideman if (cnp->cn_nameiop != LOOKUP || wantparent) { 28937715Smckusick error = EISDIR; 2907534Sroot goto bad; 2915972Swnj } 29249736Smckusick if (dp->v_type != VDIR) { 29349736Smckusick error = ENOTDIR; 29449736Smckusick goto bad; 29549736Smckusick } 29652230Sheideman if (!(cnp->cn_flags & LOCKLEAF)) 29737715Smckusick VOP_UNLOCK(dp); 29837715Smckusick ndp->ni_vp = dp; 29952230Sheideman if (cnp->cn_flags & SAVESTART) 30049736Smckusick panic("lookup: SAVESTART"); 30152633Sheideman return (0); 3025972Swnj } 3037534Sroot 3046571Smckusic /* 30537715Smckusick * Handle "..": two special cases. 30637715Smckusick * 1. If at root directory (e.g. after chroot) 30737715Smckusick * then ignore it so can't get out. 30837715Smckusick * 2. If this vnode is the root of a mounted 30949736Smckusick * filesystem, then replace it with the 31037715Smckusick * vnode which was mounted on so we take the 31137715Smckusick * .. in the other file system. 31236547Smckusick */ 31352230Sheideman if (cnp->cn_flags & ISDOTDOT) { 31436547Smckusick for (;;) { 31549736Smckusick if (dp == ndp->ni_rootdir) { 31637715Smckusick ndp->ni_dvp = dp; 31738390Smckusick ndp->ni_vp = dp; 31838347Smckusick VREF(dp); 31937715Smckusick goto nextname; 32036547Smckusick } 32141337Smckusick if ((dp->v_flag & VROOT) == 0 || 32252230Sheideman (cnp->cn_flags & NOCROSSMOUNT)) 32336547Smckusick break; 32437715Smckusick tdp = dp; 32541400Smckusick dp = dp->v_mount->mnt_vnodecovered; 32637715Smckusick vput(tdp); 32738390Smckusick VREF(dp); 32837715Smckusick VOP_LOCK(dp); 32936547Smckusick } 33036547Smckusick } 33136547Smckusick 33236547Smckusick /* 33315798Smckusick * We now have a segment name to search for, and a directory to search. 33415798Smckusick */ 33552230Sheideman ndp->ni_dvp = dp; 33652230Sheideman if (error = VOP_LOOKUP(dp, &ndp->ni_vp, cnp)) { 33749736Smckusick #ifdef DIAGNOSTIC 33837715Smckusick if (ndp->ni_vp != NULL) 33937715Smckusick panic("leaf should be empty"); 34049736Smckusick #endif 34137582Smarc #ifdef NAMEI_DIAGNOSTIC 34237715Smckusick printf("not found\n"); 34337582Smarc #endif 34452230Sheideman if (cnp->cn_nameiop == LOOKUP || cnp->cn_nameiop == DELETE || 34538581Smckusick error != ENOENT || *cp != 0) 34638581Smckusick goto bad; 3475972Swnj /* 34837715Smckusick * If creating and at end of pathname, then can consider 34937715Smckusick * allowing file to be created. 3505972Swnj */ 35152181Smckusick if (rdonly || (ndp->ni_dvp->v_mount->mnt_flag & MNT_RDONLY)) { 35237715Smckusick error = EROFS; 3537534Sroot goto bad; 35438581Smckusick } 3555972Swnj /* 35637715Smckusick * We return with ni_vp NULL to indicate that the entry 35737715Smckusick * doesn't currently exist, leaving a pointer to the 35837715Smckusick * (possibly locked) directory inode in ndp->ni_dvp. 3595972Swnj */ 36052230Sheideman if (cnp->cn_flags & SAVESTART) { 36149736Smckusick ndp->ni_startdir = ndp->ni_dvp; 36249736Smckusick VREF(ndp->ni_startdir); 36349736Smckusick } 36452633Sheideman return (0); 3657534Sroot } 36637582Smarc #ifdef NAMEI_DIAGNOSTIC 36737715Smckusick printf("found\n"); 36837582Smarc #endif 3697534Sroot 37049736Smckusick dp = ndp->ni_vp; 3717534Sroot /* 37237715Smckusick * Check for symbolic link 3737534Sroot */ 37437715Smckusick if ((dp->v_type == VLNK) && 37552230Sheideman ((cnp->cn_flags & FOLLOW) || *ndp->ni_next == '/')) { 37652230Sheideman cnp->cn_flags |= ISSYMLINK; 37752633Sheideman return (0); 37815798Smckusick } 37915798Smckusick 3807534Sroot /* 38137715Smckusick * Check to see if the vnode has been mounted on; 38237715Smckusick * if so find the root of the mounted file system. 3837534Sroot */ 38441337Smckusick while (dp->v_type == VDIR && (mp = dp->v_mountedhere) && 38552230Sheideman (cnp->cn_flags & NOCROSSMOUNT) == 0) { 38652116Smarc if (mp->mnt_flag & MNT_MLOCK) { 38741400Smckusick mp->mnt_flag |= MNT_MWAIT; 38837715Smckusick sleep((caddr_t)mp, PVFS); 389*52634Smckusick continue; 39021014Smckusick } 39149736Smckusick if (error = VFS_ROOT(dp->v_mountedhere, &tdp)) 3927534Sroot goto bad2; 39337715Smckusick vput(dp); 39437715Smckusick ndp->ni_vp = dp = tdp; 39530Sbill } 3967534Sroot 39737715Smckusick nextname: 39830Sbill /* 3997534Sroot * Not a symbolic link. If more pathname, 4007534Sroot * continue at next component, else return. 40130Sbill */ 40249736Smckusick if (*ndp->ni_next == '/') { 40352230Sheideman cnp->cn_nameptr = ndp->ni_next; 40452230Sheideman while (*cnp->cn_nameptr == '/') { 40552230Sheideman cnp->cn_nameptr++; 40637715Smckusick ndp->ni_pathlen--; 40737715Smckusick } 40837715Smckusick vrele(ndp->ni_dvp); 4097534Sroot goto dirloop; 41030Sbill } 4117534Sroot /* 41238400Smckusick * Check for read-only file systems. 4137534Sroot */ 41452230Sheideman if (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME) { 41538267Smckusick /* 41638400Smckusick * Disallow directory write attempts on read-only 41738400Smckusick * file systems. 41838267Smckusick */ 41952181Smckusick if (rdonly || (dp->v_mount->mnt_flag & MNT_RDONLY) || 42052181Smckusick (wantparent && 42152181Smckusick (ndp->ni_dvp->v_mount->mnt_flag & MNT_RDONLY))) { 42238267Smckusick error = EROFS; 42338267Smckusick goto bad2; 42438267Smckusick } 42538267Smckusick } 42652230Sheideman if (cnp->cn_flags & SAVESTART) { 42749736Smckusick ndp->ni_startdir = ndp->ni_dvp; 42849736Smckusick VREF(ndp->ni_startdir); 42949736Smckusick } 43037715Smckusick if (!wantparent) 43137715Smckusick vrele(ndp->ni_dvp); 43252230Sheideman if ((cnp->cn_flags & LOCKLEAF) == 0) 43337715Smckusick VOP_UNLOCK(dp); 43452633Sheideman return (0); 4357534Sroot 43637715Smckusick bad2: 43752230Sheideman if ((cnp->cn_flags & LOCKPARENT) && *ndp->ni_next == '\0') 43838001Smckusick VOP_UNLOCK(ndp->ni_dvp); 43937715Smckusick vrele(ndp->ni_dvp); 44037715Smckusick bad: 44137715Smckusick vput(dp); 44237715Smckusick ndp->ni_vp = NULL; 44352633Sheideman return (error); 4445972Swnj } 44552230Sheideman 44652230Sheideman 447