vop_rename(9)
NAME
VOP_RENAME - rename a file
SYNOPSIS
#include <sys/param.h> #include <sys/vnode.h> int VOP_RENAME(struct vnode *fdvp, struct vnode *fvp, struct componentname *fcnp, struct vnode *tdvp, struct vnode *tvp, struct componentname *tcnp);
DESCRIPTION
- This renames a file and possibly changes its parent directo
- ry. If the
destination object exists, it will be removed first. - Its arguments are:
- fdvp The vnode of the old parent directory.
- fvp The vnode of the file to be renamed.
- fcnp Pathname information about the file's current name.
- tdvp The vnode of the new parent directory.
- tvp The vnode of the target file (if it exists).
- tcnp Pathname information about the file's new name.
LOCKS
- The source directory and file are unlocked but are expected
- to have their
ref count bumped on entry. The VOP routine is expected to - vrele(9) both
prior to returning. - The destination directory and file are locked as well as
- having their ref
count bumped. The VOP routine is expected to vput(9) both - prior to
returning.
PSEUDOCODE
- int
vop_rename(struct vnode *fdvp, struct vnode *fvp, struct - componentname *fcnp,
- struct vnode *tdvp, struct vnode *tvp, struct
- componentname *tcnp)
- {
- int doingdirectory = 0;
int error = 0; - /*
* Check for cross-device rename.
*/ - if (fvp->v_mount != tdvp->v_mount) {
error = EXDEV;
- abortit:
if (tdvp == tvp)vrele(tdvp);elsevput(tdvp);if (tvp)vput(tvp);vrele(fdvp);
vrele(fvp);
return error; - }
- if (tvp exists and is immutable) {
error = EPERM;
goto abortit; - }
- /*
* Check if just deleting a link name.
*/ - if (fvp == tvp) {
if (fvp->v_type == VDIR) {error = EINVAL;
goto abortit;}/** Release destination.
*/vput(tdvp);
vput(tvp);/** Delete source. Pretty bizarre stuff.
*/vrele(fdvp);
vrele(fvp);
fcnp->cn_flags &= ~MODMASK;
fcnp->cn_flags |= LOCKPARENT | LOCKLEAF;
fcnp->cn_nameiop = DELETE;
VREF(fdvp);
error = relookup(fdvp, &fvp, fcnp);
if (error == 0)vrele(fdvp);return VOP_REMOVE(fdvp, fvp, fcnp); - }
- if (fvp is immutable) {
error = EPERM;
goto abortit; - }
- error = VOP_LOCK(fvp);
if (error)goto abortit; - if (vp is a directory) {
/** Avoid ".", "..", and aliases of "." for obviousreasons.
*/if ((fcnp->cn_namelen == 1 && fcnp->cn_nameptr[0] ==|| fdvp == fvp
|| ((fcnp->cn_flags | tcnp->cn_flags) & ISDOTDOT)) {
VOP_UNLOCK(fvp);
error = EINVAL;
goto abortit;}
doingdirectory = 1; - }
vrele(fdvp); - /*
* Bump link count on fvp while we are moving stuffaround. If we
* crash before completing the work, the link count maybe wrong
* but correctable.
*/ - ...;
- /*
* If ".." must be changed (ie the directory gets a new
* parent) then the source directory must not be in the
* directory hierarchy above the target, as this would
* orphan everything below the source directory. Also
* the user must have write permission in the source so
* as to be able to change "..".
*/ - error = VOP_ACCESS(fvp, VWRITE, tcnp->cn_cred, tc
- np->cn_thread);
VOP_UNLOCK(fvp);
if (doingdirectory && fdvp != tdvp) {/** Check for pathname conflict.
*/...; - }
- /*
* If the target doesn't exist, link the target to thesource and
* unlink the source. Otherwise, rewrite the target directory to
* reference the source and remove the original entry.
*/ - if (tvp == NULL) {
/** Account for ".." in new directory.
*/if (doingdirectory && fdvp != tdvp) {/** Increase link count of tdvp.
*/...;}/** Add name in new directory.
*/...;if (error) {if (doingdirectory && fdvp != tdvp) {/** Decrease link count if tdvp.
*/...;}
goto bad;}
vput(tdvp); - } else {
/** Target must be empty if a directory and have nolinks
* to it. Also, ensure source and target are compatible
* (both directories, or both not directories).
*/if (tvp is a directory) {if (tvp is not empty) {error = ENOTEMPTY;
goto bad;}
if (!doingdirectory) {error = ENOTDIR;
goto bad;}
/** Update name cache since directory is goingaway.
*/cache_purge(tdvp);} else if (doingdirectory) {error = ENOTDIR;
goto bad;}/** Change name tcnp in tdvp to point at fvp.
*/...;/** If the target directory is in same directory asthe source
* directory, decrement the link count on the parentof the
* target directory. This accounts for the factthat a
* directory links back to its parent with "..".
*/if (doingdirectory && fdvp == tdvp) {/** Decrement link count of tdvp.
*/...;}
vput(tdvp);/** Decrement the link count of tvp since the directory no
* longer points at it.
*/...;
if (doingdirectory) {/** Clean up the old directory tvp.
*/...;}
vput(tvp); - }
- /*
* Unlink the source. If a directory was moved to a newparent,
* update its ".." entry. Gobs of ugly UFS code omittedhere.
*/ - ...;
- bad:
- if (tvp)
vput(tvp);
- vput(tdvp);
- out:
- if (VOP_LOCK(fvp) == 0) {
/** Decrement link count of fvp.
*/...;
vput(fvp); - } else
vrele(fvp);
- return error;
- }
ERRORS
[EPERM] The file is immutable.
- [EXDEV] It is not possible to rename a file be
- tween different
- file systems.
- [EINVAL] An attempt was made to rename . or .., or
- to perform
- an operation which would break the direc
- tory tree
structure. - [ENOTDIR] An attempt was made to rename a directory
- to a file or
- vice versa.
- [ENOTEMPTY] An attempt was made to remove a directory
- which is not
- empty.
SEE ALSO
AUTHORS
- This manual page was written by Doug Rabson.
- BSD July 24, 1996