xref: /freebsd/share/man/man9/VOP_RENAME.9 (revision eaa8b244f1a8447ea7815796dbfa60ec5b4ab79d)
1.\" -*- nroff -*-
2.\"
3.\" Copyright (c) 1996 Doug Rabson
4.\"
5.\" All rights reserved.
6.\"
7.\" This program is free software.
8.\"
9.\" Redistribution and use in source and binary forms, with or without
10.\" modification, are permitted provided that the following conditions
11.\" are met:
12.\" 1. Redistributions of source code must retain the above copyright
13.\"    notice, this list of conditions and the following disclaimer.
14.\" 2. Redistributions in binary form must reproduce the above copyright
15.\"    notice, this list of conditions and the following disclaimer in the
16.\"    documentation and/or other materials provided with the distribution.
17.\"
18.\" THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY EXPRESS OR
19.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21.\" IN NO EVENT SHALL THE DEVELOPERS BE LIABLE FOR ANY DIRECT, INDIRECT,
22.\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23.\" NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28.\"
29.\" $Id: VOP_RENAME.9,v 1.3 1997/03/04 10:02:40 dfr Exp $
30.\"
31.Dd July 24, 1996
32.Os
33.Dt VOP_RENAME 9
34.Sh NAME
35.Nm VOP_RENAME
36.Nd rename a file
37.Sh SYNOPSIS
38.Fd #include <sys/vnode.h>
39.Ft int
40.Fn VOP_RENAME "struct vnode *fdvp" "struct vnode *fvp" "struct componentname *fcnp" "struct vnode *tdvp" "struct vnode *tvp" "struct componentname *tcnp"
41.Sh DESCRIPTION
42This renames a file and possibly changes its parent directory.
43If the destination object exists, it will be removed first.
44.Pp
45Its arguments are:
46.Bl -tag -width fdvp
47.It Ar fdvp
48the vnode of the old parent directory
49.It Ar fvp
50the vnode of the file to be renamed
51.It Ar fcnp
52pathname information about the file's current name
53.It Ar tdvp
54the vnode of the new parent directory
55.It Ar tvp
56the vnode of the target file (if it exists)
57.It Ar tcnp
58pathname information about the file's new name
59.El
60.Sh LOCKS
61The destination directory and file (if it exists) should be locked on entry.
62The source directory and file
63will be released on exit.
64The destination directory and file (if it exists) will be unlocked
65and released on exit.
66.Sh PSEUDOCODE
67.Bd -literal
68int
69vop_rename(struct vnode *fdvp, struct vnode *fvp, struct componentname *fcnp,
70	   struct vnode *tdvp, struct vnode *tvp, struct componentname *tcnp)
71{
72    int doingdirectory = 0;
73    int error = 0;
74
75    /*
76     * Check for cross-device rename.
77     */
78    if (fvp->v_mount != tdvp->v_mount) {
79	error = EXDEV;
80    abortit:
81	VOP_ABORTOP(tdvp, tcnp);
82	if (tdvp == tvp)
83	    vrele(tdvp);
84	else
85	    vput(tdvp);
86	if (tvp)
87	    vput(tvp);
88	VOP_ABORTOP(fdvp, fcnp);
89	vrele(fdvp);
90	vrele(fvp);
91	return error;
92    }
93
94    if (tvp exists and is immutable) {
95	error = EPERM;
96	goto abortit;
97    }
98
99    /*
100     * Check if just deleting a link name.
101     */
102    if (fvp == tvp) {
103	if (fvp->v_type == VDIR) {
104	    error = EINVAL;
105	    goto abortit;
106	}
107
108	/*
109	 * Release destination.
110	 */
111	VOP_ABORTOP(tdvp, tcnp);
112	vput(tdvp);
113	vput(tvp);
114
115	/*
116	 * Delete source.  Pretty bizarre stuff.
117	 */
118	vrele(fdvp);
119	vrele(fvp);
120	fcnp->cn_flags &= ~MODMASK;
121	fcnp->cn_flags |= LOCKPARENT | LOCKLEAF;
122	fcnp->cn_nameiop = DELETE;
123	VREF(fdvp);
124	error = relookup(fdvp, &fvp, fcnp);
125	if (error == 0)
126	    vrele(fdvp);
127	return VOP_REMOVE(fdvp, fvp, fcnp);
128    }
129
130    if (fvp is immutable) {
131	error = EPERM;
132	goto abortit;
133    }
134
135    error = VOP_LOCK(fvp);
136    if (error)
137	goto abortit;
138
139    if (vp is a directory) {
140	/*
141	 * Avoid ".", "..", and aliases of "." for obvious reasons.
142	 */
143	if ((fcnp->cn_namelen == 1 && fcnp->cn_nameptr[0] == '.')
144	    || fdvp == fvp
145	    || ((fcnp->cn_flags | tcnp->cn_flags) & ISDOTDOT)) {
146	    VOP_UNLOCK(fvp);
147	    error = EINVAL;
148	    goto abortit;
149	}
150	doingdirectory = 1;
151    }
152    vrele(fdvp);
153
154    /*
155     * Bump link count on fvp while we are moving stuff around.  If we
156     * crash before completing the work, the link count may be wrong
157     * but correctable.
158     */
159    ...;
160
161    /*
162     * If ".." must be changed (ie the directory gets a new
163     * parent) then the source directory must not be in the
164     * directory hierarchy above the target, as this would
165     * orphan everything below the source directory. Also
166     * the user must have write permission in the source so
167     * as to be able to change "..".
168     */
169    error = VOP_ACCESS(fvp, VWRITE, tcnp->cn_cred, tcnp->cn_proc);
170    VOP_UNLOCK(fvp);
171    if (doingdirectory && fdvp != tdvp) {
172	/*
173	 * Check for pathname conflict.
174	 */
175	...;
176    }
177
178    /*
179     * If the target doesn't exist, link the target to the source and
180     * unlink the source.  Otherwise, rewrite the target directory to
181     * reference the source and remove the original entry.
182     */
183    if (tvp == NULL) {
184	/*
185	 * Account for ".." in new directory.
186	 */
187	if (doingdirectory && fdvp != tdvp) {
188	    /*
189	     * Increase link count of tdvp.
190	     */
191	    ...;
192	}
193
194	/*
195	 * Add name in new directory.
196	 */
197	...;
198
199	if (error) {
200	    if (doingdirectory && fdvp != tdvp) {
201		/*
202		 * Decrease link count if tdvp.
203		 */
204		...;
205	    }
206	    goto bad;
207	}
208	vput(tdvp);
209    } else {
210	/*
211	 * Target must be empty if a directory and have no links
212	 * to it. Also, ensure source and target are compatible
213	 * (both directories, or both not directories).
214	 */
215	if (tvp is a directory) {
216	    if (tvp is not empty) {
217		error = ENOTEMPTY;
218		goto bad;
219	    }
220	    if (!doingdirectory) {
221		error = ENOTDIR;
222		goto bad;
223	    }
224	    /*
225	     * Update name cache since directory is going away.
226	     */
227	    cache_purge(tdvp);
228	} else if (doingdirectory) {
229	    error = ENOTDIR;
230	    goto bad;
231	}
232
233	/*
234	 * Change name tcnp in tdvp to point at fvp.
235	 */
236	...;
237
238	/*
239	 * If the target directory is in same directory as the source
240	 * directory, decrement the link count on the parent of the
241	 * target directory.  This accounts for the fact that a
242	 * directory links back to its parent with "..".
243	 */
244	if (doingdirectory && fdvp == tdvp) {
245	    /*
246	     * Decrement link count of tdvp.
247	     */
248	    ...;
249	}
250	vput(tdvp);
251
252	/*
253	 * Decrement the link count of tvp since the directory no
254	 * longer points at it.
255	 */
256	...;
257	if (doingdirectory) {
258	    /*
259	     * Clean up the old directory tvp.
260	     */
261	    ...;
262	}
263	vput(tvp);
264    }
265
266    /*
267     * Unlink the source.  If a directory was moved to a new parent,
268     * update its ".." entry.  Gobs of ugly UFS code omitted here.
269     */
270    ...;
271
272bad:
273    if (tvp)
274	vput(tvp);
275    vput(tdvp);
276out:
277    if (VOP_LOCK(fvp) == 0) {
278	/*
279	 * Decrement link count of fvp.
280	 */
281	...;
282        vput(fvp);
283    } else
284	vrele(fvp);
285
286    return error;
287}
288.Ed
289.Sh ERRORS
290.Bl -tag -width Er
291.It Bq Er EPERM
292the file is immutable
293.It Bq Er EXDEV
294cross device move
295.It Bq Er EINVAL
296illegal directory rename
297.It Bq Er ENOTDIR
298attempt to rename a directory to a file or vice versa
299.It Bq Er ENOTEMPTY
300attempt to remove a directory which is not empty
301.El
302.Sh SEE ALSO
303.Xr vnode 9
304.Sh AUTHORS
305This man page was written by Doug Rabson.
306
307