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