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