Annotation of coherent/d/bin/tar.c, revision 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.