Annotation of mstools/posix/samples/psxarc/tar.c, revision 1.1

1.1     ! root        1: //
        !             2: // Stuff to deal with tar-format files
        !             3: //
        !             4: 
        !             5: #include <sys/stat.h>
        !             6: #include <stdlib.h>
        !             7: #include <tar.h>
        !             8: #include <stdio.h>
        !             9: #include <fcntl.h>
        !            10: #include <dirent.h>
        !            11: #include <string.h>
        !            12: #include <unistd.h>
        !            13: 
        !            14: #include "buf.h"
        !            15: #include "psxarc.h"
        !            16: #include "tarhead.h"
        !            17: #include "links.h"
        !            18: 
        !            19: static unsigned long round_up(int, int);
        !            20: static int tarAtoi(char *);
        !            21: static void tarItoa(long, char *, size_t);
        !            22: static void tar_dodir(PBUF pb, char *pchfile, struct stat *psb);
        !            23: static char *modestring(PTAR_HEAD);
        !            24: extern int fVerbose;
        !            25: 
        !            26: void
        !            27: TarRead(PBUF pb)
        !            28: {
        !            29:        char name[155 + 1 + 100 + 1];           // (prefix '/' name '\0')
        !            30:        char linkname[TNAMSIZ + 1];
        !            31:        unsigned long size, i;
        !            32:        int fdout;
        !            33:        PTAR_HEAD buf = (PTAR_HEAD)pb->data;
        !            34:        
        !            35: 
        !            36:        if (0 != strcmp(buf->s.magic, TMAGIC)) {
        !            37:                fprintf(stderr, "%s: bad magic number\n", progname);
        !            38:                exit(1);
        !            39:        }
        !            40: 
        !            41:        name[sizeof(name) - 1] = '\0';
        !            42: 
        !            43:        do {
        !            44:                (void)strncpy(name, buf->s.prefix, 155);
        !            45:                // make sure 'name' is null-terminated.
        !            46:                name[155] = '\0';
        !            47:                if ('\0' != name[0]) {
        !            48:                        (void)strcat(name, "/");
        !            49:                }
        !            50:                (void)strncat(name, buf->s.name, 100);
        !            51: 
        !            52:                if (fVerbose) {
        !            53:                        printf("%s\n", name);
        !            54:                }
        !            55: 
        !            56:                if (DIRTYPE == buf->s.typeflag) {
        !            57:                        if (-1 == mkdir(name, 0777)) {
        !            58:                                fprintf(stderr, "%s: mkdir: ", progname);
        !            59:                                perror(name);
        !            60:                        }
        !            61:                        bfill(pb);
        !            62:                        continue;
        !            63:                }
        !            64:                if (FIFOTYPE == buf->s.typeflag) {
        !            65:                        if (-1 == mkfifo(name, 0666)) {
        !            66:                                fprintf(stderr, "%s: mkfifo: ", progname);
        !            67:                                perror(name);
        !            68:                        }
        !            69:                        bfill(pb);
        !            70:                        continue;
        !            71:                }
        !            72:                if (LNKTYPE == buf->s.typeflag) {
        !            73:                        strncpy(linkname, buf->s.linkname, sizeof(linkname));
        !            74:                        if (-1 == link(linkname, name)) {
        !            75:                                fprintf(stderr, "%s: link %s, %s: ",
        !            76:                                        progname, linkname, name);
        !            77:                                perror("");
        !            78:                                continue;
        !            79:                        }
        !            80:                }
        !            81: 
        !            82:                // regular file
        !            83:                if (-1 == (fdout = open(name, O_WRONLY | O_CREAT, 0666))) {
        !            84:                        fprintf(stderr, "%s: open: ", progname);
        !            85:                        perror(name);
        !            86:                        continue;
        !            87:                }
        !            88: 
        !            89:                size = tarAtoi(buf->s.size);
        !            90: 
        !            91:                if (size > 0) {
        !            92:                        bfill(pb);
        !            93: 
        !            94:                        for (i = 0; i < size; ++i) {
        !            95:                                int c;
        !            96:        
        !            97:                                c = bgetc(pb);
        !            98:                                write(fdout, &c, 1);
        !            99:                        }
        !           100:                }
        !           101:                (void)close(fdout);
        !           102: 
        !           103:                bfill(pb);
        !           104:        } while (0 != buf->s.magic[0]);
        !           105: }
        !           106: 
        !           107: //
        !           108: // TarWrite -- calls tar_dodir for directories, which calls back here.
        !           109: //
        !           110: 
        !           111: void
        !           112: TarWrite(PBUF pb, char **ppchFiles, int count)
        !           113: {
        !           114:        PTAR_HEAD pt;
        !           115:        auto struct stat statbuf;
        !           116:        int fdin;
        !           117:        int i;
        !           118:        unsigned chksum;
        !           119: 
        !           120:        // We reach into the buffer routines until it's time to write.
        !           121:        // Brutal but effective.
        !           122: 
        !           123:        pt = (PTAR_HEAD)pb->data;
        !           124: 
        !           125:        while (count > 0) {
        !           126:                int len;
        !           127: 
        !           128:                memset(pt, 0, sizeof(*pt));
        !           129:                strcpy(pt->s.magic, TMAGIC);
        !           130:                strncpy(pt->s.version, TVERSION, TVERSLEN);
        !           131: 
        !           132:                if (fVerbose) {
        !           133:                        fprintf(stderr, "%s\n", *ppchFiles);
        !           134:                }
        !           135:                if (-1 == stat(*ppchFiles, &statbuf)) {
        !           136:                        fprintf(stderr, "%s: stat: ");
        !           137:                        perror(*ppchFiles);
        !           138:                        continue;
        !           139:                }
        !           140:                len = strlen(*ppchFiles);
        !           141:                if (len > TNAMSIZ + 155 + 1) {
        !           142:                        // the filename just won't fit.  Do something
        !           143:                        // reasonable.
        !           144:                } else if (len <= TNAMSIZ) {
        !           145:                        strncpy(pt->s.name, *ppchFiles, TNAMSIZ);
        !           146:                } else {
        !           147:                        char *pch;
        !           148: 
        !           149:                        // We try to put as much of the filename as will fit
        !           150:                        // into the 'name' portion, and the rest goes in
        !           151:                        // the prefix.  To do this, we start 101 characters
        !           152:                        // from the end; if that character is a slash, we
        !           153:                        // split the string there.  If it's not, we split the
        !           154:                        // string at the next slash to the right.
        !           155:                        
        !           156:                        pch = *ppchFiles + (len - TNAMSIZ - 1);
        !           157:                        if ('/' != *pch) {
        !           158:                                pch = strchr(pch, '/');
        !           159:                                if (NULL == pch) {
        !           160:                                        // XXX.mjb: This filename has a trailing
        !           161:                                        // component more than 100 chars
        !           162:                                        // long.  Do something reasonable.
        !           163:                                        --count;
        !           164:                                        ++ppchFiles;
        !           165:                                        continue;
        !           166:                                }
        !           167:                        }
        !           168:                        *pch = '\0';
        !           169:                        strncpy(pt->s.name, pch + 1, TNAMSIZ);
        !           170:                        strncpy(pt->s.prefix, *ppchFiles, 155);
        !           171:                }
        !           172: 
        !           173:                //
        !           174:                // XXX.mjb: this assumes tar mode bits are the same as
        !           175:                // the POSIX implementation's mode bits.  Should really
        !           176:                // call a function to convert between.
        !           177:                //
        !           178:                tarItoa(statbuf.st_mode & 0777, pt->s.mode,
        !           179:                        sizeof(pt->s.mode));
        !           180: 
        !           181: #if 0
        !           182:                tarItoa(statbuf.st_uid, pt->s.uid, sizeof(pt->s.uid));
        !           183:                tarItoa(statbuf.st_gid, pt->s.gid, sizeof(pt->s.gid));
        !           184:                tarItoa(statbuf.st_mtime, pt->s.mtime, sizeof(pt->s.mtime));
        !           185: #endif
        !           186: 
        !           187:                if (S_ISDIR(statbuf.st_mode)) {
        !           188:                        pt->s.typeflag = DIRTYPE;
        !           189:                        memset(pt->s.size, '0', sizeof(pt->s.size));
        !           190:                        // put the directory entry on the tape
        !           191:                        bflush(pb);
        !           192: 
        !           193:                        // put the directory contents on tape
        !           194:                        tar_dodir(pb, *ppchFiles, &statbuf);
        !           195: 
        !           196:                        ++ppchFiles;
        !           197:                        --count;
        !           198:                        continue;
        !           199:                }
        !           200:                if (S_ISFIFO(statbuf.st_mode)) {
        !           201:                        pt->s.typeflag = FIFOTYPE;
        !           202:                        memset(pt->s.size, '0', sizeof(pt->s.size));
        !           203:                        bflush(pb);
        !           204:                        ++ppchFiles;
        !           205:                        --count;
        !           206:                        continue;
        !           207:                }
        !           208:                if (statbuf.st_nlink > 1) {
        !           209:                        PLINKFILE p;
        !           210: 
        !           211:                        if (NULL != (p = GetLinkByIno(statbuf.st_ino))) {
        !           212:                                pt->s.typeflag = LNKTYPE;
        !           213:                                memset(pt->s.size, '0', sizeof(pt->s.size));
        !           214:                                strncpy(pt->s.linkname, p->name, TNAMSIZ);
        !           215:                                bflush(pb);
        !           216: 
        !           217:                                ++ppchFiles;
        !           218:                                --count;
        !           219:                                continue;
        !           220:                        }
        !           221: 
        !           222:                        AddLinkList(&statbuf, *ppchFiles);
        !           223:                }
        !           224: 
        !           225:                pt->s.typeflag = REGTYPE;
        !           226:                tarItoa((int)statbuf.st_size, pt->s.size, sizeof(pt->s.size));
        !           227: 
        !           228:                //
        !           229:                // compute the checksum for the header
        !           230:                //
        !           231: 
        !           232:                memset(pt->s.chksum, ' ', sizeof(pt->s.chksum));
        !           233:                for (i = 0, chksum = 0; i < sizeof(pt->buf); ++i) {
        !           234:                        chksum += pt->buf[i];
        !           235:                }
        !           236:                tarItoa(chksum, pt->s.chksum, sizeof(pt->s.chksum));
        !           237: 
        !           238:                fdin = open(*ppchFiles, O_RDONLY, 0);
        !           239:                if (-1 == fdin) {
        !           240:                        fprintf(stderr, "%s: open: ");
        !           241:                        perror(*ppchFiles);
        !           242:                        continue;
        !           243:                }
        !           244: 
        !           245:                // write the header
        !           246:                bflush(pb);
        !           247: 
        !           248:                if (0 == statbuf.st_size) {
        !           249:                        //
        !           250:                        // special case: don't write any data blocks.
        !           251:                        //
        !           252:                        close(fdin);
        !           253:                        ++ppchFiles;
        !           254:                        --count;
        !           255:                        continue;
        !           256:                }
        !           257: 
        !           258:                // copy the file data
        !           259:                // XXX.mjb:  what should happen here if we find that we can't
        !           260:                //      read the number of bytes we thought we'd be able to
        !           261:                //      read?  (The file could change size, or some kind
        !           262:                //      of error could occur.)  We can't leave the data too
        !           263:                //      small, or we'll hose the rest of the tar file.  So
        !           264:                //      we write extra blocks of zeroes.  What if the file
        !           265:                //      turns out to be longer than expected?  Print a
        !           266:                //      warning and continue?
        !           267: 
        !           268:                memset(pb->data, 0, sizeof(pb->data));
        !           269:                while (statbuf.st_size > 0) {
        !           270:                        int nbytes;
        !           271:                        char c;
        !           272: 
        !           273:                        nbytes = read(fdin, &c, 1);
        !           274:                        if (-1 == nbytes) {
        !           275:                                // error occurs before we have all the data.
        !           276:                        }
        !           277:                        bputc(pb, c);
        !           278:                        --statbuf.st_size;
        !           279:                }
        !           280:                bflush(pb);
        !           281:                close(fdin);
        !           282: 
        !           283:                ++ppchFiles;
        !           284:                --count;
        !           285:        }
        !           286: }
        !           287: 
        !           288: void
        !           289: TarList(PBUF pb)
        !           290: {
        !           291:        PTAR_HEAD pt;
        !           292:        char name[155 + 1 + 100 + 1];           //  "prefix / name \0"
        !           293:        unsigned long size, i;
        !           294:        char *pch;
        !           295: 
        !           296:        pt = (PTAR_HEAD)pb->data;
        !           297: 
        !           298:        do {
        !           299:                (void)strncpy(name, pt->s.prefix, 155);
        !           300:                name[155] = '\0';
        !           301:                if ('\0' != name[0]) {
        !           302:                        (void)strcat(name, "/");
        !           303:                }
        !           304:                (void)strncat(name, pt->s.name, 100);
        !           305: 
        !           306:                size = tarAtoi(pt->s.size);
        !           307: 
        !           308:                if (!fVerbose) {
        !           309:                        printf("%s\n", name);
        !           310:                } else {
        !           311:                        pch = modestring(pt);
        !           312:                        printf("%s %6ld %s\n", pch, size, name);
        !           313:                }
        !           314: 
        !           315:                size = round_up(size, 512);
        !           316:                for (i = 0; i < size; ++i) {
        !           317:                        bfill(pb);
        !           318:                }
        !           319:                bfill(pb);
        !           320:        } while (0 != pt->s.magic[0]);
        !           321: }
        !           322: 
        !           323: //
        !           324: // tarAtof -- translate tar-style octal strings to decimal
        !           325: //
        !           326: static int
        !           327: tarAtoi(char *pch)
        !           328: {
        !           329:        int num = 0;
        !           330:        
        !           331:        while ('\0' != *pch && ' ' != *pch) {
        !           332:                num = num * 8 + (*pch - '0');
        !           333:                ++pch;
        !           334:        }
        !           335:        return num;
        !           336: }
        !           337: 
        !           338: //
        !           339: // tarItoa -- for writing numeric fields in tar headers.
        !           340: void
        !           341: tarItoa(long i, char *pch, size_t len)
        !           342: {
        !           343:        // XXX.mjb: should check width < len
        !           344:        sprintf(pch, "%-o", i);
        !           345: }
        !           346: 
        !           347: //
        !           348: // round_up -- round num up to the nearest multiple of m.
        !           349: //
        !           350: unsigned long
        !           351: round_up(int num, int m)
        !           352: {
        !           353:        return (num + (m - 1))/m;
        !           354: }
        !           355: 
        !           356: static void
        !           357: tar_dodir(
        !           358:        PBUF pb,                // the tar image file, being written
        !           359:        char *pchfile,          // the directory file to be added to the archv
        !           360:        struct stat *psb        // result of stat on the directory file.
        !           361:        )
        !           362: {
        !           363:        DIR *dp;
        !           364:        struct dirent *dirent;
        !           365:        char *pch;
        !           366: 
        !           367:        dp = opendir(pchfile);
        !           368:        if (NULL == dp) {
        !           369:                fprintf(stderr, "%s: opendir: ", progname);
        !           370:                perror(pchfile);
        !           371:                return;
        !           372:        }
        !           373:        while (NULL != (dirent = readdir(dp))) {
        !           374:                if ('.' == dirent->d_name[0] &&
        !           375:                   ('\0' == dirent->d_name[1] ||
        !           376:                    0 == strcmp(dirent->d_name, ".."))) {
        !           377:                        continue;
        !           378:                }
        !           379: 
        !           380:                //
        !           381:                // Recurse.  We append the file name read from the directory
        !           382:                // to the directory name we were given and call TarWrite to
        !           383:                // put it on the tape.  It could be a directory, so we could
        !           384:                // end up back here.  This means that we must allocate the
        !           385:                // space for the pathname dynamically.  This seems like it
        !           386:                // will be a big time-waster.
        !           387:                //
        !           388: 
        !           389:                // strlen + 2:  one extra for '/', one extra for null.
        !           390:                pch = malloc(strlen(pchfile) + strlen(dirent->d_name) + 2);
        !           391:                if (NULL == pch) {
        !           392:                        fprintf(stderr, "%s: virtual memory exhausted\n",
        !           393:                                progname);
        !           394:                        exit(4);
        !           395:                }
        !           396:                strcpy(pch, pchfile);
        !           397:                strcat(pch, "/");
        !           398:                strcat(pch, dirent->d_name);
        !           399:                
        !           400:                TarWrite(pb, &pch, 1);
        !           401:                free(pch);
        !           402:        }
        !           403:        (void)closedir(dp);
        !           404: }
        !           405: 
        !           406: static char *
        !           407: modestring(PTAR_HEAD pt)
        !           408: {
        !           409:        static char sb[11];
        !           410:        unsigned long mask, mode;
        !           411:        char *rwx = "rwxrwxrwx";
        !           412:        char *string;
        !           413: 
        !           414:        sb[11] = '\0';
        !           415:        string = sb;
        !           416: 
        !           417:        switch (pt->s.typeflag) {
        !           418:        case LNKTYPE:
        !           419:        case REGTYPE:
        !           420:                string[0] = '-';
        !           421:                break;
        !           422:        case DIRTYPE:
        !           423:                string[0] = 'd';
        !           424:                break;
        !           425:        case FIFOTYPE:
        !           426:                string[0] = 'f';
        !           427:                break;
        !           428:        case SYMTYPE:
        !           429:                string[0] = 'l';
        !           430:                break;
        !           431:        case BLKTYPE:
        !           432:                string[0] = 'b';
        !           433:                break;
        !           434:        case CHRTYPE:
        !           435:                string[0] = 'c';
        !           436:                break;
        !           437:        case CONTTYPE:
        !           438:                string[0] = '=';
        !           439:                break;
        !           440:        default:
        !           441:                fprintf(stderr, "modestring shouldn't get here\n");
        !           442:        }
        !           443:        string++;
        !           444: 
        !           445:        mode = tarAtoi(pt->s.mode);
        !           446:        
        !           447:        for (mask = 0400; mask != 0; mask >>= 1) {
        !           448:                if (mode & mask) {
        !           449:                        *string++ = *rwx++;
        !           450:                } else {
        !           451:                        *string++ = '-';
        !           452:                        rwx++;
        !           453:                }
        !           454:        }
        !           455: 
        !           456:        return sb;
        !           457: }

unix.superglobalmegacorp.com

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