1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright (c) 1995 Sun Microsystems, Inc. All Rights Reserved 24 * Copyright (c) 2016 by Delphix. All rights reserved. 25 * 26 * module: 27 * action.c 28 * 29 * purpose: 30 * routines to carryout reconciliation actions and make the 31 * appropriate updates to the database file structure. 32 * 33 * contents: 34 * do_like ... change ownership and protection 35 * do_copy ... copy a file from one side to the other 36 * do_remove . remove a file from one side 37 * do_rename . rename a file on one side 38 * copy ...... (static) do the actual copy 39 * checksparse (static) figure out if a file is sparse 40 * 41 * ASSERTIONS: 42 * any of these action routines is responsible for all baseline 43 * and statistics updates associated with the reconciliation 44 * actions. If notouch is specified, they should fake the 45 * updates well enough so that link tests will still work. 46 * 47 * success: 48 * bump bp->b_{src,dst}_{copies,deletes,misc} 49 * update fp->f_info[srcdst] 50 * update fp->f_info[OPT_BASE] from fp->f_info[srcdst] 51 * if there might be multiple links, call link_update 52 * return ERR_RESOLVABLE 53 * 54 * failure: 55 * set fp->f_flags |= F_CONFLICT 56 * set fp->f_problem 57 * bump bp->b_unresolved 58 * return ERR_UNRESOLVED 59 * 60 * pretend this never happened: 61 * return 0, and baseline will be unchanged 62 * 63 * notes: 64 * Action routines can be called in virtually any order 65 * or combination, and it is certainly possible for an 66 * earlier action to succeed while a later action fails. 67 * If each successful action results in a completed baseline 68 * update, a subsequent failure will force the baseline to 69 * roll back to the last success ... which is appropriate. 70 */ 71 #ident "%W% %E% SMI" 72 73 #include <stdio.h> 74 #include <stdlib.h> 75 #include <unistd.h> 76 #include <fcntl.h> 77 #include <utime.h> 78 #include <errno.h> 79 #include <sys/mkdev.h> 80 #include <sys/statvfs.h> 81 82 #include "filesync.h" 83 #include "database.h" 84 #include "messages.h" 85 #include "debug.h" 86 87 /* 88 * globals and importeds 89 */ 90 bool_t need_super; /* warn user that we can't fix ownership */ 91 extern char *srcname; /* file we are emulating */ 92 extern char *dstname; /* file we are updating */ 93 94 /* 95 * locals 96 */ 97 static errmask_t copy(char *, char *, int); 98 static int checksparse(int); 99 static char *copy_err_str; /* what went wrong w/copy */ 100 101 /* 102 * routine: 103 * do_like 104 * 105 * purpose: 106 * to propagate ownership and protection changes between 107 * one existing file and another. 108 * 109 * parameters: 110 * file pointer 111 * src/dst indication for who needs to change 112 * whether or not to update statistics (there may be a copy and a like) 113 * 114 * returns: 115 * error mask 116 * 117 * notes: 118 * if we are called from reconcile, we should update 119 * the statistics, but if we were called from do_copy 120 * that routine will do the honors. 121 */ 122 errmask_t 123 do_like(struct file *fp, side_t srcdst, bool_t do_stats) 124 { char *dst; 125 int rc = 0; 126 int do_chown, do_chmod, do_chgrp, do_acls; 127 errmask_t errs = 0; 128 char *errstr = 0; 129 struct base *bp; 130 struct fileinfo *sp; 131 struct fileinfo *dp; 132 struct fileinfo *ip; 133 extern int errno; 134 135 bp = fp->f_base; 136 137 /* see if this is a forbidden propagation */ 138 if (srcdst == opt_oneway) { 139 fp->f_flags |= F_CONFLICT; 140 fp->f_problem = gettext(PROB_prohibited); 141 bp->b_unresolved++; 142 return (ERR_UNRESOLVED); 143 } 144 145 146 /* get info about source and target files */ 147 if (srcdst == OPT_SRC) { 148 sp = &fp->f_info[ OPT_DST ]; 149 dp = &fp->f_info[ OPT_SRC ]; 150 dst = srcname; 151 } else { 152 sp = &fp->f_info[ OPT_SRC ]; 153 dp = &fp->f_info[ OPT_DST ]; 154 dst = dstname; 155 } 156 ip = &fp->f_info[ OPT_BASE ]; 157 158 /* figure out what needs fixing */ 159 do_chmod = (sp->f_mode != dp->f_mode); 160 do_chown = (sp->f_uid != dp->f_uid); 161 do_chgrp = (sp->f_gid != dp->f_gid); 162 do_acls = ((fp->f_srcdiffs|fp->f_dstdiffs) & D_FACLS); 163 164 /* 165 * try to anticipate things that we might not be able to 166 * do, and return appropriate errorst if the calling user 167 * cannot safely perform the requiested updates. 168 */ 169 if (my_uid != 0) { 170 if (do_chown) 171 errstr = gettext(PROB_chown); 172 else if (my_uid != dp->f_uid) { 173 if (do_chmod) 174 errstr = gettext(PROB_chmod); 175 else if (do_acls) 176 errstr = gettext(PROB_chacl); 177 else if (do_chgrp) 178 errstr = gettext(PROB_chgrp); 179 } 180 #ifdef ACL_UID_BUG 181 else if (do_acls && my_gid != dp->f_gid) 182 errstr = gettext(PROB_botch); 183 #endif 184 185 if (errstr) { 186 need_super = TRUE; 187 188 /* if the user doesn't care, shine it on */ 189 if (opt_everything == 0) 190 return (0); 191 192 /* if the user does care, return the error */ 193 rc = -1; 194 goto nogood; 195 } 196 } 197 198 if (opt_debug & DBG_RECON) { 199 fprintf(stderr, "RECO: do_like %s (", dst); 200 if (do_chmod) 201 fprintf(stderr, "chmod "); 202 if (do_acls) 203 fprintf(stderr, "acls "); 204 if (do_chown) 205 fprintf(stderr, "chown "); 206 if (do_chgrp) 207 fprintf(stderr, "chgrp "); 208 fprintf(stderr, ")\n"); 209 } 210 211 if (do_chmod) { 212 if (!opt_quiet) 213 fprintf(stdout, "chmod %o %s\n", sp->f_mode, 214 noblanks(dst)); 215 216 #ifdef DBG_ERRORS 217 /* should we simulate a chmod failure */ 218 if (errno = dbg_chk_error(dst, 'p')) 219 rc = -1; 220 else 221 #endif 222 rc = opt_notouch ? 0 : chmod(dst, sp->f_mode); 223 224 if (opt_debug & DBG_RECON) 225 fprintf(stderr, "RECO: do_chmod %o -> %d(%d)\n", 226 sp->f_mode, rc, errno); 227 228 /* update dest and baseline to reflect the change */ 229 if (rc == 0) { 230 dp->f_mode = sp->f_mode; 231 ip->f_mode = sp->f_mode; 232 } else 233 errstr = gettext(PROB_chmod); 234 } 235 236 /* 237 * see if we need to fix the acls 238 */ 239 if (rc == 0 && do_acls) { 240 if (!opt_quiet) 241 fprintf(stdout, "setfacl %s %s\n", 242 show_acls(sp->f_numacls, sp->f_acls), 243 noblanks(dst)); 244 245 #ifdef DBG_ERRORS 246 /* should we simulate a set acl failure */ 247 if (errno = dbg_chk_error(dst, 'a')) 248 rc = -1; 249 else 250 #endif 251 rc = opt_notouch ? 0 : set_acls(dst, sp); 252 253 if (opt_debug & DBG_RECON) 254 fprintf(stderr, "RECO: do_acls %d -> %d(%d)\n", 255 sp->f_numacls, rc, errno); 256 257 /* update dest and baseline to reflect the change */ 258 if (rc == 0) { 259 dp->f_numacls = sp->f_numacls; 260 dp->f_acls = sp->f_acls; 261 ip->f_numacls = sp->f_numacls; 262 ip->f_acls = sp->f_acls; 263 #ifdef ACL_UID_BUG 264 /* SETFACL changes a file's UID/GID */ 265 if (my_uid != dp->f_uid) { 266 do_chown = 1; 267 dp->f_uid = my_uid; 268 } 269 if (my_gid != dp->f_gid) { 270 do_chgrp = 1; 271 dp->f_gid = my_gid; 272 } 273 #endif 274 } else if (errno == ENOSYS) { 275 /* 276 * if the file system doesn't support ACLs 277 * we should just pretend we never saw them 278 */ 279 fprintf(stderr, gettext(WARN_noacls), dst); 280 ip->f_numacls = 0; 281 sp->f_numacls = 0; 282 dp->f_numacls = 0; 283 rc = 0; 284 } else 285 errstr = gettext(PROB_chacl); 286 } 287 288 /* 289 * see if we need to fix the ownership 290 */ 291 if (rc == 0 && (do_chown || do_chgrp)) { 292 if (do_chown) 293 fprintf(stdout, "chown %ld %s; ", 294 sp->f_uid, noblanks(dst)); 295 if (do_chgrp) 296 fprintf(stdout, "chgrp %ld %s", 297 sp->f_gid, noblanks(dst)); 298 299 fprintf(stdout, "\n"); 300 301 #ifdef DBG_ERRORS 302 /* should we simulate a chown failure */ 303 if (errno = dbg_chk_error(dst, 'O')) 304 rc = -1; 305 else 306 #endif 307 rc = opt_notouch ? 0 : lchown(dst, sp->f_uid, sp->f_gid); 308 309 if (opt_debug & DBG_RECON) 310 fprintf(stderr, "RECO: do_chown %ld %ld -> %d(%d)\n", 311 sp->f_uid, sp->f_gid, rc, errno); 312 313 /* update the destination to reflect changes */ 314 if (rc == 0) { 315 dp->f_uid = sp->f_uid; 316 dp->f_gid = sp->f_gid; 317 ip->f_uid = sp->f_uid; 318 ip->f_gid = sp->f_gid; 319 } else { 320 if (errno == EPERM) { 321 need_super = TRUE; 322 if (opt_everything == 0) 323 return (0); 324 } 325 326 if (rc != 0) 327 errstr = gettext(do_chown ? 328 PROB_chown : PROB_chgrp); 329 } 330 } 331 332 /* 333 * if we were successful, we should make sure the other links 334 * see the changes. If we were called from do_copy, we don't 335 * want to do the link_updates either because do_copy will 336 * handle them too. 337 */ 338 if (rc == 0 && do_stats) 339 link_update(fp, srcdst); 340 341 nogood: 342 if (!do_stats) 343 return (errs); 344 345 if (rc != 0) { 346 fprintf(stderr, gettext(ERR_cannot), errstr, dst); 347 fp->f_problem = errstr; 348 fp->f_flags |= F_CONFLICT; 349 bp->b_unresolved++; 350 errs |= ERR_PERM | ERR_UNRESOLVED; 351 } else { 352 /* 353 * it worked, so update the baseline and statistics 354 */ 355 if (srcdst == OPT_SRC) 356 bp->b_src_misc++; 357 else 358 bp->b_dst_misc++; 359 360 fp->f_problem = 0; 361 errs |= ERR_RESOLVABLE; 362 } 363 364 return (errs); 365 } 366 367 /* 368 * routine: 369 * do_copy 370 * 371 * purpose: 372 * to propagate a creation or change 373 * 374 * parameters: 375 * file pointer 376 * src/dst indication for who gets the copy 377 * 378 * returns: 379 * error mask 380 * 381 * note: 382 * after any successful operation we update the stat/info 383 * structure for the updated file. This is somewhat redundant 384 * because we will restat at the end of the routine, but these 385 * anticipatory updates help to ensure that the link finding 386 * code will still behave properly in notouch mode (when restats 387 * cannot be done). 388 */ 389 errmask_t 390 do_copy(struct file *fp, side_t srcdst) 391 { char *src, *dst; 392 char cmdbuf[ MAX_PATH + MAX_NAME ]; 393 int mode, maj, min, type; 394 uid_t uid; 395 gid_t gid; 396 int rc; 397 long mtime; 398 int do_chmod = 0; 399 int do_chown = 0; 400 int do_chgrp = 0; 401 int do_unlink = 0; 402 int do_acls = 0; 403 int do_create = 0; 404 char *errstr = "???"; 405 errmask_t errs = 0; 406 struct base *bp; 407 struct file *lp; 408 struct fileinfo *sp, *dp; 409 struct utimbuf newtimes; 410 struct stat statb; 411 412 bp = fp->f_base; 413 414 /* see if this is a forbidden propagation */ 415 if (srcdst == opt_oneway) { 416 fp->f_problem = gettext(PROB_prohibited); 417 fp->f_flags |= F_CONFLICT; 418 bp->b_unresolved++; 419 return (ERR_UNRESOLVED); 420 } 421 422 /* figure out who is the source and who is the destination */ 423 if (srcdst == OPT_SRC) { 424 sp = &fp->f_info[ OPT_DST ]; 425 dp = &fp->f_info[ OPT_SRC ]; 426 src = dstname; 427 dst = srcname; 428 } else { 429 sp = &fp->f_info[ OPT_SRC ]; 430 dp = &fp->f_info[ OPT_DST ]; 431 src = srcname; 432 dst = dstname; 433 } 434 435 /* note information about the file to be created */ 436 type = sp->f_type; /* type of the new file */ 437 uid = sp->f_uid; /* owner of the new file */ 438 gid = sp->f_gid; /* group of the new file */ 439 mode = sp->f_mode; /* modes for the new file */ 440 mtime = sp->f_modtime; /* modtime (if preserving) */ 441 maj = sp->f_rd_maj; /* major (if it is a device) */ 442 min = sp->f_rd_min; /* minor (if it is a device) */ 443 444 /* 445 * creating a file does not guarantee it will get the desired 446 * modes, uid and gid. If the file already exists, it will 447 * retain its old ownership and protection. If my UID/GID 448 * are not the desired ones, the new file will also require 449 * manual correction. If the file has the wrong type, we will 450 * need to delete it and recreate it. If the file is not writable, 451 * it is easier to delete it than to chmod it to permit overwrite 452 */ 453 if ((dp->f_type == S_IFREG && sp->f_type == S_IFREG) && 454 (dp->f_mode & 0200)) { 455 /* if the file already exists */ 456 if (dp->f_uid != uid) 457 do_chown = 1; 458 459 if (dp->f_gid != gid) 460 do_chgrp = 1; 461 462 if (dp->f_mode != mode) 463 do_chmod = 1; 464 } else { 465 /* if we will be creating a new file */ 466 do_create = 1; 467 if (dp->f_type) 468 do_unlink = 1; 469 if (uid != my_uid) 470 do_chown = 1; 471 if (gid != my_gid) 472 do_chgrp = 1; 473 } 474 475 /* 476 * if the source has acls, we will surely have to set them for dest 477 */ 478 if (sp->f_numacls) 479 do_acls = 1; 480 481 /* 482 * for any case other than replacing a normal file with a normal 483 * file, we need to delete the existing file before creating 484 * the new one. 485 */ 486 if (do_unlink) { 487 if (dp->f_type == S_IFDIR) { 488 if (!opt_quiet) 489 fprintf(stdout, "rmdir %s\n", noblanks(dst)); 490 491 errstr = gettext(PROB_rmdir); 492 #ifdef DBG_ERRORS 493 /* should we simulate a rmdir failure */ 494 if (errno = dbg_chk_error(dst, 'D')) 495 rc = -1; 496 else 497 #endif 498 rc = opt_notouch ? 0 : rmdir(dst); 499 } else { 500 if (!opt_quiet) 501 fprintf(stdout, "rm %s\n", noblanks(dst)); 502 503 errstr = gettext(PROB_unlink); 504 #ifdef DBG_ERRORS 505 /* should we simulate a unlink failure */ 506 if (errno = dbg_chk_error(dst, 'u')) 507 rc = -1; 508 else 509 #endif 510 rc = opt_notouch ? 0 : unlink(dst); 511 } 512 513 if (rc != 0) 514 goto cant; 515 516 /* note that this file no longer exists */ 517 dp->f_type = 0; 518 dp->f_mode = 0; 519 } 520 521 if (opt_debug & DBG_RECON) { 522 fprintf(stderr, "RECO: do_copy %s %s (", src, dst); 523 if (do_unlink) 524 fprintf(stderr, "unlink "); 525 if (do_chmod) 526 fprintf(stderr, "chmod "); 527 if (do_acls) 528 fprintf(stderr, "acls "); 529 if (do_chown) 530 fprintf(stderr, "chown "); 531 if (do_chgrp) 532 fprintf(stderr, "chgrp "); 533 fprintf(stderr, ")\n"); 534 } 535 536 /* 537 * how we go about copying a file depends on what type of file 538 * it is that we are supposed to copy 539 */ 540 switch (type) { 541 case S_IFDIR: 542 if (!opt_quiet) { 543 fprintf(stdout, "mkdir %s;", noblanks(dst)); 544 fprintf(stdout, " chmod %o %s;\n", mode, noblanks(dst)); 545 } 546 547 errstr = gettext(PROB_mkdir); 548 549 #ifdef DBG_ERRORS 550 /* should we simulate a mkdir failure */ 551 if (errno = dbg_chk_error(dst, 'd')) 552 rc = -1; 553 else 554 #endif 555 rc = opt_notouch ? 0 : mkdir(dst, mode); 556 557 /* update stat with what we have just created */ 558 if (rc == 0) { 559 dp->f_type = S_IFDIR; 560 dp->f_uid = my_uid; 561 dp->f_gid = my_gid; 562 dp->f_mode = mode; 563 } 564 565 break; 566 567 case S_IFLNK: 568 errstr = gettext(PROB_readlink); 569 #ifdef DBG_ERRORS 570 /* should we simulate a symlink read failure */ 571 if (errno = dbg_chk_error(dst, 'r')) 572 rc = -1; 573 else 574 #endif 575 rc = readlink(src, cmdbuf, sizeof (cmdbuf)); 576 if (rc > 0) { 577 cmdbuf[rc] = 0; 578 if (!opt_quiet) { 579 fprintf(stdout, "ln -s %s", noblanks(cmdbuf)); 580 fprintf(stdout, " %s;\n", noblanks(dst)); 581 } 582 errstr = gettext(PROB_symlink); 583 #ifdef DBG_ERRORS 584 /* should we simulate a symlink failure */ 585 if (errno = dbg_chk_error(dst, 'l')) 586 rc = -1; 587 else 588 #endif 589 rc = opt_notouch ? 0 : symlink(cmdbuf, dst); 590 591 if (rc == 0) 592 dp->f_type = S_IFLNK; 593 } 594 break; 595 596 case S_IFBLK: 597 case S_IFCHR: 598 if (!opt_quiet) 599 fprintf(stdout, "mknod %s %s %d %d\n", noblanks(dst), 600 (type == S_IFBLK) ? "b" : "c", maj, min); 601 602 errstr = gettext(PROB_mknod); 603 #ifdef DBG_ERRORS 604 /* should we simulate a mknod failure */ 605 if (errno = dbg_chk_error(dst, 'd')) 606 rc = -1; 607 else 608 #endif 609 rc = opt_notouch ? 0 610 : mknod(dst, mode|type, makedev(maj, min)); 611 612 /* update stat with what we have just created */ 613 if (rc == 0) { 614 dp->f_type = type; 615 dp->f_uid = my_uid; 616 dp->f_gid = my_gid; 617 dp->f_mode = 0666; 618 619 if (dp->f_mode != mode) 620 do_chmod = 1; 621 } 622 break; 623 624 case S_IFREG: 625 /* 626 * The first thing to do is ascertain whether or not 627 * the alleged new copy might in fact be a new link. 628 * We trust find_link to weigh all the various factors, 629 * so if it says make a link, we'll do it. 630 */ 631 lp = find_link(fp, srcdst); 632 if (lp) { 633 /* figure out name of existing file */ 634 src = full_name(lp, srcdst, OPT_BASE); 635 636 /* 637 * if file already exists, it must be deleted 638 */ 639 if (dp->f_type) { 640 if (!opt_quiet) 641 fprintf(stdout, "rm %s\n", 642 noblanks(dst)); 643 644 errstr = gettext(PROB_unlink); 645 #ifdef DBG_ERRORS 646 /* should we simulate a unlink failure */ 647 if (errno = dbg_chk_error(dst, 'u')) 648 rc = -1; 649 else 650 #endif 651 rc = opt_notouch ? 0 : unlink(dst); 652 653 /* 654 * if we couldn't do the unlink, we must 655 * mark the linkee in conflict as well 656 * so its reference count remains the same 657 * in the baseline and it continues to show 658 * up on the change list. 659 */ 660 if (rc != 0) { 661 lp->f_flags |= F_CONFLICT; 662 lp->f_problem = gettext(PROB_link); 663 goto cant; 664 } 665 } 666 667 if (!opt_quiet) { 668 fprintf(stdout, "ln %s", noblanks(src)); 669 fprintf(stdout, " %s\n", noblanks(dst)); 670 } 671 errstr = gettext(PROB_link); 672 673 #ifdef DBG_ERRORS 674 /* should we simulate a link failure */ 675 if (errno = dbg_chk_error(dst, 'l')) 676 rc = -1; 677 else 678 #endif 679 rc = opt_notouch ? 0 : link(src, dst); 680 681 /* 682 * if this is a link, there is no reason to worry 683 * about ownership and modes, they are automatic 684 */ 685 do_chown = 0; do_chgrp = 0; do_chmod = 0; do_acls = 0; 686 if (rc == 0) { 687 dp->f_type = type; 688 dp->f_uid = uid; 689 dp->f_gid = gid; 690 dp->f_mode = mode; 691 break; 692 } else { 693 /* 694 * if we failed to make a link, we want to 695 * mark the linkee in conflict too, so that 696 * its reference count remains the same in 697 * the baseline, and it shows up on the change 698 * list again next time. 699 */ 700 lp->f_flags |= F_CONFLICT; 701 lp->f_problem = errstr; 702 break; 703 } 704 705 /* 706 * in some situation we haven't figured out yet 707 * we might want to fall through and try a copy 708 * if the link failed. 709 */ 710 } 711 712 /* we are going to resolve this by making a copy */ 713 if (!opt_quiet) { 714 fprintf(stdout, "cp %s", noblanks(src)); 715 fprintf(stdout, " %s\n", noblanks(dst)); 716 } 717 rc = opt_notouch ? 0 : copy(src, dst, mode); 718 if (rc != 0) { 719 errs |= rc; 720 if (copy_err_str) 721 errstr = copy_err_str; 722 else 723 errstr = gettext(PROB_copy); 724 725 /* 726 * The new copy (if it exists at all) is a botch. 727 * If this was a new create or a remove and copy 728 * we should get rid of the botched copy so that 729 * it doesn't show up as two versions next time. 730 */ 731 if (do_create) 732 unlink(dst); 733 } else if (dp->f_mode == 0) { 734 dp->f_type = S_IFREG; 735 dp->f_uid = my_uid; 736 dp->f_gid = my_gid; 737 dp->f_mode = mode; 738 739 /* FIX: inode number is still wrong */ 740 } 741 742 /* for normal files we have an option to preserve mod time */ 743 if (rc == 0 && opt_notouch == 0 && opt_mtime) { 744 newtimes.actime = mtime; 745 newtimes.modtime = mtime; 746 747 /* ignore the error return on this one */ 748 (void) utime(dst, &newtimes); 749 } 750 break; 751 752 default: 753 errstr = gettext(PROB_deal); 754 rc = -1; 755 } 756 757 /* 758 * if any of the file's attributes need attention, I should let 759 * do_like take care of them, since it knows all rules for who 760 * can and cannot make what types of changes. 761 */ 762 if (rc == 0 && (do_chmod || do_chown || do_chgrp || do_acls)) { 763 rc = do_like(fp, srcdst, FALSE); 764 errstr = fp->f_problem; 765 errs |= rc; 766 } 767 768 /* 769 * finish off by re-stating the destination and using that to 770 * update the baseline. If we were completely successful in 771 * our chowns/chmods, stating the destination will confirm it. 772 * If we were unable to make all the necessary changes, stating 773 * the destination will make the source appear to have changed, 774 * so that the differences will continue to reappear as new 775 * changes (inconsistancies). 776 */ 777 if (rc == 0) 778 if (!opt_notouch) { 779 errstr = gettext(PROB_restat); 780 781 #ifdef DBG_ERRORS 782 /* should we simulate a restat failure */ 783 if (errno = dbg_chk_error(dst, 'R')) 784 rc = -1; 785 else 786 #endif 787 rc = lstat(dst, &statb); 788 789 if (rc == 0) { 790 note_info(fp, &statb, srcdst); 791 link_update(fp, srcdst); 792 if (do_acls) 793 (void) get_acls(dst, dp); 794 update_info(fp, srcdst); 795 } 796 } else { 797 /* 798 * BOGOSITY ALERT 799 * we are in notouch mode and haven't really 800 * done anything, but if we want link detection 801 * to work and be properly reflected in the 802 * what-I-would-do output for a case where 803 * multiple links are created to a new file, 804 * we have to make the new file appear to 805 * have been created. Since we didn't create 806 * the new file we can't stat it, but if 807 * no file exists, we can't make a link to 808 * it, so we will pretend we created a file. 809 */ 810 if (dp->f_ino == 0 || dp->f_nlink == 0) { 811 dp->f_ino = sp->f_ino; 812 dp->f_nlink = 1; 813 } 814 } 815 816 cant: if (rc != 0) { 817 fprintf(stderr, gettext(ERR_cannot), errstr, dst); 818 bp->b_unresolved++; 819 fp->f_flags |= F_CONFLICT; 820 fp->f_problem = errstr; 821 if (errs == 0) 822 errs = ERR_PERM; 823 errs |= ERR_UNRESOLVED; 824 } else { 825 /* update the statistics */ 826 if (srcdst == OPT_SRC) 827 bp->b_src_copies++; 828 else 829 bp->b_dst_copies++; 830 errs |= ERR_RESOLVABLE; 831 } 832 833 return (errs); 834 } 835 836 /* 837 * routine: 838 * do_remove 839 * 840 * purpose: 841 * to propagate a deletion 842 * 843 * parameters: 844 * file pointer 845 * src/dst indication for which side gets changed 846 * 847 * returns: 848 * error mask 849 */ 850 errmask_t 851 do_remove(struct file *fp, side_t srcdst) 852 { char *name; 853 int rc; 854 struct base *bp = fp->f_base; 855 errmask_t errs = 0; 856 char *errstr = "???"; 857 858 /* see if this is a forbidden propagation */ 859 if (srcdst == opt_oneway) { 860 fp->f_problem = gettext(PROB_prohibited); 861 fp->f_flags |= F_CONFLICT; 862 bp->b_unresolved++; 863 return (ERR_UNRESOLVED); 864 } 865 866 name = (srcdst == OPT_SRC) ? srcname : dstname; 867 868 if (fp->f_info[0].f_type == S_IFDIR) { 869 if (!opt_quiet) 870 fprintf(stdout, "rmdir %s\n", noblanks(name)); 871 872 errstr = gettext(PROB_rmdir); 873 874 #ifdef DBG_ERRORS 875 /* should we simulate a rmdir failure */ 876 if (errno = dbg_chk_error(name, 'D')) 877 rc = -1; 878 else 879 #endif 880 rc = opt_notouch ? 0 : rmdir(name); 881 } else { 882 if (!opt_quiet) 883 fprintf(stdout, "rm %s\n", noblanks(name)); 884 885 errstr = gettext(PROB_unlink); 886 887 #ifdef DBG_ERRORS 888 /* should we simulate an unlink failure */ 889 if (errno = dbg_chk_error(name, 'u')) 890 rc = -1; 891 else 892 #endif 893 rc = opt_notouch ? 0 : unlink(name); 894 } 895 896 if (opt_debug & DBG_RECON) 897 fprintf(stderr, "RECO: do_remove %s -> %d(%d)\n", 898 name, rc, errno); 899 900 if (rc == 0) { 901 /* tell any other hard links that one has gone away */ 902 fp->f_info[srcdst].f_nlink--; 903 link_update(fp, srcdst); 904 905 fp->f_flags |= F_REMOVE; 906 if (srcdst == OPT_SRC) 907 fp->f_base->b_src_deletes++; 908 else 909 fp->f_base->b_dst_deletes++; 910 errs |= ERR_RESOLVABLE; 911 } else { 912 fprintf(stderr, gettext(ERR_cannot), errstr, name); 913 fp->f_problem = errstr; 914 fp->f_flags |= F_CONFLICT; 915 bp->b_unresolved++; 916 errs |= ERR_PERM | ERR_UNRESOLVED; 917 } 918 919 return (errs); 920 } 921 922 /* 923 * routine: 924 * do_rename 925 * 926 * purpose: 927 * to propagate a rename 928 * 929 * parameters: 930 * file pointer for the new name 931 * src/dst indication for which side gets changed 932 * 933 * returns: 934 * error mask 935 */ 936 errmask_t 937 do_rename(struct file *fp, side_t srcdst) 938 { int rc; 939 struct file *pp = fp->f_previous; 940 struct base *bp = fp->f_base; 941 errmask_t errs = 0; 942 char *errstr = "???"; 943 char *newname; 944 char *oldname; 945 struct stat statb; 946 947 /* see if this is a forbidden propagation */ 948 if (srcdst == opt_oneway) { 949 fp->f_problem = gettext(PROB_prohibited); 950 951 /* if we can't resolve the TO, the FROM is also unresolved */ 952 pp->f_problem = gettext(PROB_prohibited); 953 pp->f_flags |= F_CONFLICT; 954 bp->b_unresolved++; 955 return (ERR_UNRESOLVED); 956 } 957 958 newname = (srcdst == OPT_SRC) ? srcname : dstname; 959 oldname = full_name(pp, srcdst, OPT_BASE); 960 961 if (!opt_quiet) 962 fprintf(stdout, "%s %s %s\n", 963 (fp->f_info[0].f_type == S_IFDIR) ? "mvdir" : "mv", 964 noblanks(oldname), noblanks(newname)); 965 966 #ifdef DBG_ERRORS 967 /* should we simulate a rename failure */ 968 if (errno = dbg_chk_error(oldname, 'm')) 969 rc = -1; 970 else 971 #endif 972 rc = opt_notouch ? 0 : rename(oldname, newname); 973 974 if (opt_debug & DBG_RECON) 975 fprintf(stderr, "RECO: do_rename %s %s -> %d(%d)\n", 976 oldname, newname, rc, errno); 977 978 /* if we succeed, update the baseline */ 979 if (rc == 0) 980 if (!opt_notouch) { 981 errstr = gettext(PROB_restat); 982 983 #ifdef DBG_ERRORS 984 /* should we simulate a restat failure */ 985 if (errno = dbg_chk_error(newname, 'S')) 986 rc = -1; 987 else 988 #endif 989 rc = lstat(newname, &statb); 990 991 if (rc == 0) { 992 note_info(fp, &statb, srcdst); 993 link_update(fp, srcdst); 994 update_info(fp, srcdst); 995 } 996 } else { 997 /* 998 * BOGOSITY ALERT 999 * in order for link tests to work in notouch 1000 * mode we have to dummy up some updated status 1001 */ 1002 fp->f_info[srcdst].f_ino = pp->f_info[srcdst].f_ino; 1003 fp->f_info[srcdst].f_nlink = pp->f_info[srcdst].f_nlink; 1004 fp->f_info[srcdst].f_type = pp->f_info[srcdst].f_type; 1005 fp->f_info[srcdst].f_size = pp->f_info[srcdst].f_size; 1006 fp->f_info[srcdst].f_mode = pp->f_info[srcdst].f_mode; 1007 fp->f_info[srcdst].f_uid = pp->f_info[srcdst].f_uid; 1008 fp->f_info[srcdst].f_gid = pp->f_info[srcdst].f_gid; 1009 update_info(fp, srcdst); 1010 } 1011 else 1012 errstr = gettext(PROB_rename2); 1013 1014 if (rc == 0) { 1015 pp->f_flags |= F_REMOVE; 1016 1017 if (srcdst == OPT_SRC) { 1018 bp->b_src_copies++; 1019 bp->b_src_deletes++; 1020 } else { 1021 bp->b_dst_copies++; 1022 bp->b_dst_deletes++; 1023 } 1024 errs |= ERR_RESOLVABLE; 1025 } else { 1026 fprintf(stderr, gettext(ERR_cannot), errstr, oldname); 1027 1028 bp->b_unresolved++; 1029 fp->f_flags |= F_CONFLICT; 1030 pp->f_flags |= F_CONFLICT; 1031 1032 fp->f_problem = errstr; 1033 pp->f_problem = gettext(PROB_rename); 1034 1035 errs |= ERR_PERM | ERR_UNRESOLVED; 1036 } 1037 1038 return (errs); 1039 } 1040 1041 /* 1042 * routine: 1043 * copy 1044 * 1045 * purpose: 1046 * to copy one file to another 1047 * 1048 * parameters: 1049 * source file name 1050 * destination file name 1051 * desired modes 1052 * 1053 * returns: 1054 * 0 OK 1055 * else error mask, and a setting of copy_err_str 1056 * 1057 * notes: 1058 * We try to preserve the holes in sparse files, by skipping over 1059 * any holes that are at least MIN_HOLE bytes long. There are 1060 * pathological cases where the hole detection test could become 1061 * expensive, but for most blocks of most files we will fall out 1062 * of the zero confirming loop in the first couple of bytes. 1063 */ 1064 static errmask_t 1065 copy(char *src, char *dst, int mode) 1066 { int ifd, ofd, count, ret; 1067 long *p, *e; 1068 long long length; /* total size of file */ 1069 errmask_t errs = 0; 1070 int bsize; /* block-size for file */ 1071 bool_t sparse; /* file may be sparse */ 1072 bool_t was_hole = FALSE; /* file ends with hole */ 1073 long inbuf[ COPY_BSIZE/4 ]; /* long to speed checks */ 1074 struct stat statbuf; /* info on source file */ 1075 struct statvfs statvsbuf; /* info on target fs */ 1076 1077 copy_err_str = 0; 1078 1079 /* open the input file */ 1080 #ifdef DBG_ERRORS 1081 if (opt_errors && dbg_chk_error(src, 'o')) 1082 ifd = -1; 1083 else 1084 #endif 1085 ifd = open(src, O_RDONLY); 1086 1087 if (ifd < 0) { 1088 copy_err_str = gettext(PROB_copyin); 1089 return (ERR_PERM); 1090 } 1091 1092 /* 1093 * if we suspect a file may be sparse, we must process it 1094 * a little more carefully, looking for holes and skipping 1095 * over them in the output. If a file is not sparse, we 1096 * can move through it at greater speed. 1097 */ 1098 bsize = checksparse(ifd); 1099 if (bsize > 0 && bsize <= COPY_BSIZE) 1100 sparse = TRUE; 1101 else { 1102 sparse = FALSE; 1103 bsize = COPY_BSIZE; 1104 } 1105 1106 /* 1107 * if the target file already exists and we overwrite it without 1108 * first ascertaining that there is enough room, we could wind 1109 * up actually losing data. Try to determine how much space is 1110 * available on the target file system, and if that is not enough 1111 * for the source file, fail without even trying. If, however, 1112 * the target file does not already exist, we have nothing to 1113 * lose by just doing the copy without checking the space. 1114 */ 1115 ret = statvfs(dst, &statvsbuf); 1116 if (ret == 0 && statvsbuf.f_frsize != 0) { 1117 #ifdef DBG_ERRORS 1118 /* should we simulate an out-of-space situation */ 1119 if ((length = dbg_chk_error(dst, 'Z')) == 0) 1120 #endif 1121 length = statvsbuf.f_bavail * statvsbuf.f_frsize; 1122 1123 ret = fstat(ifd, &statbuf); 1124 if (ret == 0) { 1125 length /= 512; /* st_blocks in 512s */ 1126 if (length < statbuf.st_blocks) { 1127 copy_err_str = gettext(PROB_space); 1128 close(ifd); 1129 return (ERR_FILES); 1130 } 1131 } else { 1132 copy_err_str = gettext(PROB_restat); 1133 close(ifd); 1134 return (ERR_FILES); 1135 } 1136 } 1137 1138 /* create the output file */ 1139 #ifdef DBG_ERRORS 1140 if (opt_errors && dbg_chk_error(dst, 'c')) 1141 ofd = -1; 1142 else 1143 #endif 1144 ofd = creat(dst, mode); 1145 1146 if (ofd < 0) { 1147 close(ifd); 1148 copy_err_str = gettext(PROB_copyout); 1149 return (ERR_PERM); 1150 } 1151 1152 /* copy the data from the input file to the output file */ 1153 for (;;) { 1154 #ifdef DBG_ERRORS 1155 if (opt_errors && dbg_chk_error(dst, 'r')) 1156 count = -1; 1157 else 1158 #endif 1159 count = read(ifd, (char *) inbuf, bsize); 1160 if (count <= 0) 1161 break; 1162 1163 /* 1164 * if the file might be sparse and we got an entire block, 1165 * we should see if the block is all zeros 1166 */ 1167 if (sparse && count == bsize) { 1168 p = inbuf; e = &inbuf[count/4]; 1169 while (p < e && *p == 0) 1170 p++; 1171 if (p == e) { 1172 (void) lseek(ofd, (off_t) count, SEEK_CUR); 1173 was_hole = TRUE; 1174 continue; 1175 } 1176 } 1177 was_hole = FALSE; 1178 1179 #ifdef DBG_ERRORS 1180 if (opt_errors && dbg_chk_error(dst, 'w')) 1181 ret = -1; 1182 else 1183 #endif 1184 ret = write(ofd, (char *) inbuf, count); 1185 1186 if (ret != count) { 1187 errs = ERR_FILES; 1188 copy_err_str = gettext(PROB_write); 1189 break; 1190 } 1191 } 1192 1193 if (count < 0) { 1194 copy_err_str = gettext(PROB_read); 1195 errs = ERR_FILES; 1196 } else if (was_hole) { 1197 /* 1198 * if we skipped the last write because of a hole, we 1199 * need to make sure that we write a single byte of null 1200 * at the end of the file to update the file length. 1201 */ 1202 (void) lseek(ofd, (off_t)-1, SEEK_CUR); 1203 (void) write(ofd, "", 1); 1204 } 1205 1206 /* 1207 * if the output file was botched, free up its space 1208 */ 1209 if (errs) 1210 ftruncate(ofd, (off_t) 0); 1211 1212 close(ifd); 1213 close(ofd); 1214 return (errs); 1215 } 1216 1217 /* 1218 * routine: 1219 * checksparse 1220 * 1221 * purpose: 1222 * to determine whether or not a file might be sparse, and if 1223 * it is sparse, what the granularity of the holes is likely 1224 * to be. 1225 * 1226 * parameters: 1227 * file descriptor for file in question 1228 * 1229 * returns: 1230 * 0 file does not appear to be sparse 1231 * else block size for this file 1232 */ 1233 static int 1234 checksparse(int fd) 1235 { 1236 struct stat statb; 1237 1238 /* 1239 * unable to stat the file is very strange (since we got it 1240 * open) but it probably isn't worth causing a fuss over. 1241 * Return the conservative answer 1242 */ 1243 if (fstat(fd, &statb) < 0) 1244 return (MIN_HOLE); 1245 1246 /* 1247 * if the file doesn't have enough blocks to account for 1248 * all of its bytes, there is a reasonable chance that it 1249 * is sparse. This test is not perfect, in that it will 1250 * fail to find holes in cases where the holes aren't 1251 * numerous enough to componsent for the indirect blocks 1252 * ... but losing those few holes is not going to be a 1253 * big deal. 1254 */ 1255 if (statb.st_size > 512 * statb.st_blocks) 1256 return (statb.st_blksize); 1257 else 1258 return (0); 1259 }