From 7e67e1e73230219ea55118f095cc1800faf2c534 Mon Sep 17 00:00:00 2001 From: dfr Date: Mon, 3 Mar 1997 18:01:01 +0000 Subject: This is the current draft of my filesystem manpages. Some files are incomplete and some are just placeholders but I wanted to try to get something at least into 2.2 on the grounds that what I have is a lot better than nothing. I also wanted to commit something which documents the interfaces in 2.2 before I start updating the documentation for 3.0. This is a definite 2.2 candidate and is also relavent to 2.1 if people still care about that branch. --- share/man/man9/VOP_LOOKUP.9 | 447 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 447 insertions(+) create mode 100644 share/man/man9/VOP_LOOKUP.9 (limited to 'share/man/man9/VOP_LOOKUP.9') diff --git a/share/man/man9/VOP_LOOKUP.9 b/share/man/man9/VOP_LOOKUP.9 new file mode 100644 index 0000000..c878e39 --- /dev/null +++ b/share/man/man9/VOP_LOOKUP.9 @@ -0,0 +1,447 @@ +.\" -*- nroff -*- +.\" +.\" Copyright (c) 1996 Doug Rabson +.\" +.\" All rights reserved. +.\" +.\" This program is free software. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY EXPRESS OR +.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +.\" IN NO EVENT SHALL THE DEVELOPERS BE LIABLE FOR ANY DIRECT, INDIRECT, +.\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +.\" NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +.\" +.\" $Id$ +.\" +.Dd July 24, 1996 +.Os FreeBSD +.Dt VOP_LOOKUP 9 +.Sh NAME +.Nm VOP_LOOKUP +.Nd lookup a component of a pathname +.Sh SYNOPSIS +.Fd #include +.Fd #include +.Ft int +.Fn VOP_LOOKUP "struct vnode *dvp" "struct vnode **vpp" "struct componentname *cnp" +.Sh DESCRIPTION +This VFS entry point looks up a single pathname component in a given directory. +.Pp +Its arguments are: +.Bl -tag -width vpp +.It Ar dvp +the locked vnode of the directory to search +.It Ar vpp +the address of a variable where the resulting locked vnode should be stored +.It Ar cnp +the pathname component to be searched for +.El +.Pp +.Fa Cnp +is a pointer to a componentname structure defined as follows: +.Bd -literal +struct componentname { + /* + * Arguments to lookup. + */ + u_long cn_nameiop; /* namei operation */ + u_long cn_flags; /* flags to namei */ + struct proc *cn_proc; /* process requesting lookup */ + struct ucred *cn_cred; /* credentials */ + /* + * Shared between lookup and commit routines. + */ + char *cn_pnbuf; /* pathname buffer */ + char *cn_nameptr; /* pointer to looked up name */ + long cn_namelen; /* length of looked up component */ + u_long cn_hash; /* hash value of looked up name */ + long cn_consume; /* chars to consume in lookup() */ +}; +.Ed +.Pp +Convert a component of a pathname into a pointer to a locked vnode. +This is a very central and rather complicated routine. +If the file system is not maintained in a strict tree hierarchy, +this can result in a deadlock situation. +.Pp +The +.Fa cnp->cn_nameiop +argument is +.Dv LOOKUP , +.Dv CREATE , +.Dv RENAME , +or +.Dv DELETE +depending on the intended use of the object. +When +.Dv CREATE , +.Dv RENAME , +or +.Dv DELETE +is specified, information usable in +creating, renaming, or deleting a directory entry may be calculated. +.Pp +Overall outline of VOP_LOOKUP: +.Bd -filled -offset indent +Check accessibility of directory. +Look for name in cache, if found, then return name. +Search for name in directory, goto to found or notfound as appropriate. +.Ed +.Pp +notfound: +.Bd -filled -offset indent +If creating or renaming and at end of pathname, +return +.Dv EJUSTRETURN , +leaving info on available slots else return +.Dv ENOENT . +.Ed +.Pp +found: +.Bd -filled -offset indent +If at end of path and deleting, return information to allow delete. +If at end of path and renaming, lock target +inode and return info to allow rename. +If not at end, add name to cache; if at end and neither creating +nor deleting, add name to cache. +.Ed +.Sh LOCKS +The directory, +.Fa dvp +should be locked on entry. +If an error (note: the return value +.Dv EJUSTRETURN +is not considered an error) +is detected, it will be returned locked. +Otherwise, it will be unlocked unless both +.Dv LOCKPARENT +and +.Dv ISLASTCN +are specified in +.Fa cnp->cn_flags . +If an entry is found in the directory, it will be returned locked. +.Sh RETURN VALUES +Zero is returned with +.Fa *vpp +set to the locked vnode of the file if the component is found. +If the component being searched for is ".", then the vnode just has +an extra reference added to it with +.Xr vref 9 . +The caller must take care to release the locks appropriately in this +case. +.Pp +If the component is not found and the operation is +.Dv CREATE +or +.Dv RENAME , +the flag +.Dv ISLASTCN +is specified and the operation would succeed, the special return value +.Dv EJUSTRETURN +is returned. +Otherwise, an appropriate error code is returned. +.Sh PSEUDOCODE +.Bd -literal +int +vop_lookup(struct vnode *dvp, + struct vnode **vpp, + struct componentname *cnp) +{ + int error; + int nameiop = cnp->cn_nameiop; + int flags = cnp->cn_flags; + int lockparent = flags & LOCKPARENT; + int islastcn = flags & ISLASTCN; + struct vnode *vp = NULL; + + /* + * Check accessiblity of directory. + */ + if (dvp->v_type != VDIR) + return ENOTDIR; + + error = VOP_ACCESS(dvp, VEXEC, cred, cnp->cn_proc); + if (error) + return (error); + + if (islastcn && (dvp->v_mount->mnt_flag & MNT_RDONLY) && + (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME)) + return (EROFS); + + /* + * Check name cachec for directory/name pair. This returns ENOENT + * if the name is known not to exist, -1 if the name was found, or + * zero if not. + */ + error = cache_lookup(dvp, vpp, cnp); + if (error) { + int vpid; + + if (error = ENOENT) + return error; + + vp = *vpp; + if (dvp == vp) { /* lookup on "." */ + VREF(vp); + error = 0; + } else if (flags & ISDOTDOT) { + /* + * We need to unlock the directory before getting + * the locked vnode for ".." to avoid deadlocks. + */ + VOP_UNLOCK(dvp); + error = vget(vp, 1); + if (!error) { + if (lockparent && islastcn) + error = VOP_LOCK(dvp); + } + } else { + error = vget(vp, 1); + if (error || !(lockparent && islastcn)) { + VOP_UNLOCK(dvp); + } + } + + /* + * Check that the capability number did not change + * while we were waiting for the lock. + */ + if (!error) { + if (vpid == vp->v_id) { + /* + * dvp is locked if lockparent && islastcn. + * vp is locked. + */ + return (0); + } + vput(vp); + + if (dvp != vp && lockparent && islastcn) + VOP_UNLOCK(pdp); + } + + /* + * Re-lock dvp for the directory search below. + */ + error = VOP_LOCK(dvp); + if (error) { + return (error); + } + + *vpp = NULL; + } + + /* + * Search dvp for the component cnp->cn_nameptr. + */ + ...; + + if (!found) { + if ((nameiop == CREATE || nameiop == RENAME) + && islastcn + && directory dvp has not been removed) { + /* + * Check for write access on directory. + */ + + /* + * Possibly record the position of a slot in the directory + * large enough for the new component name. This can be + * recorded in the vnode private data for dvp. + * Set the SAVENAME flag to hold onto the pathname for use + * later in VOP_CREATE or VOP_RENAME. + */ + cnp->cn_flags |= SAVENAME; + if (!lockparent) + /* + * Note that the extra data recorded above is only + * useful if lockparent is specified. + */ + VOP_UNLOCK(dvp); + + return EJUSTRETURN; + } + + /* + * Consider inserting name into cache. + */ + if ((cnp->cn_flags & MAKEENTRY) && nameiop != CREATE) + cache_enter(dvp, NULL, cnp); + + return ENOENT; + } else { + /* + * If deleting, and at end of pathname, return parameters + * which can be used to remove file. If the wantparent flag + * isn't set, we return only the directory, otherwise we go on + * and lock the inode, being careful with ".". + */ + if (nameiop == DELETE && islastcn) { + /* + * Check for write access on directory. + */ + error = VOP_ACCESS(dvp, VWRITE, cred, cnp->cn_proc); + if (error) + return (error); + + if (found entry is same as dvp) { + VREF(dvp); + *vpp = dvp; + return 0; + } + + error = VFS_VGET(dvp->v_mount, ..., &vp); + if (error) + return error; + + if (directory is sticky + && cred->cr_uid != 0 + && cred->cr_uid != owner of dvp + && owner of vp != cred->cr_uid) { + vput(vp); + return EPERM; + } + *vpp = vp; + if (!lockparent) + VOP_UNLOCK(dvp); + + return 0; + } + + /* + * If rewriting (RENAME), return the inode and the + * information required to rewrite the present directory + * Must get inode of directory entry to verify it's a + * regular file, or empty directory. + */ + if (nameiop == RENAME && wantparent && islastcn) { + error = VOP_ACCESS(dvp, VWRITE, cred, cnp->cn_proc); + if (error) + return (error); + + /* + * Check for "." + */ + if (found entry is same as dvp) + return EISDIR; + + error = VFS_VGET(dvp->v_mount, ..., &vp); + if (error) + return error; + *vpp = vp; + /* + * Save the name for use in VOP_RENAME later. + */ + cnp->cn_flags |= SAVENAME; + if (!lockparent) + VOP_UNLOCK(dvp); + + return 0; + } + + /* + * Step through the translation in the name. We do not `vput' the + * directory because we may need it again if a symbolic link + * is relative to the current directory. Instead we save it + * unlocked as "pdp". We must get the target inode before unlocking + * the directory to insure that the inode will not be removed + * before we get it. We prevent deadlock by always fetching + * inodes from the root, moving down the directory tree. Thus + * when following backward pointers ".." we must unlock the + * parent directory before getting the requested directory. + * There is a potential race condition here if both the current + * and parent directories are removed before the VFS_VGET for the + * inode associated with ".." returns. We hope that this occurs + * infrequently since we cannot avoid this race condition without + * implementing a sophisticated deadlock detection algorithm. + * Note also that this simple deadlock detection scheme will not + * work if the file system has any hard links other than ".." + * that point backwards in the directory structure. + */ + if (flags & ISDOTDOT) { + VOP_UNLOCK(dvp); /* race to get the inode */ + error = VFS_VGET(dvp->v_mount, ..., &vp); + if (error) { + VOP_LOCK(dvp); + return (error); + } + if (lockparent && islastcn) { + error = VOP_LOCK(dvp); + if (error) { + vput(vp); + return error; + } + } + *vpp = vp; + } else if (found entry is same as dvp) { + VREF(dvp); /* we want ourself, ie "." */ + *vpp = dvp; + } else { + error = VFS_VGET(dvp->v_mount, ..., &vp); + if (error) + return (error); + if (!lockparent || !islastcn) + VOP_UNLOCK(dvp); + *vpp = vp; + } + + /* + * Insert name into cache if appropriate. + */ + if (cnp->cn_flags & MAKEENTRY) + cache_enter(dvp, *vpp, cnp); + return (0); + } +} +.Ed +.Sh ERRORS +.Bl -tag -width EJUSTRETURN +.It Bq Er ENOTDIR +The vnode +.Fa dvp +does not represent a directory. +.It Bq Er ENOENT +The component +.Fa dvp +was not found in this directory. +.It Bq Er EACCESS +access for the specified operation is denied. +.It Bq Er EJUSTRETURN +a +.Dv CREATE +or +.Dv RENAME +operation would be successful +.El +.Sh SEE ALSO +.Xr VOP_ACCESS 9 , +.Xr VOP_CREATE 9 , +.Xr VOP_MKNOD 9 , +.Xr VOP_MKDIR 9 , +.Xr VOP_SYMLINK 9 , +.Xr VOP_RENAME 9 , +.Xr VOP_ABORTOP 9 +.Sh HISTORY +The function +.Nm +appeared in 4.3BSD. +.Sh SEE ALSO +.Xr vnode 9 +.Sh AUTHORS +This man page was written by Doug Rabson, with some text from +comments in ufs_lookup.c. -- cgit v1.1