VOP_RENAME(9)

명칭
VOP_RENAME - 파일의 이름 변경

서식
<sys/param.h> <sys/vnode.h> int VOP_RENAME(struct vnode *fdvp, struct vnode *fvp, struct componentname *fcnp, struct vnode *tdvp, struct vnode *tvp, struct componentname *tcnp)

해설
이것은 파일의 이름 변경을 해, 어쩌면 친디렉토리를 변경할지도 모릅니다. 변경처의 오브젝트가 존재하는 경우에는, 최초로 삭제됩니다.

인수는 이하대로입니다.

fdvp
    낡은 친디렉토리의 vnode 입니다.

fvp 이름 변경되어야 할 파일의 vnode 입니다.

fcnp
    파일의 현재의 이름에 대한 패스명 정보입니다.

tdvp
    새로운 친디렉토리의 vnode 입니다.

tvp (만약 존재한다면) 변경처의 파일의 vnode 입니다.

tcnp
    파일의 새로운 이름에 대한 패스명 정보입니다.

락
엔트리시에는, 변경원의 디렉토리 및 파일은 락 되지 않고, 그러한 참조 카운트는 늘려지고 있습니다. 이 VOP routine는 돌아오기 전에 양쪽 모두에 대해서 vrele() (을)를 호출할 것입니다.

변경처의 디렉토리 및 파일은, 그러한 참조 카운트가 늘려지는 것은 물론, 락 되고 있습니다. 이 VOP routine는 돌아오기 전에 양쪽 모두에 대해서 vput() (을)를 호출할 것입니다.

유사 코드

    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;
        /*
         * 디바이스를 걸치는 이름 변경을 위한 체크입니다.
         */
        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;
        }
        /*
         * 링크명을 지우려 하고 있는지 어떤지의 체크입니다.
         */
        if (fvp == tvp) {
    	if (fvp->v_type == VDIR) {
    	    error = EINVAL;
    	    goto abortit;
    	}
    	/*
    	 * 변경처를 해방합니다.
    	 */
    	vput(tdvp);
    	vput(tvp);
    	/*
    	 * 변경원을 삭제합니다. 조금 이상한 요소입니다.
    	 */
    	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) {
    	/*
    	 * 명백한 이유이기 때문에,". ", ".." (와)과 ". " 의 별명을 피합니다.
    	 */
    	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);
        /*
         * 이동 요소의 활동중의 사이는, fvp 의 링크 카운트를 늘립니다.
         * 작업 완료 전에 크래쉬 했을 경우에는, 링크 카운트는 잘못해
         * 있겠지만, 수정 가능합니다.
         */
        ...;
        /*
         * 그리고 (예를 들면 디렉토리가 새로운 부모를 얻는 등) ".." 하지만 변경
         * 되지 않으면 안 되는 경우에는, 변경원의 디렉토리는 변경처보다
         * 상위의 디렉토리 계층에 있어 되지 않습니다. 이것은 변경원의
         * 디렉토리 이하의 모두가 고아가 되기 때문입니다. 또, 유저는
         * 변경원으로 ".." (을)를 변경할 수 있도록(듯이) 기록 퍼미션을 가져
         * 있지 않으면 안됩니다.
         */
        error = VOP_ACCESS(fvp, VWRITE, tcnp->cn_cred, tcnp->cn_proc);
        VOP_UNLOCK(fvp);
        if (doingdirectory && fdvp ! = tdvp) {
    	/*
    	 * 패스명의 충돌을 체크합니다.
    	 */
    	...;
        }
        /*
         * 변경처가 존재하지 않는 경우, 변경처를 변경 바탕으로 링크 해, 변경원을
         * 안린크 합니다. 그렇지 않은 경우, 변경처 디렉토리를 고쳐 써
         * 변경원을 참조하도록(듯이) 해, 원의 엔트리를 삭제합니다.
         */
        if (tvp == NULL) {
    	/*
    	 * 새로운 디렉토리의 ".." 의 어카운트.
    	 */
    	if (doingdirectory && fdvp ! = tdvp) {
    	    /*
    	     * tdvp 의 링크 카운트를 늘립니다.
    	     */
    	    ...;
    	}
    	/*
    	 * 새로운 디렉토리에서 이름을 추가합니다.
    	 */
    	...;
    	if (error) {
    	    if (doingdirectory && fdvp ! = tdvp) {
    		/*
    		 * tdvp 이면 링크 카운트를 줄입니다.
    		 */
    		...;
    	    }
    	    goto bad;
    	}
    	vput(tdvp);
        } else {
    	/*
    	 * 변경처가 디렉토리의 경우, 이것은 하늘이 아니면 안되어, 이것에의
    	 * 링크가 있어 되지 않습니다. 또, 변경원이라고 변경처는 일치한다
    	 * (양쪽 모두 디렉토리, 또는 양쪽 모두 디렉토리는 아니다)
    	 * 일을 프로텍션해 주세요.
    	 */
    	if (tvp is a directory) {
    	    if (tvp is not empty) {
    		error = ENOTEMPTY;
    		goto bad;
    	    }
    	    if (! doingdirectory) {
    		error = ENOTDIR;
    		goto bad;
    	    }
    	    /*
    	     * 디렉토리가 사라졌기 때문에, 이름 캐쉬를 갱신합니다.
    	     */
    	    cache_purge(tdvp);
    	} else if (doingdirectory) {
    	    error = ENOTDIR;
    	    goto bad;
    	}
    	/*
    	 * fvp 가 가리키는 tdvp 의 이름 tcnp 를 변경합니다.
    	 */
    	...;
    	/*
    	 * 변경처 디렉토리가 변경원과 같은 디렉토리에 있는 경우에는,
    	 * 변경처의 디렉토리의 부모 링크 카운트를 줄입니다.
    	 * ".." 에 의해, 그 부모에 대한 귀가 방향의 링크가 되는 사실을,
    	 * 설명하는 것입니다.
    	 */
    	if (doingdirectory && fdvp == tdvp) {
    	    /*
    	     * tdvp 의 링크 카운트를 줄입니다.
    	     */
    	    ...;
    	}
    	vput(tdvp);
    	/*
    	 * 디렉토리가 이미 그것을 가리키지 않기 때문에, tvp 의 링크 카운트를
    	 * 줄입니다.
    	 */
    	...;
    	if (doingdirectory) {
    	    /*
    	     * 낡은 디렉토리 tvp 를 예쁘게 합니다.
    	     */
    	    ...;
    	}
    	vput(tvp);
        }
        /*
         * 변경원을 안린크 합니다. 디렉토리가 새로운 부모에게 이동되는 경우
         * 에는, 그 ".." 엔트리를 갱신합니다. 여기서, 많은 귀찮은
         * UFS 의 코드가 생략해졌습니다.
         */
        ...;
    bad:
        if (tvp)
    	vput(tvp);
        vput(tdvp);
    out:
        if (VOP_LOCK(fvp) == 0) {
    	/*
    	 * fvp 의 링크 카운트를 감소
    	 */
    	...;
            vput(fvp);
        } else
    	vrele(fvp);
        return error;
    }

에러

[EPERM]
    파일이 변경 가능하지는 않습니다.

[EXDEV]
    다른 파일 시스템간의 이름 변경은 할 수 없습니다.

[EINVAL]
    ‘.’ 또는 ‘..’ 의 이름 변경, 또는 디렉토리 트리를 파괴하는 것 같은 조작의 실행을 행하려고 했습니다.

[ENOTDIR]
    디렉토리로부터 파일에 또는 그 반대로 이름 변경하려고 했습니다.

[ENOTEMPTY]
    하늘이 아닌 디렉토리를 삭제하려고 했습니다.

관련 항목
vnode(9)

저자
이 메뉴얼 페이지는 Doug Rabson 하지만 썼습니다.