Annotation of coherent/d/bin/tar.c, revision 1.1.1.1

1.1       root        1: /*
                      2:  * Tape archive
                      3:  * tar [0-7bcflmrtuvwx]+ [blocks] [archive] pathname*
                      4:  */
                      5: 
                      6: #include <stdio.h>
                      7: #include <sys/types.h>
                      8: #include <errno.h>
                      9: #include <canon.h>
                     10: #include <sys/stat.h>
                     11: #include <sys/dir.h>
                     12: 
                     13: #define        S_PERM  07777           /* should be in stat.h */
                     14: 
                     15: /* Possible actions for do_checksum_error().  */
                     16: #define CLEAR 0        /* Print all pending messages.  */
                     17: #define ADD 1  /* Add another pending message.  */
                     18: 
                     19: #define        MAXBLK  20
                     20: #define        roundup(n, r)   (((n)+(r)-1)/(r))
                     21: 
                     22: typedef        struct  dirhd_t {
                     23:        dev_t   t_dev;
                     24:        ino_t   t_ino;
                     25:        unsigned short  t_nlink,
                     26:                        t_mode,
                     27:                        t_uid,
                     28:                        t_gid;
                     29:        fsize_t t_size;
                     30:        time_t  t_mtime;
                     31:        char    *t_name;
                     32:        struct  dirhd_t *t_cont[];
                     33: } dirhd_t;
                     34: 
                     35: typedef        union   tarhd_t {
                     36:        struct {
                     37:                char    th_name[100],
                     38:                        th_mode[8],
                     39:                        th_uid[8],
                     40:                        th_gid[8],
                     41:                        th_size[12],
                     42:                        th_mtime[12],
                     43:                        th_check[8],
                     44:                        th_islink,
                     45:                        th_link[100],
                     46:                        th_pad[255];
                     47:        } th_info;
                     48:        char    th_data[BUFSIZ];
                     49: } tarhd_t;
                     50: 
                     51: typedef        unsigned short  flag_t;         /* fastest type for machine */
                     52: 
                     53: flag_t linkmsg = 0,                    /* message if not all links found */
                     54:        modtime = 1,                    /* restore modtimes */
                     55:        verbose = 0;
                     56:        unixbug = 0;                    /* avoid bug in U**X tar */
                     57: FILE   *whether = (FILE *)NULL,        /* ask about each file */
                     58:        *tarfile;
                     59: char   tapedev[10] = '\0';
                     60: char   *archive = &tapedev[0];
                     61: unsigned short blocking = 1;           /* blocking factor */
                     62: time_t oldtime[2],                     /* for utime */
                     63:        recently,                       /* set to 6 months ago for tv key */
                     64:        time();
                     65: 
                     66: dirhd_t        *newdirhd(),
                     67:        *update(),
                     68:        *research();
                     69: tarhd_t        *readhdr(),
                     70:        *readblk(),
                     71:        *writeblk();
                     72: char   *havelink();
                     73: long   getoctl();
                     74: extern char    *malloc();
                     75: extern char    *ctime();
                     76: 
                     77: main(argc, argv)
                     78: int    argc;
                     79: char   *argv[];
                     80: {
                     81:        char    *key,
                     82:                unit = '\0',
                     83:                function = 0,
                     84:                deffunc,
                     85:                prefix[101] = '\0';
                     86:        unsigned short  arg = 2;
                     87:        dirhd_t *args;
                     88: 
                     89:        if (argc < 2) {
                     90:                fprintf(stderr,
                     91:        "Usage: %s [crtux][0-7bflmvw] [blocks] [archive] pathname*\n",
                     92:                        argv[0]);
                     93:                exit(-1);
                     94:        }
                     95:        for (key = argv[1];  *key != '\0';  key++) switch (*key) {
                     96:        case '0':
                     97:        case '1':
                     98:        case '2':
                     99:        case '3':
                    100:        case '4':
                    101:        case '5':
                    102:        case '6':
                    103:        case '7':
                    104:                unit = *key;
                    105:                deffunc = 't';
                    106:                continue;
                    107:        case 'b':
                    108:                if (argc <= arg)
                    109:                        fatal("missing blocking factor");
                    110:                else if ((blocking = atoi(argv[arg++])) <= 0
                    111:                         || blocking > MAXBLK)
                    112:                        fatal("illegal blocking factor");
                    113:                deffunc = 'r';
                    114:                continue;
                    115:        case 'f':
                    116:                if (argc <= arg)
                    117:                        fatal("missing archive name");
                    118:                else
                    119:                        archive = argv[arg++];
                    120:                deffunc = 't';
                    121:                continue;
                    122:        case 'l':
                    123:                linkmsg = 1;
                    124:                deffunc = 'r';
                    125:                continue;
                    126:        case 'm':
                    127:                modtime = 0;
                    128:                deffunc = 'x';
                    129:                continue;
                    130:        case 'v':
                    131:                verbose = 1;
                    132:                deffunc = 't';
                    133:                continue;
                    134:        case 'U':
                    135:                unixbug = 1;
                    136:                deffunc = 't';
                    137:                continue;
                    138:        case 'w':
                    139:                whether = fopen("/dev/tty", "r+w");
                    140:                deffunc = 'x';
                    141:                continue;
                    142:        case 'c':
                    143:        case 'r':
                    144:        case 't':
                    145:        case 'u':
                    146:        case 'x':
                    147:                if (function)
                    148:                        fatal("keys c, r, t, u, x are mutually exclusive");
                    149:                else
                    150:                        function = *key;
                    151:                continue;
                    152:        default:
                    153:                fatal("illegal key '%c'", *key);
                    154:        }
                    155:        if (!function)
                    156:                function = deffunc;
                    157:        oldtime[0] = time((time_t *)0);
                    158:        if (verbose && function=='t')
                    159:                recently = oldtime[0] - 6*((time_t)30*24*60*60);
                    160: 
                    161:        /* construct descriptors for args given */
                    162: 
                    163:        args = (dirhd_t *) malloc(sizeof (dirhd_t)
                    164:                                 + (argc-arg)*sizeof (dirhd_t *));
                    165:        if (args == NULL)
                    166:                fatal("out of memory");
                    167:        args->t_mode = S_IFDIR;
                    168:        args->t_nlink = 0;
                    169:        for (;  arg < argc;  arg++) {
                    170:                dirhd_t *argp;
                    171: 
                    172:                if ((argp = newdirhd(argv[arg], strlen(argv[arg]))) == NULL)
                    173:                        fprintf(stderr, "Tar: %s: out of memory\n", argv[arg]);
                    174:                else
                    175:                        args->t_cont[args->t_nlink++] = argp;
                    176:        }
                    177: 
                    178:        /* open archive file */
                    179: 
                    180:        if (*archive == '\0')
                    181:                sprintf(archive, "/dev/%smt%c", blocking==1 ? "" : "r", unit);
                    182:        if (function=='t' || function=='x')
                    183:                if (strcmp(archive, "-")==0)
                    184:                        tarfile = stdin;
                    185:                else
                    186:                        tarfile = fopen(archive, "r");
                    187:        else if (function=='c')
                    188:                if (strcmp(archive, "-")==0)
                    189:                        tarfile = stdout;
                    190:                else
                    191:                        tarfile = fopen(archive, "w");
                    192:        else
                    193:                tarfile = fopen(archive, "r+w");
                    194:        if (tarfile==NULL) {
                    195:                exit(perror("Tar: 1: %s", archive));
                    196:        }
                    197:        setbuf(tarfile, NULL);
                    198: 
                    199:        /* perform required function */
                    200: 
                    201:        switch (function) {
                    202:        case 't':
                    203:                table(args);
                    204:                break;
                    205:        case 'x':
                    206:                extract(args);
                    207:                break;
                    208:        case 'r':
                    209:                while (readblk() != NULL)
                    210:                        ;
                    211:                goto doappend;
                    212:        case 'u':
                    213:                if ((args = update(prefix, args, readhdr())) == NULL)
                    214:                        break;
                    215:        case 'c':
                    216:        doappend:
                    217:                append(prefix, args);
                    218:                flushtar();
                    219:        }
                    220:        /* Flush any remaining checksum messages.  */
                    221:        do_checksum_error(NULL, CLEAR);
                    222: 
                    223:        exit(errno);
                    224: }
                    225: 
                    226: fatal(args)
                    227: char   *args;
                    228: {
                    229:        /* Flush any remaining checksum messages.  */
                    230:        do_checksum_error(NULL, CLEAR);
                    231: 
                    232:        fprintf(stderr, "tar: %r\n", &args);
                    233:        exit(-1);
                    234: }
                    235: 
                    236: dirhd_t *
                    237: newdirhd(name, len)
                    238: register char  *name;
                    239: unsigned short len;
                    240: {
                    241:        register dirhd_t *dp;
                    242: 
                    243:        if ((dp = (dirhd_t *) malloc(sizeof (dirhd_t))) != NULL
                    244:         && (dp->t_name = malloc(len+1)) == NULL) {
                    245:                free(dp);
                    246:                dp = NULL;
                    247:        }
                    248:        if (dp != NULL) {
                    249:                dp->t_nlink = 0;
                    250:                strncpy(dp->t_name, name, len);
                    251:                dp->t_name[len] = '\0';
                    252:        }
                    253:        return (dp);
                    254: }
                    255: int
                    256: perror(args)
                    257: char   *args;
                    258: {
                    259:        register int    err;
                    260: 
                    261:        if ((err=errno) >= sys_nerr)
                    262:                fprintf(stderr, "%r: Bad error number\n", &args);
                    263:        else if (err)
                    264:                fprintf(stderr, "%r: %s\n", &args, sys_errlist[err]);
                    265:        return (err);
                    266: }
                    267: 
                    268: table(args)
                    269: register dirhd_t *args;
                    270: {
                    271:        register tarhd_t *header;
                    272: 
                    273:        for (;  (header = readhdr()) != NULL;  skipfile(header)) {
                    274:                if (argcont(args, header->th_info.th_name, 0) < 0)
                    275:                        continue;
                    276:                if (verbose) {
                    277:                        register unsigned short mode = getoct(header->th_info.th_mode);
                    278:                        unsigned short  uid = getoct(header->th_info.th_uid),
                    279:                                        gid = getoct(header->th_info.th_gid);
                    280:                        fsize_t size = getoctl(header->th_info.th_size);
                    281:                        time_t  mtime = getoctl(header->th_info.th_mtime);
                    282:                        char    *timestr = ctime(&mtime);
                    283:        
                    284:                        if (header->th_info.th_name[strnlen(header->th_info.th_name, 100)-1]
                    285:                                        == '/')
                    286:                                putchar('d');
                    287:                        else
                    288:                                putchar('-');
                    289:                        printf("%c%c%c",
                    290:                                mode&S_IREAD  ? 'r' : '-',
                    291:                                mode&S_IWRITE ? 'w' : '-',
                    292:                                mode&S_ISUID  ? 's' :
                    293:                                mode&S_IEXEC  ? 'x' : '-');
                    294:                        printf("%c%c%c",
                    295:                                mode&S_IREAD>>3  ? 'r' : '-',
                    296:                                mode&S_IWRITE>>3 ? 'w' : '-',
                    297:                                mode&S_ISGID     ? 's' :
                    298:                                mode&S_IEXEC>>3  ? 'x' : '-');
                    299:                        printf("%c%c%c",
                    300:                                mode&S_IREAD>>6  ? 'r' : '-',
                    301:                                mode&S_IWRITE>>6 ? 'w' : '-',
                    302:                                mode&S_ISVTX     ? 't' :
                    303:                                mode&S_IEXEC>>6  ? 'x' : '-');
                    304:                        printf("%3d %3d %6ld %.11s%.5s ",
                    305:                                gid,
                    306:                                uid,
                    307:                                size,
                    308:                                timestr,
                    309:                                mtime > recently ? timestr+11 : timestr+19);
                    310:                }
                    311:                printf("%.100s", header->th_info.th_name);
                    312:                if (header->th_info.th_islink)
                    313:                        if (verbose)
                    314:                                printf("\n%33s link to %s\n", "",
                    315:                                        header->th_info.th_link);
                    316:                        else
                    317:                                printf(" link to %s\n", header->th_info.th_link);
                    318:                else
                    319:                        putchar('\n');
                    320:        }
                    321: }
                    322: 
                    323: extract(args)
                    324: register dirhd_t *args;
                    325: {
                    326:        register tarhd_t *header;
                    327:        short   skipping = 0;
                    328: 
                    329:        while ((header = readhdr()) != NULL) {
                    330:                register char   name[101];
                    331:                unsigned short  namelen = strnlen(header->th_info.th_name, 100),
                    332:                                mode,
                    333:                                uid,
                    334:                                gid;
                    335: 
                    336:                if (!skipping || contains(name, header->th_info.th_name) >= 0) {
                    337:                        strncpy(name, header->th_info.th_name, namelen);
                    338:                        name[namelen--] = '\0';
                    339:                        if ((skipping = argcont(args, name, 0)) >= 0)
                    340:                                skipping = disallow('x', name);
                    341:                }
                    342:                switch (skipping) {
                    343:                case -1:
                    344:                        skipping = 0;
                    345:                case 1:
                    346:                        skipfile(header);
                    347:                        continue;
                    348:                }
                    349:                if (verbose)
                    350:                        printf("x %s\n", name);
                    351:                mode = getoct(header->th_info.th_mode);
                    352:                uid = getoct(header->th_info.th_uid);
                    353:                gid = getoct(header->th_info.th_gid);
                    354:                oldtime[1] = getoctl(header->th_info.th_mtime);
                    355:                if (name[namelen] == '/') {
                    356:                        name[namelen] = '\0';
                    357:                        makepath(name);
                    358:                        chmod(name, mode);
                    359:                        name[namelen] = '/';
                    360:                } else if (header->th_info.th_islink == '\0') {
                    361:                        int     fd = recreate(name, mode);
                    362:                        fsize_t size = getoctl(header->th_info.th_size);
                    363:        
                    364:                        for (;  size > 0;  size -= sizeof (tarhd_t)) {
                    365:                                int     my_size;
                    366: 
                    367:                                /* Handle unexpected EOF - mods by [email protected] */
                    368:                                if ((header = readblk()) == NULL) {
                    369:                                        fprintf(stderr, 
                    370:                                         "Unexpected end of the file %s\n",
                    371:                                                name);
                    372:                                        break;
                    373:                                }
                    374:                                if (size > sizeof(tarhd_t))
                    375:                                        my_size = sizeof(tarhd_t);
                    376:                                else
                    377:                                        my_size = (int) size;
                    378:                                if (fd >= 0 && (write(fd, header->th_data,
                    379:                                                my_size) != my_size))
                    380: 
                    381:                                        perror("Tar: 2: %s", name);
                    382:                        }
                    383:                        if (fd >= 0)
                    384:                                close(fd);
                    385:                } else {
                    386:                        struct  stat    statbuf;
                    387:                        flag_t  xlink = 1;
                    388:        
                    389:                        if (stat(header->th_info.th_link, &statbuf) < 0)
                    390:                                close(recreate(header->th_info.th_link, mode));
                    391:                        else if (havelink(statbuf.st_dev, statbuf.st_ino, 0)
                    392:                                        != NULL)
                    393:                                xlink = 0;
                    394:                        if (xlink)
                    395:                                fprintf(stderr, "Tar: Must extract %s\n",
                    396:                                        header->th_info.th_link);
                    397:                        unlink(name);
                    398:                        mkparent(name);
                    399:                        if (link(header->th_info.th_link, name) < 0)
                    400:                                fprintf(stderr, "Tar: Can't link %s to %s\n",
                    401:                                        name, header->th_info.th_link);
                    402:                }
                    403:                if (modtime)
                    404:                        utime(name, oldtime);
                    405:                chown(name, uid, gid);
                    406:        }
                    407: }
                    408: 
                    409: dirhd_t *
                    410: update(name, args, header)
                    411: char   *name;
                    412: register dirhd_t *args;
                    413: tarhd_t        *header;
                    414: {
                    415:        unsigned short  namelen = strlen(name);
                    416:        flag_t  donedir = 0;
                    417: 
                    418:        if (header == NULL)
                    419:                return (args);
                    420:        if (args->t_nlink == 0 && (args = research(name, args)) == NULL)
                    421:                return (NULL);
                    422:        do switch (args->t_mode&S_IFMT) {
                    423:                register short  arg;
                    424:                register dirhd_t *argp;
                    425: 
                    426:        case S_IFREG:
                    427:                if (args->t_mtime <= getoctl(header->th_info.th_mtime))
                    428:                        args->t_nlink = 0;
                    429:                skipfile(header);
                    430:                continue;
                    431:        case S_IFDIR:
                    432:                if (namelen != 0 && !donedir) {
                    433:                        name[namelen] = '/';
                    434:                        donedir++;
                    435:                }
                    436:                if ((arg = argcont(args, header->th_info.th_name+namelen+donedir, -1))
                    437:                                >= 0) {
                    438:                        strcpy(name+namelen+donedir,
                    439:                                (argp=args->t_cont[arg])->t_name);
                    440:                        if ((args->t_cont[arg] = update(name, argp, header))
                    441:                                        == NULL)
                    442:                                args->t_cont[arg]
                    443:                                        = args->t_cont[--args->t_nlink];
                    444:                } else
                    445:                        skipfile(header);
                    446:                name[namelen+donedir] = '\0';
                    447:        } while ((header=readhdr()) != NULL
                    448:                && contains(name, header->th_info.th_name));
                    449:        if (header != NULL)
                    450:                ungetblk();
                    451:        if (args->t_nlink == 0) {
                    452:                if (namelen != 0)
                    453:                        free(args->t_name);
                    454:                free((char *) args);
                    455:                return (NULL);
                    456:        } else
                    457:                return (args);
                    458: }
                    459: 
                    460: append(name, args)
                    461: char   *name;
                    462: register dirhd_t *args;
                    463: {
                    464:        unsigned short  namelen;
                    465:        register unsigned short arg;
                    466:        register dirhd_t *argp;
                    467: 
                    468:        if ((namelen = strlen(name)) != 0 && disallow('a', name))
                    469:                return;
                    470:        if (args->t_nlink == 0 && (args = research(name, args)) == NULL)
                    471:                return;
                    472:        switch (args->t_mode&S_IFMT) {
                    473:        case S_IFDIR:
                    474:                if (namelen != 0) {
                    475:                        name[namelen++] = '/'; name[namelen] = '\0';
                    476:                        writehdr(name, args, "");
                    477:                }
                    478:                for (arg = 0;  arg < args->t_nlink;  arg++) {
                    479:                        strcpy(name+namelen, (argp=args->t_cont[arg])->t_name);
                    480:                        append(name, argp);
                    481:                }
                    482:                break;
                    483:        case S_IFREG:
                    484:                if (args->t_nlink != 1) {
                    485:                        char    *link;
                    486: 
                    487:                        if ((link=havelink(args->t_dev,
                    488:                                        args->t_ino, 1))!=NULL) {
                    489:                                writehdr(name, args, link);
                    490:                                break;
                    491:                        } else {
                    492:                                filelink(args->t_dev,
                    493:                                         args->t_ino,
                    494:                                         args->t_nlink,
                    495:                                         name);
                    496:                        }
                    497:                }
                    498:                writehdr(name, args, "");
                    499:                writefil(name, args->t_size);
                    500:        }
                    501:        if (namelen != 0)
                    502:                free(args->t_name);
                    503:        free((char *) args);
                    504: }
                    505: 
                    506: dirhd_t *
                    507: research(name, args)
                    508: char   *name;
                    509: register dirhd_t *args;
                    510: {
                    511:        unsigned short  namelen;
                    512:        register short  nfile;
                    513:        int     fd;
                    514:        struct  stat    statbuf;
                    515: 
                    516:        if ((namelen = strlen(name)) == 0)
                    517:                name = ".";
                    518:        if (stat(name, &statbuf) < 0) {
                    519:                perror("Tar: 3: %s", name);
                    520:                return (args);
                    521:        }
                    522:        args->t_dev = statbuf.st_dev;
                    523:        args->t_ino = statbuf.st_ino;
                    524:        args->t_nlink = statbuf.st_nlink;
                    525:        args->t_uid = statbuf.st_uid;
                    526:        args->t_gid = statbuf.st_gid;
                    527:        args->t_mtime = statbuf.st_mtime;
                    528:        switch ((args->t_mode = statbuf.st_mode)&S_IFMT) {
                    529:        case S_IFREG:
                    530:                args->t_size = statbuf.st_size;
                    531:                return (args);
                    532:        default:
                    533:                args->t_size = 0;
                    534:                return (args);
                    535:        case S_IFDIR:
                    536:                args->t_size = 0;
                    537:        }
                    538:        if ((nfile = (short) (statbuf.st_size/sizeof (struct direct))) > 2) {
                    539:                args = (dirhd_t *) realloc((char *)args,
                    540:                        sizeof (dirhd_t) + (nfile-2)*sizeof (dirhd_t *));
                    541:                if (args == NULL) {
                    542:                        fprintf(stderr, "Tar: %s: out of memory\n", name);
                    543:                        return (NULL);
                    544:                }
                    545:        }
                    546:        args->t_nlink = 0;
                    547:        if ((fd = open(name, 0)) < 0) {
                    548:                perror("Tar: 4: %s", name);
                    549:                return (args);
                    550:        }
                    551:        for (;  nfile > 0;  --nfile) {
                    552:                struct  direct  dir_ent;
                    553:                unsigned short  arglen;
                    554:                dirhd_t *argp;
                    555: 
                    556:                switch (read(fd, (char *)&dir_ent, sizeof (struct direct))) {
                    557:                case -1:
                    558:                        perror("Tar: 5: %s", name);
                    559:                case 0:
                    560:                        break;
                    561:                default:
                    562:                        if (dir_ent.d_ino == 0
                    563:                         || strcmp(dir_ent.d_name, ".") == 0
                    564:                         || strcmp(dir_ent.d_name, "..") == 0)
                    565:                                continue;
                    566:                        else if ((arglen=strnlen(dir_ent.d_name, DIRSIZ))
                    567:                                 + namelen > 99)
                    568:                                fprintf(stderr,
                    569:                                        "Tar: %s/%.*s: name too long\n",
                    570:                                        name, DIRSIZ, dir_ent.d_name);
                    571:                        else if ((argp = newdirhd(dir_ent.d_name, arglen))
                    572:                                 == NULL)
                    573:                                fprintf(stderr,
                    574:                                        "Tar: %s/%.*s: out of memory\n",
                    575:                                        name, DIRSIZ, dir_ent.d_name);
                    576:                        else
                    577:                                args->t_cont[args->t_nlink++] = argp;
                    578:                        continue;
                    579:                }
                    580:                break;
                    581:        }
                    582:        close(fd);
                    583:        return (args);
                    584: }
                    585: 
                    586: int
                    587: argcont(args, name, ret)
                    588: register dirhd_t *args;
                    589: char   *name;
                    590: int    ret;
                    591: {
                    592:        register unsigned short arg;
                    593: 
                    594:        if (args->t_nlink == 0)
                    595:                return (ret);
                    596:        else for (arg = 0;  arg < args->t_nlink;  arg++)
                    597:                if (contains(args->t_cont[arg]->t_name, name))
                    598:                        return (arg);
                    599:        return (-1);
                    600: }
                    601: 
                    602: int
                    603: strnlen(str, maxlen)
                    604: register char  *str;
                    605: register unsigned short        maxlen;
                    606: {
                    607:        register unsigned short len = 0;
                    608: 
                    609:        while (maxlen && *str++ != '\0') {
                    610:                --maxlen; ++len;
                    611:        }
                    612:        return (len);
                    613: }
                    614: 
                    615: /*
                    616:  * Create file system paths
                    617:  */
                    618: 
                    619: int
                    620: makepath(pathname)
                    621: char   *pathname;
                    622: {
                    623:        struct  stat    statbuf;
                    624:        register int    err;
                    625: 
                    626:        if (stat(pathname, &statbuf) == 0)
                    627:                if ((statbuf.st_mode&S_IFMT) == S_IFDIR)
                    628:                        return (0);
                    629:                else
                    630:                        errno = ENOTDIR;
                    631:        else if (errno == ENOENT) {
                    632:                errno = 0;
                    633:                if ((err=mkparent(pathname)) != 0)
                    634:                        return err;
                    635:                return mkdir(pathname);
                    636:        }
                    637:        return (perror("Tar: 6: %s", pathname));
                    638: }
                    639: 
                    640: int
                    641: mkparent(pathname)
                    642: register char  *pathname;
                    643: {
                    644:        register char   *pathend = &pathname[strlen(pathname)];
                    645: 
                    646:        while (pathend > pathname && *--pathend != '/')
                    647:                ;
                    648:        if (pathend > pathname) {
                    649:                *pathend = '\0';
                    650:                errno = makepath(pathname);
                    651:                *pathend = '/';
                    652:        } else
                    653:                errno = 0;
                    654:        return (errno);
                    655: }
                    656: 
                    657: mkdir(pathname)
                    658: char   *pathname;
                    659: {
                    660:        int     status;
                    661: 
                    662:        switch(fork()) {
                    663:        case -1:
                    664:                break;
                    665:        case 0:
                    666:                close(2);
                    667:                execl("/bin/mkdir", "mkdir", pathname, NULL);
                    668:                exit(errno);
                    669:        default:
                    670:                wait(&status);
                    671:                errno = status>>8;
                    672:        }
                    673:        return (perror("Tar: 7: %s", pathname));
                    674: }
                    675: 
                    676: int
                    677: recreate(pathname, mode)
                    678: char   *pathname;
                    679: unsigned short mode;
                    680: {
                    681:        int     fd;
                    682: 
                    683:        if ((fd = create(pathname, mode)) < 0
                    684:        && (errno != ENOENT
                    685:          || mkparent(pathname) == 0 && (fd = create(pathname, mode)) < 0))
                    686:                perror("Tar: 8: %s", pathname);
                    687:        errno = 0;
                    688:        return (fd);
                    689: }
                    690: 
                    691: int
                    692: create(pathname, mode)
                    693: char   *pathname;
                    694: unsigned short mode;
                    695: {
                    696:        int     fd;
                    697: 
                    698:        unlink(pathname);
                    699:        if ((fd = creat(pathname, mode)) >= 0) {
                    700:                struct  stat    statbuf;
                    701: 
                    702:                fstat(fd, &statbuf);
                    703:                filelink(statbuf.st_dev, statbuf.st_ino,
                    704:                        statbuf.st_nlink, pathname);
                    705:        }
                    706:        return (fd);
                    707: }
                    708: 
                    709: /*
                    710:  * Ask about current action
                    711:  */
                    712: 
                    713: int
                    714: disallow(function, pathname)
                    715: char   function,
                    716:        *pathname;
                    717: {
                    718:        while (whether) {
                    719:                register int    c1,
                    720:                                c;
                    721: 
                    722:                fprintf(whether, "%c %s? ", function, pathname);
                    723:                for (c1=c=getc(whether);  c!=EOF && c!='\n';  c=getc(whether))
                    724:                        ;
                    725:                switch (c1) {
                    726:                case EOF:
                    727:                case 'x':
                    728:                        if (function == 'a')
                    729:                                flushtar();
                    730:                        exit(errno);
                    731:                case '\n':
                    732:                case 'n':
                    733:                case 'N':
                    734:                        return (1);
                    735:                case 'y':
                    736:                case 'Y':
                    737:                        return (0);
                    738:                }
                    739:        }
                    740:        return (0);
                    741: }
                    742: 
                    743: /*
                    744:  * High level I/O routines
                    745:  */
                    746: 
                    747: tarhd_t *
                    748: readhdr()
                    749: {
                    750:        register tarhd_t *header;
                    751: 
                    752:        while ((header = readblk()) != NULL) {
                    753:                if (header->th_info.th_name[0] == '\0')
                    754:                        if (unixbug) {
                    755:                                ungetblk();
                    756:                                return (NULL);
                    757:                        } else
                    758:                                continue;
                    759:                else {
                    760:                        int     check = getoct(header->th_info.th_check);
                    761:        
                    762:                        strncpy(header->th_info.th_check, "        ",
                    763:                                sizeof(header->th_info.th_check));
                    764:                        if (checksum(header->th_data, sizeof(tarhd_t)) != check){
                    765:                                do_checksum_error(header->th_info.th_name, ADD);
                    766:                        } else {
                    767:                                do_checksum_error(NULL, CLEAR);
                    768:                                break;
                    769:                        }
                    770:                }
                    771:        }
                    772:        /* We shouldn't have to check EVERY header, but if we do it here
                    773:         * it gets done for every routine.
                    774:         * Newer tar programs use the first eight bytes of the
                    775:         * pad field as magic to indicate the type of archive.
                    776:         * With old tar archives, these eight characters should be
                    777:         * NUL.  We'll only check the first one.
                    778:         */
                    779:        /* Check to see if this is a v7 style tar archive.  */
                    780:        if ((char)0 != header->th_info.th_pad[0]) {
                    781:                fatal("%.8s archive, not v7 archive.",
                    782:                        header->th_info.th_pad);
                    783:                
                    784:        }
                    785:        return (header);
                    786: }
                    787: 
                    788: skipfile(header)
                    789: tarhd_t        *header;
                    790: {
                    791:        register fsize_t        size;
                    792: 
                    793:        if (header->th_info.th_islink)
                    794:                return;
                    795:        for (size = getoctl(header->th_info.th_size);
                    796:                size > 0 && readblk() != NULL;
                    797:                size -= sizeof (tarhd_t))
                    798:                ;
                    799: }
                    800: 
                    801: writehdr(name, args, link)
                    802: char   *name;
                    803: register dirhd_t *args;
                    804: char   *link;
                    805: {
                    806:        register tarhd_t *header = writeblk();
                    807: 
                    808:        if (verbose)
                    809:                fprintf(stderr, "a %s", name);
                    810:        strncpy(header->th_info.th_name, name, sizeof(header->th_info.th_name));
                    811:        putoct(header->th_info.th_mode, args->t_mode&S_PERM);
                    812:        putoct(header->th_info.th_uid, args->t_uid);
                    813:        putoct(header->th_info.th_gid, args->t_gid);
                    814:        putoctl(header->th_info.th_size, args->t_size);
                    815:        putoctl(header->th_info.th_mtime, args->t_mtime);
                    816:        strncpy(header->th_info.th_check, "        ", sizeof(header->th_info.th_check));
                    817:        if (*link == '\0') {
                    818:                header->th_info.th_islink = 0;
                    819:                if (verbose)
                    820:                        if (args->t_size == 0)
                    821:                                putc('\n', stderr);
                    822:                        else
                    823:                                fprintf(stderr, " %ld block%s\n",
                    824:                                        roundup(args->t_size, BUFSIZ),
                    825:                                        args->t_size <= BUFSIZ ? "" : "s");
                    826:        } else {
                    827:                header->th_info.th_islink = '1';
                    828:                if (verbose)
                    829:                        fprintf(stderr, " link to %s\n", link);
                    830:        }
                    831:        strncpy(header->th_info.th_link, link, sizeof(header->th_info.th_link));
                    832:        strncpy(header->th_info.th_pad, "", sizeof(header->th_info.th_pad));
                    833:        putoct(header->th_info.th_check, checksum(header->th_data, sizeof(tarhd_t)));
                    834: }
                    835: 
                    836: writefil(name, size)
                    837: char   *name;
                    838: register fsize_t       size;
                    839: {
                    840:        int     fd;
                    841:        register tarhd_t *header;
                    842: 
                    843:        if ((fd = open(name, 0)) < 0) {
                    844:                perror("Tar: 9: %s", name);
                    845:        }
                    846:        for (;  size > 0;  size -= sizeof (tarhd_t)) {
                    847:                header = writeblk();
                    848:                if (fd >= 0)
                    849:                        read(fd, header->th_data, sizeof (tarhd_t));
                    850:                else
                    851:                        strncpy(header->th_data, "", sizeof (tarhd_t));
                    852:        }
                    853:        if (fd >= 0)
                    854:                close(fd);
                    855: }
                    856: 
                    857: /*
                    858:  * Tape I/O, with record blocking if specified
                    859:  */
                    860: 
                    861: tarhd_t        buffer[MAXBLK],
                    862:        *current = &buffer[0];
                    863: 
                    864: tarhd_t *
                    865: readblk()
                    866: {
                    867:        static unsigned short   blocks = 0;
                    868: 
                    869:        if (feof(tarfile))
                    870:                return (NULL);
                    871:        if (current == &buffer[blocks]) {
                    872:                current = &buffer[0];
                    873:                blocks = fread((char *) buffer,
                    874:                                sizeof (tarhd_t), MAXBLK, tarfile);
                    875:                if (ferror(tarfile)) {
                    876:                        exit(perror("Tar: 10: %s", archive));
                    877:                } else if (feof(tarfile)) {
                    878:                        /* This is a hack.  We should actually find
                    879:                         * out why returning NULL is not good enough.
                    880:                         *
                    881:                         * Really a pain without a symbolic debugger!
                    882:                         */
                    883:                        exit(0);
                    884:                }
                    885:        }
                    886:        return (current++);
                    887: }
                    888: 
                    889: ungetblk()
                    890: {
                    891:        --current;
                    892: }
                    893: 
                    894: tarhd_t *
                    895: writeblk()
                    896: {
                    897:        if (current == &buffer[blocking]) {
                    898:                current = &buffer[0];
                    899:                fwrite((char *)buffer, sizeof (tarhd_t), blocking, tarfile);
                    900:                if (ferror(tarfile) || feof(tarfile)) {
                    901:                        exit(perror("Tar: 11: %s", archive));
                    902:                }
                    903:        }
                    904:        return (current++);
                    905: }
                    906: 
                    907: flushtar()
                    908: {
                    909:        register tarhd_t *header;
                    910: 
                    911:        while ((header=writeblk()) != &buffer[0])
                    912:                strncpy(header->th_data, "", sizeof (tarhd_t));
                    913:        if (linkmsg)
                    914:                misslink();
                    915: }
                    916: 
                    917: /*
                    918:  * Keep track of files by ino in hash table
                    919:  */
                    920: 
                    921: typedef        struct  link_t  {
                    922:        dev_t   t_dev;
                    923:        ino_t   t_ino;
                    924:        unsigned short  t_nlink;
                    925:        struct  link_t  *t_next;
                    926:        char    t_link[];
                    927: } link_t;
                    928: 
                    929: #define        NHASH   64
                    930: 
                    931: link_t *linklist[NHASH];
                    932: 
                    933: filelink(dev, ino, nlink, link)
                    934: dev_t  dev;
                    935: ino_t  ino;
                    936: unsigned short nlink;
                    937: char   *link;
                    938: {
                    939:        unsigned short  id = ino%NHASH;
                    940:        register link_t *lp;
                    941: 
                    942:        lp = (link_t *) malloc(sizeof (link_t) + strlen(link) + 1);
                    943:        if (lp == NULL)
                    944:                fprintf(stderr, "Tar: %s: note: link info lost\n", link);
                    945:        else {
                    946:                lp->t_next = linklist[id];
                    947:                linklist[id] = lp;
                    948:                lp->t_dev = dev;
                    949:                lp->t_ino = ino;
                    950:                lp->t_nlink = nlink;
                    951:                strcpy(lp->t_link, link);
                    952:        }
                    953: }
                    954: 
                    955: char *
                    956: havelink(dev, ino, flag)
                    957: dev_t  dev;
                    958: ino_t  ino;
                    959: flag_t flag;
                    960: {
                    961:        register link_t *lp;
                    962: 
                    963:        for (lp = linklist[ino%NHASH];  lp != NULL;  lp = lp->t_next) {
                    964:                if (lp->t_ino == ino && lp->t_dev == dev) {
                    965:                        if (flag)
                    966:                                --lp->t_nlink;
                    967:                        return (lp->t_link);
                    968:                }
                    969:        }
                    970:        return (NULL);
                    971: }
                    972: 
                    973: misslink()
                    974: {
                    975:        unsigned short  ino;
                    976: 
                    977:        for (ino = 0;  ino < NHASH;  ino++) {
                    978:                register link_t *lp;
                    979: 
                    980:                for (lp = linklist[ino];  lp != NULL;  lp=lp->t_next) {
                    981:                        register short  nlink;
                    982: 
                    983:                        if (nlink = lp->t_nlink - 1)
                    984:                                fprintf(stderr,
                    985:                                        "Tar: missed %d link%s to %s\n",
                    986:                                        nlink, nlink==1 ? "" : "s",
                    987:                                        lp->t_link);
                    988:                }
                    989:        }
                    990: }
                    991: 
                    992: /*
                    993:  * Read unsigned octal numbers
                    994:  */
                    995: 
                    996: int
                    997: getoct(cp)
                    998: register char  *cp;
                    999: {
                   1000:        register int    val = 0;
                   1001:        register char   c;
                   1002: 
                   1003:        while (*cp == ' ')
                   1004:                cp++;
                   1005:        while ((c = *cp++ - '0') >= 0 && c <= 7)
                   1006:                val = val<<3 | c;
                   1007:        return (val);
                   1008: }
                   1009: 
                   1010: long
                   1011: getoctl(cp)
                   1012: register char  *cp;
                   1013: {
                   1014:        register long   val = 0;
                   1015:        register char   c;
                   1016: 
                   1017:        while (*cp==' ')
                   1018:                cp++;
                   1019:        while ((c = *cp++ - '0') >= 0 && c <= 7)
                   1020:                val = val<<3 | c;
                   1021:        return (val);
                   1022: }
                   1023: 
                   1024: /*
                   1025:  * Write unsigned octal numbers
                   1026:  * in fixed format
                   1027:  */
                   1028: 
                   1029: putoct(str, val)
                   1030: char   *str;
                   1031: unsigned short val;
                   1032: {
                   1033:        register char   *cp;
                   1034: 
                   1035:        *(cp = &str[7]) = '\0';
                   1036:        *--cp = ' ';
                   1037:        *--cp = (val&07) + '0';
                   1038:        while (cp != str)
                   1039:                *--cp = (val>>=3) ? (val&07) + '0' : ' ';
                   1040: }
                   1041: 
                   1042: putoctl(str, val)
                   1043: char   *str;
                   1044: register unsigned long val;
                   1045: {
                   1046:        register char   *cp;
                   1047: 
                   1048:        *(cp = &str[11]) = ' ';
                   1049:        *--cp = (val&07) + '0';
                   1050:        while (cp != str)
                   1051:                *--cp = (val>>=3) ? (val&07) + '0' : ' ';
                   1052: }
                   1053: 
                   1054: /*
                   1055:  * Compute checksum of string
                   1056:  */
                   1057: int
                   1058: checksum(str, len)
                   1059: register char  *str;
                   1060: register int   len;
                   1061: {
                   1062:        register int    check = 0;
                   1063: 
                   1064:        if (len) do
                   1065:                check += *str++;
                   1066:        while (--len);
                   1067:        return (check);
                   1068: }
                   1069: 
                   1070: /*
                   1071:  * Return -1 if dname is a directory prefix of fname
                   1072:  *     0 if no match
                   1073:  *     1 if complete match
                   1074:  */
                   1075: int
                   1076: contains(dname, fname)
                   1077: register char  *dname,
                   1078:                *fname;
                   1079: {
                   1080:        if (*dname=='\0')
                   1081:                return (-1);
                   1082:        while (*dname!='\0')
                   1083:                if (*dname++ != *fname++)
                   1084:                        return (0);
                   1085:        if (*fname=='\0')
                   1086:                return (1);
                   1087:        else if (*fname=='/' || *--fname=='/')
                   1088:                return (-1);
                   1089:        else
                   1090:                return (0);
                   1091: }
                   1092: 
                   1093: /* Handle the processing of a checksum error.
                   1094:  * This is special because sometimes end of archive will look like
                   1095:  * a lot of checksum errors.
                   1096:  */
                   1097: int
                   1098: do_checksum_error(name, action)
                   1099:        char *name;
                   1100:        int action;
                   1101: {
                   1102: #define MSG_SIZE (100 + sizeof("Tar: %.100s: bad checksum\n") + 1)
                   1103: #define MAX_CHECKERR   5 /* Give up after 5 consecutive checksum errors.  */
                   1104: 
                   1105:        static error_count = 0; /* Number of checksums we've seen.  */
                   1106:        static char *msg_list = NULL; /* Error message we've queued.  */
                   1107:        char tmp_buf[MSG_SIZE]; /* Someplace to build new errors. */
                   1108: 
                   1109:        
                   1110:        switch (action) {
                   1111:        case ADD:
                   1112:                /* If there have been too many checksum errors, or if
                   1113:                 * we can't allocate more memory for more error messages,
                   1114:                 * throw away the existing messages, and look for another
                   1115:                 * valid block.
                   1116:                 */
                   1117:                if (++error_count > MAX_CHECKERR ||
                   1118:                    (msg_list = (char *)realloc(msg_list,
                   1119:                                        strlen(msg_list) + MSG_SIZE +1)) ==
                   1120:                    NULL) {
                   1121:                        fprintf(stderr,
                   1122:                            "Tar: %s: This doesn't look like a tar archive.\n",
                   1123:                            archive);
                   1124:                        free(msg_list);
                   1125:                        msg_list = 0;
                   1126:                        error_count = 0;
                   1127:                        fprintf(stderr, "Tar: Scanning for next file.\n");
                   1128:                        scan_for_next();
                   1129:                }
                   1130: 
                   1131:                sprintf(tmp_buf, "Tar: %.100s: bad checksum\n",
                   1132:                        name);
                   1133:                strcat(msg_list, tmp_buf);
                   1134:                break;
                   1135:        case CLEAR:
                   1136:                if (NULL != msg_list) {
                   1137:                        fprintf(stderr, "%s", msg_list);
                   1138:                        free(msg_list);
                   1139:                        msg_list = NULL;
                   1140:                }
                   1141:                error_count = 0;
                   1142:                break;
                   1143:        } /* switch (action) */
                   1144: } /* do_checksum_error() */
                   1145: 
                   1146: /* Find the next valid block.  */
                   1147: int
                   1148: scan_for_next()
                   1149: {
                   1150:        int     check;
                   1151:        tarhd_t *header;
                   1152: 
                   1153:        while ( (header = readblk()) != NULL ) {
                   1154:                check = getoct(header->th_info.th_check);
                   1155: 
                   1156:                strncpy(header->th_info.th_check, "        ",
                   1157:                        sizeof(header->th_info.th_check));
                   1158:                if (checksum(header->th_data, sizeof(tarhd_t)) == check){
                   1159:                        /* Found a good header!  */
                   1160:                        ungetblk();
                   1161:                        return;
                   1162:                }
                   1163:        } /* while (more blocks to read) */
                   1164:        /* If we got here, it means we ran out of things to read.  */
                   1165:        fatal("no more valid blocks");
                   1166: 
                   1167: } /* scan_for_next() */

unix.superglobalmegacorp.com

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