VOP_RENAME - rename a file
Its arguments are:
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.
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; } /* * POSIX: "If the old argument and the new argument * both refer to links to the same existing file, * the rename() function shall return successfully * and perform no other action." * The upper layers already handle this case. */ KASSERT(fvp != tvp, ("vop_rename: source and destination are the same")); 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; }
Закладки на сайте Проследить за страницей |
Created 1996-2024 by Maxim Chirkov Добавить, Поддержать, Вебмастеру |