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 }