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