---
name: "VOP_RENAME"
section: "9"
platform: "linux"
package: "freebsd-manpages"
version: "6.0-5"
release: "Debian 4.0 (Etch)"
platforms: ["linux", "freebsd"]
url: "https://new.carta.tech/VOP_RENAME"
---

# VOP\_RENAME(9)

rename a file

## 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 directory. 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)](/vrele/9.md) 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)](/vput/9.md) 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);
	else
	    vput(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 obvious reasons.
	 */
	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 stuff around.  If we
     * crash before completing the work, the link count may be 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, tcnp->cn_thread);
    VOP_UNLOCK(fvp);
    if (doingdirectory && fdvp != tdvp) {
	/*
	 * Check for pathname conflict.
	 */
	...;
    }
    /*
     * If the target doesn't exist, link the target to the source 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 no links
	 * 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 going away.
	     */
	    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 as the source
	 * directory, decrement the link count on the parent of the
	 * target directory.  This accounts for the fact that 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 new parent,
     * update its ".." entry.  Gobs of ugly UFS code omitted here.
     */
    ...;
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 between different file systems.

- \[EINVAL\]

  An attempt was made to rename *.* or *..*, or to perform an operation which would break the directory 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

[vnode(9)](/vnode/9.md)

## AUTHORS

This manual page was written by Doug Rabson.
