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