1 /*- 2 * CPDUP.C 3 * 4 * CPDUP <options> source destination 5 * 6 * (c) Copyright 1997-1999 by Matthew Dillon and Dima Ruban. Permission to 7 * use and distribute based on the FreeBSD copyright. Supplied as-is, 8 * USE WITH EXTREME CAUTION. 9 * 10 * This program attempts to duplicate the source onto the destination as 11 * exactly as possible, retaining modify times, flags, perms, uid, and gid. 12 * It can duplicate devices, files (including hardlinks), softlinks, 13 * directories, and so forth. It is recursive by default! The duplication 14 * is inclusive of removal of files/directories on the destination that do 15 * not exist on the source. This program supports a per-directory exception 16 * file called .cpignore, or a user-specified exception file. 17 * 18 * Safety features: 19 * 20 * - does not cross partition boundries on source 21 * - asks for confirmation on deletions unless -i0 is specified 22 * - refuses to replace a destination directory with a source file 23 * unless -s0 is specified. 24 * - terminates on error 25 * 26 * Copying features: 27 * 28 * - does not copy file if mtime, flags, perms, and size match unless 29 * forced 30 * 31 * - copies to temporary and renames-over the original, allowing 32 * you to update live systems 33 * 34 * - copies uid, gid, mtime, perms, flags, softlinks, devices, hardlinks, 35 * and recurses through directories. 36 * 37 * - accesses a per-directory exclusion file, .cpignore, containing 38 * standard wildcarded ( ? / * style, NOT regex) exclusions. 39 * 40 * - tries to play permissions and flags smart in regards to overwriting 41 * schg files and doing related stuff. 42 * 43 * - Can do MD5 consistancy checks 44 * 45 * - Is able to do incremental mirroring/backups via hardlinks from 46 * the 'previous' version (supplied with -H path). 47 * 48 * $DragonFly: src/bin/cpdup/cpdup.c,v 1.32 2008/11/11 04:36:00 dillon Exp $ 49 */ 50 51 /*- 52 * Example: cc -O cpdup.c -o cpdup -lcrypto 53 * 54 * ".MD5.CHECKSUMS" contains md5 checksumms for the current directory. 55 * This file is stored on the source. 56 */ 57 58 #include "cpdup.h" 59 #include "hclink.h" 60 #include "hcproto.h" 61 62 #define HSIZE 8192 63 #define HMASK (HSIZE-1) 64 #define HLSIZE 8192 65 #define HLMASK (HLSIZE - 1) 66 67 #define GETBUFSIZE 8192 68 #define GETPATHSIZE 2048 69 #define GETLINKSIZE 1024 70 #define GETIOSIZE 65536 71 72 #ifndef _ST_FLAGS_PRESENT_ 73 #define st_flags st_mode 74 #endif 75 76 typedef struct Node { 77 struct Node *no_Next; 78 struct Node *no_HNext; 79 struct stat *no_Stat; 80 int no_Value; 81 char no_Name[4]; 82 } Node; 83 84 typedef struct List { 85 Node li_Node; 86 Node *li_Hash[HSIZE]; 87 } List; 88 89 struct hlink { 90 ino_t ino; 91 ino_t dino; 92 int refs; 93 struct hlink *next; 94 struct hlink *prev; 95 nlink_t nlinked; 96 char name[]; 97 }; 98 99 typedef struct copy_info { 100 char *spath; 101 char *dpath; 102 dev_t sdevNo; 103 dev_t ddevNo; 104 } *copy_info_t; 105 106 static struct hlink *hltable[HLSIZE]; 107 108 static void RemoveRecur(const char *dpath, dev_t devNo, struct stat *dstat); 109 static void InitList(List *list); 110 static void ResetList(List *list); 111 static Node *IterateList(List *list, Node *node, int n); 112 static int AddList(List *list, const char *name, int n, struct stat *st); 113 static int CheckList(List *list, const char *path, const char *name); 114 static int getbool(const char *str); 115 static char *SplitRemote(char **pathp); 116 static int ChgrpAllowed(gid_t g); 117 static int OwnerMatch(struct stat *st1, struct stat *st2); 118 #ifdef _ST_FLAGS_PRESENT_ 119 static int FlagsMatch(struct stat *st1, struct stat *st2); 120 #else 121 #define FlagsMatch(st1, st2) 1 122 #endif 123 static struct hlink *hltlookup(struct stat *); 124 static struct hlink *hltadd(struct stat *, const char *); 125 static char *checkHLPath(struct stat *st, const char *spath, const char *dpath); 126 static int validate_check(const char *spath, const char *dpath); 127 static int shash(const char *s); 128 static void hltdelete(struct hlink *); 129 static void hltsetdino(struct hlink *, ino_t); 130 static int YesNo(const char *path); 131 static int xrename(const char *src, const char *dst, u_long flags); 132 static int xlink(const char *src, const char *dst, u_long flags); 133 static int xremove(struct HostConf *host, const char *path); 134 static int xrmdir(struct HostConf *host, const char *path); 135 static int DoCopy(copy_info_t info, struct stat *stat1, int depth); 136 static int ScanDir(List *list, struct HostConf *host, const char *path, 137 int64_t *CountReadBytes, int n); 138 static int mtimecmp(struct stat *st1, struct stat *st2); 139 static int symlink_mfo_test(struct HostConf *hc, struct stat *st1, 140 struct stat *st2); 141 142 int AskConfirmation = 1; 143 int SafetyOpt = 1; 144 int ForceOpt; 145 int DeviceOpt = 1; 146 int VerboseOpt; 147 int DirShowOpt; 148 int NotForRealOpt; 149 int QuietOpt; 150 int NoRemoveOpt; 151 int UseMD5Opt; 152 int UseFSMIDOpt; 153 int SummaryOpt; 154 int CompressOpt; 155 int SlaveOpt; 156 int ReadOnlyOpt; 157 int ValidateOpt; 158 int ssh_argc; 159 const char *ssh_argv[16]; 160 int DstRootPrivs; 161 162 const char *UseCpFile; 163 const char *MD5CacheFile; 164 const char *FSMIDCacheFile; 165 const char *UseHLPath; 166 167 static int DstBaseLen; 168 static int HardLinkCount; 169 static int GroupCount; 170 static gid_t *GroupList; 171 172 int64_t CountSourceBytes; 173 int64_t CountSourceItems; 174 int64_t CountCopiedItems; 175 int64_t CountSourceReadBytes; 176 int64_t CountTargetReadBytes; 177 int64_t CountWriteBytes; 178 int64_t CountRemovedItems; 179 int64_t CountLinkedItems; 180 181 static struct HostConf SrcHost; 182 static struct HostConf DstHost; 183 184 int 185 main(int ac, char **av) 186 { 187 int i; 188 int opt; 189 char *src = NULL; 190 char *dst = NULL; 191 char *ptr; 192 struct timeval start; 193 struct copy_info info; 194 195 signal(SIGPIPE, SIG_IGN); 196 197 gettimeofday(&start, NULL); 198 opterr = 0; 199 while ((opt = getopt(ac, av, ":CdF:fH:hIi:j:K:klM:mnoqRSs:uVvX:x")) != -1) { 200 switch (opt) { 201 case 'C': 202 CompressOpt = 1; 203 break; 204 case 'd': 205 DirShowOpt = 1; 206 break; 207 case 'F': 208 if (ssh_argc >= 16) 209 fatal("too many -F options"); 210 ssh_argv[ssh_argc++] = optarg; 211 break; 212 case 'f': 213 ForceOpt = 1; 214 break; 215 case 'H': 216 UseHLPath = optarg; 217 break; 218 case 'h': 219 fatal(NULL); 220 /* not reached */ 221 break; 222 case 'I': 223 SummaryOpt = 1; 224 break; 225 case 'i': 226 AskConfirmation = getbool(optarg); 227 break; 228 case 'j': 229 DeviceOpt = getbool(optarg); 230 break; 231 case 'K': 232 UseFSMIDOpt = 1; 233 FSMIDCacheFile = optarg; 234 break; 235 case 'k': 236 UseFSMIDOpt = 1; 237 FSMIDCacheFile = ".FSMID.CHECK"; 238 break; 239 case 'l': 240 setlinebuf(stdout); 241 setlinebuf(stderr); 242 break; 243 case 'M': 244 UseMD5Opt = 1; 245 MD5CacheFile = optarg; 246 break; 247 case 'm': 248 UseMD5Opt = 1; 249 MD5CacheFile = ".MD5.CHECKSUMS"; 250 break; 251 case 'n': 252 NotForRealOpt = 1; 253 break; 254 case 'o': 255 NoRemoveOpt = 1; 256 break; 257 case 'q': 258 QuietOpt = 1; 259 break; 260 case 'R': 261 ReadOnlyOpt = 1; 262 break; 263 case 'S': 264 SlaveOpt = 1; 265 break; 266 case 's': 267 SafetyOpt = getbool(optarg); 268 break; 269 case 'u': 270 setvbuf(stdout, NULL, _IOLBF, 0); 271 break; 272 case 'V': 273 ++ValidateOpt; 274 break; 275 case 'v': 276 ++VerboseOpt; 277 break; 278 case 'X': 279 UseCpFile = optarg; 280 break; 281 case 'x': 282 UseCpFile = ".cpignore"; 283 break; 284 case ':': 285 fatal("missing argument for option: -%c\n", optopt); 286 /* not reached */ 287 break; 288 case '?': 289 fatal("illegal option: -%c\n", optopt); 290 /* not reached */ 291 break; 292 default: 293 fatal(NULL); 294 /* not reached */ 295 break; 296 } 297 } 298 ac -= optind; 299 av += optind; 300 if (ac > 0) 301 src = av[0]; 302 if (ac > 1) 303 dst = av[1]; 304 if (ac > 2) 305 fatal("too many arguments"); 306 307 /* 308 * If we are told to go into slave mode, run the HC protocol 309 */ 310 if (SlaveOpt) { 311 DstRootPrivs = (geteuid() == 0); 312 hc_slave(0, 1); 313 exit(0); 314 } 315 316 /* 317 * Extract the source and/or/neither target [user@]host and 318 * make any required connections. 319 */ 320 if (src && (ptr = SplitRemote(&src)) != NULL) { 321 SrcHost.host = src; 322 src = ptr; 323 if (UseMD5Opt) 324 fatal("The MD5 options are not currently supported for remote sources"); 325 if (hc_connect(&SrcHost, ReadOnlyOpt) < 0) 326 exit(1); 327 } else { 328 SrcHost.version = HCPROTO_VERSION; 329 if (ReadOnlyOpt) 330 fatal("The -R option is only supported for remote sources"); 331 } 332 333 if (dst && (ptr = SplitRemote(&dst)) != NULL) { 334 DstHost.host = dst; 335 dst = ptr; 336 if (UseFSMIDOpt) 337 fatal("The FSMID options are not currently supported for remote targets"); 338 if (hc_connect(&DstHost, 0) < 0) 339 exit(1); 340 } else { 341 DstHost.version = HCPROTO_VERSION; 342 } 343 344 /* 345 * dst may be NULL only if -m option is specified, 346 * which forces an update of the MD5 checksums 347 */ 348 if (dst == NULL && UseMD5Opt == 0) { 349 fatal(NULL); 350 /* not reached */ 351 } 352 353 if (dst) { 354 DstRootPrivs = (hc_geteuid(&DstHost) == 0); 355 if (!DstRootPrivs) 356 GroupCount = hc_getgroups(&DstHost, &GroupList); 357 } 358 #if 0 359 /* XXXX DEBUG */ 360 fprintf(stderr, "DstRootPrivs == %s\n", DstRootPrivs ? "true" : "false"); 361 fprintf(stderr, "GroupCount == %d\n", GroupCount); 362 for (i = 0; i < GroupCount; i++) 363 fprintf(stderr, "Group[%d] == %d\n", i, GroupList[i]); 364 #endif 365 366 bzero(&info, sizeof(info)); 367 if (dst) { 368 DstBaseLen = strlen(dst); 369 info.spath = src; 370 info.dpath = dst; 371 info.sdevNo = (dev_t)-1; 372 info.ddevNo = (dev_t)-1; 373 i = DoCopy(&info, NULL, -1); 374 } else { 375 info.spath = src; 376 info.dpath = NULL; 377 info.sdevNo = (dev_t)-1; 378 info.ddevNo = (dev_t)-1; 379 i = DoCopy(&info, NULL, -1); 380 } 381 #ifndef NOMD5 382 md5_flush(); 383 #endif 384 fsmid_flush(); 385 386 if (SummaryOpt && i == 0) { 387 double duration; 388 struct timeval end; 389 390 gettimeofday(&end, NULL); 391 #if 0 392 /* don't count stat's in our byte statistics */ 393 CountSourceBytes += sizeof(struct stat) * CountSourceItems; 394 CountSourceReadBytes += sizeof(struct stat) * CountSourceItems; 395 CountWriteBytes += sizeof(struct stat) * CountCopiedItems; 396 CountWriteBytes += sizeof(struct stat) * CountRemovedItems; 397 #endif 398 399 duration = (end.tv_sec - start.tv_sec); 400 duration += (double)(end.tv_usec - start.tv_usec) / 1000000.0; 401 if (duration == 0.0) 402 duration = 1.0; 403 logstd("cpdup completed successfully\n"); 404 logstd("%lld bytes source, %lld src bytes read, %lld tgt bytes read\n" 405 "%lld bytes written (%.1fX speedup)\n", 406 (long long)CountSourceBytes, 407 (long long)CountSourceReadBytes, 408 (long long)CountTargetReadBytes, 409 (long long)CountWriteBytes, 410 ((double)CountSourceBytes * 2.0) / ((double)(CountSourceReadBytes + CountTargetReadBytes + CountWriteBytes))); 411 logstd("%lld source items, %lld items copied, %lld items linked, " 412 "%lld things deleted\n", 413 (long long)CountSourceItems, 414 (long long)CountCopiedItems, 415 (long long)CountLinkedItems, 416 (long long)CountRemovedItems); 417 logstd("%.1f seconds %5d Kbytes/sec synced %5d Kbytes/sec scanned\n", 418 duration, 419 (int)((CountSourceReadBytes + CountTargetReadBytes + CountWriteBytes) / duration / 1024.0), 420 (int)(CountSourceBytes / duration / 1024.0)); 421 } 422 exit((i == 0) ? 0 : 1); 423 } 424 425 static int 426 getbool(const char *str) 427 { 428 if (strcmp(str, "0") == 0) 429 return (0); 430 if (strcmp(str, "1") == 0) 431 return (1); 432 fatal("option requires boolean argument (0 or 1): -%c\n", optopt); 433 /* not reached */ 434 return (0); 435 } 436 437 /* 438 * Check if path specifies a remote path, using the same syntax as scp(1), 439 * i.e. a path is considered remote if the first colon is not preceded by 440 * a slash, so e.g. "./foo:bar" is considered local. 441 * If a remote path is detected, the colon is replaced with a null byte, 442 * and the return value is a pointer to the next character. 443 * Otherwise NULL is returned. 444 * 445 * A path prefix of localhost is the same as a locally specified file or 446 * directory path, but prevents any further interpretation of the path 447 * as being a remote hostname (for paths that have colons in them). 448 */ 449 static char * 450 SplitRemote(char **pathp) 451 { 452 int cindex; 453 char *path = *pathp; 454 455 if (path[(cindex = strcspn(path, ":/"))] == ':') { 456 path[cindex++] = 0; 457 if (strcmp(path, "localhost") != 0) 458 return (path + cindex); 459 *pathp = path + cindex; 460 } 461 return (NULL); 462 } 463 464 /* 465 * Check if group g is in our GroupList. 466 * 467 * Typically the number of groups a user belongs to isn't large 468 * enough to warrant more effort than a simple linear search. 469 * However, we perform an optimization by moving a group to the 470 * top of the list when we have a hit. This assumes that there 471 * isn't much variance in the gids of files that a non-root user 472 * copies. So most of the time the search will terminate on the 473 * first element of the list. 474 */ 475 static int 476 ChgrpAllowed(gid_t g) 477 { 478 int i; 479 480 for (i = 0; i < GroupCount; i++) 481 if (GroupList[i] == g) { 482 if (i > 0) { 483 /* Optimize: Move g to the front of the list. */ 484 for (; i > 0; i--) 485 GroupList[i] = GroupList[i - 1]; 486 GroupList[0] = g; 487 } 488 return (1); 489 } 490 return (0); 491 } 492 493 /* 494 * The following two functions return true if the ownership (UID + GID) 495 * or the flags of two files match, respectively. 496 * 497 * Only perform weak checking if we don't have sufficient privileges on 498 * the target machine, so we don't waste transfers with things that are 499 * bound to fail anyway. 500 */ 501 static int 502 OwnerMatch(struct stat *st1, struct stat *st2) 503 { 504 if (DstRootPrivs) 505 /* Both UID and GID must match. */ 506 return (st1->st_uid == st2->st_uid && st1->st_gid == st2->st_gid); 507 else 508 /* Ignore UID, and also ignore GID if we can't chgrp to that group. */ 509 return (st1->st_gid == st2->st_gid || !ChgrpAllowed(st1->st_gid)); 510 } 511 512 #ifdef _ST_FLAGS_PRESENT_ 513 static int 514 FlagsMatch(struct stat *st1, struct stat *st2) 515 { 516 /* 517 * Ignore UF_ARCHIVE. It gets set automatically by the filesystem, for 518 * filesystems that support it. If the destination filesystem supports it, but 519 * it's cleared on the source file, then multiple invocations of cpdup would 520 * all try to copy the file because the flags wouldn't match. 521 * 522 * When unpriveleged, ignore flags we can't set 523 */ 524 u_long ignored = DstRootPrivs ? 0 : SF_SETTABLE; 525 526 #ifdef UF_ARCHIVE 527 ignored |= UF_ARCHIVE; 528 #endif 529 return (((st1->st_flags ^ st2->st_flags) & ~ignored) == 0); 530 } 531 #endif 532 533 534 static struct hlink * 535 hltlookup(struct stat *stp) 536 { 537 struct hlink *hl; 538 int n; 539 540 n = stp->st_ino & HLMASK; 541 542 for (hl = hltable[n]; hl; hl = hl->next) { 543 if (hl->ino == stp->st_ino) { 544 ++hl->refs; 545 return hl; 546 } 547 } 548 549 return NULL; 550 } 551 552 static struct hlink * 553 hltadd(struct stat *stp, const char *path) 554 { 555 struct hlink *new; 556 int plen = strlen(path); 557 int n; 558 559 new = malloc(offsetof(struct hlink, name[plen + 1])); 560 if (new == NULL) 561 fatal("out of memory"); 562 ++HardLinkCount; 563 564 /* initialize and link the new element into the table */ 565 new->ino = stp->st_ino; 566 new->dino = (ino_t)-1; 567 new->refs = 1; 568 bcopy(path, new->name, plen + 1); 569 new->nlinked = 1; 570 new->prev = NULL; 571 n = stp->st_ino & HLMASK; 572 new->next = hltable[n]; 573 if (hltable[n]) 574 hltable[n]->prev = new; 575 hltable[n] = new; 576 577 return new; 578 } 579 580 static void 581 hltsetdino(struct hlink *hl, ino_t inum) 582 { 583 hl->dino = inum; 584 } 585 586 static void 587 hltdelete(struct hlink *hl) 588 { 589 assert(hl->refs == 1); 590 --hl->refs; 591 if (hl->prev) { 592 if (hl->next) 593 hl->next->prev = hl->prev; 594 hl->prev->next = hl->next; 595 } else { 596 if (hl->next) 597 hl->next->prev = NULL; 598 599 hltable[hl->ino & HLMASK] = hl->next; 600 } 601 --HardLinkCount; 602 free(hl); 603 } 604 605 static void 606 hltrels(struct hlink *hl) 607 { 608 assert(hl->refs == 1); 609 --hl->refs; 610 } 611 612 /* 613 * If UseHLPath is defined check to see if the file in question is 614 * the same as the source file, and if it is return a pointer to the 615 * -H path based file for hardlinking. Else return NULL. 616 */ 617 static char * 618 checkHLPath(struct stat *st1, const char *spath, const char *dpath) 619 { 620 struct stat sthl; 621 char *hpath; 622 int error; 623 624 if (asprintf(&hpath, "%s%s", UseHLPath, dpath + DstBaseLen) < 0) 625 fatal("out of memory"); 626 627 /* 628 * stat info matches ? 629 */ 630 if (hc_stat(&DstHost, hpath, &sthl) < 0 || 631 st1->st_size != sthl.st_size || 632 mtimecmp(st1, &sthl) != 0 || 633 !OwnerMatch(st1, &sthl) || 634 !FlagsMatch(st1, &sthl) 635 ) { 636 free(hpath); 637 return(NULL); 638 } 639 640 /* 641 * If ForceOpt or ValidateOpt is set we have to compare the files 642 */ 643 if (ForceOpt || ValidateOpt) { 644 error = validate_check(spath, hpath); 645 if (error) { 646 free(hpath); 647 hpath = NULL; 648 } 649 } 650 return(hpath); 651 } 652 653 /* 654 * Return 0 if the contents of the file <spath> matches the contents of 655 * the file <dpath>. 656 */ 657 static int 658 validate_check(const char *spath, const char *dpath) 659 { 660 int error; 661 int fd1; 662 int fd2; 663 664 fd1 = hc_open(&SrcHost, spath, O_RDONLY, 0); 665 fd2 = hc_open(&DstHost, dpath, O_RDONLY, 0); 666 error = -1; 667 668 if (fd1 >= 0 && fd2 >= 0) { 669 int n; 670 int x; 671 char *iobuf1 = malloc(GETIOSIZE); 672 char *iobuf2 = malloc(GETIOSIZE); 673 674 while ((n = hc_read(&SrcHost, fd1, iobuf1, GETIOSIZE)) > 0) { 675 CountSourceReadBytes += n; 676 x = hc_read(&DstHost, fd2, iobuf2, GETIOSIZE); 677 if (x > 0) 678 CountTargetReadBytes += x; 679 if (x != n) 680 break; 681 if (bcmp(iobuf1, iobuf2, n) != 0) 682 break; 683 } 684 free(iobuf1); 685 free(iobuf2); 686 if (n == 0) 687 error = 0; 688 } 689 if (fd1 >= 0) 690 hc_close(&SrcHost, fd1); 691 if (fd2 >= 0) 692 hc_close(&DstHost, fd2); 693 return (error); 694 } 695 696 int 697 DoCopy(copy_info_t info, struct stat *stat1, int depth) 698 { 699 const char *spath = info->spath; 700 const char *dpath = info->dpath; 701 dev_t sdevNo = info->sdevNo; 702 dev_t ddevNo = info->ddevNo; 703 struct stat st1; 704 struct stat st2; 705 unsigned long st2_flags; 706 int r, mres, fres, st2Valid; 707 struct hlink *hln; 708 uint64_t size; 709 710 r = mres = fres = st2Valid = 0; 711 st2_flags = 0; 712 size = 0; 713 hln = NULL; 714 715 if (stat1 == NULL) { 716 if (hc_lstat(&SrcHost, spath, &st1) != 0) { 717 r = 1; 718 goto done; 719 } 720 stat1 = &st1; 721 } 722 #ifdef SF_SNAPSHOT 723 /* skip snapshot files because they're sparse and _huge_ */ 724 if (stat1->st_flags & SF_SNAPSHOT) 725 return(0); 726 #endif 727 st2.st_mode = 0; /* in case lstat fails */ 728 st2.st_flags = 0; /* in case lstat fails */ 729 if (dpath && hc_lstat(&DstHost, dpath, &st2) == 0) { 730 st2Valid = 1; 731 #ifdef _ST_FLAGS_PRESENT_ 732 st2_flags = st2.st_flags; 733 #endif 734 } 735 736 if (S_ISREG(stat1->st_mode)) 737 size = stat1->st_size; 738 739 /* 740 * Handle hardlinks 741 */ 742 743 if (S_ISREG(stat1->st_mode) && stat1->st_nlink > 1 && dpath) { 744 if ((hln = hltlookup(stat1)) != NULL) { 745 hln->nlinked++; 746 747 if (st2Valid) { 748 if (st2.st_ino == hln->dino) { 749 /* 750 * hard link is already correct, nothing to do 751 */ 752 if (VerboseOpt >= 3) 753 logstd("%-32s nochange\n", (dpath) ? dpath : spath); 754 if (hln->nlinked == stat1->st_nlink) { 755 hltdelete(hln); 756 hln = NULL; 757 } 758 CountSourceItems++; 759 r = 0; 760 goto done; 761 } else { 762 /* 763 * hard link is not correct, attempt to unlink it 764 */ 765 if (xremove(&DstHost, dpath) < 0) { 766 logerr("%-32s hardlink: unable to unlink: %s\n", 767 ((dpath) ? dpath : spath), strerror(errno)); 768 hltdelete(hln); 769 hln = NULL; 770 ++r; 771 goto done; 772 } 773 } 774 } 775 776 if (xlink(hln->name, dpath, stat1->st_flags) < 0) { 777 int tryrelink = (errno == EMLINK); 778 logerr("%-32s hardlink: unable to link to %s: %s\n", 779 (dpath ? dpath : spath), hln->name, strerror(errno) 780 ); 781 hltdelete(hln); 782 hln = NULL; 783 if (tryrelink) { 784 logerr("%-20s hardlink: will attempt to copy normally\n", 785 (dpath ? dpath : spath)); 786 goto relink; 787 } 788 ++r; 789 } else { 790 if (hln->nlinked == stat1->st_nlink) { 791 hltdelete(hln); 792 hln = NULL; 793 } 794 if (r == 0) { 795 if (VerboseOpt) { 796 logstd("%-32s hardlink: %s\n", 797 (dpath ? dpath : spath), 798 (st2Valid ? "relinked" : "linked") 799 ); 800 } 801 CountSourceItems++; 802 CountCopiedItems++; 803 r = 0; 804 goto done; 805 } 806 } 807 } else { 808 /* 809 * first instance of hardlink must be copied normally 810 */ 811 relink: 812 hln = hltadd(stat1, dpath); 813 } 814 } 815 816 /* 817 * Do we need to copy the file/dir/link/whatever? Early termination 818 * if we do not. Always redo links. Directories are always traversed 819 * except when the FSMID options are used. 820 * 821 * NOTE: st2Valid is true only if dpath != NULL *and* dpath stats good. 822 */ 823 824 if ( 825 st2Valid 826 && stat1->st_mode == st2.st_mode 827 && FlagsMatch(stat1, &st2) 828 ) { 829 if (S_ISLNK(stat1->st_mode) || S_ISDIR(stat1->st_mode)) { 830 /* 831 * If FSMID tracking is turned on we can avoid recursing through 832 * an entire directory subtree if the FSMID matches. 833 */ 834 #ifdef _ST_FSMID_PRESENT_ 835 if (ForceOpt == 0 && 836 (UseFSMIDOpt && (fres = fsmid_check(stat1->st_fsmid, dpath)) == 0) 837 ) { 838 if (VerboseOpt >= 3) { 839 if (UseFSMIDOpt) /* always true!?! */ 840 logstd("%-32s fsmid-nochange\n", (dpath ? dpath : spath)); 841 else 842 logstd("%-32s nochange\n", (dpath ? dpath : spath)); 843 } 844 r = 0; 845 goto done; 846 } 847 #endif 848 } else { 849 if (ForceOpt == 0 && 850 stat1->st_size == st2.st_size && 851 (ValidateOpt == 2 || mtimecmp(stat1, &st2) == 0) && 852 OwnerMatch(stat1, &st2) 853 #ifndef NOMD5 854 && (UseMD5Opt == 0 || !S_ISREG(stat1->st_mode) || 855 (mres = md5_check(spath, dpath)) == 0) 856 #endif 857 #ifdef _ST_FSMID_PRESENT_ 858 && (UseFSMIDOpt == 0 || 859 (fres = fsmid_check(stat1->st_fsmid, dpath)) == 0) 860 #endif 861 && (ValidateOpt == 0 || !S_ISREG(stat1->st_mode) || 862 validate_check(spath, dpath) == 0) 863 ) { 864 /* 865 * The files are identical, but if we are running as 866 * root we might need to adjust ownership/group/flags. 867 */ 868 int changedown = 0; 869 int changedflags = 0; 870 871 if (hln) 872 hltsetdino(hln, st2.st_ino); 873 874 if (!OwnerMatch(stat1, &st2)) { 875 hc_chown(&DstHost, dpath, stat1->st_uid, stat1->st_gid); 876 changedown = 1; 877 } 878 #ifdef _ST_FLAGS_PRESENT_ 879 if (!FlagsMatch(stat1, &st2)) { 880 hc_chflags(&DstHost, dpath, stat1->st_flags); 881 changedflags = 1; 882 } 883 #endif 884 if (VerboseOpt >= 3) { 885 #ifndef NOMD5 886 if (UseMD5Opt) { 887 logstd("%-32s md5-nochange", 888 (dpath ? dpath : spath)); 889 } else 890 #endif 891 if (UseFSMIDOpt) { 892 logstd("%-32s fsmid-nochange", 893 (dpath ? dpath : spath)); 894 } else if (ValidateOpt) { 895 logstd("%-32s nochange (contents validated)", 896 (dpath ? dpath : spath)); 897 } else { 898 logstd("%-32s nochange", (dpath ? dpath : spath)); 899 } 900 if (changedown) 901 logstd(" (uid/gid differ)"); 902 if (changedflags) 903 logstd(" (flags differ)"); 904 logstd("\n"); 905 } 906 CountSourceBytes += size; 907 CountSourceItems++; 908 r = 0; 909 goto done; 910 } 911 } 912 } 913 if (st2Valid && !S_ISDIR(stat1->st_mode) && S_ISDIR(st2.st_mode)) { 914 if (SafetyOpt) { 915 logerr("%-32s SAFETY - refusing to copy file over directory\n", 916 (dpath ? dpath : spath) 917 ); 918 ++r; /* XXX */ 919 r = 0; 920 goto done; /* continue with the cpdup anyway */ 921 } 922 if (QuietOpt == 0 || AskConfirmation) { 923 logstd("%-32s WARNING: non-directory source will blow away\n" 924 "%-32s preexisting dest directory, continuing anyway!\n", 925 ((dpath) ? dpath : spath), ""); 926 } 927 if (dpath) 928 RemoveRecur(dpath, ddevNo, &st2); 929 st2Valid = 0; 930 } 931 932 /* 933 * The various comparisons failed, copy it. 934 */ 935 if (S_ISDIR(stat1->st_mode)) { 936 int skipdir = 0; 937 938 if (fres < 0) 939 logerr("%-32s/ fsmid-CHECK-FAILED\n", (dpath) ? dpath : spath); 940 941 if (dpath) { 942 if (!st2Valid || S_ISDIR(st2.st_mode) == 0) { 943 if (st2Valid) 944 xremove(&DstHost, dpath); 945 if (hc_mkdir(&DstHost, dpath, stat1->st_mode | 0700) != 0) { 946 logerr("%s: mkdir failed: %s\n", 947 (dpath ? dpath : spath), strerror(errno)); 948 r = 1; 949 skipdir = 1; 950 } 951 if (hc_lstat(&DstHost, dpath, &st2) != 0) { 952 if (NotForRealOpt == 0) 953 logerr("%s: lstat of newly made dir failed: %s\n", 954 (dpath ? dpath : spath), strerror(errno)); 955 st2Valid = 0; 956 r = 1; 957 skipdir = 1; 958 } 959 else { 960 st2Valid = 1; 961 if (!OwnerMatch(stat1, &st2) && 962 hc_chown(&DstHost, dpath, stat1->st_uid, stat1->st_gid) != 0 963 ) { 964 logerr("%s: chown of newly made dir failed: %s\n", 965 (dpath ? dpath : spath), strerror(errno)); 966 r = 1; 967 /* Note that we should not set skipdir = 1 here. */ 968 } 969 } 970 if (VerboseOpt) 971 logstd("%-32s mkdir-ok\n", (dpath ? dpath : spath)); 972 CountCopiedItems++; 973 } else { 974 /* 975 * Directory must be scanable by root for cpdup to 976 * work. We'll fix it later if the directory isn't 977 * supposed to be readable ( which is why we fixup 978 * st2.st_mode to match what we did ). 979 */ 980 if ((st2.st_mode & 0700) != 0700) { 981 hc_chmod(&DstHost, dpath, st2.st_mode | 0700); 982 st2.st_mode |= 0700; 983 } 984 if (VerboseOpt >= 2) 985 logstd("%s\n", dpath ? dpath : spath); 986 } 987 } 988 989 /* 990 * When copying a directory, stop if the source crosses a mount 991 * point. 992 */ 993 if (sdevNo != (dev_t)-1 && stat1->st_dev != sdevNo) 994 skipdir = 1; 995 else 996 sdevNo = stat1->st_dev; 997 998 /* 999 * When copying a directory, stop if the destination crosses 1000 * a mount point. 1001 * 1002 * The target directory will have been created and stat'd 1003 * for st2 if it did not previously exist. st2Valid is left 1004 * as a flag. If the stat failed st2 will still only have its 1005 * default initialization. 1006 * 1007 * So we simply assume here that the directory is within the 1008 * current target mount if we had to create it (aka st2Valid is 0) 1009 * and we leave ddevNo alone. 1010 */ 1011 if (st2Valid) { 1012 if (ddevNo != (dev_t)-1 && st2.st_dev != ddevNo) 1013 skipdir = 1; 1014 else 1015 ddevNo = st2.st_dev; 1016 } 1017 1018 if (!skipdir) { 1019 List *list = malloc(sizeof(List)); 1020 Node *node; 1021 1022 if (DirShowOpt) 1023 logstd("Scanning %s ...\n", spath); 1024 InitList(list); 1025 if (ScanDir(list, &SrcHost, spath, &CountSourceReadBytes, 0) == 0) { 1026 node = NULL; 1027 while ((node = IterateList(list, node, 0)) != NULL) { 1028 char *nspath; 1029 char *ndpath = NULL; 1030 1031 nspath = mprintf("%s/%s", spath, node->no_Name); 1032 if (dpath) 1033 ndpath = mprintf("%s/%s", dpath, node->no_Name); 1034 1035 info->spath = nspath; 1036 info->dpath = ndpath; 1037 info->sdevNo = sdevNo; 1038 info->ddevNo = ddevNo; 1039 if (depth < 0) 1040 r += DoCopy(info, node->no_Stat, depth); 1041 else 1042 r += DoCopy(info, node->no_Stat, depth + 1); 1043 free(nspath); 1044 if (ndpath) 1045 free(ndpath); 1046 info->spath = NULL; 1047 info->dpath = NULL; 1048 } 1049 1050 /* 1051 * Remove files/directories from destination that do not appear 1052 * in the source. 1053 */ 1054 if (dpath && ScanDir(list, &DstHost, dpath, 1055 &CountTargetReadBytes, 3) == 0) { 1056 node = NULL; 1057 while ((node = IterateList(list, node, 3)) != NULL) { 1058 /* 1059 * If object does not exist in source or .cpignore 1060 * then recursively remove it. 1061 */ 1062 char *ndpath; 1063 1064 ndpath = mprintf("%s/%s", dpath, node->no_Name); 1065 RemoveRecur(ndpath, ddevNo, node->no_Stat); 1066 free(ndpath); 1067 } 1068 } 1069 } 1070 ResetList(list); 1071 free(list); 1072 } 1073 1074 if (dpath && st2Valid) { 1075 struct timeval tv[2]; 1076 1077 if (ForceOpt || !OwnerMatch(stat1, &st2)) 1078 hc_chown(&DstHost, dpath, stat1->st_uid, stat1->st_gid); 1079 if (stat1->st_mode != st2.st_mode) 1080 hc_chmod(&DstHost, dpath, stat1->st_mode); 1081 #ifdef _ST_FLAGS_PRESENT_ 1082 if (!FlagsMatch(stat1, &st2)) 1083 hc_chflags(&DstHost, dpath, stat1->st_flags); 1084 #endif 1085 if (ForceOpt || mtimecmp(stat1, &st2) != 0) { 1086 bzero(tv, sizeof(tv)); 1087 tv[0].tv_sec = stat1->st_mtime; 1088 tv[1].tv_sec = stat1->st_mtime; 1089 #if defined(st_mtime) /* A macro, so very likely on modern POSIX */ 1090 tv[0].tv_usec = stat1->st_mtim.tv_nsec / 1000; 1091 tv[1].tv_usec = stat1->st_mtim.tv_nsec / 1000; 1092 #endif 1093 hc_utimes(&DstHost, dpath, tv); 1094 } 1095 } 1096 } else if (dpath == NULL) { 1097 /* 1098 * If dpath is NULL, we are just updating the MD5 1099 */ 1100 #ifndef NOMD5 1101 if (UseMD5Opt && S_ISREG(stat1->st_mode)) { 1102 mres = md5_check(spath, NULL); 1103 1104 if (VerboseOpt > 1) { 1105 if (mres < 0) 1106 logstd("%-32s md5-update\n", (dpath) ? dpath : spath); 1107 else 1108 logstd("%-32s md5-ok\n", (dpath) ? dpath : spath); 1109 } else if (!QuietOpt && mres < 0) { 1110 logstd("%-32s md5-update\n", (dpath) ? dpath : spath); 1111 } 1112 } 1113 #endif 1114 } else if (S_ISREG(stat1->st_mode)) { 1115 char *path; 1116 char *hpath; 1117 int fd1; 1118 int fd2; 1119 1120 if (st2Valid) 1121 path = mprintf("%s.tmp%d", dpath, (int)getpid()); 1122 else 1123 path = mprintf("%s", dpath); 1124 1125 /* 1126 * Handle check failure message. 1127 */ 1128 #ifndef NOMD5 1129 if (mres < 0) 1130 logerr("%-32s md5-CHECK-FAILED\n", (dpath) ? dpath : spath); 1131 else 1132 #endif 1133 if (fres < 0) 1134 logerr("%-32s fsmid-CHECK-FAILED\n", (dpath) ? dpath : spath); 1135 1136 /* 1137 * Not quite ready to do the copy yet. If UseHLPath is defined, 1138 * see if we can hardlink instead. 1139 * 1140 * If we can hardlink, and the target exists, we have to remove it 1141 * first or the hardlink will fail. This can occur in a number of 1142 * situations but most typically when the '-f -H' combination is 1143 * used. 1144 */ 1145 if (UseHLPath && (hpath = checkHLPath(stat1, spath, dpath)) != NULL) { 1146 if (st2Valid) 1147 xremove(&DstHost, dpath); 1148 if (hc_link(&DstHost, hpath, dpath) == 0) { 1149 ++CountLinkedItems; 1150 if (VerboseOpt) { 1151 logstd("%-32s hardlinked(-H)\n", 1152 (dpath ? dpath : spath)); 1153 } 1154 free(hpath); 1155 goto skip_copy; 1156 } 1157 /* 1158 * Shucks, we may have hit a filesystem hard linking limit, 1159 * we have to copy instead. 1160 */ 1161 free(hpath); 1162 } 1163 1164 if ((fd1 = hc_open(&SrcHost, spath, O_RDONLY, 0)) >= 0) { 1165 if ((fd2 = hc_open(&DstHost, path, O_WRONLY|O_CREAT|O_EXCL, 0600)) < 0) { 1166 /* 1167 * There could be a .tmp file from a previously interrupted 1168 * run, delete and retry. Fail if we still can't get at it. 1169 */ 1170 #ifdef _ST_FLAGS_PRESENT_ 1171 hc_chflags(&DstHost, path, 0); 1172 #endif 1173 hc_remove(&DstHost, path); 1174 fd2 = hc_open(&DstHost, path, O_WRONLY|O_CREAT|O_EXCL|O_TRUNC, 0600); 1175 } 1176 if (fd2 >= 0) { 1177 const char *op; 1178 char *iobuf1 = malloc(GETIOSIZE); 1179 int n; 1180 1181 /* 1182 * Matt: What about holes? 1183 */ 1184 op = "read"; 1185 while ((n = hc_read(&SrcHost, fd1, iobuf1, GETIOSIZE)) > 0) { 1186 op = "write"; 1187 if (hc_write(&DstHost, fd2, iobuf1, n) != n) 1188 break; 1189 op = "read"; 1190 } 1191 hc_close(&DstHost, fd2); 1192 if (n == 0) { 1193 struct timeval tv[2]; 1194 1195 bzero(tv, sizeof(tv)); 1196 tv[0].tv_sec = stat1->st_mtime; 1197 tv[1].tv_sec = stat1->st_mtime; 1198 #if defined(st_mtime) 1199 tv[0].tv_usec = stat1->st_mtim.tv_nsec / 1000; 1200 tv[1].tv_usec = stat1->st_mtim.tv_nsec / 1000; 1201 #endif 1202 1203 if (DstRootPrivs || ChgrpAllowed(stat1->st_gid)) 1204 hc_chown(&DstHost, path, stat1->st_uid, stat1->st_gid); 1205 hc_chmod(&DstHost, path, stat1->st_mode); 1206 #ifdef _ST_FLAGS_PRESENT_ 1207 if (stat1->st_flags & (UF_IMMUTABLE|SF_IMMUTABLE)) 1208 hc_utimes(&DstHost, path, tv); 1209 #else 1210 hc_utimes(&DstHost, path, tv); 1211 #endif 1212 if (st2Valid && xrename(path, dpath, st2_flags) != 0) { 1213 logerr("%-32s rename-after-copy failed: %s\n", 1214 (dpath ? dpath : spath), strerror(errno) 1215 ); 1216 xremove(&DstHost, path); 1217 ++r; 1218 } else { 1219 if (VerboseOpt) 1220 logstd("%-32s copy-ok\n", (dpath ? dpath : spath)); 1221 #ifdef _ST_FLAGS_PRESENT_ 1222 if (DstRootPrivs ? stat1->st_flags : stat1->st_flags & UF_SETTABLE) 1223 hc_chflags(&DstHost, dpath, stat1->st_flags); 1224 #endif 1225 } 1226 #ifdef _ST_FLAGS_PRESENT_ 1227 if ((stat1->st_flags & (UF_IMMUTABLE|SF_IMMUTABLE)) == 0) 1228 hc_utimes(&DstHost, dpath, tv); 1229 #endif 1230 CountSourceReadBytes += size; 1231 CountWriteBytes += size; 1232 CountSourceBytes += size; 1233 CountSourceItems++; 1234 CountCopiedItems++; 1235 } else { 1236 logerr("%-32s %s failed: %s\n", 1237 (dpath ? dpath : spath), op, strerror(errno) 1238 ); 1239 hc_remove(&DstHost, path); 1240 ++r; 1241 } 1242 free(iobuf1); 1243 } else { 1244 logerr("%-32s create (uid %d, euid %d) failed: %s\n", 1245 (dpath ? dpath : spath), getuid(), geteuid(), 1246 strerror(errno) 1247 ); 1248 ++r; 1249 } 1250 hc_close(&SrcHost, fd1); 1251 } else { 1252 logerr("%-32s copy: open failed: %s\n", 1253 (dpath ? dpath : spath), 1254 strerror(errno) 1255 ); 1256 ++r; 1257 } 1258 skip_copy: 1259 free(path); 1260 1261 if (hln) { 1262 if (!r && hc_stat(&DstHost, dpath, &st2) == 0) { 1263 hltsetdino(hln, st2.st_ino); 1264 } else { 1265 hltdelete(hln); 1266 hln = NULL; 1267 } 1268 } 1269 } else if (S_ISLNK(stat1->st_mode)) { 1270 char *link1 = malloc(GETLINKSIZE); 1271 char *link2 = malloc(GETLINKSIZE); 1272 char *path; 1273 int n1; 1274 int n2; 1275 1276 n1 = hc_readlink(&SrcHost, spath, link1, GETLINKSIZE - 1); 1277 if (st2Valid) { 1278 path = mprintf("%s.tmp%d", dpath, (int)getpid()); 1279 n2 = hc_readlink(&DstHost, dpath, link2, GETLINKSIZE - 1); 1280 } else { 1281 path = mprintf("%s", dpath); 1282 n2 = -1; 1283 } 1284 if (n1 >= 0) { 1285 if (ForceOpt || n1 != n2 || bcmp(link1, link2, n1) != 0 || 1286 (st2Valid && symlink_mfo_test(&DstHost, stat1, &st2)) 1287 ) { 1288 struct timeval tv[2]; 1289 1290 bzero(tv, sizeof(tv)); 1291 tv[0].tv_sec = stat1->st_mtime; 1292 tv[1].tv_sec = stat1->st_mtime; 1293 #if defined(st_mtime) 1294 tv[0].tv_usec = stat1->st_mtim.tv_nsec / 1000; 1295 tv[1].tv_usec = stat1->st_mtim.tv_nsec / 1000; 1296 #endif 1297 1298 hc_umask(&DstHost, ~stat1->st_mode); 1299 xremove(&DstHost, path); 1300 link1[n1] = 0; 1301 if (hc_symlink(&DstHost, link1, path) < 0) { 1302 logerr("%-32s symlink (%s->%s) failed: %s\n", 1303 (dpath ? dpath : spath), link1, path, 1304 strerror(errno) 1305 ); 1306 ++r; 1307 } else { 1308 if (DstRootPrivs || ChgrpAllowed(stat1->st_gid)) 1309 hc_lchown(&DstHost, path, stat1->st_uid, stat1->st_gid); 1310 1311 /* 1312 * lutimes, lchmod if supported by destination. 1313 */ 1314 if (DstHost.version >= HCPROTO_VERSION_LUCC) { 1315 hc_lchmod(&DstHost, path, stat1->st_mode); 1316 hc_lutimes(&DstHost, path, tv); 1317 } 1318 1319 /* 1320 * rename (and set flags if supported by destination) 1321 */ 1322 if (st2Valid && xrename(path, dpath, st2_flags) != 0) { 1323 logerr("%-32s rename softlink (%s->%s) failed: %s\n", 1324 (dpath ? dpath : spath), 1325 path, dpath, strerror(errno)); 1326 xremove(&DstHost, path); 1327 } else { 1328 #ifdef _ST_FLAGS_PRESENT_ 1329 if (DstHost.version >= HCPROTO_VERSION_LUCC) 1330 hc_lchflags(&DstHost, dpath, stat1->st_flags); 1331 #endif 1332 if (VerboseOpt) { 1333 logstd("%-32s softlink-ok\n", 1334 (dpath ? dpath : spath)); 1335 } 1336 } 1337 hc_umask(&DstHost, 000); 1338 CountWriteBytes += n1; 1339 CountCopiedItems++; 1340 } 1341 } else { 1342 if (VerboseOpt >= 3) 1343 logstd("%-32s nochange", (dpath ? dpath : spath)); 1344 if (!OwnerMatch(stat1, &st2)) { 1345 hc_lchown(&DstHost, dpath, stat1->st_uid, stat1->st_gid); 1346 if (VerboseOpt >= 3) 1347 logstd(" (uid/gid differ)"); 1348 } 1349 if (VerboseOpt >= 3) 1350 logstd("\n"); 1351 } 1352 CountSourceBytes += n1; 1353 CountSourceReadBytes += n1; 1354 if (n2 > 0) 1355 CountTargetReadBytes += n2; 1356 CountSourceItems++; 1357 } else { 1358 r = 1; 1359 logerr("%-32s softlink-failed\n", (dpath ? dpath : spath)); 1360 } 1361 free(link1); 1362 free(link2); 1363 free(path); 1364 } else if ((S_ISCHR(stat1->st_mode) || S_ISBLK(stat1->st_mode)) && DeviceOpt) { 1365 char *path = NULL; 1366 1367 if (ForceOpt || 1368 st2Valid == 0 || 1369 stat1->st_mode != st2.st_mode || 1370 stat1->st_rdev != st2.st_rdev || 1371 !OwnerMatch(stat1, &st2) 1372 ) { 1373 if (st2Valid) { 1374 path = mprintf("%s.tmp%d", dpath, (int)getpid()); 1375 xremove(&DstHost, path); 1376 } else { 1377 path = mprintf("%s", dpath); 1378 } 1379 1380 if (hc_mknod(&DstHost, path, stat1->st_mode, stat1->st_rdev) == 0) { 1381 hc_chmod(&DstHost, path, stat1->st_mode); 1382 hc_chown(&DstHost, path, stat1->st_uid, stat1->st_gid); 1383 if (st2Valid) 1384 xremove(&DstHost, dpath); 1385 if (st2Valid && xrename(path, dpath, st2_flags) != 0) { 1386 logerr("%-32s dev-rename-after-create failed: %s\n", 1387 (dpath ? dpath : spath), 1388 strerror(errno) 1389 ); 1390 } else if (VerboseOpt) { 1391 logstd("%-32s dev-ok\n", (dpath ? dpath : spath)); 1392 } 1393 CountCopiedItems++; 1394 } else { 1395 r = 1; 1396 logerr("%-32s dev failed: %s\n", 1397 (dpath ? dpath : spath), strerror(errno) 1398 ); 1399 } 1400 } else { 1401 if (VerboseOpt >= 3) 1402 logstd("%-32s nochange\n", (dpath ? dpath : spath)); 1403 } 1404 if (path) 1405 free(path); 1406 CountSourceItems++; 1407 } 1408 done: 1409 if (hln) { 1410 if (hln->dino == (ino_t)-1) { 1411 hltdelete(hln); 1412 /*hln = NULL; unneeded */ 1413 } else { 1414 hltrels(hln); 1415 } 1416 } 1417 return (r); 1418 } 1419 1420 int 1421 ScanDir(List *list, struct HostConf *host, const char *path, 1422 int64_t *CountReadBytes, int n) 1423 { 1424 DIR *dir; 1425 struct HostConf *cphost; 1426 struct HCDirEntry *den; 1427 struct stat *statptr; 1428 1429 if (n == 0) { 1430 /* 1431 * scan .cpignore file for files/directories to ignore 1432 * (only in the source directory, i.e. if n == 0). 1433 */ 1434 if (UseCpFile) { 1435 int fd; 1436 int nread; 1437 int bufused; 1438 char *buf = malloc(GETBUFSIZE); 1439 char *nl, *next; 1440 char *fpath; 1441 1442 if (UseCpFile[0] == '/') { 1443 fpath = mprintf("%s", UseCpFile); 1444 cphost = NULL; 1445 } else { 1446 fpath = mprintf("%s/%s", path, UseCpFile); 1447 AddList(list, strrchr(fpath, '/') + 1, 1, NULL); 1448 cphost = host; 1449 } 1450 fd = hc_open(cphost, fpath, O_RDONLY, 0); 1451 if (fd >= 0) { 1452 bufused = 0; 1453 while ((nread = hc_read(cphost, fd, buf + bufused, 1454 GETBUFSIZE - bufused - 1)) > 0) { 1455 *CountReadBytes += nread; 1456 bufused += nread; 1457 buf[bufused] = 0; 1458 for (next = buf; (nl = strchr(next, '\n')); next = nl+1) { 1459 *nl = 0; 1460 AddList(list, next, 1, NULL); 1461 } 1462 bufused = strlen(next); 1463 if (bufused) 1464 bcopy(next, buf, bufused); 1465 } 1466 if (bufused) { 1467 /* last line has no trailing newline */ 1468 buf[bufused] = 0; 1469 AddList(list, buf, 1, NULL); 1470 } 1471 hc_close(cphost, fd); 1472 } 1473 free(fpath); 1474 free(buf); 1475 } 1476 1477 /* 1478 * Automatically exclude MD5CacheFile that we create on the 1479 * source from the copy to the destination. 1480 * 1481 * Automatically exclude a FSMIDCacheFile on the source that 1482 * would otherwise overwrite the one we maintain on the target. 1483 */ 1484 if (UseMD5Opt) 1485 AddList(list, MD5CacheFile, 1, NULL); 1486 if (UseFSMIDOpt) 1487 AddList(list, FSMIDCacheFile, 1, NULL); 1488 } 1489 1490 if ((dir = hc_opendir(host, path)) == NULL) 1491 return (1); 1492 while ((den = hc_readdir(host, dir, &statptr)) != NULL) { 1493 /* 1494 * ignore . and .. 1495 */ 1496 if (strcmp(den->d_name, ".") != 0 && strcmp(den->d_name, "..") != 0) { 1497 if (UseCpFile && UseCpFile[0] == '/') { 1498 if (CheckList(list, path, den->d_name) == 0) 1499 continue; 1500 } 1501 AddList(list, den->d_name, n, statptr); 1502 } 1503 } 1504 hc_closedir(host, dir); 1505 1506 return (0); 1507 } 1508 1509 /* 1510 * RemoveRecur() 1511 */ 1512 1513 static void 1514 RemoveRecur(const char *dpath, dev_t devNo, struct stat *dstat) 1515 { 1516 struct stat st; 1517 1518 if (dstat == NULL) { 1519 if (hc_lstat(&DstHost, dpath, &st) == 0) 1520 dstat = &st; 1521 } 1522 if (dstat != NULL) { 1523 if (devNo == (dev_t)-1) 1524 devNo = dstat->st_dev; 1525 if (dstat->st_dev == devNo) { 1526 if (S_ISDIR(dstat->st_mode)) { 1527 DIR *dir; 1528 1529 if ((dir = hc_opendir(&DstHost, dpath)) != NULL) { 1530 List *list = malloc(sizeof(List)); 1531 Node *node = NULL; 1532 struct HCDirEntry *den; 1533 1534 InitList(list); 1535 while ((den = hc_readdir(&DstHost, dir, &dstat)) != NULL) { 1536 if (strcmp(den->d_name, ".") == 0) 1537 continue; 1538 if (strcmp(den->d_name, "..") == 0) 1539 continue; 1540 AddList(list, den->d_name, 3, dstat); 1541 } 1542 hc_closedir(&DstHost, dir); 1543 while ((node = IterateList(list, node, 3)) != NULL) { 1544 char *ndpath; 1545 1546 ndpath = mprintf("%s/%s", dpath, node->no_Name); 1547 RemoveRecur(ndpath, devNo, node->no_Stat); 1548 free(ndpath); 1549 } 1550 ResetList(list); 1551 free(list); 1552 } 1553 if (AskConfirmation && NoRemoveOpt == 0) { 1554 if (YesNo(dpath)) { 1555 if (xrmdir(&DstHost, dpath) < 0) { 1556 logerr("%-32s rmdir failed: %s\n", 1557 dpath, strerror(errno) 1558 ); 1559 } 1560 CountRemovedItems++; 1561 } 1562 } else { 1563 if (NoRemoveOpt) { 1564 if (VerboseOpt) 1565 logstd("%-32s not-removed\n", dpath); 1566 } else if (xrmdir(&DstHost, dpath) == 0) { 1567 if (VerboseOpt) 1568 logstd("%-32s rmdir-ok\n", dpath); 1569 CountRemovedItems++; 1570 } else { 1571 logerr("%-32s rmdir failed: %s\n", 1572 dpath, strerror(errno) 1573 ); 1574 } 1575 } 1576 } else { 1577 if (AskConfirmation && NoRemoveOpt == 0) { 1578 if (YesNo(dpath)) { 1579 if (xremove(&DstHost, dpath) < 0) { 1580 logerr("%-32s remove failed: %s\n", 1581 dpath, strerror(errno) 1582 ); 1583 } 1584 CountRemovedItems++; 1585 } 1586 } else { 1587 if (NoRemoveOpt) { 1588 if (VerboseOpt) 1589 logstd("%-32s not-removed\n", dpath); 1590 } else if (xremove(&DstHost, dpath) == 0) { 1591 if (VerboseOpt) 1592 logstd("%-32s remove-ok\n", dpath); 1593 CountRemovedItems++; 1594 } else { 1595 logerr("%-32s remove failed: %s\n", 1596 dpath, strerror(errno) 1597 ); 1598 } 1599 } 1600 } 1601 } 1602 } 1603 } 1604 1605 static void 1606 InitList(List *list) 1607 { 1608 bzero(list, sizeof(List)); 1609 list->li_Node.no_Next = &list->li_Node; 1610 } 1611 1612 static void 1613 ResetList(List *list) 1614 { 1615 Node *node; 1616 1617 while ((node = list->li_Node.no_Next) != &list->li_Node) { 1618 list->li_Node.no_Next = node->no_Next; 1619 if (node->no_Stat != NULL) 1620 free(node->no_Stat); 1621 free(node); 1622 } 1623 InitList(list); 1624 } 1625 1626 static Node * 1627 IterateList(List *list, Node *node, int n) 1628 { 1629 if (node == NULL) 1630 node = list->li_Node.no_Next; 1631 else 1632 node = node->no_Next; 1633 while (node->no_Value != n && node != &list->li_Node) 1634 node = node->no_Next; 1635 return (node == &list->li_Node ? NULL : node); 1636 } 1637 1638 static int 1639 AddList(List *list, const char *name, int n, struct stat *st) 1640 { 1641 Node *node; 1642 int hv; 1643 1644 /* 1645 * Scan against wildcards. Only a node value of 1 can be a wildcard 1646 * ( usually scanned from .cpignore ) 1647 */ 1648 for (node = list->li_Hash[0]; node; node = node->no_HNext) { 1649 if (strcmp(name, node->no_Name) == 0 || 1650 (n != 1 && node->no_Value == 1 && 1651 fnmatch(node->no_Name, name, 0) == 0) 1652 ) { 1653 return(node->no_Value); 1654 } 1655 } 1656 1657 /* 1658 * Look for exact match 1659 */ 1660 1661 hv = shash(name); 1662 for (node = list->li_Hash[hv]; node; node = node->no_HNext) { 1663 if (strcmp(name, node->no_Name) == 0) { 1664 return(node->no_Value); 1665 } 1666 } 1667 node = malloc(sizeof(Node) + strlen(name) + 1); 1668 if (node == NULL) 1669 fatal("out of memory"); 1670 1671 node->no_Next = list->li_Node.no_Next; 1672 list->li_Node.no_Next = node; 1673 1674 node->no_HNext = list->li_Hash[hv]; 1675 list->li_Hash[hv] = node; 1676 1677 strcpy(node->no_Name, name); 1678 node->no_Value = n; 1679 node->no_Stat = st; 1680 1681 return(n); 1682 } 1683 1684 /* 1685 * Match against n=1 (cpignore) entries 1686 * 1687 * Returns 0 on match, non-zero if no match 1688 */ 1689 static int 1690 CheckList(List *list, const char *path, const char *name) 1691 { 1692 char *fpath = NULL; 1693 Node *node; 1694 int hv; 1695 1696 if (asprintf(&fpath, "%s/%s", path, name) < 0) 1697 fatal("out of memory"); 1698 1699 /* 1700 * Scan against wildcards. Only a node value of 1 can be a wildcard 1701 * ( usually scanned from .cpignore ) 1702 */ 1703 for (node = list->li_Hash[0]; node; node = node->no_HNext) { 1704 if (node->no_Value != 1) 1705 continue; 1706 if (fnmatch(node->no_Name, fpath, 0) == 0) { 1707 free(fpath); 1708 return 0; 1709 } 1710 } 1711 1712 /* 1713 * Look for exact match 1714 */ 1715 hv = shash(fpath); 1716 for (node = list->li_Hash[hv]; node; node = node->no_HNext) { 1717 if (node->no_Value != 1) 1718 continue; 1719 if (strcmp(fpath, node->no_Name) == 0) { 1720 free(fpath); 1721 return 0; 1722 } 1723 } 1724 1725 free(fpath); 1726 return 1; 1727 } 1728 1729 static int 1730 shash(const char *s) 1731 { 1732 int hv; 1733 1734 hv = 0xA4FB3255; 1735 1736 while (*s) { 1737 if (*s == '*' || *s == '?' || 1738 *s == '{' || *s == '}' || 1739 *s == '[' || *s == ']' || 1740 *s == '|' 1741 ) { 1742 return(0); 1743 } 1744 hv = (hv << 5) ^ *s ^ (hv >> 23); 1745 ++s; 1746 } 1747 return(((hv >> 16) ^ hv) & HMASK); 1748 } 1749 1750 static int 1751 YesNo(const char *path) 1752 { 1753 int ch, first; 1754 1755 fprintf(stderr, "remove %s (Yes/No) [No]? ", path); 1756 fflush(stderr); 1757 1758 first = ch = getchar(); 1759 while (ch != '\n' && ch != EOF) 1760 ch = getchar(); 1761 return ((first == 'y' || first == 'Y')); 1762 } 1763 1764 /* 1765 * xrename() - rename with override 1766 * 1767 * If the rename fails, attempt to override st_flags on the 1768 * destination and rename again. If that fails too, try to 1769 * set the flags back the way they were and give up. 1770 */ 1771 1772 static int 1773 xrename(const char *src, const char *dst, u_long flags) 1774 { 1775 int r; 1776 1777 if ((r = hc_rename(&DstHost, src, dst)) < 0) { 1778 #ifdef _ST_FLAGS_PRESENT_ 1779 if (DstHost.version >= HCPROTO_VERSION_LUCC) 1780 hc_lchflags(&DstHost, dst, 0); 1781 else 1782 hc_chflags(&DstHost, dst, 0); 1783 1784 if ((r = hc_rename(&DstHost, src, dst)) < 0) { 1785 if (DstHost.version >= HCPROTO_VERSION_LUCC) 1786 hc_lchflags(&DstHost, dst, flags); 1787 else 1788 hc_chflags(&DstHost, dst, flags); 1789 } 1790 #endif 1791 } 1792 return(r); 1793 } 1794 1795 static int 1796 xlink(const char *src, const char *dst, u_long flags) 1797 { 1798 int r; 1799 #ifdef _ST_FLAGS_PRESENT_ 1800 int e; 1801 #endif 1802 1803 if ((r = hc_link(&DstHost, src, dst)) < 0) { 1804 #ifdef _ST_FLAGS_PRESENT_ 1805 if (DstHost.version >= HCPROTO_VERSION_LUCC) 1806 hc_lchflags(&DstHost, dst, 0); 1807 else 1808 hc_chflags(&DstHost, src, 0); 1809 r = hc_link(&DstHost, src, dst); 1810 e = errno; 1811 hc_chflags(&DstHost, src, flags); 1812 errno = e; 1813 #endif 1814 } 1815 if (r == 0) 1816 ++CountLinkedItems; 1817 return(r); 1818 } 1819 1820 static int 1821 xremove(struct HostConf *host, const char *path) 1822 { 1823 int res; 1824 1825 res = hc_remove(host, path); 1826 #ifdef _ST_FLAGS_PRESENT_ 1827 if (res == -EPERM) { 1828 if (host->version >= HCPROTO_VERSION_LUCC) 1829 hc_lchflags(host, path, 0); 1830 else 1831 hc_chflags(host, path, 0); 1832 res = hc_remove(host, path); 1833 } 1834 #endif 1835 return(res); 1836 } 1837 1838 static int 1839 xrmdir(struct HostConf *host, const char *path) 1840 { 1841 int res; 1842 1843 res = hc_rmdir(host, path); 1844 #ifdef _ST_FLAGS_PRESENT_ 1845 if (res == -EPERM) { 1846 hc_chflags(host, path, 0); 1847 res = hc_rmdir(host, path); 1848 } 1849 #endif 1850 return(res); 1851 } 1852 1853 /* 1854 * Compare mtimes. By default cpdup only compares the seconds field 1855 * because different operating systems and filesystems will store time 1856 * fields with varying amounts of precision. 1857 * 1858 * This subroutine can be adjusted to also compare to microseconds or 1859 * nanoseconds precision. However, since cpdup() uses utimes() to 1860 * set a file's timestamp and utimes() only takes timeval's (usec precision), 1861 * I strongly recommend only comparing down to usec precision at best. 1862 */ 1863 static int 1864 mtimecmp(struct stat *st1, struct stat *st2) 1865 { 1866 if (st1->st_mtime < st2->st_mtime) 1867 return -1; 1868 if (st1->st_mtime == st2->st_mtime) 1869 return 0; 1870 return 1; 1871 } 1872 1873 /* 1874 * Check to determine if a symlink's mtime, flags, or mode differ. 1875 * 1876 * This is only supported on targets that support lchflags, lutimes, 1877 * and lchmod. 1878 */ 1879 static int 1880 symlink_mfo_test(struct HostConf *hc, struct stat *st1, struct stat *st2) 1881 { 1882 int res = 0; 1883 1884 if (hc->version >= HCPROTO_VERSION_LUCC) { 1885 if (!FlagsMatch(st1, st2)) 1886 res = 1; 1887 if (mtimecmp(st1, st2) != 0) 1888 res = 1; 1889 if (st1->st_mode != st2->st_mode) 1890 res = 1; 1891 } 1892 return res; 1893 } 1894