|
|
1.1 ! root 1: /* ! 2: * reccp [-z] source dest ! 3: * ! 4: * or ! 5: * ! 6: * reccp [-z] source1 ... sourcen dest ! 7: * ! 8: * In the first case, dest must not be a directory (else we have a ! 9: * degenerate version of the second case). In the second case, ! 10: * dest must be a directory; the resulting objects will be ! 11: * named dest/source1 ... dest/sourcen. ! 12: * ! 13: * If any source is a directory, the tree structure under it ! 14: * will be (recursively) copied; this process will attempt to ! 15: * preserve any links that exist within the hierarchy. ! 16: * ! 17: * This version of reccp copies symbolic links as symbolic links. ! 18: * ! 19: * -z ==> copy blocks of zeros as holes. ! 20: */ ! 21: ! 22: #include <stdio.h> ! 23: #include <sys/types.h> ! 24: #include <sys/stat.h> ! 25: #include <signal.h> ! 26: ! 27: #define FTW_more_to_come 1 ! 28: #include <ftw.h> ! 29: /* rest of struct FTW: */ ! 30: int obase; /* added to give basename offset of output file */ ! 31: }; ! 32: /* #include "ftw.body" */ ! 33: /* ! 34: * Struct FTW (whose definition starts at the end of ftw.h) must ! 35: * must include at least the integers quit, base, and level. ! 36: */ ! 37: ! 38: #define FTW_PATHLEN0 1000 ! 39: #define FTW_PATHINC 1000 ! 40: #ifndef S_IFLNK ! 41: #define lstat stat ! 42: #endif ! 43: #ifdef S_IFSOCK ! 44: #include <sys/dir.h> ! 45: #else ! 46: #include "ndir.h" ! 47: #endif ! 48: #ifndef ENOMEM ! 49: #include <errno.h> ! 50: #endif ! 51: ! 52: extern int errno; ! 53: ! 54: /* ! 55: * Each generation of ftw1 (the real ftw) allocates one copy, R, of the ! 56: * following structure; it passes a pointer to this structure when it ! 57: * recursively invokes itself. These structures are chained together, ! 58: * so that if it becomes necessary to recycle file descriptors, then ! 59: * the oldest descriptor (the one at the shallowest depth still open) ! 60: * can be recycled. ! 61: */ ! 62: ! 63: struct FTW_rec { ! 64: struct FTW_rec *prev; ! 65: long here; /* seek to here when reopening at this level */ ! 66: DIR *fd; /* file descriptor at this level */ ! 67: }; ! 68: ! 69: /* ! 70: * One instance, T, of the following structure is allocated by ftw; a ! 71: * pointer to it is passed to all generations of ftw1 (the real ftw). ! 72: * T could often be a global variable, but this way the parameter fn ! 73: * can invoke ftw for an independent tree walk. ! 74: * Component T->path points to storage for the object path-names; ! 75: * this storage may be relocated by realloc if T->path needs to be ! 76: * more than T->pathlast characters long. ! 77: * T->path[T->pathnext] is the next free character in the pathnames. ! 78: * T->depth = parameter depth to ftw. T->lastout is the deepest level at ! 79: * which a file descriptor has been recycled. ! 80: */ ! 81: ! 82: struct FTW_top { ! 83: int (*fn)(); ! 84: char *path; ! 85: unsigned pathlast, pathnext; ! 86: int lastout; ! 87: int depth; ! 88: }; ! 89: ! 90: int ! 91: ftw (path, fn, depth) ! 92: char *path; ! 93: int (*fn)(); ! 94: int depth; ! 95: { ! 96: struct FTW_top T; ! 97: struct FTW_rec R; ! 98: struct FTW S; ! 99: int rc; ! 100: char *malloc(), *strcpy(); ! 101: ! 102: T.depth = depth; ! 103: T.lastout = -1; ! 104: T.fn = fn; ! 105: S.quit = 0; ! 106: S.level = -1; ! 107: ! 108: /* initialize S.base, T.pathnext... */ ! 109: { ! 110: register char c, *p, *q; ! 111: for (p = q = path; c = *p; p++) if (c == '/') q = p + 1; ! 112: S.base = q - path; ! 113: T.pathnext = p - path; ! 114: } ! 115: ! 116: T.pathlast = T.pathnext + FTW_PATHLEN0; ! 117: T.path = malloc(T.pathlast); ! 118: if (!T.path) { errno = ENOMEM; return -1; } ! 119: strcpy(T.path, path); ! 120: rc = ftw_1_(&R, &T, 0, &S); ! 121: free(T.path); ! 122: return rc; ! 123: } ! 124: ! 125: int ! 126: ftw_1_ (R, T, level, S1) ! 127: register struct FTW_rec *R; ! 128: register struct FTW_top *T; ! 129: int level; ! 130: struct FTW *S1; ! 131: { ! 132: int rc, n; ! 133: DIR *fd; ! 134: struct direct *dirp; ! 135: char *component, *path; ! 136: struct stat sb; ! 137: struct FTW_rec mr; ! 138: unsigned nextsave; ! 139: struct FTW S; ! 140: char *realloc(); ! 141: long lseek(); ! 142: ! 143: mr.prev = R; ! 144: path = T->path; ! 145: S.level = level; ! 146: S.quit = 0; ! 147: S.base = S1->base; ! 148: ! 149: /* Try to get file status. If unsuccessful, errno will say why. */ ! 150: if (lstat(path, &sb) < 0) { ! 151: badstat: rc = -1; ! 152: if (errno == EACCES) { ! 153: rc = (*T->fn) (path, &sb, FTW_NS, &S); ! 154: S1->quit = S.quit; ! 155: } ! 156: return rc; ! 157: }; ! 158: ! 159: /* ! 160: * The stat succeeded, so we know the object exists. ! 161: * If not a directory, call the user function and return. ! 162: */ ! 163: #ifdef S_IFLNK ! 164: if ((sb.st_mode & S_IFMT) == S_IFLNK) { ! 165: rc = (*T->fn) (path, &sb, FTW_SL, &S); ! 166: S1->quit = S.quit; ! 167: if (rc || S.quit == FTW_SKR) return rc; ! 168: if (S.quit != FTW_FOLLOW) return 0; ! 169: S1->quit = S.quit = 0; ! 170: if (stat(path, &sb) < 0) goto badstat; ! 171: } ! 172: #endif ! 173: ! 174: if ((sb.st_mode & S_IFMT) != S_IFDIR) { ! 175: rc = (*T->fn) (path, &sb, FTW_F, &S); ! 176: S1->quit = S.quit; ! 177: return rc; ! 178: } ! 179: ! 180: /* ! 181: * The object was a directory. ! 182: * ! 183: * Open a file to read the directory ! 184: */ ! 185: mr.fd = fd = opendir(path); ! 186: ! 187: /* ! 188: * Call the user function, telling it whether ! 189: * the directory can be read. If it can't be read ! 190: * call the user function or indicate an error, ! 191: * depending on the reason it couldn't be read. ! 192: */ ! 193: if (!fd) { ! 194: rc = -1; ! 195: if (errno == EACCES) { ! 196: rc = (*T->fn) (path, &sb, FTW_DNR, &S); ! 197: S1->quit = S.quit; ! 198: } ! 199: return rc; ! 200: } ! 201: ! 202: /* We could read the directory. Call user function. */ ! 203: rc = (*T->fn) (path, &sb, FTW_D, &S); ! 204: if (rc != 0) ! 205: return rc; ! 206: if (S.quit == FTW_SKD) return 0; ! 207: if (S.quit == FTW_SKR) {S1->quit = FTW_SKR; return 0;} ! 208: ! 209: /* Make sure path is big enough to hold generated pathnames. */ ! 210: ! 211: n = nextsave = T->pathnext; ! 212: if (n + MAXNAMLEN + 1 >= T->pathlast) { ! 213: T->pathlast += FTW_PATHINC; ! 214: path = T->path = realloc(T->path, T->pathlast); ! 215: if (!path) { ! 216: (void) closedir(fd); ! 217: errno = ENOMEM; ! 218: return -1; ! 219: } ! 220: } ! 221: ! 222: /* Create a prefix to which we will append component names */ ! 223: ! 224: if (n > 0 && path[n-1] != '/') path[n++] = '/'; ! 225: component = path + n; ! 226: ! 227: /* ! 228: * Read the directory one component at a time. ! 229: * We must ignore "." and "..", but other than that, ! 230: * just create a path name and call self to check it out. ! 231: */ ! 232: while (dirp = readdir(fd)) { ! 233: if (dirp->d_ino != 0 ! 234: && strcmp (dirp->d_name, ".") != 0 ! 235: && strcmp (dirp->d_name, "..") != 0) { ! 236: int i; ! 237: struct FTW_rec *pr; ! 238: ! 239: /* Append the component name to the working path */ ! 240: strcpy(component, dirp->d_name); ! 241: T->pathnext = n + strlen(dirp->d_name); ! 242: ! 243: /* ! 244: * If we are about to exceed our depth, ! 245: * remember where we are and close the file. ! 246: */ ! 247: if (level - T->lastout >= T->depth) { ! 248: pr = &mr; ! 249: i = T->lastout++; ! 250: while (++i < level) pr = pr->prev; ! 251: pr->here = telldir(pr->fd); ! 252: closedir(pr->fd); ! 253: } ! 254: ! 255: /* ! 256: * Do a recursive call to process the file. ! 257: */ ! 258: S.quit = 0; ! 259: S.base = n; ! 260: rc = ftw_1_(&mr, T, level+1, &S); ! 261: if (rc != 0 || S.quit == FTW_SKR) { ! 262: if (level > T->lastout) closedir(fd); ! 263: T->pathnext = nextsave; ! 264: return rc; ! 265: } ! 266: ! 267: /* ! 268: * If we closed the file, try to reopen it. ! 269: */ ! 270: if (level <= T->lastout) { ! 271: char c = path[nextsave]; ! 272: path[nextsave] = 0; ! 273: T->lastout = level - 1; ! 274: mr.fd = fd = opendir(path); ! 275: if (!fd) return -1; ! 276: path[nextsave] = c; ! 277: seekdir(fd, mr.here); ! 278: } ! 279: } ! 280: } ! 281: T->pathnext = nextsave; ! 282: path[nextsave] = 0; ! 283: ! 284: /* ! 285: * We got out of the subdirectory loop. Call the user ! 286: * function again at the end and clean up. ! 287: */ ! 288: ! 289: rc = (*T->fn) (path, &sb, FTW_DP, &S); ! 290: closedir(fd); ! 291: S1->quit = S.quit; ! 292: return rc; ! 293: } ! 294: ! 295: #define BLKSIZE BUFSIZ ! 296: char zero[BLKSIZE]; /* keep as zero */ ! 297: int zflag; ! 298: ! 299: /* destination path-name buffer initial value, increment */ ! 300: #define PATHLEN0 1000 ! 301: #define PATHINC 1000 ! 302: #define IHTABLEN 287 ! 303: #define SBUFLEN 1000 ! 304: ! 305: /* Non-zero if stat buffer b refers to a directory, zero otherwise */ ! 306: #define isdir(b) (((b).st_mode & S_IFMT) == S_IFDIR) ! 307: ! 308: char *malloc(), *realloc(), *strcpy(), *strcat(); ! 309: int copy(); ! 310: ! 311: char symbuf[SBUFLEN]; /* Buffer for symbolic link names */ ! 312: int firstyell = 1; ! 313: int destlen; /* length of destination (last arg) */ ! 314: int iamsu; ! 315: char *dest; ! 316: char *destdir; /* Storage for output pathname -- handled like ! 317: * the source pathname in ftw, subject to being ! 318: * relocated by realloc. ! 319: */ ! 320: unsigned dlast, dnext; /* Offsets of next available, last+1 chars of ! 321: * output pathname. ! 322: */ ! 323: ! 324: /* Final component of the path name by which we were invoked */ ! 325: char *pgmname; ! 326: ! 327: struct inodetab { /* for keeping track of links */ ! 328: struct inodetab *nextint; ! 329: ino_t i_ino; ! 330: dev_t i_dev; ! 331: char iname[1]; ! 332: }; ! 333: ! 334: struct inodetab *ihtab[IHTABLEN]; /* hash table for remembering links */ ! 335: ! 336: int retcode; ! 337: ! 338: main(argc, argv) ! 339: int argc; ! 340: char **argv; ! 341: { ! 342: char *p, *q; ! 343: struct stat *argbufs, destbuf, statbuf, rootbuf; ! 344: int i; ! 345: ! 346: umask(0); ! 347: pgmname = argv[0]; ! 348: ! 349: if (argc > 1 && !strcmp(argv[1],"-z")) { ! 350: zflag = 1; ! 351: --argc; ! 352: ++argv; ! 353: } ! 354: ! 355: /* ! 356: * Start validity checking ! 357: */ ! 358: ! 359: /* Check for too few arguments given */ ! 360: if (argc < 3) { ! 361: fprintf(stderr, ! 362: "usage: %s [-z] f1 f2 or %s [-z] f1 ... fn d\n", ! 363: pgmname, pgmname); ! 364: return 1; ! 365: } ! 366: ! 367: /* ! 368: * If the last argument is a non-directory, we require ! 369: * argc == 3 (in the case of: cp f1 f2) ! 370: */ ! 371: dest = argv[argc-1]; ! 372: destbuf.st_mode = 0; /* Force isdir(destbuf) false */ ! 373: if ((stat (dest, &destbuf) < 0 || !isdir(destbuf)) && argc != 3) { ! 374: scream ("%s not a directory", dest); ! 375: return 1; ! 376: } ! 377: ! 378: /* ! 379: * Allocate storage for a stat buffer for each argument ! 380: * but the last. This will be used to check for trying to ! 381: * copy something into a subdirectory of itself. ! 382: */ ! 383: argbufs = (struct stat *) ! 384: malloc ((unsigned) (sizeof (struct stat) * (argc-2))); ! 385: if (argbufs == NULL) { ! 386: scream ("insufficient storage", ""); ! 387: return 1; ! 388: } ! 389: iamsu = (getuid() == 0); ! 390: ! 391: for (i = 0; i < argc-2; i++) { ! 392: if (lstat (argv[i+1], &argbufs[i]) < 0) { ! 393: scream ("cannot access %s", argv[i+1]); ! 394: return 1; ! 395: } ! 396: } ! 397: ! 398: /* ! 399: * Now run back from the destination to the root directory, ! 400: * checking along the way for any matches with anything in ! 401: * the argbufs array. If we find any, we tried a forbidden ! 402: * operation. If the destination is not already a directory, ! 403: * we must start from its parent. Note that even in this case, ! 404: * we can't elide the test, because otherwise we wouldn't get ! 405: * ! 406: * cp . x ! 407: * ! 408: * This code also handles pathological but legal destinations ! 409: * properly; in particular note that the null string is a ! 410: * valid name for the current directory. Sigh. ! 411: * ! 412: * First figure out the name of the directory to check. ! 413: */ ! 414: dnext = destlen = strlen(dest); ! 415: dlast = destlen + 2; ! 416: if (dlast < PATHLEN0) dlast = PATHLEN0; ! 417: destdir = malloc(dlast); ! 418: if (!destdir) { scream ("no storage", ""); return 1; } ! 419: strcpy (destdir, dest); ! 420: if (!isdir (destbuf)) { ! 421: p = q = destdir; ! 422: while (*q) { ! 423: if (*q++ == '/') ! 424: p = q - 1; ! 425: } ! 426: if (p == destdir) { ! 427: strcpy (destdir, "."); ! 428: dnext = 1; ! 429: } ! 430: else { ! 431: *p = '\0'; ! 432: dnext = p - destdir; ! 433: } ! 434: } ! 435: ! 436: /* Now stat the root directory for later use */ ! 437: if (stat ("/", &rootbuf) < 0) { ! 438: scream ("cannot access root directory", ""); ! 439: return 1; ! 440: } ! 441: ! 442: /* Now run back from destdir to the root, checking against argbufs */ ! 443: do { ! 444: if (stat (destdir, &statbuf) < 0) { ! 445: scream ("cannot stat %s", destdir); ! 446: return 1; ! 447: } ! 448: for (i = 0; i < argc-2; i++) ! 449: if (argbufs[i].st_dev == statbuf.st_dev ! 450: && argbufs[i].st_ino == statbuf.st_ino) { ! 451: fprintf (stderr, "%s: %s contains %s\n", ! 452: pgmname, argv[i+1], dest); ! 453: return 1; ! 454: } ! 455: dcheck(3, "initial arg checking"); ! 456: strcpy(destdir+dnext, "/.."); ! 457: dnext += 3; ! 458: } while (statbuf.st_dev != rootbuf.st_dev ! 459: || statbuf.st_ino != rootbuf.st_ino); ! 460: ! 461: /* ! 462: * End of validity checking ! 463: */ ! 464: ! 465: strcpy(destdir, dest); ! 466: for (i = 0; i < IHTABLEN; i++) ihtab[i] = 0; ! 467: if (isdir(destbuf)) { ! 468: destdir[destlen] = '/'; ! 469: dnext = destlen + 1; ! 470: for (i = 1; i < argc-1; i++) { ! 471: ! 472: char *p, *q; ! 473: ! 474: p = q = argv[i]; ! 475: while (*p) ! 476: if (*p++ == '/') ! 477: q = p; ! 478: dnext = destlen + (p - q) + 1; ! 479: ! 480: p = destdir + destlen; ! 481: *p = '/'; ! 482: strcpy(p+1, q); ! 483: retcode |= ftw(argv[i], copy, 12); ! 484: } ! 485: } ! 486: ! 487: else { ! 488: dnext = destlen; ! 489: retcode = ftw(argv[1], copy, 12); ! 490: } ! 491: ! 492: return retcode; ! 493: } ! 494: ! 495: int ! 496: copy(source, srcbuf, code, S) ! 497: char *source; ! 498: struct stat *srcbuf; ! 499: int code; ! 500: struct FTW *S; ! 501: { ! 502: char *s; ! 503: int rc, slen; ! 504: ! 505: switch(code) { ! 506: ! 507: case FTW_F: /* nondirectory */ ! 508: ! 509: dcheck(MAXNAMLEN+1,source); ! 510: if (S->level) ! 511: strcpy(destdir + dnext, source + S->base); ! 512: return copy1(source, srcbuf, destdir); ! 513: ! 514: case FTW_D: /* new directory */ ! 515: ! 516: dcheck(MAXNAMLEN+1,source); ! 517: S->obase = dnext; ! 518: s = destdir+dnext; ! 519: if (S->level) { ! 520: for (source += S->base; *s = *source;) ! 521: { s++, source++; } ! 522: } ! 523: dnext = s - destdir; ! 524: if (mkdir(destdir,0700)) { ! 525: scream("can't mkdir %s", destdir); ! 526: return 1; ! 527: } ! 528: *s++ = '/'; *s = 0; ! 529: ++dnext; ! 530: return 0; ! 531: ! 532: case FTW_DNR: /* unreadable directory */ ! 533: ! 534: scream("can't read %s", source); ! 535: return 1; ! 536: ! 537: case FTW_NS: /* unstatable file */ ! 538: ! 539: scream("can't stat %s", source); ! 540: return 1; ! 541: ! 542: case FTW_DP: /* end of directory */ ! 543: ! 544: destdir[dnext-1] = 0; ! 545: dnext = S->obase; ! 546: if (chmod(destdir, (int)srcbuf->st_mode)) ! 547: scream("can't chmod %s", destdir); ! 548: if(iamsu && chown(destdir, srcbuf->st_uid, ! 549: srcbuf->st_gid)) ! 550: scream("can't chown %s", destdir); ! 551: return settime(srcbuf, destdir); ! 552: ! 553: #ifdef S_IFLNK ! 554: case FTW_SL: /* symbolic link */ ! 555: ! 556: slen = readlink(source, symbuf, SBUFLEN); ! 557: if (slen >= SBUFLEN) { ! 558: scream("Symbolic path to %s too long.", ! 559: source); ! 560: return 1; ! 561: } ! 562: dcheck(MAXNAMLEN+1,source); ! 563: symbuf[slen] = 0; ! 564: if (S->level) strcpy(destdir + dnext, ! 565: source + S->base); ! 566: rc = 0; ! 567: umask(~(int)srcbuf->st_mode); ! 568: if (symlink(symbuf,destdir)) { ! 569: fprintf(stderr, ! 570: "%s: can't symbolically link %s to %s\n", ! 571: pgmname, destdir, symbuf); ! 572: rc = 1; ! 573: } ! 574: umask(0); ! 575: return rc; ! 576: #endif ! 577: ! 578: default: /* bug */ ! 579: fprintf(stderr,"%s: unknown code = %d from ftw\n", ! 580: pgmname, code); ! 581: exit(1); ! 582: } ! 583: } ! 584: ! 585: /* ! 586: * Copy a file. The source file name is in "source", ! 587: * and the destination file name is in "dest". "srcbuf" points to ! 588: * a stat buffer for the source. ! 589: */ ! 590: ! 591: int ! 592: copy1(source, srcbuf, dest) ! 593: char *source, *dest; ! 594: struct stat *srcbuf; ! 595: { ! 596: int bsize, inf, outf, n, type, zsize; ! 597: char buffer[BLKSIZE]; ! 598: struct stat destbuf; ! 599: long lseek(); ! 600: ! 601: if (stat (dest, &destbuf) >= 0 ! 602: && srcbuf->st_dev == destbuf.st_dev ! 603: && srcbuf->st_ino == destbuf.st_ino) { ! 604: scream ("cannot copy %s to itself", source); ! 605: return 1; ! 606: } ! 607: ! 608: switch(type = srcbuf->st_mode & S_IFMT) { ! 609: ! 610: case S_IFCHR: /* character special */ ! 611: case S_IFBLK: /* block special */ ! 612: if (!iamsu) { ! 613: scream("can't copy special file %s", source); ! 614: return 1; ! 615: } ! 616: if (n = linkchk(srcbuf,destdir)) return n-1; ! 617: if (mknod(destdir, (int) srcbuf->st_mode, ! 618: (int) srcbuf->st_rdev)) { ! 619: scream("can't create %s", destdir); ! 620: return 1; ! 621: } ! 622: goto finish; ! 623: ! 624: case S_IFREG: /* regular file */ ! 625: if (n = linkchk(srcbuf,destdir)) return n-1; ! 626: break; ! 627: ! 628: default: ! 629: fprintf(stderr, ! 630: "%s: unknown file type 0x%x for %s\n", ! 631: pgmname, type, source); ! 632: return 1; ! 633: } ! 634: ! 635: /* Now copy the file, whether or not there was a link */ ! 636: ! 637: if ((outf = creat (dest, (int) (srcbuf->st_mode & 0777))) < 0) { ! 638: scream ("cannot create %s", dest); ! 639: return 1; ! 640: } ! 641: if ((inf = open (source, 0)) < 0) { ! 642: scream ("cannot open %s", source); ! 643: close(outf); ! 644: return 1; ! 645: } ! 646: if (zflag) { ! 647: fstat(outf, &destbuf); ! 648: bsize = BSIZE(destbuf.st_dev); ! 649: if (bsize > BLKSIZE) { ! 650: fprintf(stderr, "%s: BSIZE(%s) > %d\n", pgmname, ! 651: dest, BLKSIZE); ! 652: return 1; ! 653: } ! 654: } ! 655: else bsize = BLKSIZE; ! 656: zsize = 0; ! 657: while ((n = read (inf, buffer, bsize)) > 0) { ! 658: if (zflag && (n == bsize) && !memcmp(buffer, zero, bsize)) { ! 659: if (lseek(outf, (long)bsize, 1) < 0) { ! 660: scream("lseek (for block of 0's) failed on %s", ! 661: dest); ! 662: goto endit; ! 663: } ! 664: zsize = bsize; ! 665: } ! 666: else if (write (outf, buffer, n) != n) { ! 667: scream ("output error on %s", dest); ! 668: endit: ! 669: close (inf); ! 670: close (outf); ! 671: return 1; ! 672: } ! 673: else zsize = 0; ! 674: } ! 675: if (n < 0) { ! 676: scream ("input error on %s", source); ! 677: goto endit; ! 678: } ! 679: if (zsize && (lseek(outf, (long)-zsize, 1) < 0 ! 680: || write(outf,zero,zsize) != zsize)) { ! 681: scream("error writing trailing 0's from %s", source); ! 682: goto endit; ! 683: } ! 684: if (close (outf) < 0) { ! 685: scream ("cannot close %s", dest); ! 686: close (inf); ! 687: return 1; ! 688: } ! 689: if (close (inf) < 0) { ! 690: scream ("cannot close %s", source); ! 691: return 1; ! 692: } ! 693: ! 694: finish: ! 695: if(iamsu && chown(dest, srcbuf->st_uid, srcbuf->st_gid)) { ! 696: scream("can't chown %s", dest); ! 697: return 1; ! 698: } ! 699: return settime(srcbuf, dest); ! 700: } ! 701: ! 702: scream (s1, s2) ! 703: char *s1, *s2; ! 704: { ! 705: fprintf (stderr, "%s: ", pgmname); ! 706: fprintf (stderr, s1, s2); ! 707: putc ('\n', stderr); ! 708: retcode |= 1; ! 709: } ! 710: ! 711: dcheck(len, source) ! 712: int len; ! 713: char *source; ! 714: { ! 715: int dnext1 = dnext + len; ! 716: if (dnext1 >= dlast) { ! 717: dlast += PATHINC; ! 718: destdir = realloc(destdir, dlast); ! 719: if (!destdir) { ! 720: scream("malloc failed on %s",source); ! 721: exit(1); ! 722: } ! 723: } ! 724: } ! 725: ! 726: int ! 727: linkchk(sb,d) ! 728: struct stat *sb; ! 729: char *d; ! 730: { ! 731: register struct inodetab *p, *p0; ! 732: struct stat buf; ! 733: ! 734: if (sb->st_nlink < 2) return 0; ! 735: ! 736: p0 = (struct inodetab *) ! 737: (((sb->st_dev + sb->st_ino) % IHTABLEN) + ihtab); ! 738: while ((p = p0->nextint) && ! 739: (p->i_ino != sb->st_ino || p->i_dev != sb->st_dev)) p0 = p; ! 740: ! 741: if (p) {/* If this is a link to a file already seen... */ ! 742: if (link(p->iname, d)) { ! 743: ! 744: /* unlink d and try again, unless d is a directory */ ! 745: ! 746: if (lstat(d,&buf) ! 747: || (buf.st_mode & S_IFMT) == S_IFDIR ! 748: || unlink(d) ! 749: || link(p->iname,d)) { ! 750: fprintf(stderr,"%s: can't link %s to %s\n", ! 751: pgmname, p->iname, d); ! 752: return 2; ! 753: } ! 754: } ! 755: return 1; ! 756: } ! 757: ! 758: /* This file has more than one link to it -- add it to the list */ ! 759: /* of files that may be seen later. */ ! 760: ! 761: p = (struct inodetab *) ! 762: malloc((unsigned) (sizeof(struct inodetab) + strlen(d))); ! 763: if (!p) { ! 764: if (firstyell) { ! 765: firstyell = 0; ! 766: scream("storage for links exhausted with %s", d); ! 767: } ! 768: return 0; ! 769: } ! 770: ! 771: p0->nextint = p; ! 772: p->nextint = 0; ! 773: p->i_ino = sb->st_ino; ! 774: p->i_dev = sb->st_dev; ! 775: strcpy(p->iname, d); ! 776: return 0; ! 777: } ! 778: ! 779: settime(srcbuf, dest) /* set time and mode of dest */ ! 780: struct stat *srcbuf; ! 781: char *dest; ! 782: { ! 783: time_t utimbuf[2]; ! 784: int m, rc = 0; ! 785: ! 786: utimbuf[0] = srcbuf->st_atime; ! 787: utimbuf[1] = srcbuf->st_mtime; ! 788: utime (dest, utimbuf); ! 789: ! 790: m = srcbuf->st_mode; ! 791: #ifdef S_ISVTX ! 792: if (m & S_ISVTX && !iamsu) { ! 793: scream("can't set save-text bit of %s", dest); ! 794: m &= ~S_ISVTX; ! 795: } ! 796: if ((m & (S_ISUID | S_ISGID | S_ISVTX)) && (rc = chmod(dest,m))) ! 797: #else ! 798: if ((m & (S_ISUID | S_ISGID)) && (rc = chmod(dest,m))) ! 799: #endif ! 800: scream("can't set mode of %s", dest); ! 801: return rc; ! 802: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.