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