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