|
|
1.1 ! root 1: /* ! 2: * Cpdir. Copy hierarchies in a file system, preserving structure. ! 3: * Define SLOW for 'block at a time copying' - not recommended tho. ! 4: */ ! 5: #include <stdio.h> ! 6: #include <errno.h> ! 7: #include <signal.h> ! 8: #include <sys/types.h> ! 9: #include <sys/stat.h> ! 10: #include <sys/dir.h> ! 11: #include <ctype.h> ! 12: #include <access.h> ! 13: #include <canon.h> ! 14: ! 15: #define VERSION "1.1" ! 16: #define CPBUFSIZ (50*BUFSIZ) /* copy buffer */ ! 17: #define SDSIZ (sizeof(struct direct)) ! 18: #define MAXINT 32767 ! 19: #define SOURCE 0 ! 20: #define TARGET 1 ! 21: #define DEV0 ((dev_t)0) ! 22: #define INODE0 ((ino_t)0) ! 23: #define ROOTUID 0 ! 24: #define HASHSIZE 37 ! 25: ! 26: #define hash(ino) ((ino)%HASHSIZE) ! 27: ! 28: #define TRUE (0==0) ! 29: #define FALSE (0==1) ! 30: ! 31: typedef char bool; ! 32: typedef unsigned char uchar; ! 33: typedef unsigned int uint; ! 34: typedef unsigned short ushort; ! 35: typedef unsigned long ulong; ! 36: ! 37: typedef union { ! 38: struct direct dbuf; ! 39: char cbuf[SDSIZ + 1]; ! 40: } DIRBUF; ! 41: #define db_ino dbuf.d_ino ! 42: #define db_name dbuf.d_name ! 43: ! 44: typedef struct link { ! 45: ino_t l_ino; ! 46: dev_t l_dev; ! 47: dev_t l_tdev; ! 48: struct link *l_next; ! 49: uint l_nlink; ! 50: char l_name[]; ! 51: } LINK; ! 52: ! 53: typedef struct str { ! 54: struct str *s_next; ! 55: char s_str[]; ! 56: } STR; ! 57: ! 58: ! 59: ! 60: /* ! 61: * Global variables. ! 62: */ ! 63: extern int errno; ! 64: dev_t dir2_dev; ! 65: ino_t dir2_ino; ! 66: dev_t src_dev; ! 67: dev_t tgt_dev; ! 68: struct stat srcstat; ! 69: struct stat tgtstat; ! 70: LINK *srctab[HASHSIZE]; ! 71: LINK *tgttab[HASHSIZE]; ! 72: STR *strtab[HASHSIZE]; ! 73: ! 74: bool aflag; ! 75: bool dflag; ! 76: bool eflag; ! 77: bool sflag; ! 78: bool tflag; ! 79: bool uflag; ! 80: bool vflag; ! 81: bool wflag; ! 82: bool root; ! 83: bool splitmsg; ! 84: bool errprefix; ! 85: bool dir1slash; ! 86: bool dir2slash; ! 87: ! 88: int rlimit = MAXINT; ! 89: int rlevel = 1; ! 90: int exitval; ! 91: int numsuppress; ! 92: int broken; ! 93: int srclinks; ! 94: int tgtlinks; ! 95: int srcsize; ! 96: int tgtsize; ! 97: int dir1len; ! 98: int dir2len; ! 99: int interrupted; /* For handling SIGINT and SIGQUIT */ ! 100: ! 101: short uid; ! 102: short gid; ! 103: ! 104: char *dir1; ! 105: char *dir2; ! 106: char *target; ! 107: char *source; ! 108: ! 109: /* ! 110: * Error message and other strings. ! 111: */ ! 112: char *dot = "."; ! 113: char *dotdot = ".."; ! 114: char *fmt1 = "%s\n"; ! 115: char *fmt1a = "%-72s\r"; ! 116: char *fmt2 = "%s: %s\n"; ! 117: char *fmt3 = "%s: %s%s\n"; ! 118: char *fmt4 = "%s: %s%s%s\n"; ! 119: char *usage = "usage: cpdir [options] dir1 dir2"; ! 120: char *devbound = "crossing device boundary"; ! 121: char *writeerr = "write error"; ! 122: char *readerr = "read error"; ! 123: char *supressd = "suppressed"; ! 124: char *linked = "linked"; ! 125: char *notdir = "not a directory"; ! 126: char *nomemory = "out of memory"; ! 127: char *nopermit = "permission denied"; ! 128: char *nomkdir = "cannot make directory"; ! 129: char *nounlink = "cannot unlink "; ! 130: char *nolink = "cannot link "; ! 131: char *nocreate = "cannot create"; ! 132: char *nofind = "cannot find"; ! 133: char *noopen = "cannot open"; ! 134: ! 135: /* ! 136: * Functions returning non_int. ! 137: */ ! 138: long lseek(); ! 139: char *tmalloc(); ! 140: char *realloc(); ! 141: char *rindex(); ! 142: char *concat(); ! 143: char *parent(); ! 144: bool suppress(); ! 145: bool isslash(); ! 146: bool dirchecks(); ! 147: bool linkattempt(); ! 148: bool tgtunlink(); ! 149: LINK *linklocate(); ! 150: LINK *linkinstall(); ! 151: ! 152: main(ac, av) int ac; char *av[]; ! 153: { ! 154: ac = 0; ! 155: aarghh(av); ! 156: init(); ! 157: cpdir(); ! 158: report(); ! 159: if (aflag) ! 160: printf("%72s\r", ""); ! 161: return (exitval); ! 162: } ! 163: ! 164: aarghh(av) ! 165: register char *av[]; ! 166: { ! 167: register char *cp; ! 168: ! 169: for (;;) { ! 170: if ((cp = *++av) == NULL) { ! 171: errprint(fmt1, usage); ! 172: exit(1); ! 173: } ! 174: if (*cp++ != '-') ! 175: break; ! 176: while (*cp) ! 177: switch (*cp++) { ! 178: case 'a': ! 179: aflag = TRUE; ! 180: break; ! 181: case 'd': ! 182: dflag = TRUE; ! 183: break; ! 184: case 'e': ! 185: eflag = TRUE; ! 186: break; ! 187: case 'r': ! 188: if (!isdigit(*cp)) { ! 189: rlimit = 1; ! 190: break; ! 191: } ! 192: *av = cp; ! 193: rlimit = new_atoi(av); ! 194: cp = *av; ! 195: break; ! 196: case 's': ! 197: sflag = TRUE; ! 198: strinstall(cp); ! 199: ++numsuppress; ! 200: goto NEXTARG; ! 201: break; ! 202: case 't': ! 203: tflag = wflag = eflag = TRUE; ! 204: break; ! 205: case 'u': ! 206: uflag = TRUE; ! 207: break; ! 208: case 'v': ! 209: vflag = wflag = TRUE; ! 210: break; ! 211: case 'V': ! 212: fprintf(stderr, "cpdir: V%s\n", VERSION); ! 213: break; ! 214: default: ! 215: errprint(fmt1, usage); ! 216: exit(1); ! 217: } ! 218: NEXTARG:; ! 219: } ! 220: ! 221: if ((dir1=*av++) == NULL || (dir2=*av++) == NULL || *av != NULL) { ! 222: errprint(fmt1, usage); ! 223: exit(1); ! 224: } ! 225: return; ! 226: } ! 227: ! 228: /* ! 229: * Actions: Initialize certain flags and the name buffers source and target. ! 230: * Verify dir1 and dir2 permissions. Dir2 is made if necessary. ! 231: * Side Effects: On return srcstat contains the status of dir1. If dir2 ! 232: * exists tgtstat contains its status. In the case that tflag is set and dir2 ! 233: * does not exist, tgt_dev and tgtstat.st_dev are the device of target's ! 234: * parent, the device that target would be created on except for tflag. ! 235: */ ! 236: init() ! 237: { ! 238: struct stat outstat; ! 239: struct stat errstat; ! 240: ! 241: uid = getuid(); ! 242: gid = getgid(); ! 243: root = (uid == ROOTUID); ! 244: if (root) ! 245: umask(0); ! 246: ! 247: errprefix = !isatty(fileno(stdin)); ! 248: fstat(fileno(stdout), &outstat); ! 249: fstat(fileno(stderr), &errstat); ! 250: splitmsg = (outstat.st_ino != errstat.st_ino) || ! 251: (outstat.st_dev != errstat.st_dev); ! 252: ! 253: dir1len = strlen(dir1); ! 254: srcsize = (dir1len + 1); ! 255: source = tmalloc(srcsize); ! 256: strcpy(source, dir1); ! 257: dir1slash = isslash(dir1); ! 258: ! 259: dir2len = strlen(dir2); ! 260: tgtsize = dir2len + 1; ! 261: target = tmalloc(tgtsize); ! 262: strcpy(target, dir2); ! 263: dir2slash = isslash(dir2); ! 264: ! 265: /* ! 266: * We must check boundary conditions before we call dirchecks(). ! 267: * These are: source exists and is a directory, and if target does not ! 268: * exist that we have write and search permission on its parent and ! 269: * tgt_dev contains the device number of the parent. ! 270: */ ! 271: if (stat(dir1, &srcstat) < 0) { ! 272: errprint(fmt2, dir1, nofind); ! 273: exit(1); ! 274: } ! 275: if ((srcstat.st_mode & S_IFMT) != S_IFDIR) { ! 276: errprint(fmt2, dir1, notdir); ! 277: exit(1); ! 278: } ! 279: if (access(dir2, 0) < 0) { ! 280: register char *cp; ! 281: cp = parent(dir2); ! 282: if (stat(cp, &tgtstat) < 0) { ! 283: errprint(fmt2, dir2, "cannot find parent"); ! 284: exit(1); ! 285: } ! 286: if (access(cp, AWRITE|ASRCH) < 0) { ! 287: errprint(fmt2, dir2, nomkdir); ! 288: exit(1); ! 289: } ! 290: tgt_dev = tgtstat.st_dev; ! 291: } ! 292: if (!dirchecks()) ! 293: exit(1); ! 294: ! 295: src_dev = srcstat.st_dev; ! 296: dir2_dev = tgt_dev = tgtstat.st_dev; ! 297: if (access(target, 0) == 0) ! 298: dir2_ino = tgtstat.st_ino; ! 299: return; ! 300: } ! 301: ! 302: ! 303: /* ! 304: * Assume: Source is a directory we can read and search. Srcstat contains its ! 305: * status. Target is a directory we can write and search. Tgtstat contains its ! 306: * status. Src_dev and tgt_dev are the devices of the parents of source and ! 307: * target. If tflag is on target may not exist. In this case tgtstat.st_dev ! 308: * contains the device where target would have been created if tflag were off. ! 309: */ ! 310: cpdir() ! 311: { ! 312: register int n; ! 313: register int fd; ! 314: register DIRBUF *dbp; ! 315: DIRBUF dirbuf; ! 316: long address; ! 317: dev_t sdev; ! 318: dev_t tdev; ! 319: struct stat locsrcstat; ! 320: struct stat loctgtstat; ! 321: ! 322: /* ! 323: * Check for circular copy. ! 324: */ ! 325: if (srcstat.st_ino == dir2_ino && ! 326: srcstat.st_dev == dir2_dev) { ! 327: if (wflag) ! 328: printf(fmt2, source, ! 329: "not copied to avoid circular copy"); ! 330: return; ! 331: } ! 332: ! 333: /* ! 334: * Open source, and prepare dirbuf. ! 335: */ ! 336: if ((fd = open(source, 0)) < 0) { ! 337: errprint(fmt2, source, noopen); ! 338: return; ! 339: } ! 340: dbp = &dirbuf; ! 341: dbp->cbuf[SDSIZ] = '\0'; ! 342: ! 343: /* ! 344: * Save srcstat, src_dev, tgtstat, tgt_dev to restore before exit. ! 345: */ ! 346: locsrcstat = srcstat; ! 347: loctgtstat = tgtstat; ! 348: tdev = tgt_dev; ! 349: sdev = src_dev; ! 350: ! 351: /* ! 352: * Detect the crossing of device boundaries. ! 353: */ ! 354: if (tgt_dev != tgtstat.st_dev) { ! 355: if (wflag) ! 356: printf(fmt2, target, devbound); ! 357: tgt_dev = tgtstat.st_dev; ! 358: } ! 359: if (src_dev != srcstat.st_dev) { ! 360: if (wflag) ! 361: printf(fmt2, source, devbound); ! 362: src_dev = srcstat.st_dev; ! 363: } ! 364: ! 365: /* ! 366: * Loop through the directory source. ! 367: */ ! 368: while ((n = read(fd, dbp->cbuf, SDSIZ)) > 0) { ! 369: if (n != SDSIZ) { ! 370: errprint(fmt2, source, readerr); ! 371: close(fd); ! 372: goto OUT; ! 373: } ! 374: ! 375: canino(dbp->db_ino); ! 376: if (dbp->db_ino == INODE0 || ! 377: !strcmp(dbp->db_name, dot) || ! 378: !strcmp(dbp->db_name, dotdot)) ! 379: continue; ! 380: ! 381: grow(dbp->db_name); ! 382: if (sflag && suppress()) { ! 383: if (vflag) ! 384: printf(fmt2, source, supressd); ! 385: shrink(); ! 386: continue; ! 387: } ! 388: if (stat(source, &srcstat) < 0) { ! 389: errprint(fmt2, source, nofind); ! 390: shrink(); ! 391: continue; ! 392: } ! 393: ! 394: switch (srcstat.st_mode & S_IFMT) { ! 395: default: ! 396: errprint(fmt2, source, "unknown file type"); ! 397: shrink(); ! 398: continue; ! 399: case S_IFCHR: ! 400: case S_IFBLK: ! 401: cpnode(); ! 402: shrink(); ! 403: continue; ! 404: case S_IFPIP: ! 405: srcstat.st_rdev = DEV0; ! 406: cpnode(); ! 407: shrink(); ! 408: continue; ! 409: case S_IFREG: ! 410: cpfile(); ! 411: shrink(); ! 412: continue; ! 413: case S_IFDIR: ! 414: if (rlevel == rlimit) { ! 415: if (vflag) ! 416: printf(fmt2, source, supressd); ! 417: shrink(); ! 418: continue; ! 419: } ! 420: if (!dirchecks()) { ! 421: shrink(); ! 422: continue; ! 423: } ! 424: ! 425: address = lseek(fd, 0L, 1); ! 426: close(fd); ! 427: ++rlevel; ! 428: cpdir(); ! 429: --rlevel; ! 430: shrink(); ! 431: if ((fd = open(source, 0)) < 0) { ! 432: errprint(fmt2, source, ! 433: "cannot reopen, copy incomplete"); ! 434: goto OUT; ! 435: } ! 436: lseek(fd, address, 0); ! 437: continue; ! 438: } ! 439: } ! 440: close(fd); ! 441: ! 442: OUT: ! 443: vprintf(); ! 444: srcstat = locsrcstat; ! 445: tgtstat = loctgtstat; ! 446: tgt_dev = tdev; ! 447: src_dev = sdev; ! 448: adjust(); ! 449: return; ! 450: } ! 451: ! 452: /* ! 453: * Assume source names the file to be copied, srcstat contains its status, ! 454: * and target is the file to copy to. Target may or may not exist. ! 455: */ ! 456: cpfile() ! 457: { ! 458: #ifndef SLOW ! 459: register char *ip; ! 460: #endif ! 461: register int n; ! 462: register int i; ! 463: register int fd1; ! 464: register int fd2; ! 465: register fsize_t size; ! 466: #ifndef SLOW ! 467: register char *wp; /* write pointer */ ! 468: register int wflag; /* write flag */ ! 469: static char buf[CPBUFSIZ]; /* copy buffer */ ! 470: #else ! 471: static char buf[BUFSIZ]; ! 472: #endif ! 473: int intflag, hupflag; ! 474: ! 475: if (access(source, AREAD) < 0) { ! 476: errprint(fmt2, source, noopen); ! 477: return; ! 478: } ! 479: ! 480: if (uflag && stat(target, &tgtstat) == 0) ! 481: if (srcstat.st_mtime <= tgtstat.st_mtime) { ! 482: if (vflag) ! 483: printf(fmt2, target, "no update"); ! 484: return; ! 485: } ! 486: ! 487: if (!tgtunlink()) ! 488: return; ! 489: if (srcstat.st_nlink > 1) ! 490: if (linkattempt()) ! 491: return; ! 492: ! 493: if (tflag) { ! 494: vprintf(); ! 495: return; ! 496: } ! 497: ! 498: intflag = catch(SIGINT); ! 499: hupflag = catch(SIGHUP); ! 500: if ((fd1 = open(source, 0)) < 0) { ! 501: errprint(fmt2, source, noopen); ! 502: return; ! 503: } ! 504: if ((fd2 = creat(target, 0)) < 0) { ! 505: close(fd1); ! 506: errprint(fmt2, target, nocreate); ! 507: return; ! 508: } ! 509: ! 510: size = srcstat.st_size; ! 511: #ifndef SLOW ! 512: while ((n = read(fd1, buf, sizeof(buf))) > 0) { ! 513: #else ! 514: while ((n = read(fd1, buf, BUFSIZ)) > 0) { ! 515: #endif ! 516: /* ! 517: * Check for blocks of zeroes (holes in a sparse file). ! 518: * However, a block of zeroes at the end of a file must be ! 519: * written so the file has correct length. ! 520: */ ! 521: #ifndef SLOW ! 522: wp = ip = buf; ! 523: size -= n; ! 524: while ((n-BUFSIZ) > 0 || ((n-BUFSIZ) == 0 && size != 0)) { ! 525: n -= BUFSIZ; ! 526: wflag = FALSE; ! 527: ip = wp; ! 528: for (i = 0; i < BUFSIZ; ++i) ! 529: if (*ip++ != '\0') { ! 530: wflag = TRUE; ! 531: break; ! 532: } ! 533: if (wflag) { ! 534: if (write(fd2, wp, BUFSIZ) < BUFSIZ) { ! 535: errprint(fmt2, target, writeerr); ! 536: close(fd1); ! 537: close(fd2); ! 538: return (FALSE); ! 539: } ! 540: } else { ! 541: lseek(fd2, (long)BUFSIZ, 1); ! 542: } ! 543: wp += BUFSIZ; ! 544: } ! 545: if (write(fd2, wp, n) < n) { ! 546: errprint(fmt2, target, writeerr); ! 547: close(fd1); ! 548: close(fd2); ! 549: return (FALSE); ! 550: } ! 551: #else ! 552: if ((size -= n) == (fsize_t)0) ! 553: goto WRITE; ! 554: for (i = 0; i < n; ++i) ! 555: if (buf[i] != '\0') ! 556: goto WRITE; ! 557: lseek(fd2, (long)BUFSIZ, 1); ! 558: continue; ! 559: ! 560: WRITE: ! 561: if (write(fd2, buf, n) < n) { ! 562: errprint(fmt2, target, writeerr); ! 563: close(fd1); ! 564: close(fd2); ! 565: return (FALSE); ! 566: } ! 567: #endif ! 568: } ! 569: close(fd1); ! 570: close(fd2); ! 571: adjust(); ! 572: if (intflag) ! 573: signal(SIGINT, SIG_DFL); ! 574: if (hupflag) ! 575: signal(SIGHUP, SIG_DFL); ! 576: if (interrupted) ! 577: exit(1); ! 578: ! 579: if (n < 0) ! 580: errprint(fmt2, source, readerr); ! 581: else vprintf(); ! 582: return; ! 583: } ! 584: ! 585: /* ! 586: * Copy special nodes and named pipes. ! 587: */ ! 588: cpnode() ! 589: { ! 590: if (!root) { ! 591: if (vflag) ! 592: printf(fmt2, source, "not the super-user"); ! 593: return; ! 594: } ! 595: if (!tgtunlink()) ! 596: return; ! 597: if (srcstat.st_nlink > 1) ! 598: if (linkattempt()) ! 599: return; ! 600: if (!tflag) { ! 601: if (mknod(target, srcstat.st_mode, srcstat.st_rdev) < 0) { ! 602: errprint(fmt2, target, "cannot make node"); ! 603: return; ! 604: } ! 605: adjust(); ! 606: } ! 607: if (vflag) ! 608: printf(fmt2, target, "copied node"); ! 609: else if (aflag) ! 610: printf(fmt1a, target); ! 611: return; ! 612: } ! 613: ! 614: ! 615: /* ! 616: * Grow each of target and source by appending '/' and cp. ! 617: */ ! 618: grow(cp) ! 619: register char *cp; ! 620: { ! 621: register int a; ! 622: register int b; ! 623: ! 624: a = strlen(cp) + 2; ! 625: ! 626: b = strlen(source); ! 627: if (a+b > srcsize) { ! 628: if ((source = realloc(source, a+b)) == NULL) { ! 629: errprint(fmt1, nomemory); ! 630: exit(1); ! 631: } ! 632: srcsize = a+b; ! 633: } ! 634: if (rlevel > 1 || !dir1slash) ! 635: source[b++] = '/'; ! 636: strcpy(source+b, cp); ! 637: ! 638: b = strlen(target); ! 639: if (a+b > tgtsize) { ! 640: if ((target = realloc(target, a+b)) == NULL) { ! 641: errprint(fmt1, nomemory); ! 642: exit(1); ! 643: } ! 644: tgtsize = a+b; ! 645: } ! 646: if (rlevel > 1 || !dir2slash) ! 647: target[b++] = '/'; ! 648: strcpy(target+b, cp); ! 649: } ! 650: ! 651: /* ! 652: * Shrink source and target down by the last pathname component. ! 653: */ ! 654: shrink() ! 655: { ! 656: if (rlevel == 1 && dir1slash) ! 657: source[dir1len] = '\0'; ! 658: else ! 659: *rindex(source, '/') = '\0'; ! 660: if (rlevel == 1 && dir2slash) ! 661: target[dir2len] = '\0'; ! 662: else ! 663: *rindex(target, '/') = '\0'; ! 664: return; ! 665: } ! 666: ! 667: ! 668: /* ! 669: * Returns a value equal to atoi(*cpp). Positive decimal integers only. ! 670: * Leaves *cpp pointing to the character that terminated the digit string. ! 671: */ ! 672: new_atoi(cpp) ! 673: char **cpp; ! 674: { ! 675: register int sum = 0; ! 676: register int c; ! 677: register char *cp; ! 678: ! 679: sum = 0; ! 680: cp = *cpp; ! 681: while (isdigit(c = *cp++)) { ! 682: sum *= 10; ! 683: sum -= '0'; ! 684: sum += c; ! 685: } ! 686: *cpp = cp-1; ! 687: return (sum); ! 688: } ! 689: ! 690: errprint(arg) ! 691: char *arg[]; ! 692: { ! 693: register char *format; ! 694: ! 695: format = (errprefix) ? "cpdir: %r" : "%r"; ! 696: fprintf(stderr, format, &arg); ! 697: if (wflag && splitmsg) ! 698: printf(format, &arg); ! 699: if (!eflag) ! 700: exit(1); ! 701: exitval = 1; ! 702: return; ! 703: } ! 704: ! 705: /* ! 706: * Interface to malloc to check for bad returns. ! 707: */ ! 708: char * ! 709: tmalloc(n) ! 710: int n; ! 711: { ! 712: register char *cp; ! 713: if ((cp = malloc(n)) == NULL) { ! 714: errprint(fmt1, nomemory); ! 715: exit(1); ! 716: } ! 717: return (cp); ! 718: } ! 719: ! 720: /* ! 721: * Assume: source is a dir, srcstat has its status, we have write and search ! 722: * permission on target's parent directory, tgt_dev is the device of target's ! 723: * parent. ! 724: * Actions: Check permissions on source. Check permissions on target if it ! 725: * exists. If non-extant and tflag is off, make it. ! 726: * Side Effects: On return, if target exists, tgtstat contains its status. If ! 727: * it does not exist, tgtstat.st_dev is the device it would have been created ! 728: * on if tflag were off. ! 729: * Return TRUE if everything Aok, FALSE otherwise. ! 730: */ ! 731: bool ! 732: dirchecks() ! 733: { ! 734: register int n; ! 735: static int status; ! 736: ! 737: if (access(source, AREAD | ASRCH) < 0) { ! 738: errprint(fmt2, source, nopermit); ! 739: return (FALSE); ! 740: } ! 741: ! 742: if (stat(target, &tgtstat) == 0) { ! 743: if ((tgtstat.st_mode & S_IFMT) != S_IFDIR) { ! 744: errprint(fmt3, source, "target is ", notdir); ! 745: return (FALSE); ! 746: } ! 747: if (access(target, AWRITE | ASRCH) < 0) { ! 748: errprint(fmt2, target, nopermit); ! 749: return (FALSE); ! 750: } ! 751: return (TRUE); ! 752: } ! 753: ! 754: if (tflag) { ! 755: tgtstat.st_dev = tgt_dev; ! 756: return (TRUE); ! 757: } ! 758: ! 759: if (mkdir(target, 0700)) { ! 760: errprint(fmt2, target, nomkdir); ! 761: return (FALSE); ! 762: } ! 763: ! 764: if (stat(target, &tgtstat) < 0) { ! 765: errprint(fmt2, target, "made but cannot stat"); ! 766: return (FALSE); ! 767: } ! 768: return (TRUE); ! 769: } ! 770: ! 771: strinstall(cp) ! 772: register char *cp; ! 773: { ! 774: register STR *sp; ! 775: register int n; ! 776: ! 777: n = strhash(cp); ! 778: for (sp = strtab[n]; sp != NULL; sp = sp->s_next) ! 779: if (strcmp(cp, sp->s_str) == 0) ! 780: return; ! 781: sp = (STR *) tmalloc(sizeof(STR) + strlen(cp) + 1); ! 782: sp->s_next = strtab[n]; ! 783: strtab[n] = sp; ! 784: strcpy(sp->s_str, cp); ! 785: return; ! 786: } ! 787: ! 788: bool ! 789: suppress() ! 790: { ! 791: register char *cp; ! 792: register STR *sp; ! 793: register STR **spp; ! 794: ! 795: cp = source + dir1len; ! 796: if (!dir1slash) ! 797: ++cp; ! 798: spp = strtab + strhash(cp); ! 799: if ((sp = *spp) == NULL) ! 800: return (FALSE); ! 801: while (sp != NULL) { ! 802: if (strcmp(cp, sp->s_str) == 0) { ! 803: *spp = sp->s_next; ! 804: free(sp); ! 805: if (--numsuppress == 0) ! 806: sflag = FALSE; ! 807: return (TRUE); ! 808: } ! 809: spp = &(sp->s_next); ! 810: sp = *spp; ! 811: } ! 812: return (FALSE); ! 813: } ! 814: ! 815: strhash(cp) ! 816: register uchar *cp; ! 817: { ! 818: register uint sum = 0; ! 819: for (sum = 0; *cp != '\0'; sum += *cp++) ! 820: ; ! 821: return (sum % HASHSIZE); ! 822: } ! 823: ! 824: LINK * ! 825: linklocate(flag) ! 826: int flag; ! 827: { ! 828: register LINK *lp; ! 829: register struct stat *stp; ! 830: ! 831: if (flag == SOURCE) { ! 832: stp = &srcstat; ! 833: lp = srctab[hash(stp->st_ino)]; ! 834: } ! 835: else { ! 836: stp = &tgtstat; ! 837: lp = tgttab[hash(stp->st_ino)]; ! 838: } ! 839: ! 840: for ( ; lp != NULL; lp = lp->l_next) { ! 841: if (lp->l_ino != stp->st_ino) ! 842: continue; ! 843: if (lp->l_dev != stp->st_dev) ! 844: continue; ! 845: --(lp->l_nlink); ! 846: return (lp); ! 847: } ! 848: return (NULL); ! 849: } ! 850: ! 851: LINK * ! 852: linkinstall(flag) ! 853: int flag; ! 854: { ! 855: register LINK **lpp; ! 856: register LINK *lp; ! 857: register struct stat *stp; ! 858: ! 859: if (flag == SOURCE) { ! 860: ++srclinks; ! 861: stp = &srcstat; ! 862: lpp = hash(stp->st_ino) + srctab; ! 863: } ! 864: else { ! 865: ++tgtlinks; ! 866: stp = &tgtstat; ! 867: lpp = hash(stp->st_ino) + tgttab; ! 868: } ! 869: ! 870: lp = (LINK *) tmalloc(sizeof(LINK) + strlen(target) - dir2len + 1); ! 871: if (!dir2slash) ! 872: strcpy(lp->l_name, target + dir2len + 1); ! 873: else ! 874: strcpy(lp->l_name, target + dir2len); ! 875: lp->l_dev = stp->st_dev; ! 876: lp->l_ino = stp->st_ino; ! 877: lp->l_tdev = tgt_dev; ! 878: lp->l_nlink = stp->st_nlink - 1; ! 879: lp->l_next = *lpp; ! 880: *lpp = lp; ! 881: return (lp); ! 882: } ! 883: ! 884: linkpurge(flag, lp) ! 885: int flag; ! 886: register LINK *lp; ! 887: { ! 888: register LINK *lp1; ! 889: register LINK **lpp; ! 890: ! 891: if (flag == SOURCE) { ! 892: --srclinks; ! 893: lpp = hash(srcstat.st_ino) + srctab; ! 894: } ! 895: else { ! 896: --tgtlinks; ! 897: lpp = hash(tgtstat.st_ino) + tgttab; ! 898: } ! 899: ! 900: for (lp1 = *lpp; lp1 != NULL; *lpp = lp1, lp1 = lp1->l_next) { ! 901: if (lp1 != lp) ! 902: continue; ! 903: *lpp = lp1->l_next; ! 904: free((char *)lp1); ! 905: return; ! 906: } ! 907: return; ! 908: } ! 909: ! 910: bool ! 911: linkattempt() ! 912: { ! 913: register LINK *lp; ! 914: register bool ret; ! 915: register char *cp; ! 916: ! 917: if ((lp = linklocate(SOURCE)) == NULL) { ! 918: linkinstall(SOURCE); ! 919: return (FALSE); ! 920: } ! 921: cp = concat(dir2, lp->l_name); ! 922: ! 923: if (tflag) { ! 924: if (tgt_dev != lp->l_tdev) { ! 925: errprint(fmt4, target, nolink, " to ", cp); ! 926: ++broken; ! 927: ret = FALSE; ! 928: } ! 929: else { ! 930: vprintf(); ! 931: ret = TRUE; ! 932: } ! 933: } ! 934: else if (link(cp, target) == 0) { ! 935: vprintf(); ! 936: ret = TRUE; ! 937: } ! 938: else { ! 939: errprint(fmt4, target, nolink, " to ", cp); ! 940: ++broken; ! 941: ret = FALSE; ! 942: } ! 943: ! 944: if (lp->l_nlink == 0) ! 945: linkpurge(SOURCE, lp); ! 946: return (ret); ! 947: } ! 948: ! 949: bool ! 950: tgtunlink() ! 951: { ! 952: register LINK *lp; ! 953: ! 954: if (stat(target, &tgtstat) < 0) ! 955: return (TRUE); ! 956: if ((tgtstat.st_mode & S_IFMT) == S_IFDIR) { ! 957: errprint(fmt3, target, nounlink, "directory"); ! 958: return (FALSE); ! 959: } ! 960: else if ((tgtstat.st_mode & S_IFMT) != (srcstat.st_mode & S_IFMT)) { ! 961: errprint(fmt3, source, "file type mismatch with ", target); ! 962: return (FALSE); ! 963: } ! 964: ! 965: if (!tflag) ! 966: if (unlink(target) < 0) { ! 967: errprint(fmt2, target, nounlink); ! 968: return (FALSE); ! 969: } ! 970: if (tflag) ! 971: printf(fmt2, target, "unlinked"); ! 972: ! 973: if ((lp = linklocate(TARGET)) != NULL) { ! 974: if (lp->l_nlink == 0) ! 975: linkpurge(TARGET, lp); ! 976: } ! 977: else if (tgtstat.st_nlink > 1) ! 978: linkinstall(TARGET); ! 979: return (TRUE); ! 980: } ! 981: ! 982: report() ! 983: { ! 984: register LINK *lp; ! 985: register LINK **lpp; ! 986: static char *fmtlinks = "%s external links into hierarchy %s:\n"; ! 987: ! 988: if (!wflag) ! 989: return; ! 990: if (broken) ! 991: printf("%d internal link%s broken\n", broken, ! 992: (broken == 1) ? "" : "s"); ! 993: if (srclinks) { ! 994: printf(fmtlinks, "missed", dir1); ! 995: for (lpp = srctab; lpp < srctab + HASHSIZE; ++lpp) ! 996: for (lp = *lpp; lp != NULL; lp = lp->l_next) ! 997: printf("\t%d\t%s (inode %d)\n", lp->l_nlink, ! 998: concat(dir1, lp->l_name), lp->l_ino); ! 999: } ! 1000: if (tgtlinks) { ! 1001: printf(fmtlinks, "broken", target); ! 1002: for (lpp = tgttab; lpp < tgttab + HASHSIZE; ++lpp) ! 1003: for (lp = *lpp; lp != NULL; lp = lp->l_next) ! 1004: printf("\t%d\t%s (inode %d)\n", lp->l_nlink, ! 1005: concat(dir2, lp->l_name), lp->l_ino); ! 1006: } ! 1007: return; ! 1008: } ! 1009: ! 1010: /* ! 1011: * Chown, chmod, and chdate target. Assume srcstat has status of source, ! 1012: * and tgtstat has status of target if it exists. ! 1013: */ ! 1014: adjust() ! 1015: { ! 1016: time_t date[2]; ! 1017: ! 1018: if (tflag) ! 1019: return; ! 1020: if (root) ! 1021: chown(target, srcstat.st_uid, srcstat.st_gid); ! 1022: else ! 1023: chown(target, uid, gid); ! 1024: chmod(target, srcstat.st_mode & (root ? 07777 : 06777)); ! 1025: if (dflag) { ! 1026: time(&date[0]); ! 1027: date[1] = srcstat.st_mtime; ! 1028: utime(target, date); ! 1029: } ! 1030: return; ! 1031: } ! 1032: ! 1033: /* ! 1034: * Concatenate pieces of pathnames, a and b. If a is not "/" a '/' char ! 1035: * is placed between the names. Previous return is freed. ! 1036: */ ! 1037: char * ! 1038: concat(a, b) ! 1039: register char *a; ! 1040: char *b; ! 1041: { ! 1042: static char *ret; ! 1043: register int a1; ! 1044: register char *rp; ! 1045: ! 1046: if (ret != NULL) ! 1047: free(ret); ! 1048: a1 = strlen(a); ! 1049: rp = ret = tmalloc(a1 + strlen(b) + 2); ! 1050: strcpy(rp, a); ! 1051: rp += a1; ! 1052: if (!isslash(ret)) ! 1053: *rp++ = '/'; ! 1054: strcpy(rp, b); ! 1055: return (ret); ! 1056: } ! 1057: ! 1058: char * ! 1059: parent(cp) ! 1060: register char *cp; ! 1061: { ! 1062: static char *ret; ! 1063: register char *cp0; ! 1064: ! 1065: if (ret != NULL) ! 1066: free(ret); ! 1067: if ((cp0 = rindex(cp, '/')) == NULL) ! 1068: return (dot); ! 1069: ret = tmalloc(cp0 - cp + 1); ! 1070: strncpy(ret, cp, cp0 - cp); ! 1071: return (ret); ! 1072: } ! 1073: ! 1074: bool ! 1075: isslash(cp) ! 1076: register char *cp; ! 1077: { ! 1078: register int c; ! 1079: while ((c = *cp++) != '\0') ! 1080: if (c != '/') ! 1081: return (FALSE); ! 1082: return (TRUE); ! 1083: } ! 1084: ! 1085: /* ! 1086: * Routine exectuted when SIGINT or SIGHUP caught. ! 1087: * Set the interrupted flag. ! 1088: */ ! 1089: onintr() ! 1090: { ! 1091: signal(SIGINT, SIG_IGN); ! 1092: signal(SIGHUP, SIG_IGN); ! 1093: ++interrupted; ! 1094: } ! 1095: ! 1096: /* ! 1097: * If sig's handler is currently SIG_DFL, ! 1098: * catch it with onintr and return 1. ! 1099: * If not, leave its handler unchanged and return 0. ! 1100: */ ! 1101: int ! 1102: catch(sig) int sig; ! 1103: { ! 1104: int (*old)(); ! 1105: ! 1106: if ((old = signal(sig, SIG_IGN)) == SIG_DFL) { ! 1107: signal(sig, onintr); ! 1108: return 1; ! 1109: } ! 1110: signal(sig, old); ! 1111: return 0; ! 1112: } ! 1113: ! 1114: vprintf() ! 1115: { ! 1116: if (vflag) ! 1117: printf(fmt1, target); ! 1118: else if (aflag) { ! 1119: printf(fmt1a, target); ! 1120: fflush(stdout); ! 1121: } ! 1122: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.