Annotation of mstools/posix/samples/psxarc/tar.c, revision 1.1.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.