1 /* $NetBSD: ext2fs_rename.c,v 1.11 2016/08/15 18:38:10 jdolecek Exp $ */ 2 3 /*- 4 * Copyright (c) 2012 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Taylor R Campbell. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 /* 33 * Ext2fs Rename 34 */ 35 36 #include <sys/cdefs.h> 37 __KERNEL_RCSID(0, "$NetBSD: ext2fs_rename.c,v 1.11 2016/08/15 18:38:10 jdolecek Exp $"); 38 39 #include <sys/param.h> 40 #include <sys/buf.h> 41 #include <sys/errno.h> 42 #include <sys/kauth.h> 43 #include <sys/mount.h> 44 #include <sys/namei.h> 45 #include <sys/vnode.h> 46 #include <sys/vnode_if.h> 47 #include <sys/dirent.h> 48 49 #include <miscfs/genfs/genfs.h> 50 51 #include <ufs/ext2fs/ext2fs.h> 52 #include <ufs/ext2fs/ext2fs_dir.h> 53 #include <ufs/ext2fs/ext2fs_extern.h> 54 #include <ufs/ufs/inode.h> 55 #include <ufs/ufs/ufs_extern.h> 56 #include <ufs/ufs/ufsmount.h> 57 58 /* 59 * Forward declarations 60 */ 61 static int ext2fs_sane_rename(struct vnode *, struct componentname *, 62 struct vnode *, struct componentname *, 63 kauth_cred_t, bool); 64 static bool ext2fs_rename_ulr_overlap_p(const struct ufs_lookup_results *, 65 const struct ufs_lookup_results *); 66 static int ext2fs_rename_recalculate_fulr(struct vnode *, 67 struct ufs_lookup_results *, const struct ufs_lookup_results *, 68 const struct componentname *); 69 static bool ext2fs_rmdired_p(struct vnode *); 70 static int ext2fs_read_dotdot(struct vnode *, kauth_cred_t, ino_t *); 71 static int ext2fs_rename_replace_dotdot(struct vnode *, 72 struct vnode *, struct vnode *, kauth_cred_t); 73 static int ext2fs_gro_lock_directory(struct mount *, struct vnode *); 74 75 static const struct genfs_rename_ops ext2fs_genfs_rename_ops; 76 77 /* 78 * ext2fs_sane_rename: The hairiest vop, with the saner API. 79 * 80 * Arguments: 81 * 82 * . fdvp (from directory vnode), 83 * . fcnp (from component name), 84 * . tdvp (to directory vnode), 85 * . tcnp (to component name), 86 * . cred (credentials structure), and 87 * . posixly_correct (flag for behaviour if target & source link same file). 88 * 89 * fdvp and tdvp may be the same, and must be referenced and unlocked. 90 */ 91 static int 92 ext2fs_sane_rename( 93 struct vnode *fdvp, struct componentname *fcnp, 94 struct vnode *tdvp, struct componentname *tcnp, 95 kauth_cred_t cred, bool posixly_correct) 96 { 97 struct ufs_lookup_results fulr, tulr; 98 99 return genfs_sane_rename(&ext2fs_genfs_rename_ops, 100 fdvp, fcnp, &fulr, tdvp, tcnp, &tulr, 101 cred, posixly_correct); 102 } 103 104 /* 105 * ext2fs_rename: The hairiest vop, with the insanest API. Defer to 106 * genfs_insane_rename immediately. 107 */ 108 int 109 ext2fs_rename(void *v) 110 { 111 112 return genfs_insane_rename(v, &ext2fs_sane_rename); 113 } 114 115 /* 116 * ext2fs_gro_directory_empty_p: Return true if the directory vp is 117 * empty. dvp is its parent. 118 * 119 * vp and dvp must be locked and referenced. 120 */ 121 static bool 122 ext2fs_gro_directory_empty_p(struct mount *mp, kauth_cred_t cred, 123 struct vnode *vp, struct vnode *dvp) 124 { 125 126 (void)mp; 127 KASSERT(mp != NULL); 128 KASSERT(vp != NULL); 129 KASSERT(dvp != NULL); 130 KASSERT(vp != dvp); 131 KASSERT(vp->v_mount == mp); 132 KASSERT(dvp->v_mount == mp); 133 KASSERT(VOP_ISLOCKED(vp) == LK_EXCLUSIVE); 134 KASSERT(VOP_ISLOCKED(dvp) == LK_EXCLUSIVE); 135 136 return ext2fs_dirempty(VTOI(vp), VTOI(dvp)->i_number, cred); 137 } 138 139 /* 140 * ext2fs_gro_rename_check_possible: Check whether a rename is possible 141 * independent of credentials. 142 */ 143 static int 144 ext2fs_gro_rename_check_possible(struct mount *mp, 145 struct vnode *fdvp, struct vnode *fvp, 146 struct vnode *tdvp, struct vnode *tvp) 147 { 148 149 (void)mp; 150 KASSERT(mp != NULL); 151 KASSERT(fdvp != NULL); 152 KASSERT(fvp != NULL); 153 KASSERT(tdvp != NULL); 154 KASSERT(fdvp != fvp); 155 KASSERT(fdvp != tvp); 156 KASSERT(tdvp != fvp); 157 KASSERT(tdvp != tvp); 158 KASSERT(fvp != tvp); 159 KASSERT(fdvp->v_type == VDIR); 160 KASSERT(tdvp->v_type == VDIR); 161 KASSERT(fdvp->v_mount == mp); 162 KASSERT(fvp->v_mount == mp); 163 KASSERT(tdvp->v_mount == mp); 164 KASSERT((tvp == NULL) || (tvp->v_mount == mp)); 165 KASSERT(VOP_ISLOCKED(fdvp) == LK_EXCLUSIVE); 166 KASSERT(VOP_ISLOCKED(fvp) == LK_EXCLUSIVE); 167 KASSERT(VOP_ISLOCKED(tdvp) == LK_EXCLUSIVE); 168 KASSERT((tvp == NULL) || (VOP_ISLOCKED(tvp) == LK_EXCLUSIVE)); 169 170 return genfs_ufslike_rename_check_possible( 171 VTOI(fdvp)->i_e2fs_flags, VTOI(fvp)->i_e2fs_flags, 172 VTOI(tdvp)->i_e2fs_flags, (tvp? VTOI(tvp)->i_e2fs_flags : 0), 173 (tvp != NULL), 174 EXT2_IMMUTABLE, EXT2_APPEND); 175 } 176 177 /* 178 * ext2fs_gro_rename_check_permitted: Check whether a rename is 179 * permitted given our credentials. 180 */ 181 static int 182 ext2fs_gro_rename_check_permitted(struct mount *mp, kauth_cred_t cred, 183 struct vnode *fdvp, struct vnode *fvp, 184 struct vnode *tdvp, struct vnode *tvp) 185 { 186 187 (void)mp; 188 KASSERT(mp != NULL); 189 KASSERT(fdvp != NULL); 190 KASSERT(fvp != NULL); 191 KASSERT(tdvp != NULL); 192 KASSERT(fdvp != fvp); 193 KASSERT(fdvp != tvp); 194 KASSERT(tdvp != fvp); 195 KASSERT(tdvp != tvp); 196 KASSERT(fvp != tvp); 197 KASSERT(fdvp->v_type == VDIR); 198 KASSERT(tdvp->v_type == VDIR); 199 KASSERT(fdvp->v_mount == mp); 200 KASSERT(fvp->v_mount == mp); 201 KASSERT(tdvp->v_mount == mp); 202 KASSERT((tvp == NULL) || (tvp->v_mount == mp)); 203 KASSERT(VOP_ISLOCKED(fdvp) == LK_EXCLUSIVE); 204 KASSERT(VOP_ISLOCKED(fvp) == LK_EXCLUSIVE); 205 KASSERT(VOP_ISLOCKED(tdvp) == LK_EXCLUSIVE); 206 KASSERT((tvp == NULL) || (VOP_ISLOCKED(tvp) == LK_EXCLUSIVE)); 207 208 return genfs_ufslike_rename_check_permitted(cred, 209 fdvp, VTOI(fdvp)->i_e2fs_mode, VTOI(fdvp)->i_uid, 210 fvp, VTOI(fvp)->i_uid, 211 tdvp, VTOI(tdvp)->i_e2fs_mode, VTOI(tdvp)->i_uid, 212 tvp, (tvp? VTOI(tvp)->i_uid : 0)); 213 } 214 215 /* 216 * ext2fs_gro_remove_check_possible: Check whether a remove is possible 217 * independent of credentials. 218 */ 219 static int 220 ext2fs_gro_remove_check_possible(struct mount *mp, 221 struct vnode *dvp, struct vnode *vp) 222 { 223 224 (void)mp; 225 KASSERT(mp != NULL); 226 KASSERT(dvp != NULL); 227 KASSERT(vp != NULL); 228 KASSERT(dvp != vp); 229 KASSERT(dvp->v_type == VDIR); 230 KASSERT(vp->v_type != VDIR); 231 KASSERT(dvp->v_mount == mp); 232 KASSERT(vp->v_mount == mp); 233 KASSERT(VOP_ISLOCKED(dvp) == LK_EXCLUSIVE); 234 KASSERT(VOP_ISLOCKED(vp) == LK_EXCLUSIVE); 235 236 return genfs_ufslike_remove_check_possible( 237 VTOI(dvp)->i_e2fs_flags, VTOI(vp)->i_e2fs_flags, 238 EXT2_IMMUTABLE, EXT2_APPEND); 239 } 240 241 /* 242 * ext2fs_gro_remove_check_permitted: Check whether a remove is 243 * permitted given our credentials. 244 */ 245 static int 246 ext2fs_gro_remove_check_permitted(struct mount *mp, kauth_cred_t cred, 247 struct vnode *dvp, struct vnode *vp) 248 { 249 250 (void)mp; 251 KASSERT(mp != NULL); 252 KASSERT(dvp != NULL); 253 KASSERT(vp != NULL); 254 KASSERT(dvp != vp); 255 KASSERT(dvp->v_type == VDIR); 256 KASSERT(vp->v_type != VDIR); 257 KASSERT(dvp->v_mount == mp); 258 KASSERT(vp->v_mount == mp); 259 KASSERT(VOP_ISLOCKED(dvp) == LK_EXCLUSIVE); 260 KASSERT(VOP_ISLOCKED(vp) == LK_EXCLUSIVE); 261 262 return genfs_ufslike_remove_check_permitted(cred, 263 dvp, VTOI(dvp)->i_e2fs_mode, VTOI(dvp)->i_uid, 264 vp, VTOI(vp)->i_uid); 265 } 266 267 /* 268 * ext2fs_gro_rename: Actually perform the rename operation. 269 */ 270 static int 271 ext2fs_gro_rename(struct mount *mp, kauth_cred_t cred, 272 struct vnode *fdvp, struct componentname *fcnp, 273 void *fde, struct vnode *fvp, 274 struct vnode *tdvp, struct componentname *tcnp, 275 void *tde, struct vnode *tvp) 276 { 277 struct ufs_lookup_results *fulr = fde; 278 struct ufs_lookup_results *tulr = tde; 279 bool directory_p, reparent_p; 280 int error; 281 282 (void)mp; 283 KASSERT(mp != NULL); 284 KASSERT(fdvp != NULL); 285 KASSERT(fcnp != NULL); 286 KASSERT(fulr != NULL); 287 KASSERT(fvp != NULL); 288 KASSERT(tdvp != NULL); 289 KASSERT(tcnp != NULL); 290 KASSERT(tulr != NULL); 291 KASSERT(fulr != tulr); 292 KASSERT(fdvp != fvp); 293 KASSERT(fdvp != tvp); 294 KASSERT(tdvp != fvp); 295 KASSERT(tdvp != tvp); 296 KASSERT(fvp != tvp); 297 KASSERT(fdvp->v_mount == mp); 298 KASSERT(fvp->v_mount == mp); 299 KASSERT(tdvp->v_mount == mp); 300 KASSERT((tvp == NULL) || (tvp->v_mount == mp)); 301 KASSERT(VOP_ISLOCKED(fdvp) == LK_EXCLUSIVE); 302 KASSERT(VOP_ISLOCKED(fvp) == LK_EXCLUSIVE); 303 KASSERT(VOP_ISLOCKED(tdvp) == LK_EXCLUSIVE); 304 KASSERT((tvp == NULL) || (VOP_ISLOCKED(tvp) == LK_EXCLUSIVE)); 305 306 /* 307 * We shall need to temporarily bump the link count, so make 308 * sure there is room to do so. 309 */ 310 if ((nlink_t)VTOI(fvp)->i_e2fs_nlink >= EXT2FS_LINK_MAX) 311 return EMLINK; 312 313 directory_p = (fvp->v_type == VDIR); 314 KASSERT(directory_p == ((VTOI(fvp)->i_e2fs_mode & IFMT) == IFDIR)); 315 KASSERT((tvp == NULL) || (directory_p == (tvp->v_type == VDIR))); 316 KASSERT((tvp == NULL) || (directory_p == 317 ((VTOI(tvp)->i_e2fs_mode & IFMT) == IFDIR))); 318 319 reparent_p = (fdvp != tdvp); 320 KASSERT(reparent_p == (VTOI(fdvp)->i_number != VTOI(tdvp)->i_number)); 321 322 /* 323 * Commence hacking of the data on disk. 324 */ 325 326 /* 327 * 1) Bump link count while we're moving stuff 328 * around. If we crash somewhere before 329 * completing our work, the link count 330 * may be wrong, but correctable. 331 */ 332 333 KASSERT((nlink_t)VTOI(fvp)->i_e2fs_nlink < EXT2FS_LINK_MAX); 334 VTOI(fvp)->i_e2fs_nlink++; 335 VTOI(fvp)->i_flag |= IN_CHANGE; 336 error = ext2fs_update(fvp, NULL, NULL, UPDATE_WAIT); 337 if (error) 338 goto whymustithurtsomuch; 339 340 /* 341 * 2) If target doesn't exist, link the target 342 * to the source and unlink the source. 343 * Otherwise, rewrite the target directory 344 * entry to reference the source inode and 345 * expunge the original entry's existence. 346 */ 347 348 if (tvp == NULL) { 349 /* 350 * Account for ".." in new directory. 351 * When source and destination have the same 352 * parent we don't fool with the link count. 353 */ 354 if (directory_p && reparent_p) { 355 if ((nlink_t)VTOI(tdvp)->i_e2fs_nlink >= EXT2FS_LINK_MAX) { 356 error = EMLINK; 357 goto whymustithurtsomuch; 358 } 359 KASSERT((nlink_t)VTOI(tdvp)->i_e2fs_nlink < EXT2FS_LINK_MAX); 360 VTOI(tdvp)->i_e2fs_nlink++; 361 VTOI(tdvp)->i_flag |= IN_CHANGE; 362 error = ext2fs_update(tdvp, NULL, NULL, UPDATE_WAIT); 363 if (error) { 364 /* 365 * Link count update didn't take -- 366 * back out the in-memory link count. 367 */ 368 KASSERT(0 < VTOI(tdvp)->i_e2fs_nlink); 369 VTOI(tdvp)->i_e2fs_nlink--; 370 VTOI(tdvp)->i_flag |= IN_CHANGE; 371 goto whymustithurtsomuch; 372 } 373 } 374 375 error = ext2fs_direnter(VTOI(fvp), tdvp, tulr, tcnp); 376 if (error) { 377 if (directory_p && reparent_p) { 378 /* 379 * Directory update didn't take, but 380 * the link count update did -- back 381 * out the in-memory link count and the 382 * on-disk link count. 383 */ 384 KASSERT(0 < VTOI(tdvp)->i_e2fs_nlink); 385 VTOI(tdvp)->i_e2fs_nlink--; 386 VTOI(tdvp)->i_flag |= IN_CHANGE; 387 (void)ext2fs_update(tdvp, NULL, NULL, 388 UPDATE_WAIT); 389 } 390 goto whymustithurtsomuch; 391 } 392 } else { 393 if (directory_p) 394 /* XXX WTF? Why purge here? Why not purge others? */ 395 cache_purge(tdvp); 396 397 /* 398 * Make the target directory's entry for tcnp point at 399 * the source node. 400 */ 401 error = ext2fs_dirrewrite(VTOI(tdvp), tulr, VTOI(fvp), tcnp); 402 if (error) 403 goto whymustithurtsomuch; 404 405 /* 406 * If the source and target are directories, and the 407 * target is in the same directory as the source, 408 * decrement the link count of the common parent 409 * directory, since we are removing the target from 410 * that directory. 411 */ 412 if (directory_p && !reparent_p) { 413 KASSERT(fdvp == tdvp); 414 /* XXX check, don't kassert */ 415 KASSERT(0 < VTOI(tdvp)->i_e2fs_nlink); 416 VTOI(tdvp)->i_e2fs_nlink--; 417 VTOI(tdvp)->i_flag |= IN_CHANGE; 418 } 419 420 /* 421 * Adjust the link count of the target to 422 * reflect the dirrewrite above. If this is 423 * a directory it is empty and there are 424 * no links to it, so we can squash the inode and 425 * any space associated with it. We disallowed 426 * renaming over top of a directory with links to 427 * it above, as the remaining link would point to 428 * a directory without "." or ".." entries. 429 */ 430 /* XXX check, don't kassert */ 431 KASSERT(0 < VTOI(tvp)->i_e2fs_nlink); 432 VTOI(tvp)->i_e2fs_nlink--; 433 if (directory_p) { 434 /* 435 * XXX The ext2fs_dirempty call earlier does 436 * not guarantee anything about nlink. 437 */ 438 if (VTOI(tvp)->i_e2fs_nlink != 1) 439 ufs_dirbad(VTOI(tvp), (doff_t)0, 440 "hard-linked directory"); 441 VTOI(tvp)->i_e2fs_nlink = 0; 442 error = ext2fs_truncate(tvp, (off_t)0, IO_SYNC, cred); 443 #if 0 /* XXX This branch was not in ext2fs_rename! */ 444 if (error) 445 goto whymustithurtsomuch; 446 #endif 447 } 448 /* 449 * XXX Why is this here, and not above the preceding 450 * conditional? 451 */ 452 VTOI(tvp)->i_flag |= IN_CHANGE; 453 } 454 455 /* 456 * If the source is a directory with a new parent, the link 457 * count of the old parent directory must be decremented and 458 * ".." set to point to the new parent. 459 */ 460 if (directory_p && reparent_p) { 461 error = ext2fs_rename_replace_dotdot(fvp, fdvp, tdvp, cred); 462 if (error) 463 goto whymustithurtsomuch; 464 465 /* XXX WTF? Why purge here? Why not purge others? */ 466 cache_purge(fdvp); 467 } 468 469 /* 470 * 3) Unlink the source. 471 */ 472 473 /* 474 * ext2fs_direnter may compact the directory in the process of 475 * inserting a new entry. That may invalidate fulr, which we 476 * need in order to remove the old entry. In that case, we 477 * need to recalculate what fulr should be. 478 */ 479 if (!reparent_p && (tvp == NULL) && 480 ext2fs_rename_ulr_overlap_p(fulr, tulr)) { 481 error = ext2fs_rename_recalculate_fulr(fdvp, fulr, tulr, fcnp); 482 #if 0 /* XXX */ 483 if (error) /* XXX Try to back out changes? */ 484 goto whymustithurtsomuch; 485 #endif 486 } 487 488 error = ext2fs_dirremove(fdvp, fulr, fcnp); 489 if (error) 490 goto whymustithurtsomuch; 491 492 /* 493 * XXX Perhaps this should go at the top, in case the file 494 * system is modified but incompletely so because of an 495 * intermediate error. 496 */ 497 genfs_rename_knote(fdvp, fvp, tdvp, tvp, 498 ((tvp != NULL) && (VTOI(tvp)->i_e2fs_nlink == 0))); 499 #if 0 /* XXX */ 500 genfs_rename_cache_purge(fdvp, fvp, tdvp, tvp); 501 #endif 502 503 whymustithurtsomuch: 504 KASSERT(0 < VTOI(fvp)->i_e2fs_nlink); 505 VTOI(fvp)->i_e2fs_nlink--; 506 VTOI(fvp)->i_flag |= IN_CHANGE; 507 return error; 508 } 509 510 /* 511 * ext2fs_rename_ulr_overlap_p: True iff tulr overlaps with fulr so 512 * that entering a directory entry at tulr may move fulr. 513 */ 514 static bool 515 ext2fs_rename_ulr_overlap_p(const struct ufs_lookup_results *fulr, 516 const struct ufs_lookup_results *tulr) 517 { 518 doff_t from_prev_start, from_prev_end, to_start, to_end; 519 520 KASSERT(fulr != NULL); 521 KASSERT(tulr != NULL); 522 KASSERT(fulr != tulr); 523 524 /* 525 * fulr is from a DELETE lookup, so fulr->ulr_count is the size 526 * of the preceding entry (d_reclen). 527 */ 528 from_prev_end = fulr->ulr_offset; 529 KASSERT(fulr->ulr_count <= from_prev_end); 530 from_prev_start = (from_prev_end - fulr->ulr_count); 531 532 /* 533 * tulr is from a RENAME lookup, so tulr->ulr_count is the size 534 * of the free space for an entry that we are about to fill. 535 */ 536 to_start = tulr->ulr_offset; 537 KASSERT(tulr->ulr_count < (EXT2FS_MAXDIRSIZE - to_start)); 538 to_end = (to_start + tulr->ulr_count); 539 540 return 541 (((to_start <= from_prev_start) && (from_prev_start < to_end)) || 542 ((to_start <= from_prev_end) && (from_prev_end < to_end))); 543 } 544 545 /* 546 * ext2fs_rename_recalculate_fulr: If we have just entered a directory 547 * into dvp at tulr, and we were about to remove one at fulr for an 548 * entry named fcnp, fulr may be invalid. So, if necessary, 549 * recalculate it. 550 */ 551 static int 552 ext2fs_rename_recalculate_fulr(struct vnode *dvp, 553 struct ufs_lookup_results *fulr, const struct ufs_lookup_results *tulr, 554 const struct componentname *fcnp) 555 { 556 struct mount *mp; 557 struct ufsmount *ump; 558 /* XXX int is a silly type for this; blame ufsmount::um_dirblksiz. */ 559 int dirblksiz; 560 doff_t search_start, search_end; 561 doff_t offset; /* Offset of entry we're examining. */ 562 struct buf *bp; /* I/O block we're examining. */ 563 char *dirbuf; /* Pointer into directory at search_start. */ 564 struct ext2fs_direct *ep; /* Pointer to the entry we're examining. */ 565 /* XXX direct::d_reclen is 16-bit; 566 * ufs_lookup_results::ulr_reclen is 32-bit. Blah. */ 567 uint32_t reclen; /* Length of the entry we're examining. */ 568 uint32_t prev_reclen; /* Length of the preceding entry. */ 569 int error; 570 571 KASSERT(dvp != NULL); 572 KASSERT(dvp->v_mount != NULL); 573 KASSERT(VTOI(dvp) != NULL); 574 KASSERT(fulr != NULL); 575 KASSERT(tulr != NULL); 576 KASSERT(fulr != tulr); 577 KASSERT(ext2fs_rename_ulr_overlap_p(fulr, tulr)); 578 579 mp = dvp->v_mount; 580 ump = VFSTOUFS(mp); 581 KASSERT(ump != NULL); 582 KASSERT(ump == VTOI(dvp)->i_ump); 583 584 dirblksiz = ump->um_dirblksiz; 585 KASSERT(0 < dirblksiz); 586 KASSERT((dirblksiz & (dirblksiz - 1)) == 0); 587 588 /* A directory block may not span across multiple I/O blocks. */ 589 KASSERT(dirblksiz <= mp->mnt_stat.f_iosize); 590 591 /* Find the bounds of the search. */ 592 search_start = tulr->ulr_offset; 593 KASSERT(fulr->ulr_reclen < (EXT2FS_MAXDIRSIZE - fulr->ulr_offset)); 594 search_end = (fulr->ulr_offset + fulr->ulr_reclen); 595 596 /* Compaction must happen only within a directory block. (*) */ 597 KASSERT(search_start <= search_end); 598 KASSERT((search_end - (search_start &~ (dirblksiz - 1))) <= dirblksiz); 599 600 dirbuf = NULL; 601 bp = NULL; 602 error = ext2fs_blkatoff(dvp, (off_t)search_start, &dirbuf, &bp); 603 if (error) 604 return error; 605 KASSERT(dirbuf != NULL); 606 KASSERT(bp != NULL); 607 608 /* 609 * Guarantee we sha'n't go past the end of the buffer we got. 610 * dirbuf is bp->b_data + (search_start & (iosize - 1)), and 611 * the valid range is [bp->b_data, bp->b_data + bp->b_bcount). 612 */ 613 KASSERT((search_end - search_start) <= 614 (bp->b_bcount - (search_start & (mp->mnt_stat.f_iosize - 1)))); 615 616 prev_reclen = fulr->ulr_count; 617 offset = search_start; 618 619 /* 620 * Search from search_start to search_end for the entry matching 621 * fcnp, which must be there because we found it before and it 622 * should only at most have moved earlier. 623 */ 624 for (;;) { 625 KASSERT(search_start <= offset); 626 KASSERT(offset < search_end); 627 628 /* 629 * Examine the directory entry at offset. 630 */ 631 ep = (struct ext2fs_direct *) 632 (dirbuf + (offset - search_start)); 633 reclen = fs2h16(ep->e2d_reclen); 634 635 if (ep->e2d_ino == 0) 636 goto next; /* Entry is unused. */ 637 638 if (fs2h32(ep->e2d_ino) == UFS_WINO) 639 goto next; /* Entry is whiteout. */ 640 641 if (fcnp->cn_namelen != ep->e2d_namlen) 642 goto next; /* Wrong name length. */ 643 644 if (memcmp(ep->e2d_name, fcnp->cn_nameptr, fcnp->cn_namelen)) 645 goto next; /* Wrong name. */ 646 647 /* Got it! */ 648 break; 649 650 next: 651 if (! ((reclen < search_end) && 652 (offset < (search_end - reclen)))) { 653 brelse(bp, 0); 654 return EIO; /* XXX Panic? What? */ 655 } 656 657 /* We may not move past the search end. */ 658 KASSERT(reclen < search_end); 659 KASSERT(offset < (search_end - reclen)); 660 661 /* 662 * We may not move across a directory block boundary; 663 * see (*) above. 664 */ 665 KASSERT((offset &~ (dirblksiz - 1)) == 666 ((offset + reclen) &~ (dirblksiz - 1))); 667 668 prev_reclen = reclen; 669 offset += reclen; 670 } 671 672 /* 673 * Found the entry. Record where. 674 */ 675 fulr->ulr_offset = offset; 676 fulr->ulr_reclen = reclen; 677 678 /* 679 * Record the preceding record length, but not if we're at the 680 * start of a directory block. 681 */ 682 fulr->ulr_count = ((offset & (dirblksiz - 1))? prev_reclen : 0); 683 684 brelse(bp, 0); 685 return 0; 686 } 687 688 /* 689 * ext2fs_gro_remove: Rename an object over another link to itself, 690 * effectively removing just the original link. 691 */ 692 static int 693 ext2fs_gro_remove(struct mount *mp, kauth_cred_t cred, 694 struct vnode *dvp, struct componentname *cnp, void *de, struct vnode *vp) 695 { 696 struct ufs_lookup_results *ulr = de; 697 int error; 698 699 (void)mp; 700 KASSERT(mp != NULL); 701 KASSERT(dvp != NULL); 702 KASSERT(cnp != NULL); 703 KASSERT(ulr != NULL); 704 KASSERT(vp != NULL); 705 KASSERT(dvp != vp); 706 KASSERT(dvp->v_mount == mp); 707 KASSERT(vp->v_mount == mp); 708 KASSERT(dvp->v_type == VDIR); 709 KASSERT(vp->v_type != VDIR); 710 KASSERT(VOP_ISLOCKED(dvp) == LK_EXCLUSIVE); 711 KASSERT(VOP_ISLOCKED(vp) == LK_EXCLUSIVE); 712 713 error = ext2fs_dirremove(dvp, ulr, cnp); 714 if (error) 715 return error; 716 717 KASSERT(0 < VTOI(vp)->i_e2fs_nlink); 718 VTOI(vp)->i_e2fs_nlink--; 719 VTOI(vp)->i_flag |= IN_CHANGE; 720 721 VN_KNOTE(dvp, NOTE_WRITE); 722 VN_KNOTE(vp, (VTOI(vp)->i_e2fs_nlink? NOTE_LINK : NOTE_DELETE)); 723 724 return 0; 725 } 726 727 /* 728 * ext2fs_gro_lookup: Look up and save the lookup results. 729 */ 730 static int 731 ext2fs_gro_lookup(struct mount *mp, struct vnode *dvp, 732 struct componentname *cnp, void *de_ret, struct vnode **vp_ret) 733 { 734 struct ufs_lookup_results *ulr_ret = de_ret; 735 struct vnode *vp; 736 int error; 737 738 (void)mp; 739 KASSERT(mp != NULL); 740 KASSERT(dvp != NULL); 741 KASSERT(cnp != NULL); 742 KASSERT(ulr_ret != NULL); 743 KASSERT(vp_ret != NULL); 744 KASSERT(VOP_ISLOCKED(dvp) == LK_EXCLUSIVE); 745 746 /* Kludge cargo-culted from dholland's ufs_rename. */ 747 cnp->cn_flags &=~ MODMASK; 748 cnp->cn_flags |= (LOCKPARENT | LOCKLEAF); 749 750 error = relookup(dvp, &vp, cnp, 0 /* dummy */); 751 if ((error == 0) && (vp == NULL)) { 752 error = ENOENT; 753 goto out; 754 } else if (error) { 755 return error; 756 } 757 758 /* 759 * Thanks to VFS insanity, relookup locks vp, which screws us 760 * in various ways. 761 */ 762 KASSERT(vp != NULL); 763 VOP_UNLOCK(vp); 764 765 out: *ulr_ret = VTOI(dvp)->i_crap; 766 *vp_ret = vp; 767 return error; 768 } 769 770 /* 771 * ext2fs_rmdired_p: Check whether the directory vp has been rmdired. 772 * 773 * vp must be locked and referenced. 774 */ 775 static bool 776 ext2fs_rmdired_p(struct vnode *vp) 777 { 778 779 KASSERT(vp != NULL); 780 KASSERT(VOP_ISLOCKED(vp) == LK_EXCLUSIVE); 781 KASSERT(vp->v_type == VDIR); 782 783 /* XXX Is this correct? */ 784 return ext2fs_size(VTOI(vp)) == 0; 785 } 786 787 /* 788 * ext2fs_gro_genealogy: Analyze the genealogy of the source and target 789 * directories. 790 */ 791 static int 792 ext2fs_gro_genealogy(struct mount *mp, kauth_cred_t cred, 793 struct vnode *fdvp, struct vnode *tdvp, 794 struct vnode **intermediate_node_ret) 795 { 796 struct vnode *vp, *dvp; 797 ino_t dotdot_ino = -1; /* XXX gcc 4.8.3: maybe-uninitialized */ 798 int error; 799 800 KASSERT(mp != NULL); 801 KASSERT(fdvp != NULL); 802 KASSERT(tdvp != NULL); 803 KASSERT(fdvp != tdvp); 804 KASSERT(intermediate_node_ret != NULL); 805 KASSERT(fdvp->v_mount == mp); 806 KASSERT(tdvp->v_mount == mp); 807 KASSERT(fdvp->v_type == VDIR); 808 KASSERT(tdvp->v_type == VDIR); 809 810 /* 811 * We need to provisionally lock tdvp to keep rmdir from 812 * deleting it -- or any ancestor -- at an inopportune moment. 813 */ 814 error = ext2fs_gro_lock_directory(mp, tdvp); 815 if (error) 816 return error; 817 818 vp = tdvp; 819 vref(vp); 820 821 for (;;) { 822 KASSERT(vp != NULL); 823 KASSERT(VOP_ISLOCKED(vp) == LK_EXCLUSIVE); 824 KASSERT(vp->v_mount == mp); 825 KASSERT(vp->v_type == VDIR); 826 KASSERT(!ext2fs_rmdired_p(vp)); 827 828 /* Did we hit the root without finding fdvp? */ 829 if (VTOI(vp)->i_number == UFS_ROOTINO) { 830 vput(vp); 831 *intermediate_node_ret = NULL; 832 return 0; 833 } 834 835 error = ext2fs_read_dotdot(vp, cred, &dotdot_ino); 836 if (error) { 837 vput(vp); 838 return error; 839 } 840 841 /* Did we find that fdvp is an ancestor of tdvp? */ 842 if (VTOI(fdvp)->i_number == dotdot_ino) { 843 /* Unlock vp, but keep it referenced. */ 844 VOP_UNLOCK(vp); 845 *intermediate_node_ret = vp; 846 return 0; 847 } 848 849 /* Neither -- keep ascending the family tree. */ 850 error = vcache_get(mp, &dotdot_ino, sizeof(dotdot_ino), &dvp); 851 vput(vp); 852 if (error) 853 return error; 854 error = vn_lock(dvp, LK_EXCLUSIVE); 855 if (error) { 856 vrele(dvp); 857 return error; 858 } 859 860 KASSERT(dvp != NULL); 861 KASSERT(VOP_ISLOCKED(dvp) == LK_EXCLUSIVE); 862 vp = dvp; 863 864 if (vp->v_type != VDIR) { 865 /* 866 * XXX Panic? Print a warning? Can this 867 * happen if we lose the race I suspect to 868 * exist above, and the `..' inode number has 869 * been recycled? 870 */ 871 vput(vp); 872 return ENOTDIR; 873 } 874 875 if (ext2fs_rmdired_p(vp)) { 876 vput(vp); 877 return ENOENT; 878 } 879 } 880 } 881 882 /* 883 * ext2fs_read_dotdot: Store in *ino_ret the inode number of the parent 884 * of the directory vp. 885 */ 886 static int 887 ext2fs_read_dotdot(struct vnode *vp, kauth_cred_t cred, ino_t *ino_ret) 888 { 889 struct ext2fs_dirtemplate dirbuf; 890 int error; 891 892 KASSERT(vp != NULL); 893 KASSERT(ino_ret != NULL); 894 KASSERT(vp->v_type == VDIR); 895 896 error = ufs_bufio(UIO_READ, vp, &dirbuf, sizeof dirbuf, (off_t)0, 897 IO_NODELOCKED, cred, NULL, NULL); 898 if (error) 899 return error; 900 901 if (dirbuf.dotdot_namlen != 2 || 902 dirbuf.dotdot_name[0] != '.' || 903 dirbuf.dotdot_name[1] != '.') 904 /* XXX Panic? Print warning? */ 905 return ENOTDIR; 906 907 *ino_ret = fs2h32(dirbuf.dotdot_ino); 908 return 0; 909 } 910 911 /* 912 * ext2fs_rename_replace_dotdot: Change the target of the `..' entry of 913 * the directory vp from fdvp to tdvp. 914 */ 915 static int 916 ext2fs_rename_replace_dotdot(struct vnode *vp, 917 struct vnode *fdvp, struct vnode *tdvp, 918 kauth_cred_t cred) 919 { 920 struct ext2fs_dirtemplate dirbuf; 921 int error; 922 923 /* XXX Does it make sense to do this before the sanity checks below? */ 924 KASSERT(0 < VTOI(fdvp)->i_e2fs_nlink); 925 VTOI(fdvp)->i_e2fs_nlink--; 926 VTOI(fdvp)->i_flag |= IN_CHANGE; 927 928 error = ufs_bufio(UIO_READ, vp, &dirbuf, sizeof dirbuf, (off_t)0, 929 IO_NODELOCKED, cred, NULL, NULL); 930 if (error) 931 return error; 932 933 if (dirbuf.dotdot_namlen != 2 || 934 dirbuf.dotdot_name[0] != '.' || 935 dirbuf.dotdot_name[1] != '.') { 936 ufs_dirbad(VTOI(vp), (doff_t)12, "bad `..' entry"); 937 return 0; 938 } 939 940 if (fs2h32(dirbuf.dotdot_ino) != VTOI(fdvp)->i_number) { 941 ufs_dirbad(VTOI(vp), (doff_t)12, 942 "`..' does not point at parent"); 943 return 0; 944 } 945 946 dirbuf.dotdot_ino = h2fs32(VTOI(tdvp)->i_number); 947 /* XXX WTF? Why not check error? */ 948 (void)ufs_bufio(UIO_WRITE, vp, &dirbuf, sizeof dirbuf, (off_t)0, 949 (IO_NODELOCKED | IO_SYNC), cred, NULL, NULL); 950 951 return 0; 952 } 953 954 /* 955 * ext2fs_gro_lock_directory: Lock the directory vp, but fail if it has 956 * been rmdir'd. 957 */ 958 static int 959 ext2fs_gro_lock_directory(struct mount *mp, struct vnode *vp) 960 { 961 962 (void)mp; 963 KASSERT(mp != NULL); 964 KASSERT(vp != NULL); 965 KASSERT(vp->v_mount == mp); 966 967 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); 968 969 if (ext2fs_rmdired_p(vp)) { 970 VOP_UNLOCK(vp); 971 return ENOENT; 972 } 973 974 return 0; 975 } 976 977 static const struct genfs_rename_ops ext2fs_genfs_rename_ops = { 978 .gro_directory_empty_p = ext2fs_gro_directory_empty_p, 979 .gro_rename_check_possible = ext2fs_gro_rename_check_possible, 980 .gro_rename_check_permitted = ext2fs_gro_rename_check_permitted, 981 .gro_remove_check_possible = ext2fs_gro_remove_check_possible, 982 .gro_remove_check_permitted = ext2fs_gro_remove_check_permitted, 983 .gro_rename = ext2fs_gro_rename, 984 .gro_remove = ext2fs_gro_remove, 985 .gro_lookup = ext2fs_gro_lookup, 986 .gro_genealogy = ext2fs_gro_genealogy, 987 .gro_lock_directory = ext2fs_gro_lock_directory, 988 }; 989