Annotation of 43BSDReno/bin/tar/tar.c, revision 1.1.1.1

1.1       root        1: /*
                      2:  * Copyright (c) 1980 Regents of the University of California.
                      3:  * All rights reserved.  The Berkeley software License Agreement
                      4:  * specifies the terms and conditions for redistribution.
                      5:  */
                      6: 
                      7: #ifndef lint
                      8: char copyright[] =
                      9: "@(#) Copyright (c) 1980 Regents of the University of California.\n\
                     10:  All rights reserved.\n";
                     11: #endif /* not lint */
                     12: 
                     13: #ifndef lint
                     14: static char sccsid[] = "@(#)tar.c      5.15 (Berkeley) 5/15/90";
                     15: #endif /* not lint */
                     16: 
                     17: /*
                     18:  * Tape Archival Program
                     19:  */
                     20: #include <sys/param.h>
                     21: #include <sys/stat.h>
                     22: #include <sys/file.h>
                     23: #include <sys/dir.h>
                     24: #include <sys/ioctl.h>
                     25: #include <sys/mtio.h>
                     26: #include <sys/time.h>
                     27: #include <signal.h>
                     28: #include <errno.h>
                     29: #include <fcntl.h>
                     30: #include <string.h>
                     31: #include <stdio.h>
                     32: #include "pathnames.h"
                     33: 
                     34: #define TBLOCK 512
                     35: #define NBLOCK 20
                     36: #define NAMSIZ 100
                     37: 
                     38: #define        writetape(b)    writetbuf(b, 1)
                     39: #define        min(a,b)  ((a) < (b) ? (a) : (b))
                     40: #define        max(a,b)  ((a) > (b) ? (a) : (b))
                     41: 
                     42: union hblock {
                     43:        char dummy[TBLOCK];
                     44:        struct header {
                     45:                char name[NAMSIZ];
                     46:                char mode[8];
                     47:                char uid[8];
                     48:                char gid[8];
                     49:                char size[12];
                     50:                char mtime[12];
                     51:                char chksum[8];
                     52:                char linkflag;
                     53:                char linkname[NAMSIZ];
                     54:        } dbuf;
                     55: };
                     56: 
                     57: struct linkbuf {
                     58:        ino_t   inum;
                     59:        dev_t   devnum;
                     60:        int     count;
                     61:        char    pathname[NAMSIZ];
                     62:        struct  linkbuf *nextp;
                     63: };
                     64: 
                     65: union  hblock dblock;
                     66: union  hblock *tbuf;
                     67: struct linkbuf *ihead;
                     68: struct stat stbuf;
                     69: 
                     70: int    rflag;
                     71: int    sflag;
                     72: int    xflag;
                     73: int    vflag;
                     74: int    tflag;
                     75: int    cflag;
                     76: int    mflag;
                     77: int    fflag;
                     78: int    iflag;
                     79: int    oflag;
                     80: int    pflag;
                     81: int    wflag;
                     82: int    hflag;
                     83: int    Bflag;
                     84: int    Fflag;
                     85: 
                     86: int    mt;
                     87: int    term;
                     88: int    chksum;
                     89: int    recno;
                     90: int    first;
                     91: int    prtlinkerr;
                     92: int    freemem = 1;
                     93: int    nblock = 0;
                     94: int    onintr();
                     95: int    onquit();
                     96: int    onhup();
                     97: #ifdef notdef
                     98: int    onterm();
                     99: #endif
                    100: 
                    101: daddr_t        low;
                    102: daddr_t        high;
                    103: daddr_t        bsrch();
                    104: 
                    105: FILE   *vfile = stdout;
                    106: FILE   *tfile;
                    107: char   tname[] = _PATH_TMP;
                    108: char   *usefile;
                    109: char   magtape[] = _PATH_MAGTAPE;
                    110: char   *malloc();
                    111: long   time();
                    112: off_t  lseek();
                    113: char   *mktemp();
                    114: char   *getcwd();
                    115: char   *getwd();
                    116: char   *getmem();
                    117: 
                    118: extern int errno;
                    119: 
                    120: main(argc, argv)
                    121:        int argc;
                    122:        char **argv;
                    123: {
                    124:        char *cp;
                    125: 
                    126:        if (argc < 2)
                    127:                usage();
                    128: 
                    129:        tfile = NULL;
                    130:        usefile =  magtape;
                    131:        argv[argc] = 0;
                    132:        argv++;
                    133:        for (cp = *argv++; *cp; cp++) 
                    134:                switch(*cp) {
                    135: 
                    136:                case 'f':
                    137:                        if (*argv == 0) {
                    138:                                fprintf(stderr,
                    139:                        "tar: tapefile must be specified with 'f' option\n");
                    140:                                usage();
                    141:                        }
                    142:                        usefile = *argv++;
                    143:                        fflag++;
                    144:                        break;
                    145: 
                    146:                case 'c':
                    147:                        cflag++;
                    148:                        rflag++;
                    149:                        break;
                    150: 
                    151:                case 'o':
                    152:                        oflag++;
                    153:                        break;
                    154: 
                    155:                case 'p':
                    156:                        pflag++;
                    157:                        break;
                    158:                
                    159:                case 'u':
                    160:                        (void)mktemp(tname);
                    161:                        if ((tfile = fopen(tname, "w")) == NULL) {
                    162:                                fprintf(stderr,
                    163:                                 "tar: cannot create temporary file (%s)\n",
                    164:                                 tname);
                    165:                                done(1);
                    166:                        }
                    167:                        fprintf(tfile, "!!!!!/!/!/!/!/!/!/! 000\n");
                    168:                        /*FALL THRU*/
                    169: 
                    170:                case 'r':
                    171:                        rflag++;
                    172:                        break;
                    173: 
                    174:                case 's':
                    175:                        sflag++;
                    176:                        break;
                    177: 
                    178:                case 'v':
                    179:                        vflag++;
                    180:                        break;
                    181: 
                    182:                case 'w':
                    183:                        wflag++;
                    184:                        break;
                    185: 
                    186:                case 'x':
                    187:                        xflag++;
                    188:                        break;
                    189: 
                    190:                case 't':
                    191:                        tflag++;
                    192:                        break;
                    193: 
                    194:                case 'm':
                    195:                        mflag++;
                    196:                        break;
                    197: 
                    198:                case '-':
                    199:                        break;
                    200: 
                    201:                case '0':
                    202:                case '1':
                    203:                case '4':
                    204:                case '5':
                    205:                case '7':
                    206:                case '8':
                    207:                        magtape[8] = *cp;
                    208:                        usefile = magtape;
                    209:                        break;
                    210: 
                    211:                case 'b':
                    212:                        if (*argv == 0) {
                    213:                                fprintf(stderr,
                    214:                        "tar: blocksize must be specified with 'b' option\n");
                    215:                                usage();
                    216:                        }
                    217:                        nblock = atoi(*argv);
                    218:                        if (nblock <= 0) {
                    219:                                fprintf(stderr,
                    220:                                    "tar: invalid blocksize \"%s\"\n", *argv);
                    221:                                done(1);
                    222:                        }
                    223:                        argv++;
                    224:                        break;
                    225: 
                    226:                case 'l':
                    227:                        prtlinkerr++;
                    228:                        break;
                    229: 
                    230:                case 'h':
                    231:                        hflag++;
                    232:                        break;
                    233: 
                    234:                case 'i':
                    235:                        iflag++;
                    236:                        break;
                    237: 
                    238:                case 'B':
                    239:                        Bflag++;
                    240:                        break;
                    241: 
                    242:                case 'F':
                    243:                        Fflag++;
                    244:                        break;
                    245: 
                    246:                default:
                    247:                        fprintf(stderr, "tar: %c: unknown option\n", *cp);
                    248:                        usage();
                    249:                }
                    250: 
                    251:        if (!rflag && !xflag && !tflag)
                    252:                usage();
                    253:        if (rflag) {
                    254:                if (cflag && tfile != NULL)
                    255:                        usage();
                    256:                if (signal(SIGINT, SIG_IGN) != SIG_IGN)
                    257:                        (void) signal(SIGINT, onintr);
                    258:                if (signal(SIGHUP, SIG_IGN) != SIG_IGN)
                    259:                        (void) signal(SIGHUP, onhup);
                    260:                if (signal(SIGQUIT, SIG_IGN) != SIG_IGN)
                    261:                        (void) signal(SIGQUIT, onquit);
                    262: #ifdef notdef
                    263:                if (signal(SIGTERM, SIG_IGN) != SIG_IGN)
                    264:                        (void) signal(SIGTERM, onterm);
                    265: #endif
                    266:                mt = openmt(usefile, 1);
                    267:                dorep(argv);
                    268:                done(0);
                    269:        }
                    270:        mt = openmt(usefile, 0);
                    271:        if (xflag)
                    272:                doxtract(argv);
                    273:        else
                    274:                dotable(argv);
                    275:        done(0);
                    276: }
                    277: 
                    278: usage()
                    279: {
                    280:        fprintf(stderr,
                    281: "tar: usage: tar -{txru}[cvfblmhopwBi] [tapefile] [blocksize] file1 file2...\n");
                    282:        done(1);
                    283: }
                    284: 
                    285: int
                    286: openmt(tape, writing)
                    287:        char *tape;
                    288:        int writing;
                    289: {
                    290:        if (strcmp(tape, "-") == 0) {
                    291:                /*
                    292:                 * Read from standard input or write to standard output.
                    293:                 */
                    294:                if (writing) {
                    295:                        if (cflag == 0) {
                    296:                                fprintf(stderr,
                    297:                         "tar: can only create standard output archives\n");
                    298:                                done(1);
                    299:                        }
                    300:                        vfile = stderr;
                    301:                        setlinebuf(vfile);
                    302:                        mt = dup(1);
                    303:                } else {
                    304:                        mt = dup(0);
                    305:                        Bflag++;
                    306:                }
                    307:        } else {
                    308:                /*
                    309:                 * Use file or tape on local machine.
                    310:                 */
                    311:                if (writing) {
                    312:                        if (cflag)
                    313:                                mt = open(tape, O_RDWR|O_CREAT|O_TRUNC, 0666);
                    314:                        else
                    315:                                mt = open(tape, O_RDWR);
                    316:                } else
                    317:                        mt = open(tape, O_RDONLY);
                    318:                if (mt < 0) {
                    319:                        fprintf(stderr, "tar: %s: %s\n", tape, strerror(errno));
                    320:                        done(1);
                    321:                }
                    322:        }
                    323:        return(mt);
                    324: }
                    325: 
                    326: dorep(argv)
                    327:        char *argv[];
                    328: {
                    329:        register char *cp, *cp2;
                    330:        char wdir[MAXPATHLEN], tempdir[MAXPATHLEN], *parent;
                    331: 
                    332:        if (!cflag) {
                    333:                getdir();
                    334:                do {
                    335:                        passtape();
                    336:                        if (term)
                    337:                                done(0);
                    338:                        getdir();
                    339:                } while (!endtape());
                    340:                backtape();
                    341:                if (tfile != NULL) {
                    342:                        char buf[200];
                    343: 
                    344:                        (void)sprintf(buf,
                    345: "sort +0 -1 +1nr %s -o %s; awk '$1 != prev {print; prev=$1}' %s >%sX; mv %sX %s",
                    346:                                tname, tname, tname, tname, tname, tname);
                    347:                        fflush(tfile);
                    348:                        system(buf);
                    349:                        freopen(tname, "r", tfile);
                    350:                        fstat(fileno(tfile), &stbuf);
                    351:                        high = stbuf.st_size;
                    352:                }
                    353:        }
                    354: 
                    355:        (void) getcwd(wdir);
                    356:        while (*argv && ! term) {
                    357:                cp2 = *argv;
                    358:                if (!strcmp(cp2, "-C") && argv[1]) {
                    359:                        argv++;
                    360:                        if (chdir(*argv) < 0) {
                    361:                                fprintf(stderr,
                    362:                                    "tar: can't change directories to %s: %s\n",
                    363:                                    *argv, strerror(errno));
                    364:                        } else
                    365:                                (void) getcwd(wdir);
                    366:                        argv++;
                    367:                        continue;
                    368:                }
                    369:                parent = wdir;
                    370:                for (cp = *argv; *cp; cp++)
                    371:                        if (*cp == '/')
                    372:                                cp2 = cp;
                    373:                if (cp2 != *argv) {
                    374:                        *cp2 = '\0';
                    375:                        if (chdir(*argv) < 0) {
                    376:                                fprintf(stderr,
                    377:                                    "tar: can't change directories to %s: %s\n",
                    378:                                    *argv, strerror(errno));
                    379:                                continue;
                    380:                        }
                    381:                        parent = getcwd(tempdir);
                    382:                        *cp2 = '/';
                    383:                        cp2++;
                    384:                }
                    385:                putfile(*argv++, cp2, parent);
                    386:                if (chdir(wdir) < 0)
                    387:                        fprintf(stderr, "tar: cannot change back?: %s: %s\n",
                    388:                            wdir, strerror(errno));
                    389:        }
                    390:        putempty();
                    391:        putempty();
                    392:        flushtape();
                    393:        if (prtlinkerr == 0)
                    394:                return;
                    395:        for (; ihead != NULL; ihead = ihead->nextp) {
                    396:                if (ihead->count == 0)
                    397:                        continue;
                    398:                fprintf(stderr, "tar: missing links to %s\n", ihead->pathname);
                    399:        }
                    400: }
                    401: 
                    402: endtape()
                    403: {
                    404:        return (dblock.dbuf.name[0] == '\0');
                    405: }
                    406: 
                    407: getdir()
                    408: {
                    409:        register struct stat *sp;
                    410:        int i;
                    411: 
                    412: top:
                    413:        readtape((char *)&dblock);
                    414:        if (dblock.dbuf.name[0] == '\0')
                    415:                return;
                    416:        sp = &stbuf;
                    417:        sscanf(dblock.dbuf.mode, "%o", &i);
                    418:        sp->st_mode = i;
                    419:        sscanf(dblock.dbuf.uid, "%o", &i);
                    420:        sp->st_uid = i;
                    421:        sscanf(dblock.dbuf.gid, "%o", &i);
                    422:        sp->st_gid = i;
                    423:        sscanf(dblock.dbuf.size, "%lo", &sp->st_size);
                    424:        sscanf(dblock.dbuf.mtime, "%lo", &sp->st_mtime);
                    425:        sscanf(dblock.dbuf.chksum, "%o", &chksum);
                    426:        if (chksum != (i = checksum())) {
                    427:                fprintf(stderr, "tar: directory checksum error (%d != %d)\n",
                    428:                    chksum, i);
                    429:                if (iflag)
                    430:                        goto top;
                    431:                done(2);
                    432:        }
                    433:        /* strip off leading "/" if present */
                    434:        if (sflag && dblock.dbuf.name[0] == '/') {
                    435:                register char *cp1, *cp2;
                    436:                for (cp1 = cp2 = dblock.dbuf.name; *cp2 && *cp2 == '/'; ++cp2);
                    437:                if (!*cp2)
                    438:                        goto top;
                    439:                while (*cp1++ = *cp2++);
                    440:        }
                    441:        if (tfile != NULL)
                    442:                fprintf(tfile, "%s %s\n", dblock.dbuf.name, dblock.dbuf.mtime);
                    443: }
                    444: 
                    445: passtape()
                    446: {
                    447:        long blocks;
                    448:        char *bufp;
                    449: 
                    450:        if (dblock.dbuf.linkflag == '1')
                    451:                return;
                    452:        blocks = stbuf.st_size;
                    453:        blocks += TBLOCK-1;
                    454:        blocks /= TBLOCK;
                    455: 
                    456:        while (blocks-- > 0)
                    457:                (void) readtbuf(&bufp, TBLOCK);
                    458: }
                    459: 
                    460: putfile(longname, shortname, parent)
                    461:        char *longname;
                    462:        char *shortname;
                    463:        char *parent;
                    464: {
                    465:        int infile = 0;
                    466:        long blocks;
                    467:        char buf[TBLOCK];
                    468:        char *bigbuf;
                    469:        register char *cp;
                    470:        struct direct *dp;
                    471:        DIR *dirp;
                    472:        register int i;
                    473:        long l;
                    474:        char newparent[NAMSIZ+64];
                    475:        int     maxread;
                    476:        int     hint;           /* amount to write to get "in sync" */
                    477: 
                    478:        if (!hflag)
                    479:                i = lstat(shortname, &stbuf);
                    480:        else
                    481:                i = stat(shortname, &stbuf);
                    482:        if (i < 0) {
                    483:                fprintf(stderr, "tar: %s: %s\n", longname, strerror(errno));
                    484:                return;
                    485:        }
                    486:        if (tfile != NULL && checkupdate(longname) == 0)
                    487:                return;
                    488:        if (checkw('r', longname) == 0)
                    489:                return;
                    490:        if (Fflag && checkf(shortname, stbuf.st_mode, Fflag) == 0)
                    491:                return;
                    492: 
                    493:        switch (stbuf.st_mode & S_IFMT) {
                    494:        case S_IFDIR:
                    495:                for (i = 0, cp = buf; *cp++ = longname[i++];)
                    496:                        ;
                    497:                *--cp = '/';
                    498:                *++cp = 0  ;
                    499:                if (!oflag) {
                    500:                        if ((cp - buf) >= NAMSIZ) {
                    501:                                fprintf(stderr, "tar: %s: file name too long\n",
                    502:                                    longname);
                    503:                                return;
                    504:                        }
                    505:                        stbuf.st_size = 0;
                    506:                        tomodes(&stbuf);
                    507:                        strcpy(dblock.dbuf.name,buf);
                    508:                        (void)sprintf(dblock.dbuf.chksum, "%6o", checksum());
                    509:                        (void) writetape((char *)&dblock);
                    510:                }
                    511:                (void)sprintf(newparent, "%s/%s", parent, shortname);
                    512:                if (chdir(shortname) < 0) {
                    513:                        fprintf(stderr, "tar: chdir %s: %s\n",
                    514:                            shortname, strerror(errno));
                    515:                        return;
                    516:                }
                    517:                if ((dirp = opendir(".")) == NULL) {
                    518:                        fprintf(stderr, "tar: %s: directory read error\n",
                    519:                            longname);
                    520:                        if (chdir(parent) < 0) {
                    521:                                fprintf(stderr,
                    522:                                    "tar: cannot change back?: %s: %s\n",
                    523:                                    parent, strerror(errno));
                    524:                        }
                    525:                        return;
                    526:                }
                    527:                while ((dp = readdir(dirp)) != NULL && !term) {
                    528:                        if (!strcmp(".", dp->d_name) ||
                    529:                            !strcmp("..", dp->d_name))
                    530:                                continue;
                    531:                        strcpy(cp, dp->d_name);
                    532:                        l = telldir(dirp);
                    533:                        closedir(dirp);
                    534:                        putfile(buf, cp, newparent);
                    535:                        dirp = opendir(".");
                    536:                        seekdir(dirp, l);
                    537:                }
                    538:                closedir(dirp);
                    539:                if (chdir(parent) < 0) {
                    540:                        fprintf(stderr,
                    541:                            "tar: cannot change back?: %s: %s\n",
                    542:                            parent, strerror(errno));
                    543:                }
                    544:                break;
                    545: 
                    546:        case S_IFLNK:
                    547:                tomodes(&stbuf);
                    548:                if (strlen(longname) >= NAMSIZ) {
                    549:                        fprintf(stderr, "tar: %s: file name too long\n",
                    550:                            longname);
                    551:                        return;
                    552:                }
                    553:                strcpy(dblock.dbuf.name, longname);
                    554:                if (stbuf.st_size + 1 >= NAMSIZ) {
                    555:                        fprintf(stderr, "tar: %s: symbolic link too long\n",
                    556:                            longname);
                    557:                        return;
                    558:                }
                    559:                i = readlink(shortname, dblock.dbuf.linkname, NAMSIZ - 1);
                    560:                if (i < 0) {
                    561:                        fprintf(stderr,
                    562:                            "tar: can't read symbolic link %s: %s\n",
                    563:                            longname, strerror(errno));
                    564:                        return;
                    565:                }
                    566:                dblock.dbuf.linkname[i] = '\0';
                    567:                dblock.dbuf.linkflag = '2';
                    568:                if (vflag)
                    569:                        fprintf(vfile, "a %s symbolic link to %s\n",
                    570:                            longname, dblock.dbuf.linkname);
                    571:                (void)sprintf(dblock.dbuf.size, "%11lo", 0L);
                    572:                (void)sprintf(dblock.dbuf.chksum, "%6o", checksum());
                    573:                (void) writetape((char *)&dblock);
                    574:                break;
                    575: 
                    576:        case S_IFREG:
                    577:                if ((infile = open(shortname, 0)) < 0) {
                    578:                        fprintf(stderr, "tar: %s: %s\n",
                    579:                            longname, strerror(errno));
                    580:                        return;
                    581:                }
                    582:                tomodes(&stbuf);
                    583:                if (strlen(longname) >= NAMSIZ) {
                    584:                        fprintf(stderr, "tar: %s: file name too long\n",
                    585:                            longname);
                    586:                        close(infile);
                    587:                        return;
                    588:                }
                    589:                strcpy(dblock.dbuf.name, longname);
                    590:                if (stbuf.st_nlink > 1) {
                    591:                        struct linkbuf *lp;
                    592:                        int found = 0;
                    593: 
                    594:                        for (lp = ihead; lp != NULL; lp = lp->nextp)
                    595:                                if (lp->inum == stbuf.st_ino &&
                    596:                                    lp->devnum == stbuf.st_dev) {
                    597:                                        found++;
                    598:                                        break;
                    599:                                }
                    600:                        if (found) {
                    601:                                strcpy(dblock.dbuf.linkname, lp->pathname);
                    602:                                dblock.dbuf.linkflag = '1';
                    603:                                (void)sprintf(dblock.dbuf.chksum, "%6o", checksum());
                    604:                                (void) writetape( (char *) &dblock);
                    605:                                if (vflag)
                    606:                                        fprintf(vfile, "a %s link to %s\n",
                    607:                                            longname, lp->pathname);
                    608:                                lp->count--;
                    609:                                close(infile);
                    610:                                return;
                    611:                        }
                    612:                        lp = (struct linkbuf *) getmem(sizeof(*lp));
                    613:                        if (lp != NULL) {
                    614:                                lp->nextp = ihead;
                    615:                                ihead = lp;
                    616:                                lp->inum = stbuf.st_ino;
                    617:                                lp->devnum = stbuf.st_dev;
                    618:                                lp->count = stbuf.st_nlink - 1;
                    619:                                strcpy(lp->pathname, longname);
                    620:                        }
                    621:                }
                    622:                blocks = (stbuf.st_size + (TBLOCK-1)) / TBLOCK;
                    623:                if (vflag)
                    624:                        fprintf(vfile, "a %s %ld blocks\n", longname, blocks);
                    625:                (void)sprintf(dblock.dbuf.chksum, "%6o", checksum());
                    626:                hint = writetape((char *)&dblock);
                    627:                maxread = max(stbuf.st_blksize, (nblock * TBLOCK));
                    628:                if ((bigbuf = malloc((unsigned)maxread)) == 0) {
                    629:                        maxread = TBLOCK;
                    630:                        bigbuf = buf;
                    631:                }
                    632: 
                    633:                while ((i = read(infile, bigbuf, min((hint*TBLOCK), maxread))) > 0
                    634:                  && blocks > 0) {
                    635:                        register int nblks;
                    636: 
                    637:                        nblks = ((i-1)/TBLOCK)+1;
                    638:                        if (nblks > blocks)
                    639:                                nblks = blocks;
                    640:                        hint = writetbuf(bigbuf, nblks);
                    641:                        blocks -= nblks;
                    642:                }
                    643:                close(infile);
                    644:                if (bigbuf != buf)
                    645:                        free(bigbuf);
                    646:                if (i < 0) {
                    647:                        fprintf(stderr, "tar: Read error on %s: %s\n",
                    648:                            longname, strerror(errno));
                    649:                } else if (blocks != 0 || i != 0)
                    650:                        fprintf(stderr, "tar: %s: file changed size\n",
                    651:                            longname);
                    652:                while (--blocks >=  0)
                    653:                        putempty();
                    654:                break;
                    655: 
                    656:        default:
                    657:                fprintf(stderr, "tar: %s is not a file. Not dumped\n",
                    658:                    longname);
                    659:                break;
                    660:        }
                    661: }
                    662: 
                    663: doxtract(argv)
                    664:        char *argv[];
                    665: {
                    666:        long blocks, bytes;
                    667:        int ofile, i;
                    668: 
                    669:        for (;;) {
                    670:                if ((i = wantit(argv)) == 0)
                    671:                        continue;
                    672:                if (i == -1)
                    673:                        break;          /* end of tape */
                    674:                if (checkw('x', dblock.dbuf.name) == 0) {
                    675:                        passtape();
                    676:                        continue;
                    677:                }
                    678:                if (Fflag) {
                    679:                        char *s;
                    680: 
                    681:                        if ((s = rindex(dblock.dbuf.name, '/')) == 0)
                    682:                                s = dblock.dbuf.name;
                    683:                        else
                    684:                                s++;
                    685:                        if (checkf(s, stbuf.st_mode, Fflag) == 0) {
                    686:                                passtape();
                    687:                                continue;
                    688:                        }
                    689:                }
                    690:                if (checkdir(dblock.dbuf.name)) {       /* have a directory */
                    691:                        if (mflag == 0)
                    692:                                dodirtimes(&dblock);
                    693:                        continue;
                    694:                }
                    695:                if (dblock.dbuf.linkflag == '2') {      /* symlink */
                    696:                        /*
                    697:                         * only unlink non directories or empty
                    698:                         * directories
                    699:                         */
                    700:                        if (rmdir(dblock.dbuf.name) < 0) {
                    701:                                if (errno == ENOTDIR)
                    702:                                        unlink(dblock.dbuf.name);
                    703:                        }
                    704:                        if (symlink(dblock.dbuf.linkname, dblock.dbuf.name)<0) {
                    705:                                fprintf(stderr,
                    706:                                    "tar: %s: symbolic link failed: %s\n",
                    707:                                    dblock.dbuf.name, strerror(errno));
                    708:                                continue;
                    709:                        }
                    710:                        if (vflag)
                    711:                                fprintf(vfile, "x %s symbolic link to %s\n",
                    712:                                    dblock.dbuf.name, dblock.dbuf.linkname);
                    713: #ifdef notdef
                    714:                        /* ignore alien orders */
                    715:                        chown(dblock.dbuf.name, stbuf.st_uid, stbuf.st_gid);
                    716:                        if (mflag == 0)
                    717:                                setimes(dblock.dbuf.name, stbuf.st_mtime);
                    718:                        if (pflag)
                    719:                                chmod(dblock.dbuf.name, stbuf.st_mode & 07777);
                    720: #endif
                    721:                        continue;
                    722:                }
                    723:                if (dblock.dbuf.linkflag == '1') {      /* regular link */
                    724:                        /*
                    725:                         * only unlink non directories or empty
                    726:                         * directories
                    727:                         */
                    728:                        if (rmdir(dblock.dbuf.name) < 0) {
                    729:                                if (errno == ENOTDIR)
                    730:                                        unlink(dblock.dbuf.name);
                    731:                        }
                    732:                        if (link(dblock.dbuf.linkname, dblock.dbuf.name) < 0) {
                    733:                                fprintf(stderr,
                    734:                                    "tar: can't link %s to %s: %s\n",
                    735:                                    dblock.dbuf.name, dblock.dbuf.linkname,
                    736:                                    strerror(errno));
                    737:                                continue;
                    738:                        }
                    739:                        if (vflag)
                    740:                                fprintf(vfile, "%s linked to %s\n",
                    741:                                    dblock.dbuf.name, dblock.dbuf.linkname);
                    742:                        continue;
                    743:                }
                    744:                if ((ofile = creat(dblock.dbuf.name,stbuf.st_mode&0xfff)) < 0) {
                    745:                        fprintf(stderr, "tar: can't create %s: %s\n",
                    746:                            dblock.dbuf.name, strerror(errno));
                    747:                        passtape();
                    748:                        continue;
                    749:                }
                    750:                chown(dblock.dbuf.name, stbuf.st_uid, stbuf.st_gid);
                    751:                blocks = ((bytes = stbuf.st_size) + TBLOCK-1)/TBLOCK;
                    752:                if (vflag)
                    753:                        fprintf(vfile, "x %s, %ld bytes, %ld tape blocks\n",
                    754:                            dblock.dbuf.name, bytes, blocks);
                    755:                for (; blocks > 0;) {
                    756:                        register int nread;
                    757:                        char    *bufp;
                    758:                        register int nwant;
                    759:                        
                    760:                        nwant = NBLOCK*TBLOCK;
                    761:                        if (nwant > (blocks*TBLOCK))
                    762:                                nwant = (blocks*TBLOCK);
                    763:                        nread = readtbuf(&bufp, nwant);
                    764:                        if (write(ofile, bufp, (int)min(nread, bytes)) < 0) {
                    765:                                fprintf(stderr,
                    766:                                    "tar: %s: HELP - extract write error: %s\n",
                    767:                                    dblock.dbuf.name, strerror(errno));
                    768:                                done(2);
                    769:                        }
                    770:                        bytes -= nread;
                    771:                        blocks -= (((nread-1)/TBLOCK)+1);
                    772:                }
                    773:                close(ofile);
                    774:                if (mflag == 0)
                    775:                        setimes(dblock.dbuf.name, stbuf.st_mtime);
                    776:                if (pflag)
                    777:                        chmod(dblock.dbuf.name, stbuf.st_mode & 07777);
                    778:        }
                    779:        if (mflag == 0) {
                    780:                dblock.dbuf.name[0] = '\0';     /* process the whole stack */
                    781:                dodirtimes(&dblock);
                    782:        }
                    783: }
                    784: 
                    785: dotable(argv)
                    786:        char *argv[];
                    787: {
                    788:        register int i;
                    789: 
                    790:        for (;;) {
                    791:                if ((i = wantit(argv)) == 0)
                    792:                        continue;
                    793:                if (i == -1)
                    794:                        break;          /* end of tape */
                    795:                if (vflag)
                    796:                        longt(&stbuf);
                    797:                printf("%s", dblock.dbuf.name);
                    798:                if (dblock.dbuf.linkflag == '1')
                    799:                        printf(" linked to %s", dblock.dbuf.linkname);
                    800:                if (dblock.dbuf.linkflag == '2')
                    801:                        printf(" symbolic link to %s", dblock.dbuf.linkname);
                    802:                printf("\n");
                    803:                passtape();
                    804:        }
                    805: }
                    806: 
                    807: putempty()
                    808: {
                    809:        char buf[TBLOCK];
                    810: 
                    811:        bzero(buf, sizeof (buf));
                    812:        (void) writetape(buf);
                    813: }
                    814: 
                    815: longt(st)
                    816:        register struct stat *st;
                    817: {
                    818:        register char *cp;
                    819:        char *ctime();
                    820: 
                    821:        pmode(st);
                    822:        printf("%3u/%1u", st->st_uid, st->st_gid);
                    823:        printf("%7ld", st->st_size);
                    824:        cp = ctime(&st->st_mtime);
                    825:        printf(" %-12.12s %-4.4s ", cp+4, cp+20);
                    826: }
                    827: 
                    828: #define        SUID    04000
                    829: #define        SGID    02000
                    830: #define        ROWN    0400
                    831: #define        WOWN    0200
                    832: #define        XOWN    0100
                    833: #define        RGRP    040
                    834: #define        WGRP    020
                    835: #define        XGRP    010
                    836: #define        ROTH    04
                    837: #define        WOTH    02
                    838: #define        XOTH    01
                    839: #define        STXT    01000
                    840: int    m1[] = { 1, ROWN, 'r', '-' };
                    841: int    m2[] = { 1, WOWN, 'w', '-' };
                    842: int    m3[] = { 2, SUID, 's', XOWN, 'x', '-' };
                    843: int    m4[] = { 1, RGRP, 'r', '-' };
                    844: int    m5[] = { 1, WGRP, 'w', '-' };
                    845: int    m6[] = { 2, SGID, 's', XGRP, 'x', '-' };
                    846: int    m7[] = { 1, ROTH, 'r', '-' };
                    847: int    m8[] = { 1, WOTH, 'w', '-' };
                    848: int    m9[] = { 2, STXT, 't', XOTH, 'x', '-' };
                    849: 
                    850: int    *m[] = { m1, m2, m3, m4, m5, m6, m7, m8, m9};
                    851: 
                    852: pmode(st)
                    853:        register struct stat *st;
                    854: {
                    855:        register int **mp;
                    856: 
                    857:        for (mp = &m[0]; mp < &m[9];)
                    858:                selectbits(*mp++, st);
                    859: }
                    860: 
                    861: selectbits(pairp, st)
                    862:        int *pairp;
                    863:        struct stat *st;
                    864: {
                    865:        register int n, *ap;
                    866: 
                    867:        ap = pairp;
                    868:        n = *ap++;
                    869:        while (--n>=0 && (st->st_mode&*ap++)==0)
                    870:                ap++;
                    871:        putchar(*ap);
                    872: }
                    873: 
                    874: /*
                    875:  * Make all directories needed by `name'.  If `name' is itself
                    876:  * a directory on the tar tape (indicated by a trailing '/'),
                    877:  * return 1; else 0.
                    878:  */
                    879: checkdir(name)
                    880:        register char *name;
                    881: {
                    882:        register char *cp;
                    883: 
                    884:        /*
                    885:         * Quick check for existence of directory.
                    886:         */
                    887:        if ((cp = rindex(name, '/')) == 0)
                    888:                return (0);
                    889:        *cp = '\0';
                    890:        if (access(name, F_OK) == 0) {  /* already exists */
                    891:                *cp = '/';
                    892:                return (cp[1] == '\0'); /* return (lastchar == '/') */
                    893:        }
                    894:        *cp = '/';
                    895: 
                    896:        /*
                    897:         * No luck, try to make all directories in path.
                    898:         */
                    899:        for (cp = name; *cp; cp++) {
                    900:                if (*cp != '/')
                    901:                        continue;
                    902:                *cp = '\0';
                    903:                if (access(name, F_OK) < 0) {
                    904:                        if (mkdir(name, 0777) < 0) {
                    905:                                fprintf(stderr, "tar: mkdir: %s: %s\n",
                    906:                                    name, strerror(errno));
                    907:                                *cp = '/';
                    908:                                return (0);
                    909:                        }
                    910:                        chown(name, stbuf.st_uid, stbuf.st_gid);
                    911:                        if (pflag && cp[1] == '\0')     /* dir on the tape */
                    912:                                chmod(name, stbuf.st_mode & 07777);
                    913:                }
                    914:                *cp = '/';
                    915:        }
                    916:        return (cp[-1]=='/');
                    917: }
                    918: 
                    919: onintr()
                    920: {
                    921:        (void) signal(SIGINT, SIG_IGN);
                    922:        term++;
                    923: }
                    924: 
                    925: onquit()
                    926: {
                    927:        (void) signal(SIGQUIT, SIG_IGN);
                    928:        term++;
                    929: }
                    930: 
                    931: onhup()
                    932: {
                    933:        (void) signal(SIGHUP, SIG_IGN);
                    934:        term++;
                    935: }
                    936: 
                    937: #ifdef notdef
                    938: onterm()
                    939: {
                    940:        (void) signal(SIGTERM, SIG_IGN);
                    941:        term++;
                    942: }
                    943: #endif
                    944: 
                    945: tomodes(sp)
                    946: register struct stat *sp;
                    947: {
                    948:        register char *cp;
                    949: 
                    950:        for (cp = dblock.dummy; cp < &dblock.dummy[TBLOCK]; cp++)
                    951:                *cp = '\0';
                    952:        (void)sprintf(dblock.dbuf.mode, "%6o ", sp->st_mode & 07777);
                    953:        (void)sprintf(dblock.dbuf.uid, "%6o ", sp->st_uid);
                    954:        (void)sprintf(dblock.dbuf.gid, "%6o ", sp->st_gid);
                    955:        (void)sprintf(dblock.dbuf.size, "%11lo ", sp->st_size);
                    956:        (void)sprintf(dblock.dbuf.mtime, "%11lo ", sp->st_mtime);
                    957: }
                    958: 
                    959: checksum()
                    960: {
                    961:        register i;
                    962:        register char *cp;
                    963: 
                    964:        for (cp = dblock.dbuf.chksum;
                    965:             cp < &dblock.dbuf.chksum[sizeof(dblock.dbuf.chksum)]; cp++)
                    966:                *cp = ' ';
                    967:        i = 0;
                    968:        for (cp = dblock.dummy; cp < &dblock.dummy[TBLOCK]; cp++)
                    969:                i += *cp;
                    970:        return (i);
                    971: }
                    972: 
                    973: checkw(c, name)
                    974:        char *name;
                    975: {
                    976:        if (!wflag)
                    977:                return (1);
                    978:        printf("%c ", c);
                    979:        if (vflag)
                    980:                longt(&stbuf);
                    981:        printf("%s: ", name);
                    982:        return (response() == 'y');
                    983: }
                    984: 
                    985: response()
                    986: {
                    987:        char c;
                    988: 
                    989:        c = getchar();
                    990:        if (c != '\n')
                    991:                while (getchar() != '\n')
                    992:                        ;
                    993:        else
                    994:                c = 'n';
                    995:        return (c);
                    996: }
                    997: 
                    998: checkf(name, mode, howmuch)
                    999:        char *name;
                   1000:        int mode, howmuch;
                   1001: {
                   1002:        int l;
                   1003: 
                   1004:        if ((mode & S_IFMT) == S_IFDIR){
                   1005:                if ((strcmp(name, "SCCS")==0) || (strcmp(name, "RCS")==0)) 
                   1006:                        return(0); 
                   1007:                return(1);
                   1008:        }
                   1009:        if ((l = strlen(name)) < 3)
                   1010:                return (1);
                   1011:        if (howmuch > 1 && name[l-2] == '.' && name[l-1] == 'o')
                   1012:                return (0);
                   1013:        if (strcmp(name, "core") == 0 ||
                   1014:            strcmp(name, "errs") == 0 ||
                   1015:            (howmuch > 1 && strcmp(name, "a.out") == 0))
                   1016:                return (0);
                   1017:        /* SHOULD CHECK IF IT IS EXECUTABLE */
                   1018:        return (1);
                   1019: }
                   1020: 
                   1021: /* Is the current file a new file, or the newest one of the same name? */
                   1022: checkupdate(arg)
                   1023:        char *arg;
                   1024: {
                   1025:        char name[100];
                   1026:        long mtime;
                   1027:        daddr_t seekp;
                   1028:        daddr_t lookup();
                   1029: 
                   1030:        rewind(tfile);
                   1031:        for (;;) {
                   1032:                if ((seekp = lookup(arg)) < 0)
                   1033:                        return (1);
                   1034:                fseek(tfile, seekp, 0);
                   1035:                fscanf(tfile, "%s %lo", name, &mtime);
                   1036:                return (stbuf.st_mtime > mtime);
                   1037:        }
                   1038: }
                   1039: 
                   1040: done(n)
                   1041: {
                   1042:        unlink(tname);
                   1043:        exit(n);
                   1044: }
                   1045: 
                   1046: /* 
                   1047:  * Do we want the next entry on the tape, i.e. is it selected?  If
                   1048:  * not, skip over the entire entry.  Return -1 if reached end of tape.
                   1049:  */
                   1050: wantit(argv)
                   1051:        char *argv[];
                   1052: {
                   1053:        register char **cp;
                   1054: 
                   1055:        getdir();
                   1056:        if (endtape())
                   1057:                return (-1);
                   1058:        if (*argv == 0)
                   1059:                return (1);
                   1060:        for (cp = argv; *cp; cp++)
                   1061:                if (prefix(*cp, dblock.dbuf.name))
                   1062:                        return (1);
                   1063:        passtape();
                   1064:        return (0);
                   1065: }
                   1066: 
                   1067: /*
                   1068:  * Does s2 begin with the string s1, on a directory boundary?
                   1069:  */
                   1070: prefix(s1, s2)
                   1071:        register char *s1, *s2;
                   1072: {
                   1073:        while (*s1)
                   1074:                if (*s1++ != *s2++)
                   1075:                        return (0);
                   1076:        if (*s2)
                   1077:                return (*s2 == '/');
                   1078:        return (1);
                   1079: }
                   1080: 
                   1081: #define        N       200
                   1082: int    njab;
                   1083: 
                   1084: daddr_t
                   1085: lookup(s)
                   1086:        char *s;
                   1087: {
                   1088:        register i;
                   1089:        daddr_t a;
                   1090: 
                   1091:        for(i=0; s[i]; i++)
                   1092:                if (s[i] == ' ')
                   1093:                        break;
                   1094:        a = bsrch(s, i, low, high);
                   1095:        return (a);
                   1096: }
                   1097: 
                   1098: daddr_t
                   1099: bsrch(s, n, l, h)
                   1100:        daddr_t l, h;
                   1101:        char *s;
                   1102: {
                   1103:        register i, j;
                   1104:        char b[N];
                   1105:        daddr_t m, m1;
                   1106: 
                   1107:        njab = 0;
                   1108: 
                   1109: loop:
                   1110:        if (l >= h)
                   1111:                return ((daddr_t) -1);
                   1112:        m = l + (h-l)/2 - N/2;
                   1113:        if (m < l)
                   1114:                m = l;
                   1115:        fseek(tfile, m, 0);
                   1116:        fread(b, 1, N, tfile);
                   1117:        njab++;
                   1118:        for(i=0; i<N; i++) {
                   1119:                if (b[i] == '\n')
                   1120:                        break;
                   1121:                m++;
                   1122:        }
                   1123:        if (m >= h)
                   1124:                return ((daddr_t) -1);
                   1125:        m1 = m;
                   1126:        j = i;
                   1127:        for(i++; i<N; i++) {
                   1128:                m1++;
                   1129:                if (b[i] == '\n')
                   1130:                        break;
                   1131:        }
                   1132:        i = cmp(b+j, s, n);
                   1133:        if (i < 0) {
                   1134:                h = m;
                   1135:                goto loop;
                   1136:        }
                   1137:        if (i > 0) {
                   1138:                l = m1;
                   1139:                goto loop;
                   1140:        }
                   1141:        return (m);
                   1142: }
                   1143: 
                   1144: cmp(b, s, n)
                   1145:        char *b, *s;
                   1146: {
                   1147:        register i;
                   1148: 
                   1149:        if (b[0] != '\n')
                   1150:                exit(2);
                   1151:        for(i=0; i<n; i++) {
                   1152:                if (b[i+1] > s[i])
                   1153:                        return (-1);
                   1154:                if (b[i+1] < s[i])
                   1155:                        return (1);
                   1156:        }
                   1157:        return (b[i+1] == ' '? 0 : -1);
                   1158: }
                   1159: 
                   1160: readtape(buffer)
                   1161:        char *buffer;
                   1162: {
                   1163:        char *bufp;
                   1164: 
                   1165:        if (first == 0)
                   1166:                getbuf();
                   1167:        (void) readtbuf(&bufp, TBLOCK);
                   1168:        bcopy(bufp, buffer, TBLOCK);
                   1169:        return(TBLOCK);
                   1170: }
                   1171: 
                   1172: readtbuf(bufpp, size)
                   1173:        char **bufpp;
                   1174:        int size;
                   1175: {
                   1176:        register int i;
                   1177: 
                   1178:        if (recno >= nblock || first == 0) {
                   1179:                if ((i = bread(mt, (char *)tbuf, TBLOCK*nblock)) < 0)
                   1180:                        mterr("read", i, 3);
                   1181:                if (first == 0) {
                   1182:                        if ((i % TBLOCK) != 0) {
                   1183:                                fprintf(stderr, "tar: tape blocksize error\n");
                   1184:                                done(3);
                   1185:                        }
                   1186:                        i /= TBLOCK;
                   1187:                        if (i != nblock) {
                   1188:                                fprintf(stderr, "tar: blocksize = %d\n", i);
                   1189:                                nblock = i;
                   1190:                        }
                   1191:                        first = 1;
                   1192:                }
                   1193:                recno = 0;
                   1194:        }
                   1195:        if (size > ((nblock-recno)*TBLOCK))
                   1196:                size = (nblock-recno)*TBLOCK;
                   1197:        *bufpp = (char *)&tbuf[recno];
                   1198:        recno += (size/TBLOCK);
                   1199:        return (size);
                   1200: }
                   1201: 
                   1202: writetbuf(buffer, n)
                   1203:        register char *buffer;
                   1204:        register int n;
                   1205: {
                   1206:        int i;
                   1207: 
                   1208:        if (first == 0) {
                   1209:                getbuf();
                   1210:                first = 1;
                   1211:        }
                   1212:        if (recno >= nblock) {
                   1213:                i = write(mt, (char *)tbuf, TBLOCK*nblock);
                   1214:                if (i != TBLOCK*nblock)
                   1215:                        mterr("write", i, 2);
                   1216:                recno = 0;
                   1217:        }
                   1218: 
                   1219:        /*
                   1220:         *  Special case:  We have an empty tape buffer, and the
                   1221:         *  users data size is >= the tape block size:  Avoid
                   1222:         *  the bcopy and dma direct to tape.  BIG WIN.  Add the
                   1223:         *  residual to the tape buffer.
                   1224:         */
                   1225:        while (recno == 0 && n >= nblock) {
                   1226:                i = write(mt, buffer, TBLOCK*nblock);
                   1227:                if (i != TBLOCK*nblock)
                   1228:                        mterr("write", i, 2);
                   1229:                n -= nblock;
                   1230:                buffer += (nblock * TBLOCK);
                   1231:        }
                   1232:                
                   1233:        while (n-- > 0) {
                   1234:                bcopy(buffer, (char *)&tbuf[recno++], TBLOCK);
                   1235:                buffer += TBLOCK;
                   1236:                if (recno >= nblock) {
                   1237:                        i = write(mt, (char *)tbuf, TBLOCK*nblock);
                   1238:                        if (i != TBLOCK*nblock)
                   1239:                                mterr("write", i, 2);
                   1240:                        recno = 0;
                   1241:                }
                   1242:        }
                   1243: 
                   1244:        /* Tell the user how much to write to get in sync */
                   1245:        return (nblock - recno);
                   1246: }
                   1247: 
                   1248: backtape()
                   1249: {
                   1250:        static int mtdev = 1;
                   1251:        static struct mtop mtop = {MTBSR, 1};
                   1252:        struct mtget mtget;
                   1253:        
                   1254:        if (mtdev == 1)
                   1255:                mtdev = ioctl(mt, MTIOCGET, (char *)&mtget);
                   1256:        if (mtdev == 0) {
                   1257:                if (ioctl(mt, MTIOCTOP, (char *)&mtop) < 0) {
                   1258:                        fprintf(stderr, "tar: tape backspace error: %s\n",
                   1259:                            strerror(errno));
                   1260:                        done(4);
                   1261:                }
                   1262:        } else
                   1263:                (void)lseek(mt, (daddr_t) -TBLOCK*nblock, 1);
                   1264:        recno--;
                   1265: }
                   1266: 
                   1267: flushtape()
                   1268: {
                   1269:        int i;
                   1270: 
                   1271:        i = write(mt, (char *)tbuf, TBLOCK*nblock);
                   1272:        if (i != TBLOCK*nblock)
                   1273:                mterr("write", i, 2);
                   1274: }
                   1275: 
                   1276: mterr(operation, i, exitcode)
                   1277:        char *operation;
                   1278:        int i;
                   1279: {
                   1280:        fprintf(stderr, "tar: tape %s error: %s\n",
                   1281:            operation, i < 0 ? strerror(errno) : "unexpected EOF");
                   1282:        done(exitcode);
                   1283: }
                   1284: 
                   1285: bread(fd, buf, size)
                   1286:        int fd;
                   1287:        char *buf;
                   1288:        int size;
                   1289: {
                   1290:        int count;
                   1291:        static int lastread = 0;
                   1292: 
                   1293:        if (!Bflag)
                   1294:                return (read(fd, buf, size)); 
                   1295: 
                   1296:        for (count = 0; count < size; count += lastread) {
                   1297:                lastread = read(fd, buf, size - count);
                   1298:                if (lastread <= 0) {
                   1299:                        if (count > 0)
                   1300:                                return (count);
                   1301:                        return (lastread);
                   1302:                }
                   1303:                buf += lastread;
                   1304:        }
                   1305:        return (count);
                   1306: }
                   1307: 
                   1308: char *
                   1309: getcwd(buf)
                   1310:        char *buf;
                   1311: {
                   1312:        if (getwd(buf) == NULL) {
                   1313:                fprintf(stderr, "tar: %s\n", buf);
                   1314:                exit(1);
                   1315:        }
                   1316:        return (buf);
                   1317: }
                   1318: 
                   1319: getbuf()
                   1320: {
                   1321:        
                   1322:        if (nblock == 0) {
                   1323:                fstat(mt, &stbuf);
                   1324:                if ((stbuf.st_mode & S_IFMT) == S_IFCHR)
                   1325:                        nblock = NBLOCK;
                   1326:                else {
                   1327:                        nblock = stbuf.st_blksize / TBLOCK;
                   1328:                        if (nblock == 0)
                   1329:                                nblock = NBLOCK;
                   1330:                }
                   1331:        }
                   1332:        tbuf = (union hblock *)malloc((unsigned)nblock*TBLOCK);
                   1333:        if (tbuf == NULL) {
                   1334:                fprintf(stderr, "tar: blocksize %d too big, can't get memory\n",
                   1335:                    nblock);
                   1336:                done(1);
                   1337:        }
                   1338: }
                   1339: 
                   1340: /*
                   1341:  * Save this directory and its mtime on the stack, popping and setting
                   1342:  * the mtimes of any stacked dirs which aren't parents of this one.
                   1343:  * A null directory causes the entire stack to be unwound and set.
                   1344:  *
                   1345:  * Since all the elements of the directory "stack" share a common
                   1346:  * prefix, we can make do with one string.  We keep only the current
                   1347:  * directory path, with an associated array of mtime's, one for each
                   1348:  * '/' in the path.  A negative mtime means no mtime.  The mtime's are
                   1349:  * offset by one (first index 1, not 0) because calling this with a null
                   1350:  * directory causes mtime[0] to be set.
                   1351:  * 
                   1352:  * This stack algorithm is not guaranteed to work for tapes created
                   1353:  * with the 'r' option, but the vast majority of tapes with
                   1354:  * directories are not.  This avoids saving every directory record on
                   1355:  * the tape and setting all the times at the end.
                   1356:  */
                   1357: char dirstack[NAMSIZ];
                   1358: #define NTIM (NAMSIZ/2+1)              /* a/b/c/d/... */
                   1359: time_t mtime[NTIM];
                   1360: 
                   1361: dodirtimes(hp)
                   1362:        union hblock *hp;
                   1363: {
                   1364:        register char *p = dirstack;
                   1365:        register char *q = hp->dbuf.name;
                   1366:        register int ndir = 0;
                   1367:        char *savp;
                   1368:        int savndir;
                   1369: 
                   1370:        /* Find common prefix */
                   1371:        while (*p == *q && *p) {
                   1372:                if (*p++ == '/')
                   1373:                        ++ndir;
                   1374:                q++;
                   1375:        }
                   1376: 
                   1377:        savp = p;
                   1378:        savndir = ndir;
                   1379:        while (*p) {
                   1380:                /*
                   1381:                 * Not a child: unwind the stack, setting the times.
                   1382:                 * The order we do this doesn't matter, so we go "forward."
                   1383:                 */
                   1384:                if (*p++ == '/')
                   1385:                        if (mtime[++ndir] >= 0) {
                   1386:                                *--p = '\0';    /* zap the slash */
                   1387:                                setimes(dirstack, mtime[ndir]);
                   1388:                                *p++ = '/';
                   1389:                        }
                   1390:        }
                   1391:        p = savp;
                   1392:        ndir = savndir;
                   1393: 
                   1394:        /* Push this one on the "stack" */
                   1395:        while (*p = *q++)       /* append the rest of the new dir */
                   1396:                if (*p++ == '/')
                   1397:                        mtime[++ndir] = -1;
                   1398:        mtime[ndir] = stbuf.st_mtime;   /* overwrite the last one */
                   1399: }
                   1400: 
                   1401: setimes(path, mt)
                   1402:        char *path;
                   1403:        time_t mt;
                   1404: {
                   1405:        struct timeval tv[2];
                   1406: 
                   1407:        tv[0].tv_sec = time((time_t *) 0);
                   1408:        tv[1].tv_sec = mt;
                   1409:        tv[0].tv_usec = tv[1].tv_usec = 0;
                   1410:        if (utimes(path, tv) < 0)
                   1411:                fprintf(stderr, "tar: can't set time on %s: %s\n",
                   1412:                    path, strerror(errno));
                   1413: }
                   1414: 
                   1415: char *
                   1416: getmem(size)
                   1417: {
                   1418:        char *p = malloc((unsigned) size);
                   1419: 
                   1420:        if (p == NULL && freemem) {
                   1421:                fprintf(stderr,
                   1422:                    "tar: out of memory, link and directory modtime info lost\n");
                   1423:                freemem = 0;
                   1424:        }
                   1425:        return (p);
                   1426: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.