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*52181Smckusick * @(#)vfs_lookup.c 7.34 (Berkeley) 01/13/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 */ 4549736Smckusick namei(ndp, p) 4649736Smckusick register struct nameidata *ndp; 4749736Smckusick struct proc *p; 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; 5549736Smckusick 5649736Smckusick ndp->ni_cred = p->p_ucred; 5749736Smckusick fdp = p->p_fd; 5849736Smckusick 5949736Smckusick /* 6049736Smckusick * Get a buffer for the name to be translated, and copy the 6149736Smckusick * name into the buffer. 6249736Smckusick */ 6349810Smckusick if ((ndp->ni_nameiop & HASBUF) == 0) 6449810Smckusick MALLOC(ndp->ni_pnbuf, caddr_t, MAXPATHLEN, M_NAMEI, M_WAITOK); 6549736Smckusick if (ndp->ni_segflg == UIO_SYSSPACE) 6649736Smckusick error = copystr(ndp->ni_dirp, ndp->ni_pnbuf, 6749736Smckusick MAXPATHLEN, &ndp->ni_pathlen); 6849736Smckusick else 6949736Smckusick error = copyinstr(ndp->ni_dirp, ndp->ni_pnbuf, 7049736Smckusick MAXPATHLEN, &ndp->ni_pathlen); 7149736Smckusick if (error) { 7249736Smckusick free(ndp->ni_pnbuf, M_NAMEI); 7349736Smckusick ndp->ni_vp = NULL; 7449736Smckusick return (error); 7549736Smckusick } 7649736Smckusick ndp->ni_loopcnt = 0; 7749736Smckusick #ifdef KTRACE 7849736Smckusick if (KTRPOINT(p, KTR_NAMEI)) 7949736Smckusick ktrnamei(p->p_tracep, ndp->ni_pnbuf); 8049736Smckusick #endif 8149736Smckusick 8249736Smckusick /* 8349736Smckusick * Get starting point for the translation. 8449736Smckusick */ 8549736Smckusick if ((ndp->ni_rootdir = fdp->fd_rdir) == NULL) 8649736Smckusick ndp->ni_rootdir = rootdir; 8749736Smckusick dp = fdp->fd_cdir; 8849736Smckusick VREF(dp); 8949736Smckusick for (;;) { 9049736Smckusick /* 9149736Smckusick * Check if root directory should replace current directory. 9249736Smckusick * Done at start of translation and after symbolic link. 9349736Smckusick */ 9449736Smckusick ndp->ni_ptr = ndp->ni_pnbuf; 9549736Smckusick if (*ndp->ni_ptr == '/') { 9649736Smckusick vrele(dp); 9749736Smckusick while (*ndp->ni_ptr == '/') { 9849736Smckusick ndp->ni_ptr++; 9949736Smckusick ndp->ni_pathlen--; 10049736Smckusick } 10149736Smckusick dp = ndp->ni_rootdir; 10249736Smckusick VREF(dp); 10349736Smckusick } 10449736Smckusick ndp->ni_startdir = dp; 10549736Smckusick if (error = lookup(ndp, p)) { 10649736Smckusick FREE(ndp->ni_pnbuf, M_NAMEI); 10749736Smckusick return (error); 10849736Smckusick } 10949736Smckusick /* 11049736Smckusick * Check for symbolic link 11149736Smckusick */ 11249736Smckusick if (ndp->ni_more == 0) { 11349736Smckusick if ((ndp->ni_nameiop & (SAVENAME | SAVESTART)) == 0) 11449736Smckusick FREE(ndp->ni_pnbuf, M_NAMEI); 11549736Smckusick else 11649736Smckusick ndp->ni_nameiop |= HASBUF; 11749736Smckusick return (0); 11849736Smckusick } 11949736Smckusick if ((ndp->ni_nameiop & LOCKPARENT) && ndp->ni_pathlen == 1) 12049736Smckusick VOP_UNLOCK(ndp->ni_dvp); 12149736Smckusick if (ndp->ni_loopcnt++ >= MAXSYMLINKS) { 12249736Smckusick error = ELOOP; 12349736Smckusick break; 12449736Smckusick } 12549736Smckusick if (ndp->ni_pathlen > 1) 12649736Smckusick MALLOC(cp, char *, MAXPATHLEN, M_NAMEI, M_WAITOK); 12749736Smckusick else 12849736Smckusick cp = ndp->ni_pnbuf; 12949736Smckusick aiov.iov_base = cp; 13049736Smckusick aiov.iov_len = MAXPATHLEN; 13149736Smckusick auio.uio_iov = &aiov; 13249736Smckusick auio.uio_iovcnt = 1; 13349736Smckusick auio.uio_offset = 0; 13449736Smckusick auio.uio_rw = UIO_READ; 13549736Smckusick auio.uio_segflg = UIO_SYSSPACE; 13649736Smckusick auio.uio_procp = (struct proc *)0; 13749736Smckusick auio.uio_resid = MAXPATHLEN; 13849736Smckusick if (error = VOP_READLINK(ndp->ni_vp, &auio, p->p_ucred)) { 13949736Smckusick if (ndp->ni_pathlen > 1) 14049736Smckusick free(cp, M_NAMEI); 14149736Smckusick break; 14249736Smckusick } 14349736Smckusick linklen = MAXPATHLEN - auio.uio_resid; 14449736Smckusick if (linklen + ndp->ni_pathlen >= MAXPATHLEN) { 14549736Smckusick if (ndp->ni_pathlen > 1) 14649736Smckusick free(cp, M_NAMEI); 14749736Smckusick error = ENAMETOOLONG; 14849736Smckusick break; 14949736Smckusick } 15049736Smckusick if (ndp->ni_pathlen > 1) { 15149736Smckusick bcopy(ndp->ni_next, cp + linklen, ndp->ni_pathlen); 15249736Smckusick FREE(ndp->ni_pnbuf, M_NAMEI); 15349736Smckusick ndp->ni_pnbuf = cp; 15449736Smckusick } else 15549736Smckusick ndp->ni_pnbuf[linklen] = '\0'; 15649736Smckusick ndp->ni_pathlen += linklen; 15749736Smckusick vput(ndp->ni_vp); 15849736Smckusick dp = ndp->ni_dvp; 15949736Smckusick } 16049736Smckusick FREE(ndp->ni_pnbuf, M_NAMEI); 16149736Smckusick vrele(ndp->ni_dvp); 16249736Smckusick vput(ndp->ni_vp); 16349736Smckusick ndp->ni_vp = NULL; 16449736Smckusick return (error); 16549736Smckusick } 16649736Smckusick 16749736Smckusick /* 16849736Smckusick * Search a pathname. 16949736Smckusick * This is a very central and rather complicated routine. 17049736Smckusick * 17149736Smckusick * The pathname is pointed to by ni_ptr and is of length ni_pathlen. 17249736Smckusick * The starting directory is taken from ni_startdir. The pathname is 17349736Smckusick * descended until done, or a symbolic link is encountered. The variable 17449736Smckusick * ni_more is clear if the path is completed; it is set to one if a 17549736Smckusick * symbolic link needing interpretation is encountered. 17649736Smckusick * 17749736Smckusick * The flag argument is LOOKUP, CREATE, RENAME, or DELETE depending on 17849736Smckusick * whether the name is to be looked up, created, renamed, or deleted. 17949736Smckusick * When CREATE, RENAME, or DELETE is specified, information usable in 18049736Smckusick * creating, renaming, or deleting a directory entry may be calculated. 18149736Smckusick * If flag has LOCKPARENT or'ed into it, the parent directory is returned 18249736Smckusick * locked. If flag has WANTPARENT or'ed into it, the parent directory is 18349736Smckusick * returned unlocked. Otherwise the parent directory is not returned. If 18449736Smckusick * the target of the pathname exists and LOCKLEAF is or'ed into the flag 18549736Smckusick * the target is returned locked, otherwise it is returned unlocked. 18649736Smckusick * When creating or renaming and LOCKPARENT is specified, the target may not 18749736Smckusick * be ".". When deleting and LOCKPARENT is specified, the target may be ".". 18849736Smckusick * NOTE: (LOOKUP | LOCKPARENT) currently returns the parent vnode unlocked. 18949736Smckusick * 19049736Smckusick * Overall outline of lookup: 19149736Smckusick * 1927534Sroot * dirloop: 19349736Smckusick * identify next component of name at ndp->ni_ptr 1947534Sroot * handle degenerate case where name is null string 19549736Smckusick * if .. and crossing mount points and on mounted filesys, find parent 19649736Smckusick * call VOP_LOOKUP routine for next component name 19749736Smckusick * directory vnode returned in ni_dvp, unlocked unless LOCKPARENT set 19849736Smckusick * component vnode returned in ni_vp (if it exists), locked. 19949736Smckusick * if result vnode is mounted on and crossing mount points, 20049736Smckusick * find mounted on vnode 2017534Sroot * if more components of name, do next level at dirloop 20249736Smckusick * return the answer in ni_vp, locked if LOCKLEAF set 20349736Smckusick * if LOCKPARENT set, return locked parent in ni_dvp 20449736Smckusick * if WANTPARENT set, return unlocked parent in ni_dvp 20530Sbill */ 20649736Smckusick lookup(ndp, p) 20716688Smckusick register struct nameidata *ndp; 20847540Skarels struct proc *p; 20930Sbill { 2107534Sroot register char *cp; /* pointer into pathname argument */ 21137715Smckusick register struct vnode *dp = 0; /* the directory we are searching */ 21237715Smckusick struct vnode *tdp; /* saved dp */ 21337715Smckusick struct mount *mp; /* mount table entry */ 21418109Smckusick int docache; /* == 0 do not cache last component */ 21537715Smckusick int flag; /* LOOKUP, CREATE, RENAME or DELETE */ 21637715Smckusick int wantparent; /* 1 => wantparent or lockparent flag */ 217*52181Smckusick int rdonly; /* lookup read-only flag bit */ 21837715Smckusick int error = 0; 21930Sbill 22041337Smckusick /* 22141337Smckusick * Setup: break out flag bits into variables. 22241337Smckusick */ 22346508Smckusick flag = ndp->ni_nameiop & OPMASK; 22437715Smckusick wantparent = ndp->ni_nameiop & (LOCKPARENT|WANTPARENT); 22516688Smckusick docache = (ndp->ni_nameiop & NOCACHE) ^ NOCACHE; 22646746Smckusick if (flag == DELETE || (wantparent && flag != CREATE)) 22715798Smckusick docache = 0; 228*52181Smckusick rdonly = ndp->ni_nameiop & RDONLY; 22949736Smckusick ndp->ni_dvp = NULL; 23049736Smckusick ndp->ni_more = 0; 23149736Smckusick dp = ndp->ni_startdir; 23249736Smckusick ndp->ni_startdir = NULLVP; 23337715Smckusick VOP_LOCK(dp); 2347534Sroot 2356571Smckusic dirloop: 23630Sbill /* 23749736Smckusick * Search a new directory. 23849736Smckusick * 23949736Smckusick * The ni_hash value is for use by vfs_cache. 24049736Smckusick * The last component of the filename is left accessible via 24149736Smckusick * ndp->ptr for callers that need the name. Callers needing 24249736Smckusick * the name set the SAVENAME flag. When done, they assume 24349736Smckusick * responsibility for freeing the pathname buffer. 2447534Sroot */ 24549736Smckusick ndp->ni_hash = 0; 24649841Smckusick for (cp = ndp->ni_ptr; *cp != 0 && *cp != '/'; cp++) 24749736Smckusick ndp->ni_hash += (unsigned char)*cp; 24849736Smckusick ndp->ni_namelen = cp - ndp->ni_ptr; 24949736Smckusick if (ndp->ni_namelen >= NAME_MAX) { 25049736Smckusick error = ENAMETOOLONG; 25149736Smckusick goto bad; 25249736Smckusick } 25337743Smckusick #ifdef NAMEI_DIAGNOSTIC 25449736Smckusick { char c = *cp; 25549736Smckusick *cp = '\0'; 25649736Smckusick printf("{%s}: ", ndp->ni_ptr); 25749736Smckusick *cp = c; } 25837743Smckusick #endif 25949736Smckusick ndp->ni_pathlen -= ndp->ni_namelen; 26049736Smckusick ndp->ni_next = cp; 26137715Smckusick ndp->ni_makeentry = 1; 26218109Smckusick if (*cp == '\0' && docache == 0) 26337715Smckusick ndp->ni_makeentry = 0; 26437715Smckusick ndp->ni_isdotdot = (ndp->ni_namelen == 2 && 26549736Smckusick ndp->ni_ptr[1] == '.' && ndp->ni_ptr[0] == '.'); 2667534Sroot 2677534Sroot /* 2687534Sroot * Check for degenerate name (e.g. / or "") 2697534Sroot * which is a way of talking about a directory, 2707534Sroot * e.g. like "/." or ".". 2717534Sroot */ 27237715Smckusick if (ndp->ni_ptr[0] == '\0') { 27337715Smckusick if (flag != LOOKUP || wantparent) { 27437715Smckusick error = EISDIR; 2757534Sroot goto bad; 2765972Swnj } 27749736Smckusick if (dp->v_type != VDIR) { 27849736Smckusick error = ENOTDIR; 27949736Smckusick goto bad; 28049736Smckusick } 28137715Smckusick if (!(ndp->ni_nameiop & LOCKLEAF)) 28237715Smckusick VOP_UNLOCK(dp); 28337715Smckusick ndp->ni_vp = dp; 28449736Smckusick if (ndp->ni_nameiop & SAVESTART) 28549736Smckusick panic("lookup: SAVESTART"); 28637715Smckusick return (0); 2875972Swnj } 2887534Sroot 2896571Smckusic /* 29037715Smckusick * Handle "..": two special cases. 29137715Smckusick * 1. If at root directory (e.g. after chroot) 29237715Smckusick * then ignore it so can't get out. 29337715Smckusick * 2. If this vnode is the root of a mounted 29449736Smckusick * filesystem, then replace it with the 29537715Smckusick * vnode which was mounted on so we take the 29637715Smckusick * .. in the other file system. 29736547Smckusick */ 29837715Smckusick if (ndp->ni_isdotdot) { 29936547Smckusick for (;;) { 30049736Smckusick if (dp == ndp->ni_rootdir) { 30137715Smckusick ndp->ni_dvp = dp; 30238390Smckusick ndp->ni_vp = dp; 30338347Smckusick VREF(dp); 30437715Smckusick goto nextname; 30536547Smckusick } 30641337Smckusick if ((dp->v_flag & VROOT) == 0 || 30749736Smckusick (ndp->ni_nameiop & NOCROSSMOUNT)) 30836547Smckusick break; 30937715Smckusick tdp = dp; 31041400Smckusick dp = dp->v_mount->mnt_vnodecovered; 31137715Smckusick vput(tdp); 31238390Smckusick VREF(dp); 31337715Smckusick VOP_LOCK(dp); 31436547Smckusick } 31536547Smckusick } 31636547Smckusick 31736547Smckusick /* 31815798Smckusick * We now have a segment name to search for, and a directory to search. 31915798Smckusick */ 32048025Smckusick if (error = VOP_LOOKUP(dp, ndp, p)) { 32149736Smckusick #ifdef DIAGNOSTIC 32237715Smckusick if (ndp->ni_vp != NULL) 32337715Smckusick panic("leaf should be empty"); 32449736Smckusick #endif 32537582Smarc #ifdef NAMEI_DIAGNOSTIC 32637715Smckusick printf("not found\n"); 32737582Smarc #endif 32838581Smckusick if (flag == LOOKUP || flag == DELETE || 32938581Smckusick error != ENOENT || *cp != 0) 33038581Smckusick goto bad; 3315972Swnj /* 33237715Smckusick * If creating and at end of pathname, then can consider 33337715Smckusick * allowing file to be created. 3345972Swnj */ 335*52181Smckusick if (rdonly || (ndp->ni_dvp->v_mount->mnt_flag & MNT_RDONLY)) { 33637715Smckusick error = EROFS; 3377534Sroot goto bad; 33838581Smckusick } 3395972Swnj /* 34037715Smckusick * We return with ni_vp NULL to indicate that the entry 34137715Smckusick * doesn't currently exist, leaving a pointer to the 34237715Smckusick * (possibly locked) directory inode in ndp->ni_dvp. 3435972Swnj */ 34449736Smckusick if (ndp->ni_nameiop & SAVESTART) { 34549736Smckusick ndp->ni_startdir = ndp->ni_dvp; 34649736Smckusick VREF(ndp->ni_startdir); 34749736Smckusick } 34849736Smckusick return (0); 3497534Sroot } 35037582Smarc #ifdef NAMEI_DIAGNOSTIC 35137715Smckusick printf("found\n"); 35237582Smarc #endif 3537534Sroot 35449736Smckusick dp = ndp->ni_vp; 3557534Sroot /* 35637715Smckusick * Check for symbolic link 3577534Sroot */ 35837715Smckusick if ((dp->v_type == VLNK) && 35937715Smckusick ((ndp->ni_nameiop & FOLLOW) || *ndp->ni_next == '/')) { 36049736Smckusick ndp->ni_more = 1; 36149736Smckusick return (0); 36215798Smckusick } 36315798Smckusick 3647534Sroot /* 36537715Smckusick * Check to see if the vnode has been mounted on; 36637715Smckusick * if so find the root of the mounted file system. 3677534Sroot */ 36837715Smckusick mntloop: 36941337Smckusick while (dp->v_type == VDIR && (mp = dp->v_mountedhere) && 37041337Smckusick (ndp->ni_nameiop & NOCROSSMOUNT) == 0) { 37152116Smarc if (mp->mnt_flag & MNT_MLOCK) { 37241400Smckusick mp->mnt_flag |= MNT_MWAIT; 37337715Smckusick sleep((caddr_t)mp, PVFS); 37437715Smckusick goto mntloop; 37521014Smckusick } 37649736Smckusick if (error = VFS_ROOT(dp->v_mountedhere, &tdp)) 3777534Sroot goto bad2; 37837715Smckusick vput(dp); 37937715Smckusick ndp->ni_vp = dp = tdp; 38030Sbill } 3817534Sroot 38237715Smckusick nextname: 38330Sbill /* 3847534Sroot * Not a symbolic link. If more pathname, 3857534Sroot * continue at next component, else return. 38630Sbill */ 38749736Smckusick if (*ndp->ni_next == '/') { 38849736Smckusick ndp->ni_ptr = ndp->ni_next; 38937715Smckusick while (*ndp->ni_ptr == '/') { 39037715Smckusick ndp->ni_ptr++; 39137715Smckusick ndp->ni_pathlen--; 39237715Smckusick } 39337715Smckusick vrele(ndp->ni_dvp); 3947534Sroot goto dirloop; 39530Sbill } 3967534Sroot /* 39738400Smckusick * Check for read-only file systems. 3987534Sroot */ 39938400Smckusick if (flag == DELETE || flag == RENAME) { 40038267Smckusick /* 40138400Smckusick * Disallow directory write attempts on read-only 40238400Smckusick * file systems. 40338267Smckusick */ 404*52181Smckusick if (rdonly || (dp->v_mount->mnt_flag & MNT_RDONLY) || 405*52181Smckusick (wantparent && 406*52181Smckusick (ndp->ni_dvp->v_mount->mnt_flag & MNT_RDONLY))) { 40738267Smckusick error = EROFS; 40838267Smckusick goto bad2; 40938267Smckusick } 41038267Smckusick } 41149736Smckusick if (ndp->ni_nameiop & SAVESTART) { 41249736Smckusick ndp->ni_startdir = ndp->ni_dvp; 41349736Smckusick VREF(ndp->ni_startdir); 41449736Smckusick } 41537715Smckusick if (!wantparent) 41637715Smckusick vrele(ndp->ni_dvp); 41737715Smckusick if ((ndp->ni_nameiop & LOCKLEAF) == 0) 41837715Smckusick VOP_UNLOCK(dp); 41937715Smckusick return (0); 4207534Sroot 42137715Smckusick bad2: 42249736Smckusick if ((ndp->ni_nameiop & LOCKPARENT) && *ndp->ni_next == '\0') 42338001Smckusick VOP_UNLOCK(ndp->ni_dvp); 42437715Smckusick vrele(ndp->ni_dvp); 42537715Smckusick bad: 42637715Smckusick vput(dp); 42737715Smckusick ndp->ni_vp = NULL; 42810849Ssam return (error); 4295972Swnj } 430