1 1.25 thorpej /* $NetBSD: lfs_rename.c,v 1.25 2021/10/20 03:08:19 thorpej Exp $ */ 2 1.21 dholland /* from NetBSD: ufs_rename.c,v 1.12 2015/03/27 17:27:56 riastradh Exp */ 3 1.1 dholland 4 1.1 dholland /*- 5 1.1 dholland * Copyright (c) 2012 The NetBSD Foundation, Inc. 6 1.1 dholland * All rights reserved. 7 1.1 dholland * 8 1.1 dholland * This code is derived from software contributed to The NetBSD Foundation 9 1.1 dholland * by Taylor R Campbell. 10 1.1 dholland * 11 1.1 dholland * Redistribution and use in source and binary forms, with or without 12 1.1 dholland * modification, are permitted provided that the following conditions 13 1.1 dholland * are met: 14 1.1 dholland * 1. Redistributions of source code must retain the above copyright 15 1.1 dholland * notice, this list of conditions and the following disclaimer. 16 1.1 dholland * 2. Redistributions in binary form must reproduce the above copyright 17 1.1 dholland * notice, this list of conditions and the following disclaimer in the 18 1.1 dholland * documentation and/or other materials provided with the distribution. 19 1.1 dholland * 20 1.1 dholland * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 21 1.1 dholland * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 22 1.1 dholland * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 23 1.1 dholland * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 24 1.1 dholland * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 25 1.1 dholland * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 26 1.1 dholland * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 27 1.1 dholland * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 28 1.1 dholland * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 29 1.1 dholland * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 30 1.1 dholland * POSSIBILITY OF SUCH DAMAGE. 31 1.1 dholland */ 32 1.1 dholland /*- 33 1.1 dholland * Copyright (c) 1999, 2000, 2001, 2002, 2003 The NetBSD Foundation, Inc. 34 1.1 dholland * All rights reserved. 35 1.1 dholland * 36 1.1 dholland * This code is derived from software contributed to The NetBSD Foundation 37 1.1 dholland * by Konrad E. Schroder <perseant (at) hhhh.org>. 38 1.1 dholland * 39 1.1 dholland * Redistribution and use in source and binary forms, with or without 40 1.1 dholland * modification, are permitted provided that the following conditions 41 1.1 dholland * are met: 42 1.1 dholland * 1. Redistributions of source code must retain the above copyright 43 1.1 dholland * notice, this list of conditions and the following disclaimer. 44 1.1 dholland * 2. Redistributions in binary form must reproduce the above copyright 45 1.1 dholland * notice, this list of conditions and the following disclaimer in the 46 1.1 dholland * documentation and/or other materials provided with the distribution. 47 1.1 dholland * 48 1.1 dholland * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 49 1.1 dholland * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 50 1.1 dholland * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 51 1.1 dholland * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 52 1.1 dholland * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 53 1.1 dholland * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 54 1.1 dholland * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 55 1.1 dholland * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 56 1.1 dholland * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 57 1.1 dholland * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 58 1.1 dholland * POSSIBILITY OF SUCH DAMAGE. 59 1.1 dholland */ 60 1.1 dholland /* 61 1.1 dholland * Copyright (c) 1986, 1989, 1991, 1993, 1995 62 1.1 dholland * The Regents of the University of California. All rights reserved. 63 1.1 dholland * 64 1.1 dholland * Redistribution and use in source and binary forms, with or without 65 1.1 dholland * modification, are permitted provided that the following conditions 66 1.1 dholland * are met: 67 1.1 dholland * 1. Redistributions of source code must retain the above copyright 68 1.1 dholland * notice, this list of conditions and the following disclaimer. 69 1.1 dholland * 2. Redistributions in binary form must reproduce the above copyright 70 1.1 dholland * notice, this list of conditions and the following disclaimer in the 71 1.1 dholland * documentation and/or other materials provided with the distribution. 72 1.1 dholland * 3. Neither the name of the University nor the names of its contributors 73 1.1 dholland * may be used to endorse or promote products derived from this software 74 1.1 dholland * without specific prior written permission. 75 1.1 dholland * 76 1.1 dholland * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 77 1.1 dholland * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 78 1.1 dholland * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 79 1.1 dholland * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 80 1.1 dholland * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 81 1.1 dholland * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 82 1.1 dholland * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 83 1.1 dholland * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 84 1.1 dholland * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 85 1.1 dholland * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 86 1.1 dholland * SUCH DAMAGE. 87 1.1 dholland * 88 1.1 dholland * @(#)lfs_vnops.c 8.13 (Berkeley) 6/10/95 89 1.1 dholland */ 90 1.1 dholland 91 1.1 dholland #include <sys/cdefs.h> 92 1.25 thorpej __KERNEL_RCSID(0, "$NetBSD: lfs_rename.c,v 1.25 2021/10/20 03:08:19 thorpej Exp $"); 93 1.1 dholland 94 1.1 dholland #include <sys/param.h> 95 1.1 dholland #include <sys/systm.h> 96 1.1 dholland #include <sys/errno.h> 97 1.1 dholland #include <sys/namei.h> 98 1.1 dholland #include <sys/resourcevar.h> 99 1.1 dholland #include <sys/kernel.h> 100 1.1 dholland #include <sys/file.h> 101 1.1 dholland #include <sys/stat.h> 102 1.1 dholland #include <sys/buf.h> 103 1.1 dholland #include <sys/proc.h> 104 1.1 dholland #include <sys/mount.h> 105 1.1 dholland #include <sys/vnode.h> 106 1.1 dholland #include <sys/vnode_if.h> 107 1.1 dholland #include <sys/pool.h> 108 1.1 dholland #include <sys/signalvar.h> 109 1.1 dholland #include <sys/kauth.h> 110 1.1 dholland #include <sys/syslog.h> 111 1.1 dholland 112 1.1 dholland #include <miscfs/fifofs/fifo.h> 113 1.1 dholland #include <miscfs/genfs/genfs.h> 114 1.1 dholland #include <miscfs/specfs/specdev.h> 115 1.1 dholland 116 1.1 dholland #include <ufs/lfs/ulfs_inode.h> 117 1.1 dholland #include <ufs/lfs/ulfsmount.h> 118 1.1 dholland #include <ufs/lfs/ulfs_bswap.h> 119 1.1 dholland #include <ufs/lfs/ulfs_extern.h> 120 1.1 dholland 121 1.1 dholland #include <ufs/lfs/lfs.h> 122 1.9 dholland #include <ufs/lfs/lfs_accessors.h> 123 1.1 dholland #include <ufs/lfs/lfs_extern.h> 124 1.1 dholland 125 1.1 dholland /* 126 1.1 dholland * ulfs_gro_directory_empty_p: Return true if the directory vp is 127 1.1 dholland * empty. dvp is its parent. 128 1.1 dholland * 129 1.1 dholland * vp and dvp must be locked and referenced. 130 1.1 dholland */ 131 1.1 dholland static bool 132 1.1 dholland ulfs_gro_directory_empty_p(struct mount *mp, kauth_cred_t cred, 133 1.1 dholland struct vnode *vp, struct vnode *dvp) 134 1.1 dholland { 135 1.1 dholland 136 1.1 dholland (void)mp; 137 1.1 dholland KASSERT(mp != NULL); 138 1.1 dholland KASSERT(vp != NULL); 139 1.1 dholland KASSERT(dvp != NULL); 140 1.1 dholland KASSERT(vp != dvp); 141 1.1 dholland KASSERT(vp->v_mount == mp); 142 1.1 dholland KASSERT(dvp->v_mount == mp); 143 1.1 dholland KASSERT(VOP_ISLOCKED(vp) == LK_EXCLUSIVE); 144 1.1 dholland KASSERT(VOP_ISLOCKED(dvp) == LK_EXCLUSIVE); 145 1.1 dholland 146 1.1 dholland return ulfs_dirempty(VTOI(vp), VTOI(dvp)->i_number, cred); 147 1.1 dholland } 148 1.1 dholland 149 1.1 dholland /* 150 1.1 dholland * ulfs_gro_rename_check_possible: Check whether a rename is possible 151 1.1 dholland * independent of credentials. 152 1.1 dholland */ 153 1.1 dholland static int 154 1.1 dholland ulfs_gro_rename_check_possible(struct mount *mp, 155 1.1 dholland struct vnode *fdvp, struct vnode *fvp, 156 1.1 dholland struct vnode *tdvp, struct vnode *tvp) 157 1.1 dholland { 158 1.1 dholland 159 1.1 dholland (void)mp; 160 1.1 dholland KASSERT(mp != NULL); 161 1.1 dholland KASSERT(fdvp != NULL); 162 1.1 dholland KASSERT(fvp != NULL); 163 1.1 dholland KASSERT(tdvp != NULL); 164 1.1 dholland KASSERT(fdvp != fvp); 165 1.1 dholland KASSERT(fdvp != tvp); 166 1.1 dholland KASSERT(tdvp != fvp); 167 1.1 dholland KASSERT(tdvp != tvp); 168 1.1 dholland KASSERT(fvp != tvp); 169 1.1 dholland KASSERT(fdvp->v_type == VDIR); 170 1.1 dholland KASSERT(tdvp->v_type == VDIR); 171 1.1 dholland KASSERT(fdvp->v_mount == mp); 172 1.1 dholland KASSERT(fvp->v_mount == mp); 173 1.1 dholland KASSERT(tdvp->v_mount == mp); 174 1.1 dholland KASSERT((tvp == NULL) || (tvp->v_mount == mp)); 175 1.1 dholland KASSERT(VOP_ISLOCKED(fdvp) == LK_EXCLUSIVE); 176 1.1 dholland KASSERT(VOP_ISLOCKED(fvp) == LK_EXCLUSIVE); 177 1.1 dholland KASSERT(VOP_ISLOCKED(tdvp) == LK_EXCLUSIVE); 178 1.1 dholland KASSERT((tvp == NULL) || (VOP_ISLOCKED(tvp) == LK_EXCLUSIVE)); 179 1.1 dholland 180 1.1 dholland return genfs_ufslike_rename_check_possible( 181 1.1 dholland VTOI(fdvp)->i_flags, VTOI(fvp)->i_flags, 182 1.1 dholland VTOI(tdvp)->i_flags, (tvp? VTOI(tvp)->i_flags : 0), 183 1.1 dholland (tvp != NULL), 184 1.1 dholland IMMUTABLE, APPEND); 185 1.1 dholland } 186 1.1 dholland 187 1.1 dholland /* 188 1.1 dholland * ulfs_gro_rename_check_permitted: Check whether a rename is permitted 189 1.1 dholland * given our credentials. 190 1.1 dholland */ 191 1.1 dholland static int 192 1.1 dholland ulfs_gro_rename_check_permitted(struct mount *mp, kauth_cred_t cred, 193 1.1 dholland struct vnode *fdvp, struct vnode *fvp, 194 1.1 dholland struct vnode *tdvp, struct vnode *tvp) 195 1.1 dholland { 196 1.1 dholland 197 1.1 dholland (void)mp; 198 1.1 dholland KASSERT(mp != NULL); 199 1.1 dholland KASSERT(fdvp != NULL); 200 1.1 dholland KASSERT(fvp != NULL); 201 1.1 dholland KASSERT(tdvp != NULL); 202 1.1 dholland KASSERT(fdvp != fvp); 203 1.1 dholland KASSERT(fdvp != tvp); 204 1.1 dholland KASSERT(tdvp != fvp); 205 1.1 dholland KASSERT(tdvp != tvp); 206 1.1 dholland KASSERT(fvp != tvp); 207 1.1 dholland KASSERT(fdvp->v_type == VDIR); 208 1.1 dholland KASSERT(tdvp->v_type == VDIR); 209 1.1 dholland KASSERT(fdvp->v_mount == mp); 210 1.1 dholland KASSERT(fvp->v_mount == mp); 211 1.1 dholland KASSERT(tdvp->v_mount == mp); 212 1.1 dholland KASSERT((tvp == NULL) || (tvp->v_mount == mp)); 213 1.1 dholland KASSERT(VOP_ISLOCKED(fdvp) == LK_EXCLUSIVE); 214 1.1 dholland KASSERT(VOP_ISLOCKED(fvp) == LK_EXCLUSIVE); 215 1.1 dholland KASSERT(VOP_ISLOCKED(tdvp) == LK_EXCLUSIVE); 216 1.1 dholland KASSERT((tvp == NULL) || (VOP_ISLOCKED(tvp) == LK_EXCLUSIVE)); 217 1.1 dholland 218 1.1 dholland return genfs_ufslike_rename_check_permitted(cred, 219 1.1 dholland fdvp, VTOI(fdvp)->i_mode, VTOI(fdvp)->i_uid, 220 1.1 dholland fvp, VTOI(fvp)->i_uid, 221 1.1 dholland tdvp, VTOI(tdvp)->i_mode, VTOI(tdvp)->i_uid, 222 1.1 dholland tvp, (tvp? VTOI(tvp)->i_uid : 0)); 223 1.1 dholland } 224 1.1 dholland 225 1.1 dholland /* 226 1.1 dholland * ulfs_gro_remove_check_possible: Check whether a remove is possible 227 1.1 dholland * independent of credentials. 228 1.1 dholland */ 229 1.1 dholland static int 230 1.1 dholland ulfs_gro_remove_check_possible(struct mount *mp, 231 1.1 dholland struct vnode *dvp, struct vnode *vp) 232 1.1 dholland { 233 1.1 dholland 234 1.1 dholland (void)mp; 235 1.1 dholland KASSERT(mp != NULL); 236 1.1 dholland KASSERT(dvp != NULL); 237 1.1 dholland KASSERT(vp != NULL); 238 1.1 dholland KASSERT(dvp != vp); 239 1.1 dholland KASSERT(dvp->v_type == VDIR); 240 1.1 dholland KASSERT(vp->v_type != VDIR); 241 1.1 dholland KASSERT(dvp->v_mount == mp); 242 1.1 dholland KASSERT(vp->v_mount == mp); 243 1.1 dholland KASSERT(VOP_ISLOCKED(dvp) == LK_EXCLUSIVE); 244 1.1 dholland KASSERT(VOP_ISLOCKED(vp) == LK_EXCLUSIVE); 245 1.1 dholland 246 1.1 dholland return genfs_ufslike_remove_check_possible( 247 1.1 dholland VTOI(dvp)->i_flags, VTOI(vp)->i_flags, 248 1.1 dholland IMMUTABLE, APPEND); 249 1.1 dholland } 250 1.1 dholland 251 1.1 dholland /* 252 1.1 dholland * ulfs_gro_remove_check_permitted: Check whether a remove is permitted 253 1.1 dholland * given our credentials. 254 1.1 dholland */ 255 1.1 dholland static int 256 1.1 dholland ulfs_gro_remove_check_permitted(struct mount *mp, kauth_cred_t cred, 257 1.1 dholland struct vnode *dvp, struct vnode *vp) 258 1.1 dholland { 259 1.1 dholland 260 1.1 dholland (void)mp; 261 1.1 dholland KASSERT(mp != NULL); 262 1.1 dholland KASSERT(dvp != NULL); 263 1.1 dholland KASSERT(vp != NULL); 264 1.1 dholland KASSERT(dvp != vp); 265 1.1 dholland KASSERT(dvp->v_type == VDIR); 266 1.1 dholland KASSERT(vp->v_type != VDIR); 267 1.1 dholland KASSERT(dvp->v_mount == mp); 268 1.1 dholland KASSERT(vp->v_mount == mp); 269 1.1 dholland KASSERT(VOP_ISLOCKED(dvp) == LK_EXCLUSIVE); 270 1.1 dholland KASSERT(VOP_ISLOCKED(vp) == LK_EXCLUSIVE); 271 1.1 dholland 272 1.1 dholland return genfs_ufslike_remove_check_permitted(cred, 273 1.1 dholland dvp, VTOI(dvp)->i_mode, VTOI(dvp)->i_uid, vp, VTOI(vp)->i_uid); 274 1.1 dholland } 275 1.1 dholland 276 1.1 dholland /* 277 1.1 dholland * ulfs_rename_ulr_overlap_p: True iff tulr overlaps with fulr so that 278 1.1 dholland * entering a directory entry at tulr may move fulr. 279 1.1 dholland */ 280 1.1 dholland static bool 281 1.1 dholland ulfs_rename_ulr_overlap_p(const struct ulfs_lookup_results *fulr, 282 1.1 dholland const struct ulfs_lookup_results *tulr) 283 1.1 dholland { 284 1.1 dholland doff_t from_prev_start, from_prev_end, to_start, to_end; 285 1.1 dholland 286 1.1 dholland KASSERT(fulr != NULL); 287 1.1 dholland KASSERT(tulr != NULL); 288 1.1 dholland KASSERT(fulr != tulr); 289 1.1 dholland 290 1.1 dholland /* 291 1.1 dholland * fulr is from a DELETE lookup, so fulr->ulr_count is the size 292 1.1 dholland * of the preceding entry (d_reclen). 293 1.1 dholland */ 294 1.1 dholland from_prev_end = fulr->ulr_offset; 295 1.1 dholland KASSERT(fulr->ulr_count <= from_prev_end); 296 1.1 dholland from_prev_start = (from_prev_end - fulr->ulr_count); 297 1.1 dholland 298 1.1 dholland /* 299 1.1 dholland * tulr is from a RENAME lookup, so tulr->ulr_count is the size 300 1.1 dholland * of the free space for an entry that we are about to fill. 301 1.1 dholland */ 302 1.1 dholland to_start = tulr->ulr_offset; 303 1.1 dholland KASSERT(tulr->ulr_count < (LFS_MAXDIRSIZE - to_start)); 304 1.1 dholland to_end = (to_start + tulr->ulr_count); 305 1.1 dholland 306 1.1 dholland return 307 1.1 dholland (((to_start <= from_prev_start) && (from_prev_start < to_end)) || 308 1.1 dholland ((to_start <= from_prev_end) && (from_prev_end < to_end))); 309 1.1 dholland } 310 1.1 dholland 311 1.1 dholland /* 312 1.1 dholland * ulfs_direct_namlen: Return the namlen of the directory entry ep from 313 1.1 dholland * the directory vp. 314 1.1 dholland */ 315 1.1 dholland static int /* XXX int? uint8_t? */ 316 1.16 dholland ulfs_direct_namlen(const LFS_DIRHEADER *ep, const struct vnode *vp) 317 1.1 dholland { 318 1.9 dholland struct lfs *fs; 319 1.1 dholland 320 1.1 dholland KASSERT(ep != NULL); 321 1.1 dholland KASSERT(vp != NULL); 322 1.1 dholland KASSERT(VTOI(vp) != NULL); 323 1.1 dholland KASSERT(VTOI(vp)->i_ump != NULL); 324 1.9 dholland KASSERT(VTOI(vp)->i_lfs != NULL); 325 1.9 dholland fs = VTOI(vp)->i_lfs; 326 1.1 dholland 327 1.9 dholland return lfs_dir_getnamlen(fs, ep); 328 1.1 dholland } 329 1.1 dholland 330 1.1 dholland /* 331 1.1 dholland * ulfs_rename_recalculate_fulr: If we have just entered a directory into 332 1.1 dholland * dvp at tulr, and we were about to remove one at fulr for an entry 333 1.1 dholland * named fcnp, fulr may be invalid. So, if necessary, recalculate it. 334 1.1 dholland */ 335 1.1 dholland static int 336 1.1 dholland ulfs_rename_recalculate_fulr(struct vnode *dvp, 337 1.1 dholland struct ulfs_lookup_results *fulr, const struct ulfs_lookup_results *tulr, 338 1.1 dholland const struct componentname *fcnp) 339 1.1 dholland { 340 1.1 dholland struct mount *mp; 341 1.4 dholland struct lfs *fs; 342 1.1 dholland struct ulfsmount *ump; 343 1.1 dholland /* XXX int is a silly type for this; blame ulfsmount::um_dirblksiz. */ 344 1.1 dholland int dirblksiz; 345 1.1 dholland doff_t search_start, search_end; 346 1.1 dholland doff_t offset; /* Offset of entry we're examining. */ 347 1.1 dholland struct buf *bp; /* I/O block we're examining. */ 348 1.1 dholland char *dirbuf; /* Pointer into directory at search_start. */ 349 1.16 dholland LFS_DIRHEADER *ep; /* Pointer to the entry we're examining. */ 350 1.1 dholland /* XXX direct::d_reclen is 16-bit; 351 1.1 dholland * ulfs_lookup_results::ulr_reclen is 32-bit. Blah. */ 352 1.1 dholland uint32_t reclen; /* Length of the entry we're examining. */ 353 1.1 dholland uint32_t prev_reclen; /* Length of the preceding entry. */ 354 1.1 dholland int error; 355 1.1 dholland 356 1.1 dholland KASSERT(dvp != NULL); 357 1.1 dholland KASSERT(dvp->v_mount != NULL); 358 1.1 dholland KASSERT(VTOI(dvp) != NULL); 359 1.1 dholland KASSERT(fulr != NULL); 360 1.1 dholland KASSERT(tulr != NULL); 361 1.1 dholland KASSERT(fulr != tulr); 362 1.1 dholland KASSERT(ulfs_rename_ulr_overlap_p(fulr, tulr)); 363 1.1 dholland 364 1.1 dholland mp = dvp->v_mount; 365 1.1 dholland ump = VFSTOULFS(mp); 366 1.4 dholland fs = ump->um_lfs; 367 1.1 dholland KASSERT(ump != NULL); 368 1.1 dholland KASSERT(ump == VTOI(dvp)->i_ump); 369 1.4 dholland KASSERT(fs == VTOI(dvp)->i_lfs); 370 1.1 dholland 371 1.4 dholland dirblksiz = fs->um_dirblksiz; 372 1.1 dholland KASSERT(0 < dirblksiz); 373 1.1 dholland KASSERT((dirblksiz & (dirblksiz - 1)) == 0); 374 1.1 dholland 375 1.1 dholland /* A directory block may not span across multiple I/O blocks. */ 376 1.1 dholland KASSERT(dirblksiz <= mp->mnt_stat.f_iosize); 377 1.1 dholland 378 1.1 dholland /* Find the bounds of the search. */ 379 1.1 dholland search_start = tulr->ulr_offset; 380 1.1 dholland KASSERT(fulr->ulr_reclen < (LFS_MAXDIRSIZE - fulr->ulr_offset)); 381 1.1 dholland search_end = (fulr->ulr_offset + fulr->ulr_reclen); 382 1.1 dholland 383 1.1 dholland /* Compaction must happen only within a directory block. (*) */ 384 1.1 dholland KASSERT(search_start <= search_end); 385 1.1 dholland KASSERT((search_end - (search_start &~ (dirblksiz - 1))) <= dirblksiz); 386 1.1 dholland 387 1.1 dholland dirbuf = NULL; 388 1.1 dholland bp = NULL; 389 1.1 dholland error = ulfs_blkatoff(dvp, (off_t)search_start, &dirbuf, &bp, false); 390 1.1 dholland if (error) 391 1.1 dholland return error; 392 1.1 dholland KASSERT(dirbuf != NULL); 393 1.1 dholland KASSERT(bp != NULL); 394 1.1 dholland 395 1.1 dholland /* 396 1.1 dholland * Guarantee we sha'n't go past the end of the buffer we got. 397 1.1 dholland * dirbuf is bp->b_data + (search_start & (iosize - 1)), and 398 1.1 dholland * the valid range is [bp->b_data, bp->b_data + bp->b_bcount). 399 1.1 dholland */ 400 1.1 dholland KASSERT((search_end - search_start) <= 401 1.1 dholland (bp->b_bcount - (search_start & (mp->mnt_stat.f_iosize - 1)))); 402 1.1 dholland 403 1.1 dholland prev_reclen = fulr->ulr_count; 404 1.1 dholland offset = search_start; 405 1.1 dholland 406 1.1 dholland /* 407 1.1 dholland * Search from search_start to search_end for the entry matching 408 1.1 dholland * fcnp, which must be there because we found it before and it 409 1.1 dholland * should only at most have moved earlier. 410 1.1 dholland */ 411 1.1 dholland for (;;) { 412 1.1 dholland KASSERT(search_start <= offset); 413 1.1 dholland KASSERT(offset < search_end); 414 1.1 dholland 415 1.1 dholland /* 416 1.1 dholland * Examine the directory entry at offset. 417 1.1 dholland */ 418 1.16 dholland ep = (LFS_DIRHEADER *)(dirbuf + (offset - search_start)); 419 1.10 dholland reclen = lfs_dir_getreclen(fs, ep); 420 1.1 dholland 421 1.10 dholland if (lfs_dir_getino(fs, ep) == 0) 422 1.1 dholland goto next; /* Entry is unused. */ 423 1.1 dholland 424 1.10 dholland if (lfs_dir_getino(fs, ep) == ULFS_WINO) 425 1.1 dholland goto next; /* Entry is whiteout. */ 426 1.1 dholland 427 1.1 dholland if (fcnp->cn_namelen != ulfs_direct_namlen(ep, dvp)) 428 1.1 dholland goto next; /* Wrong name length. */ 429 1.1 dholland 430 1.12 dholland if (memcmp(lfs_dir_nameptr(fs, ep), fcnp->cn_nameptr, fcnp->cn_namelen)) 431 1.1 dholland goto next; /* Wrong name. */ 432 1.1 dholland 433 1.1 dholland /* Got it! */ 434 1.1 dholland break; 435 1.1 dholland 436 1.1 dholland next: 437 1.1 dholland if (! ((reclen < search_end) && 438 1.1 dholland (offset < (search_end - reclen)))) { 439 1.1 dholland brelse(bp, 0); 440 1.1 dholland return EIO; /* XXX Panic? What? */ 441 1.1 dholland } 442 1.1 dholland 443 1.1 dholland /* We may not move past the search end. */ 444 1.1 dholland KASSERT(reclen < search_end); 445 1.1 dholland KASSERT(offset < (search_end - reclen)); 446 1.1 dholland 447 1.1 dholland /* 448 1.1 dholland * We may not move across a directory block boundary; 449 1.1 dholland * see (*) above. 450 1.1 dholland */ 451 1.1 dholland KASSERT((offset &~ (dirblksiz - 1)) == 452 1.1 dholland ((offset + reclen) &~ (dirblksiz - 1))); 453 1.1 dholland 454 1.1 dholland prev_reclen = reclen; 455 1.1 dholland offset += reclen; 456 1.1 dholland } 457 1.1 dholland 458 1.1 dholland /* 459 1.1 dholland * Found the entry. Record where. 460 1.1 dholland */ 461 1.1 dholland fulr->ulr_offset = offset; 462 1.1 dholland fulr->ulr_reclen = reclen; 463 1.1 dholland 464 1.1 dholland /* 465 1.1 dholland * Record the preceding record length, but not if we're at the 466 1.1 dholland * start of a directory block. 467 1.1 dholland */ 468 1.1 dholland fulr->ulr_count = ((offset & (dirblksiz - 1))? prev_reclen : 0); 469 1.1 dholland 470 1.1 dholland brelse(bp, 0); 471 1.1 dholland return 0; 472 1.1 dholland } 473 1.1 dholland 474 1.1 dholland /* 475 1.1 dholland * ulfs_gro_remove: Rename an object over another link to itself, 476 1.1 dholland * effectively removing just the original link. 477 1.1 dholland */ 478 1.1 dholland static int 479 1.1 dholland ulfs_gro_remove(struct mount *mp, kauth_cred_t cred, 480 1.25 thorpej struct vnode *dvp, struct componentname *cnp, void *de, struct vnode *vp, 481 1.25 thorpej nlink_t *tvp_nlinkp) 482 1.1 dholland { 483 1.1 dholland struct ulfs_lookup_results *ulr = de; 484 1.1 dholland int error; 485 1.1 dholland 486 1.1 dholland KASSERT(mp != NULL); 487 1.1 dholland KASSERT(dvp != NULL); 488 1.1 dholland KASSERT(cnp != NULL); 489 1.1 dholland KASSERT(ulr != NULL); 490 1.1 dholland KASSERT(vp != NULL); 491 1.1 dholland KASSERT(dvp != vp); 492 1.1 dholland KASSERT(dvp->v_mount == mp); 493 1.1 dholland KASSERT(vp->v_mount == mp); 494 1.1 dholland KASSERT(dvp->v_type == VDIR); 495 1.1 dholland KASSERT(vp->v_type != VDIR); 496 1.1 dholland KASSERT(VOP_ISLOCKED(dvp) == LK_EXCLUSIVE); 497 1.1 dholland KASSERT(VOP_ISLOCKED(vp) == LK_EXCLUSIVE); 498 1.1 dholland KASSERT(cnp->cn_nameiop == DELETE); 499 1.1 dholland 500 1.1 dholland /* XXX ulfs_dirremove decrements vp's link count for us. */ 501 1.1 dholland error = ulfs_dirremove(dvp, ulr, VTOI(vp), cnp->cn_flags, 0); 502 1.1 dholland 503 1.25 thorpej *tvp_nlinkp = VTOI(vp)->i_nlink; 504 1.1 dholland 505 1.1 dholland return error; 506 1.1 dholland } 507 1.1 dholland 508 1.1 dholland /* 509 1.1 dholland * ulfs_gro_lookup: Look up and save the lookup results. 510 1.1 dholland */ 511 1.1 dholland static int 512 1.1 dholland ulfs_gro_lookup(struct mount *mp, struct vnode *dvp, 513 1.1 dholland struct componentname *cnp, void *de_ret, struct vnode **vp_ret) 514 1.1 dholland { 515 1.1 dholland struct ulfs_lookup_results *ulr_ret = de_ret; 516 1.1 dholland struct vnode *vp = NULL; 517 1.1 dholland int error; 518 1.1 dholland 519 1.1 dholland (void)mp; 520 1.1 dholland KASSERT(mp != NULL); 521 1.1 dholland KASSERT(dvp != NULL); 522 1.1 dholland KASSERT(cnp != NULL); 523 1.1 dholland KASSERT(ulr_ret != NULL); 524 1.1 dholland KASSERT(vp_ret != NULL); 525 1.1 dholland KASSERT(VOP_ISLOCKED(dvp) == LK_EXCLUSIVE); 526 1.1 dholland 527 1.1 dholland /* Kludge cargo-culted from dholland's ulfs_rename. */ 528 1.1 dholland cnp->cn_flags &=~ MODMASK; 529 1.1 dholland cnp->cn_flags |= (LOCKPARENT | LOCKLEAF); 530 1.1 dholland 531 1.1 dholland error = relookup(dvp, &vp, cnp, 0 /* dummy */); 532 1.1 dholland if ((error == 0) && (vp == NULL)) { 533 1.1 dholland error = ENOENT; 534 1.1 dholland goto out; 535 1.1 dholland } else if (error) { 536 1.1 dholland return error; 537 1.1 dholland } 538 1.1 dholland 539 1.1 dholland /* 540 1.1 dholland * Thanks to VFS insanity, relookup locks vp, which screws us 541 1.1 dholland * in various ways. 542 1.1 dholland */ 543 1.1 dholland KASSERT(vp != NULL); 544 1.1 dholland VOP_UNLOCK(vp); 545 1.1 dholland 546 1.1 dholland out: *ulr_ret = VTOI(dvp)->i_crap; 547 1.1 dholland *vp_ret = vp; 548 1.1 dholland return error; 549 1.1 dholland } 550 1.1 dholland 551 1.1 dholland /* 552 1.1 dholland * ulfs_rmdired_p: Check whether the directory vp has been rmdired. 553 1.1 dholland * 554 1.1 dholland * vp must be locked and referenced. 555 1.1 dholland */ 556 1.1 dholland static bool 557 1.1 dholland ulfs_rmdired_p(struct vnode *vp) 558 1.1 dholland { 559 1.1 dholland 560 1.1 dholland KASSERT(vp != NULL); 561 1.1 dholland KASSERT(VOP_ISLOCKED(vp) == LK_EXCLUSIVE); 562 1.1 dholland KASSERT(vp->v_type == VDIR); 563 1.1 dholland 564 1.1 dholland /* XXX Is this correct? */ 565 1.1 dholland return (VTOI(vp)->i_size == 0); 566 1.1 dholland } 567 1.1 dholland 568 1.1 dholland /* 569 1.1 dholland * ulfs_read_dotdot: Store in *ino_ret the inode number of the parent 570 1.1 dholland * of the directory vp. 571 1.1 dholland */ 572 1.1 dholland static int 573 1.1 dholland ulfs_read_dotdot(struct vnode *vp, kauth_cred_t cred, ino_t *ino_ret) 574 1.1 dholland { 575 1.14 dholland struct lfs *fs; 576 1.16 dholland union lfs_dirtemplate dirbuf; 577 1.16 dholland LFS_DIRHEADER *dotdot; 578 1.16 dholland const char *name; 579 1.1 dholland int error; 580 1.1 dholland 581 1.1 dholland KASSERT(vp != NULL); 582 1.1 dholland KASSERT(ino_ret != NULL); 583 1.1 dholland KASSERT(vp->v_type == VDIR); 584 1.1 dholland 585 1.14 dholland KASSERT(VTOI(vp) != NULL); 586 1.14 dholland KASSERT(VTOI(vp)->i_lfs != NULL); 587 1.14 dholland fs = VTOI(vp)->i_lfs; 588 1.14 dholland 589 1.8 riastrad error = ulfs_bufio(UIO_READ, vp, &dirbuf, sizeof dirbuf, (off_t)0, 590 1.8 riastrad IO_NODELOCKED, cred, NULL, NULL); 591 1.1 dholland if (error) 592 1.1 dholland return error; 593 1.1 dholland 594 1.16 dholland dotdot = lfs_dirtemplate_dotdot(fs, &dirbuf); 595 1.16 dholland name = lfs_dirtemplate_dotdotname(fs, &dirbuf); 596 1.16 dholland if (lfs_dir_getnamlen(fs, dotdot) != 2 || 597 1.16 dholland name[0] != '.' || 598 1.16 dholland name[1] != '.') 599 1.1 dholland /* XXX Panic? Print warning? */ 600 1.1 dholland return ENOTDIR; 601 1.1 dholland 602 1.16 dholland *ino_ret = lfs_dir_getino(fs, dotdot); 603 1.1 dholland return 0; 604 1.1 dholland } 605 1.1 dholland 606 1.1 dholland /* 607 1.1 dholland * ulfs_gro_lock_directory: Lock the directory vp, but fail if it has 608 1.1 dholland * been rmdir'd. 609 1.1 dholland */ 610 1.1 dholland static int 611 1.1 dholland ulfs_gro_lock_directory(struct mount *mp, struct vnode *vp) 612 1.1 dholland { 613 1.1 dholland 614 1.1 dholland (void)mp; 615 1.1 dholland KASSERT(mp != NULL); 616 1.1 dholland KASSERT(vp != NULL); 617 1.1 dholland KASSERT(vp->v_mount == mp); 618 1.1 dholland 619 1.1 dholland vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); 620 1.1 dholland 621 1.1 dholland if (ulfs_rmdired_p(vp)) { 622 1.1 dholland VOP_UNLOCK(vp); 623 1.1 dholland return ENOENT; 624 1.1 dholland } 625 1.1 dholland 626 1.1 dholland return 0; 627 1.1 dholland } 628 1.1 dholland 629 1.1 dholland /* 630 1.1 dholland * ulfs_gro_genealogy: Analyze the genealogy of the source and target 631 1.1 dholland * directories. 632 1.1 dholland */ 633 1.1 dholland static int 634 1.1 dholland ulfs_gro_genealogy(struct mount *mp, kauth_cred_t cred, 635 1.1 dholland struct vnode *fdvp, struct vnode *tdvp, 636 1.1 dholland struct vnode **intermediate_node_ret) 637 1.1 dholland { 638 1.1 dholland struct vnode *vp, *dvp; 639 1.5 martin ino_t dotdot_ino = -1; /* XXX gcc 4.8: maybe-uninitialized */ 640 1.1 dholland int error; 641 1.1 dholland 642 1.1 dholland KASSERT(mp != NULL); 643 1.1 dholland KASSERT(fdvp != NULL); 644 1.1 dholland KASSERT(tdvp != NULL); 645 1.1 dholland KASSERT(fdvp != tdvp); 646 1.1 dholland KASSERT(intermediate_node_ret != NULL); 647 1.1 dholland KASSERT(fdvp->v_mount == mp); 648 1.1 dholland KASSERT(tdvp->v_mount == mp); 649 1.1 dholland KASSERT(fdvp->v_type == VDIR); 650 1.1 dholland KASSERT(tdvp->v_type == VDIR); 651 1.1 dholland 652 1.1 dholland /* 653 1.1 dholland * We need to provisionally lock tdvp to keep rmdir from 654 1.1 dholland * deleting it -- or any ancestor -- at an inopportune moment. 655 1.1 dholland */ 656 1.1 dholland error = ulfs_gro_lock_directory(mp, tdvp); 657 1.1 dholland if (error) 658 1.1 dholland return error; 659 1.1 dholland 660 1.1 dholland vp = tdvp; 661 1.1 dholland vref(vp); 662 1.1 dholland 663 1.1 dholland for (;;) { 664 1.1 dholland KASSERT(vp != NULL); 665 1.1 dholland KASSERT(VOP_ISLOCKED(vp) == LK_EXCLUSIVE); 666 1.1 dholland KASSERT(vp->v_mount == mp); 667 1.1 dholland KASSERT(vp->v_type == VDIR); 668 1.1 dholland KASSERT(!ulfs_rmdired_p(vp)); 669 1.1 dholland 670 1.1 dholland /* Did we hit the root without finding fdvp? */ 671 1.1 dholland if (VTOI(vp)->i_number == ULFS_ROOTINO) { 672 1.1 dholland vput(vp); 673 1.1 dholland *intermediate_node_ret = NULL; 674 1.1 dholland return 0; 675 1.1 dholland } 676 1.1 dholland 677 1.1 dholland error = ulfs_read_dotdot(vp, cred, &dotdot_ino); 678 1.1 dholland if (error) { 679 1.1 dholland vput(vp); 680 1.1 dholland return error; 681 1.1 dholland } 682 1.1 dholland 683 1.1 dholland /* Did we find that fdvp is an ancestor of tdvp? */ 684 1.1 dholland if (VTOI(fdvp)->i_number == dotdot_ino) { 685 1.1 dholland /* Unlock vp, but keep it referenced. */ 686 1.1 dholland VOP_UNLOCK(vp); 687 1.1 dholland *intermediate_node_ret = vp; 688 1.1 dholland return 0; 689 1.1 dholland } 690 1.1 dholland 691 1.1 dholland /* Neither -- keep ascending the family tree. */ 692 1.20 dholland error = vcache_get(mp, &dotdot_ino, sizeof(dotdot_ino), &dvp); 693 1.19 dholland vput(vp); 694 1.1 dholland if (error) 695 1.1 dholland return error; 696 1.19 dholland error = vn_lock(dvp, LK_EXCLUSIVE); 697 1.19 dholland if (error) { 698 1.19 dholland vrele(dvp); 699 1.19 dholland return error; 700 1.19 dholland } 701 1.1 dholland 702 1.1 dholland KASSERT(dvp != NULL); 703 1.1 dholland KASSERT(VOP_ISLOCKED(dvp) == LK_EXCLUSIVE); 704 1.1 dholland vp = dvp; 705 1.1 dholland 706 1.1 dholland if (vp->v_type != VDIR) { 707 1.1 dholland /* 708 1.1 dholland * XXX Panic? Print a warning? Can this 709 1.1 dholland * happen if we lose the race I suspect to 710 1.1 dholland * exist above, and the `..' inode number has 711 1.1 dholland * been recycled? 712 1.1 dholland */ 713 1.1 dholland vput(vp); 714 1.1 dholland return ENOTDIR; 715 1.1 dholland } 716 1.1 dholland 717 1.1 dholland if (ulfs_rmdired_p(vp)) { 718 1.1 dholland vput(vp); 719 1.1 dholland return ENOENT; 720 1.1 dholland } 721 1.1 dholland } 722 1.1 dholland } 723 1.1 dholland 724 1.1 dholland /* 725 1.1 dholland * ulfs_gro_rename: Actually perform the rename operation. 726 1.1 dholland */ 727 1.1 dholland static int 728 1.1 dholland ulfs_gro_rename(struct mount *mp, kauth_cred_t cred, 729 1.1 dholland struct vnode *fdvp, struct componentname *fcnp, 730 1.1 dholland void *fde, struct vnode *fvp, 731 1.1 dholland struct vnode *tdvp, struct componentname *tcnp, 732 1.25 thorpej void *tde, struct vnode *tvp, nlink_t *tvp_nlinkp) 733 1.1 dholland { 734 1.16 dholland struct lfs *fs; 735 1.1 dholland struct ulfs_lookup_results *fulr = fde; 736 1.1 dholland struct ulfs_lookup_results *tulr = tde; 737 1.1 dholland bool directory_p, reparent_p; 738 1.1 dholland int error; 739 1.1 dholland 740 1.1 dholland KASSERT(mp != NULL); 741 1.1 dholland KASSERT(fdvp != NULL); 742 1.1 dholland KASSERT(fcnp != NULL); 743 1.1 dholland KASSERT(fulr != NULL); 744 1.1 dholland KASSERT(fvp != NULL); 745 1.1 dholland KASSERT(tdvp != NULL); 746 1.1 dholland KASSERT(tcnp != NULL); 747 1.1 dholland KASSERT(tulr != NULL); 748 1.1 dholland KASSERT(fulr != tulr); 749 1.1 dholland KASSERT(fdvp != fvp); 750 1.1 dholland KASSERT(fdvp != tvp); 751 1.1 dholland KASSERT(tdvp != fvp); 752 1.1 dholland KASSERT(tdvp != tvp); 753 1.1 dholland KASSERT(fvp != tvp); 754 1.1 dholland KASSERT(fdvp->v_mount == mp); 755 1.1 dholland KASSERT(fvp->v_mount == mp); 756 1.1 dholland KASSERT(tdvp->v_mount == mp); 757 1.1 dholland KASSERT((tvp == NULL) || (tvp->v_mount == mp)); 758 1.1 dholland KASSERT(VOP_ISLOCKED(fdvp) == LK_EXCLUSIVE); 759 1.1 dholland KASSERT(VOP_ISLOCKED(fvp) == LK_EXCLUSIVE); 760 1.1 dholland KASSERT(VOP_ISLOCKED(tdvp) == LK_EXCLUSIVE); 761 1.1 dholland KASSERT((tvp == NULL) || (VOP_ISLOCKED(tvp) == LK_EXCLUSIVE)); 762 1.1 dholland 763 1.16 dholland fs = VTOI(fdvp)->i_lfs; 764 1.16 dholland KASSERT(fs == VTOI(tdvp)->i_lfs); 765 1.16 dholland 766 1.1 dholland /* 767 1.1 dholland * We shall need to temporarily bump the link count, so make 768 1.1 dholland * sure there is room to do so. 769 1.1 dholland */ 770 1.1 dholland if ((nlink_t)VTOI(fvp)->i_nlink >= LINK_MAX) 771 1.1 dholland return EMLINK; 772 1.1 dholland 773 1.1 dholland directory_p = (fvp->v_type == VDIR); 774 1.1 dholland KASSERT(directory_p == ((VTOI(fvp)->i_mode & LFS_IFMT) == LFS_IFDIR)); 775 1.1 dholland KASSERT((tvp == NULL) || (directory_p == (tvp->v_type == VDIR))); 776 1.1 dholland KASSERT((tvp == NULL) || (directory_p == 777 1.1 dholland ((VTOI(tvp)->i_mode & LFS_IFMT) == LFS_IFDIR))); 778 1.1 dholland 779 1.1 dholland reparent_p = (fdvp != tdvp); 780 1.1 dholland KASSERT(reparent_p == (VTOI(fdvp)->i_number != VTOI(tdvp)->i_number)); 781 1.1 dholland 782 1.1 dholland /* 783 1.1 dholland * Commence hacking of the data on disk. 784 1.1 dholland */ 785 1.1 dholland 786 1.1 dholland error = 0; 787 1.1 dholland 788 1.1 dholland /* 789 1.1 dholland * 1) Bump link count while we're moving stuff 790 1.1 dholland * around. If we crash somewhere before 791 1.1 dholland * completing our work, the link count 792 1.1 dholland * may be wrong, but correctable. 793 1.1 dholland */ 794 1.1 dholland 795 1.1 dholland KASSERT((nlink_t)VTOI(fvp)->i_nlink < LINK_MAX); 796 1.1 dholland VTOI(fvp)->i_nlink++; 797 1.1 dholland DIP_ASSIGN(VTOI(fvp), nlink, VTOI(fvp)->i_nlink); 798 1.22 maya VTOI(fvp)->i_state |= IN_CHANGE; 799 1.3 dholland error = lfs_update(fvp, NULL, NULL, UPDATE_DIROP); 800 1.1 dholland if (error) 801 1.1 dholland goto whymustithurtsomuch; 802 1.1 dholland 803 1.1 dholland /* 804 1.1 dholland * 2) If target doesn't exist, link the target 805 1.1 dholland * to the source and unlink the source. 806 1.1 dholland * Otherwise, rewrite the target directory 807 1.1 dholland * entry to reference the source inode and 808 1.1 dholland * expunge the original entry's existence. 809 1.1 dholland */ 810 1.1 dholland 811 1.1 dholland if (tvp == NULL) { 812 1.1 dholland /* 813 1.1 dholland * Account for ".." in new directory. 814 1.1 dholland * When source and destination have the same 815 1.1 dholland * parent we don't fool with the link count. 816 1.1 dholland */ 817 1.1 dholland if (directory_p && reparent_p) { 818 1.1 dholland if ((nlink_t)VTOI(tdvp)->i_nlink >= LINK_MAX) { 819 1.1 dholland error = EMLINK; 820 1.1 dholland goto whymustithurtsomuch; 821 1.1 dholland } 822 1.1 dholland KASSERT((nlink_t)VTOI(tdvp)->i_nlink < LINK_MAX); 823 1.1 dholland VTOI(tdvp)->i_nlink++; 824 1.1 dholland DIP_ASSIGN(VTOI(tdvp), nlink, VTOI(tdvp)->i_nlink); 825 1.22 maya VTOI(tdvp)->i_state |= IN_CHANGE; 826 1.3 dholland error = lfs_update(tdvp, NULL, NULL, UPDATE_DIROP); 827 1.1 dholland if (error) { 828 1.1 dholland /* 829 1.1 dholland * Link count update didn't take -- 830 1.1 dholland * back out the in-memory link count. 831 1.1 dholland */ 832 1.1 dholland KASSERT(0 < VTOI(tdvp)->i_nlink); 833 1.1 dholland VTOI(tdvp)->i_nlink--; 834 1.1 dholland DIP_ASSIGN(VTOI(tdvp), nlink, 835 1.1 dholland VTOI(tdvp)->i_nlink); 836 1.22 maya VTOI(tdvp)->i_state |= IN_CHANGE; 837 1.1 dholland goto whymustithurtsomuch; 838 1.1 dholland } 839 1.1 dholland } 840 1.1 dholland 841 1.11 dholland error = ulfs_direnter(tdvp, tulr, 842 1.11 dholland NULL, tcnp, VTOI(fvp)->i_number, LFS_IFTODT(VTOI(fvp)->i_mode), 843 1.11 dholland NULL); 844 1.1 dholland if (error) { 845 1.1 dholland if (directory_p && reparent_p) { 846 1.1 dholland /* 847 1.1 dholland * Directory update didn't take, but 848 1.1 dholland * the link count update did -- back 849 1.1 dholland * out the in-memory link count and the 850 1.1 dholland * on-disk link count. 851 1.1 dholland */ 852 1.1 dholland KASSERT(0 < VTOI(tdvp)->i_nlink); 853 1.1 dholland VTOI(tdvp)->i_nlink--; 854 1.1 dholland DIP_ASSIGN(VTOI(tdvp), nlink, 855 1.1 dholland VTOI(tdvp)->i_nlink); 856 1.22 maya VTOI(tdvp)->i_state |= IN_CHANGE; 857 1.3 dholland (void)lfs_update(tdvp, NULL, NULL, 858 1.1 dholland UPDATE_WAIT | UPDATE_DIROP); 859 1.1 dholland } 860 1.1 dholland goto whymustithurtsomuch; 861 1.1 dholland } 862 1.1 dholland } else { 863 1.1 dholland if (directory_p) 864 1.1 dholland /* XXX WTF? Why purge here? Why not purge others? */ 865 1.1 dholland cache_purge(tdvp); 866 1.1 dholland 867 1.1 dholland /* 868 1.1 dholland * Make the target directory's entry for tcnp point at 869 1.1 dholland * the source node. 870 1.1 dholland * 871 1.1 dholland * XXX ulfs_dirrewrite decrements tvp's link count, but 872 1.1 dholland * doesn't touch the link count of the new inode. Go 873 1.1 dholland * figure. 874 1.1 dholland */ 875 1.1 dholland error = ulfs_dirrewrite(VTOI(tdvp), tulr->ulr_offset, 876 1.1 dholland VTOI(tvp), VTOI(fvp)->i_number, LFS_IFTODT(VTOI(fvp)->i_mode), 877 1.1 dholland ((directory_p && reparent_p) ? reparent_p : directory_p), 878 1.1 dholland IN_CHANGE | IN_UPDATE); 879 1.1 dholland if (error) 880 1.1 dholland goto whymustithurtsomuch; 881 1.1 dholland 882 1.1 dholland /* 883 1.1 dholland * If the source and target are directories, and the 884 1.1 dholland * target is in the same directory as the source, 885 1.1 dholland * decrement the link count of the common parent 886 1.1 dholland * directory, since we are removing the target from 887 1.1 dholland * that directory. 888 1.1 dholland */ 889 1.1 dholland if (directory_p && !reparent_p) { 890 1.1 dholland KASSERT(fdvp == tdvp); 891 1.1 dholland /* XXX check, don't kassert */ 892 1.1 dholland KASSERT(0 < VTOI(tdvp)->i_nlink); 893 1.1 dholland VTOI(tdvp)->i_nlink--; 894 1.1 dholland DIP_ASSIGN(VTOI(tdvp), nlink, VTOI(tdvp)->i_nlink); 895 1.22 maya VTOI(tdvp)->i_state |= IN_CHANGE; 896 1.1 dholland } 897 1.1 dholland 898 1.1 dholland if (directory_p) { 899 1.1 dholland /* 900 1.1 dholland * XXX I don't understand the following comment 901 1.1 dholland * from ulfs_rename -- in particular, the part 902 1.1 dholland * about `there may be other hard links'. 903 1.1 dholland * 904 1.1 dholland * Truncate inode. The only stuff left in the directory 905 1.1 dholland * is "." and "..". The "." reference is inconsequential 906 1.1 dholland * since we are quashing it. We have removed the "." 907 1.1 dholland * reference and the reference in the parent directory, 908 1.1 dholland * but there may be other hard links. 909 1.1 dholland * 910 1.1 dholland * XXX The ulfs_dirempty call earlier does 911 1.1 dholland * not guarantee anything about nlink. 912 1.1 dholland */ 913 1.1 dholland if (VTOI(tvp)->i_nlink != 1) 914 1.1 dholland ulfs_dirbad(VTOI(tvp), (doff_t)0, 915 1.1 dholland "hard-linked directory"); 916 1.1 dholland VTOI(tvp)->i_nlink = 0; 917 1.1 dholland DIP_ASSIGN(VTOI(tvp), nlink, 0); 918 1.3 dholland error = lfs_truncate(tvp, (off_t)0, IO_SYNC, cred); 919 1.1 dholland if (error) 920 1.1 dholland goto whymustithurtsomuch; 921 1.1 dholland } 922 1.1 dholland } 923 1.1 dholland 924 1.1 dholland /* 925 1.1 dholland * If the source is a directory with a new parent, the link 926 1.1 dholland * count of the old parent directory must be decremented and 927 1.1 dholland * ".." set to point to the new parent. 928 1.1 dholland * 929 1.1 dholland * XXX ulfs_dirrewrite updates the link count of fdvp, but not 930 1.1 dholland * the link count of fvp or the link count of tdvp. Go figure. 931 1.1 dholland */ 932 1.1 dholland if (directory_p && reparent_p) { 933 1.14 dholland off_t position; 934 1.14 dholland 935 1.14 dholland /* 936 1.14 dholland * The .. entry goes immediately after the . entry, so 937 1.14 dholland * the position is the record length of the . entry, 938 1.14 dholland * namely LFS_DIRECTSIZ(1). 939 1.14 dholland */ 940 1.15 dholland position = LFS_DIRECTSIZ(fs, 1); 941 1.14 dholland error = ulfs_dirrewrite(VTOI(fvp), position, 942 1.1 dholland VTOI(fdvp), VTOI(tdvp)->i_number, LFS_DT_DIR, 0, IN_CHANGE); 943 1.1 dholland #if 0 /* XXX This branch was not in ulfs_rename! */ 944 1.1 dholland if (error) 945 1.1 dholland goto whymustithurtsomuch; 946 1.1 dholland #endif 947 1.1 dholland 948 1.1 dholland /* XXX WTF? Why purge here? Why not purge others? */ 949 1.1 dholland cache_purge(fdvp); 950 1.1 dholland } 951 1.1 dholland 952 1.1 dholland /* 953 1.1 dholland * 3) Unlink the source. 954 1.1 dholland */ 955 1.1 dholland 956 1.1 dholland /* 957 1.1 dholland * ulfs_direnter may compact the directory in the process of 958 1.1 dholland * inserting a new entry. That may invalidate fulr, which we 959 1.1 dholland * need in order to remove the old entry. In that case, we 960 1.1 dholland * need to recalculate what fulr should be. 961 1.1 dholland */ 962 1.1 dholland if (!reparent_p && (tvp == NULL) && 963 1.1 dholland ulfs_rename_ulr_overlap_p(fulr, tulr)) { 964 1.1 dholland error = ulfs_rename_recalculate_fulr(fdvp, fulr, tulr, fcnp); 965 1.1 dholland #if 0 /* XXX */ 966 1.1 dholland if (error) /* XXX Try to back out changes? */ 967 1.1 dholland goto whymustithurtsomuch; 968 1.1 dholland #endif 969 1.1 dholland } 970 1.1 dholland 971 1.1 dholland /* 972 1.1 dholland * XXX 0 means !isrmdir. But can't this be an rmdir? 973 1.1 dholland * XXX Well, turns out that argument to ulfs_dirremove is ignored... 974 1.1 dholland * XXX And it turns out ulfs_dirremove updates the link count of fvp. 975 1.1 dholland * XXX But it doesn't update the link count of fdvp. Go figure. 976 1.1 dholland * XXX fdvp's link count is updated in ulfs_dirrewrite instead. 977 1.1 dholland * XXX Actually, sometimes it doesn't update fvp's link count. 978 1.1 dholland * XXX I hate the world. 979 1.1 dholland */ 980 1.1 dholland error = ulfs_dirremove(fdvp, fulr, VTOI(fvp), fcnp->cn_flags, 0); 981 1.1 dholland if (error) 982 1.1 dholland #if 0 /* XXX */ 983 1.1 dholland goto whymustithurtsomuch; 984 1.1 dholland #endif 985 1.1 dholland goto arghmybrainhurts; 986 1.1 dholland 987 1.25 thorpej if (tvp != NULL) { 988 1.25 thorpej *tvp_nlinkp = VTOI(tvp)->i_nlink; 989 1.25 thorpej } 990 1.1 dholland #if 0 /* XXX */ 991 1.1 dholland genfs_rename_cache_purge(fdvp, fvp, tdvp, tvp); 992 1.1 dholland #endif 993 1.1 dholland goto arghmybrainhurts; 994 1.1 dholland 995 1.1 dholland whymustithurtsomuch: 996 1.1 dholland KASSERT(0 < VTOI(fvp)->i_nlink); 997 1.1 dholland VTOI(fvp)->i_nlink--; 998 1.1 dholland DIP_ASSIGN(VTOI(fvp), nlink, VTOI(fvp)->i_nlink); 999 1.22 maya VTOI(fvp)->i_state |= IN_CHANGE; 1000 1.1 dholland 1001 1.1 dholland arghmybrainhurts: 1002 1.1 dholland /*ihateyou:*/ 1003 1.1 dholland return error; 1004 1.1 dholland } 1005 1.1 dholland 1006 1.1 dholland /* 1007 1.1 dholland * lfs_gro_rename: Actually perform the rename operation. Do a little 1008 1.1 dholland * LFS bookkeeping and then defer to ulfs_gro_rename. 1009 1.1 dholland */ 1010 1.1 dholland static int 1011 1.1 dholland lfs_gro_rename(struct mount *mp, kauth_cred_t cred, 1012 1.1 dholland struct vnode *fdvp, struct componentname *fcnp, 1013 1.1 dholland void *fde, struct vnode *fvp, 1014 1.1 dholland struct vnode *tdvp, struct componentname *tcnp, 1015 1.25 thorpej void *tde, struct vnode *tvp, nlink_t *tvp_nlinkp) 1016 1.1 dholland { 1017 1.1 dholland int error; 1018 1.1 dholland 1019 1.1 dholland KASSERT(mp != NULL); 1020 1.1 dholland KASSERT(fdvp != NULL); 1021 1.1 dholland KASSERT(fcnp != NULL); 1022 1.1 dholland KASSERT(fde != NULL); 1023 1.1 dholland KASSERT(fvp != NULL); 1024 1.1 dholland KASSERT(tdvp != NULL); 1025 1.1 dholland KASSERT(tcnp != NULL); 1026 1.1 dholland KASSERT(tde != NULL); 1027 1.1 dholland KASSERT(fdvp != fvp); 1028 1.1 dholland KASSERT(fdvp != tvp); 1029 1.1 dholland KASSERT(tdvp != fvp); 1030 1.1 dholland KASSERT(tdvp != tvp); 1031 1.1 dholland KASSERT(fvp != tvp); 1032 1.1 dholland KASSERT(fdvp->v_mount == mp); 1033 1.1 dholland KASSERT(fvp->v_mount == mp); 1034 1.1 dholland KASSERT(tdvp->v_mount == mp); 1035 1.1 dholland KASSERT((tvp == NULL) || (tvp->v_mount == mp)); 1036 1.1 dholland KASSERT(VOP_ISLOCKED(fdvp) == LK_EXCLUSIVE); 1037 1.1 dholland KASSERT(VOP_ISLOCKED(fvp) == LK_EXCLUSIVE); 1038 1.1 dholland KASSERT(VOP_ISLOCKED(tdvp) == LK_EXCLUSIVE); 1039 1.1 dholland KASSERT((tvp == NULL) || (VOP_ISLOCKED(tvp) == LK_EXCLUSIVE)); 1040 1.1 dholland 1041 1.7 dholland error = lfs_set_dirop(tdvp, tvp); 1042 1.1 dholland if (error != 0) 1043 1.1 dholland return error; 1044 1.1 dholland 1045 1.1 dholland MARK_VNODE(fdvp); 1046 1.1 dholland MARK_VNODE(fvp); 1047 1.1 dholland 1048 1.1 dholland error = ulfs_gro_rename(mp, cred, 1049 1.1 dholland fdvp, fcnp, fde, fvp, 1050 1.25 thorpej tdvp, tcnp, tde, tvp, 1051 1.25 thorpej tvp_nlinkp); 1052 1.1 dholland 1053 1.23 riastrad if (tvp && VTOI(tvp)->i_nlink == 0) 1054 1.23 riastrad lfs_orphan(VTOI(tvp)->i_lfs, VTOI(tvp)->i_number); 1055 1.23 riastrad 1056 1.1 dholland UNMARK_VNODE(fdvp); 1057 1.1 dholland UNMARK_VNODE(fvp); 1058 1.7 dholland UNMARK_VNODE(tdvp); 1059 1.7 dholland if (tvp) { 1060 1.7 dholland UNMARK_VNODE(tvp); 1061 1.7 dholland } 1062 1.7 dholland lfs_unset_dirop(VFSTOULFS(mp)->um_lfs, tdvp, "rename"); 1063 1.7 dholland vrele(tdvp); 1064 1.7 dholland if (tvp) { 1065 1.7 dholland vrele(tvp); 1066 1.7 dholland } 1067 1.1 dholland 1068 1.1 dholland return error; 1069 1.1 dholland } 1070 1.1 dholland 1071 1.1 dholland static const struct genfs_rename_ops lfs_genfs_rename_ops = { 1072 1.1 dholland .gro_directory_empty_p = ulfs_gro_directory_empty_p, 1073 1.1 dholland .gro_rename_check_possible = ulfs_gro_rename_check_possible, 1074 1.1 dholland .gro_rename_check_permitted = ulfs_gro_rename_check_permitted, 1075 1.1 dholland .gro_remove_check_possible = ulfs_gro_remove_check_possible, 1076 1.1 dholland .gro_remove_check_permitted = ulfs_gro_remove_check_permitted, 1077 1.1 dholland .gro_rename = lfs_gro_rename, 1078 1.1 dholland .gro_remove = ulfs_gro_remove, 1079 1.1 dholland .gro_lookup = ulfs_gro_lookup, 1080 1.1 dholland .gro_genealogy = ulfs_gro_genealogy, 1081 1.1 dholland .gro_lock_directory = ulfs_gro_lock_directory, 1082 1.1 dholland }; 1083 1.1 dholland 1084 1.1 dholland /* 1085 1.1 dholland * lfs_sane_rename: The hairiest vop, with the saner API. 1086 1.1 dholland * 1087 1.1 dholland * Arguments: 1088 1.1 dholland * 1089 1.1 dholland * . fdvp (from directory vnode), 1090 1.1 dholland * . fcnp (from component name), 1091 1.1 dholland * . tdvp (to directory vnode), 1092 1.1 dholland * . tcnp (to component name), 1093 1.1 dholland * . cred (credentials structure), and 1094 1.1 dholland * . posixly_correct (flag for behaviour if target & source link same file). 1095 1.1 dholland * 1096 1.1 dholland * fdvp and tdvp may be the same, and must be referenced and unlocked. 1097 1.1 dholland */ 1098 1.1 dholland static int 1099 1.1 dholland lfs_sane_rename( 1100 1.1 dholland struct vnode *fdvp, struct componentname *fcnp, 1101 1.1 dholland struct vnode *tdvp, struct componentname *tcnp, 1102 1.1 dholland kauth_cred_t cred, bool posixly_correct) 1103 1.1 dholland { 1104 1.1 dholland struct ulfs_lookup_results fulr, tulr; 1105 1.1 dholland 1106 1.1 dholland /* 1107 1.1 dholland * XXX Provisional kludge -- ulfs_lookup does not reject rename 1108 1.1 dholland * of . or .. (from or to), so we hack it here. This is not 1109 1.1 dholland * the right place: it should be caller's responsibility to 1110 1.1 dholland * reject this case. 1111 1.1 dholland */ 1112 1.1 dholland KASSERT(fcnp != NULL); 1113 1.1 dholland KASSERT(tcnp != NULL); 1114 1.1 dholland KASSERT(fcnp != tcnp); 1115 1.1 dholland KASSERT(fcnp->cn_nameptr != NULL); 1116 1.1 dholland KASSERT(tcnp->cn_nameptr != NULL); 1117 1.1 dholland 1118 1.1 dholland if ((fcnp->cn_flags | tcnp->cn_flags) & ISDOTDOT) 1119 1.1 dholland return EINVAL; /* XXX EISDIR? */ 1120 1.1 dholland if ((fcnp->cn_namelen == 1) && (fcnp->cn_nameptr[0] == '.')) 1121 1.1 dholland return EINVAL; 1122 1.1 dholland if ((tcnp->cn_namelen == 1) && (tcnp->cn_nameptr[0] == '.')) 1123 1.1 dholland return EINVAL; 1124 1.1 dholland 1125 1.1 dholland return genfs_sane_rename(&lfs_genfs_rename_ops, 1126 1.1 dholland fdvp, fcnp, &fulr, tdvp, tcnp, &tulr, 1127 1.1 dholland cred, posixly_correct); 1128 1.1 dholland } 1129 1.1 dholland 1130 1.1 dholland /* 1131 1.1 dholland * lfs_rename: The hairiest vop, with the insanest API. Defer to 1132 1.1 dholland * genfs_insane_rename immediately. 1133 1.1 dholland */ 1134 1.1 dholland int 1135 1.1 dholland lfs_rename(void *v) 1136 1.1 dholland { 1137 1.1 dholland 1138 1.1 dholland return genfs_insane_rename(v, &lfs_sane_rename); 1139 1.1 dholland } 1140