Initial import from FreeBSD RELENG_4:
[dragonfly.git] / share / man / man9 / VOP_RENAME.9
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 .\" $FreeBSD: src/share/man/man9/VOP_RENAME.9,v 1.10.2.2 2001/12/17 11:30:18 ru 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 .In sys/param.h
39 .In sys/vnode.h
40 .Ft int
41 .Fn VOP_RENAME "struct vnode *fdvp" "struct vnode *fvp" "struct componentname *fcnp" "struct vnode *tdvp" "struct vnode *tvp" "struct componentname *tcnp"
42 .Sh DESCRIPTION
43 This renames a file and possibly changes its parent directory.
44 If the destination object exists, it will be removed first.
45 .Pp
46 Its arguments are:
47 .Bl -tag -width fdvp
48 .It Ar fdvp
49 the vnode of the old parent directory
50 .It Ar fvp
51 the vnode of the file to be renamed
52 .It Ar fcnp
53 pathname information about the file's current name
54 .It Ar tdvp
55 the vnode of the new parent directory
56 .It Ar tvp
57 the vnode of the target file (if it exists)
58 .It Ar tcnp
59 pathname information about the file's new name
60 .El
61 .Sh LOCKS
62 The source directory and file are unlocked but are expected to have their
63 ref count bumped on entry.  The VOP routine is expected to
64 .Fn vrele
65 both prior
66 to returning.
67 .Pp
68 The destination directory and file are locked as well as having their ref
69 count bumped.  The VOP routine is expected to
70 .Fn vput
71 both prior to
72 returning.
73 .Sh PSEUDOCODE
74 .Bd -literal
75 int
76 vop_rename(struct vnode *fdvp, struct vnode *fvp, struct componentname *fcnp,
77            struct vnode *tdvp, struct vnode *tvp, struct componentname *tcnp)
78 {
79     int doingdirectory = 0;
80     int error = 0;
81
82     /*
83      * Check for cross-device rename.
84      */
85     if (fvp->v_mount != tdvp->v_mount) {
86         error = EXDEV;
87     abortit:
88         VOP_ABORTOP(tdvp, tcnp);
89         if (tdvp == tvp)
90             vrele(tdvp);
91         else
92             vput(tdvp);
93         if (tvp)
94             vput(tvp);
95         VOP_ABORTOP(fdvp, fcnp);
96         vrele(fdvp);
97         vrele(fvp);
98         return error;
99     }
100
101     if (tvp exists and is immutable) {
102         error = EPERM;
103         goto abortit;
104     }
105
106     /*
107      * Check if just deleting a link name.
108      */
109     if (fvp == tvp) {
110         if (fvp->v_type == VDIR) {
111             error = EINVAL;
112             goto abortit;
113         }
114
115         /*
116          * Release destination.
117          */
118         VOP_ABORTOP(tdvp, tcnp);
119         vput(tdvp);
120         vput(tvp);
121
122         /*
123          * Delete source.  Pretty bizarre stuff.
124          */
125         vrele(fdvp);
126         vrele(fvp);
127         fcnp->cn_flags &= ~MODMASK;
128         fcnp->cn_flags |= LOCKPARENT | LOCKLEAF;
129         fcnp->cn_nameiop = DELETE;
130         VREF(fdvp);
131         error = relookup(fdvp, &fvp, fcnp);
132         if (error == 0)
133             vrele(fdvp);
134         return VOP_REMOVE(fdvp, fvp, fcnp);
135     }
136
137     if (fvp is immutable) {
138         error = EPERM;
139         goto abortit;
140     }
141
142     error = VOP_LOCK(fvp);
143     if (error)
144         goto abortit;
145
146     if (vp is a directory) {
147         /*
148          * Avoid ".", "..", and aliases of "." for obvious reasons.
149          */
150         if ((fcnp->cn_namelen == 1 && fcnp->cn_nameptr[0] == '.')
151             || fdvp == fvp
152             || ((fcnp->cn_flags | tcnp->cn_flags) & ISDOTDOT)) {
153             VOP_UNLOCK(fvp);
154             error = EINVAL;
155             goto abortit;
156         }
157         doingdirectory = 1;
158     }
159     vrele(fdvp);
160
161     /*
162      * Bump link count on fvp while we are moving stuff around.  If we
163      * crash before completing the work, the link count may be wrong
164      * but correctable.
165      */
166     ...;
167
168     /*
169      * If ".." must be changed (ie the directory gets a new
170      * parent) then the source directory must not be in the
171      * directory hierarchy above the target, as this would
172      * orphan everything below the source directory. Also
173      * the user must have write permission in the source so
174      * as to be able to change "..".
175      */
176     error = VOP_ACCESS(fvp, VWRITE, tcnp->cn_cred, tcnp->cn_proc);
177     VOP_UNLOCK(fvp);
178     if (doingdirectory && fdvp != tdvp) {
179         /*
180          * Check for pathname conflict.
181          */
182         ...;
183     }
184
185     /*
186      * If the target doesn't exist, link the target to the source and
187      * unlink the source.  Otherwise, rewrite the target directory to
188      * reference the source and remove the original entry.
189      */
190     if (tvp == NULL) {
191         /*
192          * Account for ".." in new directory.
193          */
194         if (doingdirectory && fdvp != tdvp) {
195             /*
196              * Increase link count of tdvp.
197              */
198             ...;
199         }
200
201         /*
202          * Add name in new directory.
203          */
204         ...;
205
206         if (error) {
207             if (doingdirectory && fdvp != tdvp) {
208                 /*
209                  * Decrease link count if tdvp.
210                  */
211                 ...;
212             }
213             goto bad;
214         }
215         vput(tdvp);
216     } else {
217         /*
218          * Target must be empty if a directory and have no links
219          * to it. Also, ensure source and target are compatible
220          * (both directories, or both not directories).
221          */
222         if (tvp is a directory) {
223             if (tvp is not empty) {
224                 error = ENOTEMPTY;
225                 goto bad;
226             }
227             if (!doingdirectory) {
228                 error = ENOTDIR;
229                 goto bad;
230             }
231             /*
232              * Update name cache since directory is going away.
233              */
234             cache_purge(tdvp);
235         } else if (doingdirectory) {
236             error = ENOTDIR;
237             goto bad;
238         }
239
240         /*
241          * Change name tcnp in tdvp to point at fvp.
242          */
243         ...;
244
245         /*
246          * If the target directory is in same directory as the source
247          * directory, decrement the link count on the parent of the
248          * target directory.  This accounts for the fact that a
249          * directory links back to its parent with "..".
250          */
251         if (doingdirectory && fdvp == tdvp) {
252             /*
253              * Decrement link count of tdvp.
254              */
255             ...;
256         }
257         vput(tdvp);
258
259         /*
260          * Decrement the link count of tvp since the directory no
261          * longer points at it.
262          */
263         ...;
264         if (doingdirectory) {
265             /*
266              * Clean up the old directory tvp.
267              */
268             ...;
269         }
270         vput(tvp);
271     }
272
273     /*
274      * Unlink the source.  If a directory was moved to a new parent,
275      * update its ".." entry.  Gobs of ugly UFS code omitted here.
276      */
277     ...;
278
279 bad:
280     if (tvp)
281         vput(tvp);
282     vput(tdvp);
283 out:
284     if (VOP_LOCK(fvp) == 0) {
285         /*
286          * Decrement link count of fvp.
287          */
288         ...;
289         vput(fvp);
290     } else
291         vrele(fvp);
292
293     return error;
294 }
295 .Ed
296 .Sh ERRORS
297 .Bl -tag -width Er
298 .It Bq Er EPERM
299 the file is immutable
300 .It Bq Er EXDEV
301 cross device move
302 .It Bq Er EINVAL
303 illegal directory rename
304 .It Bq Er ENOTDIR
305 attempt to rename a directory to a file or vice versa
306 .It Bq Er ENOTEMPTY
307 attempt to remove a directory which is not empty
308 .El
309 .Sh SEE ALSO
310 .Xr vnode 9
311 .Sh AUTHORS
312 This man page was written by
313 .An Doug Rabson .