This is untar.c in view mode; [Download] [Up]
/* untar.c */ /* DESCRIPTION: * Untar extracts files from an uncompressed tar archive, or one which * has been compressed with gzip. Usually such archives will have file * names that end with ".tar" or ".tgz" respectively, although untar * doesn't depend on any naming conventions. * * HOW TO COMPILE: * Untar doesn't require any special libraries or compile-time flags. * A simple "cc untar.c -o untar" (or the local equivelent) is * sufficient. Even "make untar" works, without needing a Makefile. * For Microsoft Visual C++, the command is either "cl untar.c" * (for 32 bit compilers) or "cl /F 1400 untar.c" (for 16-bit). * IF YOU SEE COMPILER WARNINGS, THAT'S NORMAL; you can ignore them. * * PORTABILITY: * Untar uses only the <stdio.h> header. It uses old-style function * definitions. It opens all files in binary mode. Taken together, * this means that untar should compile & run on just about anything * ... though your compiler may give a lot of warning messages. * * If your system supports the POSIX chmod(2) and utime(2) calls, then * you may wish to compile with -D_POSIX_SOURCE, which will enable untar * to use those system calls to restore the timestamp and permissions of * the extracted files. (For Linux, _POSIX_SOURCE is always defined.) * * SELF-EXTRACTING ARCHIVES: * You can create a self-extracting archive by compiling untar.c for the * target system, and then appending the gzipped tar archive onto the end * of the executable. When the resulting executable is executed with "-s" * it will locate the data inside itself, and extract it. An example of * this under UNIX: * cc untar.c -o mystuff * tar cvfz - datafiles... >>mystuff * mystuff -s -t * * AUTHOR & COPYRIGHT INFO: * Written by Steve Kirkendall, kirkenda@cs.pdx.edu * Placed in public domain, 6 October 1995 * * Portions derived from inflate.c -- Not copyrighted 1992 by Mark Adler * version c10p1, 10 January 1993 */ #include <stdio.h> #ifndef SEEK_SET # define SEEK_SET 0 #endif #ifdef _POSIX_SOURCE # include <sys/types.h> # include <sys/stat.h> # include <utime.h> #endif #define WSIZE 32768 /* size of decompression buffer */ #define TSIZE 512 /* size of a "tape" block */ #define CR 13 /* carriage-return character */ #define LF 10 /* line-feed character */ typedef unsigned char uchar_t; typedef unsigned short ushort_t; typedef unsigned long ulong_t; typedef struct { uchar_t magic[2]; /* magic: 0x1F, 0x8b */ uchar_t compression; /* compression method: 8=deflated */ uchar_t flags; /* content flags: 0x08 bit -> name present */ uchar_t mtime[4]; /* time_t when archive created */ uchar_t extraflags; /* ? */ uchar_t os; /* operating system: 3=UNIX */ /* if flags&0x08, then original file name goes here, '\0'-terminated */ } gzhdr_t; #define MAGIC0 0x1f #define MAGIC1 0x8b #define DEFLATE 0x08 #define NAME 0x08 typedef struct { char filename[100]; /* 0 name of next file */ char mode[8]; /* 100 Permissions and type (octal digits) */ char owner[8]; /* 108 Owner ID (ignored) */ char group[8]; /* 116 Group ID (ignored) */ char size[12]; /* 124 Bytes in file (octal digits) */ char mtime[12]; /* 136 Modification time stamp (octal digits)*/ char checksum[8]; /* 148 Header checksum (ignored) */ char type; /* 156 File type (see below) */ char linkto[100]; /* 157 Linked-to name (ignored) */ char brand[8]; /* 257 Identifies tar version (ignored) */ char ownername[32]; /* 265 Name of owner (ignored) */ char groupname[32]; /* 297 Name of group (ignored) */ char devmajor[8]; /* 329 Device major number (ignored) */ char defminor[8]; /* 337 Device minor number (ignored) */ char prefix[155]; /* 345 Prefix of name (optional) */ char RESERVED[12]; /* 500 Pad header size to 512 bytes */ } tar_t; #define ISREGULAR(hdr) ((hdr).type < '1' || (hdr).type > '6') typedef struct huft { uchar_t e; /* number of extra bits or operation */ uchar_t b; /* number of bits in this code or subcode */ union { ushort_t n; /* literal, length base, or distance base */ struct huft *t; /* pointer to next level of table */ } v; } huft_t; int wp; /* output counter */ uchar_t slide[WSIZE]; #define error(desc) {fprintf(stderr, "%s:%s", inname, (desc)); exit(1);} /* Tables for deflate from PKZIP's appnote.txt. */ static unsigned border[] = { /* Order of the bit length code lengths */ 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}; static ushort_t cplens[] = { /* Copy lengths for literal codes 257..285 */ 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0}; /* note: see note #13 above about the 258 in this list. */ static ushort_t cplext[] = { /* Extra bits for literal codes 257..285 */ 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, 99, 99}; /* 99==invalid */ static ushort_t cpdist[] = { /* Copy offsets for distance codes 0..29 */ 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, 8193, 12289, 16385, 24577}; static ushort_t cpdext[] = { /* Extra bits for distance codes */ 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13}; char *inname;/* name of input archive */ FILE *infp; /* input byte stream */ FILE *outfp; /* output stream, for file currently being extracted */ FILE *tarfp; /* usually NULL; else file for writing gunzipped data */ int maketar;/* -u: 1 to gunzip only, 0 to gunzip and extract tar files */ int listing;/* -t: 1 if listing, 0 if extracting */ int quiet; /* -q: 1 to write nothing to stderr, 0 for normal chatter */ int force; /* -f: 1 to overwrite existing files, 0 to skip them */ int convert;/* -c: 1 to convert newlines, 0 to leave unchanged */ int selfext;/* -s: 1 to skip data preceding a GZIP archive */ int nskips; /* number of files skipped in absence of "force" option */ char **only; /* array of filenames to extract/list */ int nonlys; /* number of filenames in "only" array; 0=extract all */ ulong_t bb; /* bit buffer */ unsigned bk; /* bits in bit buffer */ ushort_t mask_bits[] = { 0x0000, 0x0001, 0x0003, 0x0007, 0x000f, 0x001f, 0x003f, 0x007f, 0x00ff, 0x01ff, 0x03ff, 0x07ff, 0x0fff, 0x1fff, 0x3fff, 0x7fff, 0xffff }; #define NEXTBYTE() (uchar_t)getc(infp) #define NEEDBITS(n) {while(k<(n)){b|=((ulong_t)NEXTBYTE())<<k;k+=8;}} #define DUMPBITS(n) {b>>=(n);k-=(n);} int lbits = 9; /* bits in base literal/length lookup table */ int dbits = 6; /* bits in base distance lookup table */ /* If BMAX needs to be larger than 16, then h and x[] should be ulong_t. */ #define BMAX 16 /* maximum bit length of any code (16 for explode) */ #define N_MAX 288 /* maximum number of codes in any set */ unsigned hufts; /* track memory usage */ /*----------------------------------------------------------------------------*/ /* create a file for writing. If necessary, create the directories leading up * to that file as well. */ static FILE *createpath(name) char *name; /* pathname of file to create */ { FILE *fp; int i; /* if we aren't allowed to overwrite and this file exists, return NULL */ if (!force && access(name, 0) == 0) { fprintf(stderr, "%s: exists, will not overwrite without -f\n", name); return NULL; } /* first try creating it the easy way */ fp = fopen(name, convert ? "w" : "wb"); if (fp) return fp; /* Else try making all of its directories, and then try creating * the file again. */ for (i = 0; name[i]; i++) { /* If this is a slash, then temporarily replace the '/' * with a '\0' and do a mkdir() on the resulting string. * Ignore errors for now. */ if (name[i] == '/') { name[i] = '\0'; (void)mkdir(name, 0777); name[i] = '/'; } } fp = fopen(name, convert ? "w" : "wb"); if (!fp) perror(name); return fp; } /* This calls fwrite(), possibly after converting CR-LF to LF */ static void cvtwrite(blk, size, fp) uchar_t *blk; /* the block to be written */ ulong_t size; /* number of characters to be written */ FILE *fp; /* file to write to */ { int i, j; static uchar_t mod[TSIZE]; if (convert) { for (i = j = 0; i < size; i++) { /* convert LF to local newline convention */ if (blk[i] == LF) mod[j++] = '\n'; /* If CR-LF pair, then delete the CR */ else if (blk[i] == CR && (i+1 >= size || blk[i+1] == LF)) ; /* other characters copied literally */ else mod[j++] = blk[i]; } size = j; blk = mod; } fwrite(blk, (size_t)size, sizeof(uchar_t), fp); } /* list files in an archive, and optionally extract them as well */ static void untar(blk) uchar_t *blk; /* a tape block */ { static char nbuf[256];/* storage space for prefix+name, combined */ static char *name; /* prefix and name, combined */ static ulong_t size; /* number of bytes in file */ int i; #ifdef _POSIX_SOURCE static mode_t mode; /* file permissions */ static struct utimbuf timestamp; /* file timestamp */ #endif /* process each type of tape block differently */ if (size > TSIZE) { /* data block, but not the last one */ if (outfp) cvtwrite(blk, (ulong_t)TSIZE, outfp); size -= TSIZE; } else if (size > 0) { /* last data block of current file */ if (outfp) { cvtwrite(blk, size, outfp); fclose(outfp); #ifdef _POSIX_SOURCE utime(name, ×tamp); chmod(name, mode); #endif } size = 0; } else if (((tar_t *)blk)->filename[0] == '\0') { /* end-of-archive marker */ exit(0); } else { /* file header */ /* half-assed verification -- does it look like header? */ if (((tar_t *)blk)->filename[99] != '\0' || (((tar_t *)blk)->size[0] < '0' && ((tar_t *)blk)->size[0] != ' ') || ((tar_t *)blk)->size[0] > '9') { fprintf(stderr, "%s: not a valid tar file\n", inname); exit(2); } /* combine prefix and filename */ memset(nbuf, 0, sizeof nbuf); name = nbuf; if (((tar_t *)blk)->prefix[0]) { strncpy(name, ((tar_t *)blk)->prefix, sizeof ((tar_t *)blk)->prefix); strcat(name, "/"); strncat(name + strlen(name), ((tar_t *)blk)->filename, sizeof ((tar_t *)blk)->filename); } else { strncpy(name, ((tar_t *)blk)->filename, sizeof ((tar_t *)blk)->filename); } /* strip off leading '/' characters */ while (*name == '/') name++; /* if last character of name is '/' then assume directory */ if (*name && name[strlen(name) - 1] == '/') ((tar_t *)blk)->type = '5'; /* convert file size */ for (size = 0L, i = 0; i < sizeof(((tar_t *)blk)->size); i++) { if (((tar_t *)blk)->size[i] >= '0' && ((tar_t *)blk)->size[i] <= '7') size = size * 8 + ((tar_t *)blk)->size[i] - '0'; } #ifdef _POSIX_SOURCE /* convert file timestamp */ for (timestamp.modtime = 0L, i = 0; i < sizeof(((tar_t *)blk)->mtime); i++) { if (((tar_t *)blk)->mtime[i] >= '0' && ((tar_t *)blk)->mtime[i] <= '7') timestamp.modtime = timestamp.modtime * 8 + ((tar_t *)blk)->mtime[i] - '0'; } timestamp.actime = timestamp.modtime; /* convert file permissions */ for (mode = i = 0; i < sizeof(((tar_t *)blk)->mode); i++) { if (((tar_t *)blk)->mode[i] >= '0' && ((tar_t *)blk)->mode[i] <= '7') mode = mode * 8 + ((tar_t *)blk)->mode[i] - '0'; } #endif /* If we have an "only" list, and this file isn't in it, * then skip it. */ if (nonlys > 0) { for (i = 0; i < nonlys && strcmp(only[i], name) && (strncmp(only[i], name, strlen(only[i])) || name[strlen(only[i])] != '/'); i++) { } if (i >= nonlys) { outfp = NULL; return; } } /* list the file */ if (!quiet) { printf("%c %s", ISREGULAR(*(tar_t *)blk) ? '-' : ("Llcbdp"[((tar_t *)blk)->type - '1']), name); } /* if not a regular file, then skip it */ if (!ISREGULAR(*(tar_t *)blk)) { if (!quiet) printf("\n"); return; } /* print file statistics */ if (!quiet) { printf(" (%ld byte%s, %ld tape block%s)\n", size, size == 1 ? "" : "s", (size + TSIZE - 1) / TSIZE, (size > 0 && size <= TSIZE) ? "" : "s"); } /* if extracting, then try to create the file */ if (!listing) outfp = createpath(name); else outfp = NULL; /* if file is 0 bytes long, then we're done already! */ if (size == 0 && outfp) { fclose(outfp); #ifdef _POSIX_SOURCE utime(name, ×tamp); chmod(name, mode); #endif } } } /* send decompressed tape blocks to untar() */ void flush_output(w) unsigned w; /* number of bytes in slide[] */ { unsigned i; if (tarfp) { cvtwrite(slide, (ulong_t)w, tarfp); } else { /* send each block to untar() */ for (i = 0; i < w; i += TSIZE) { untar(&slide[i]); } } } /*----------------------------------------------------------------------------*/ /* Given a list of code lengths and a maximum table size, make a set of * tables to decode that set of codes. Return zero on success, one if * the given code set is incomplete (the tables are still built in this * case), two if the input is invalid (all zero length codes or an * oversubscribed set of lengths), and three if not enough memory. */ int huft_build(b, n, s, d, e, t, m) unsigned *b; /* code lengths in bits (all assumed <= BMAX) */ unsigned n; /* number of codes (assumed <= N_MAX) */ unsigned s; /* number of simple-valued codes (0..s-1) */ ushort_t *d; /* list of base values for non-simple codes */ ushort_t *e; /* list of extra bits for non-simple codes */ huft_t **t; /* result: starting table */ int *m; /* maximum lookup bits, returns actual */ { unsigned a; /* counter for codes of length k */ unsigned c[BMAX+1]; /* bit length count table */ unsigned f; /* i repeats in table every f entries */ int g; /* maximum code length */ int h; /* table level */ register unsigned i; /* counter, current code */ register unsigned j; /* counter */ register int k; /* number of bits in current code */ int l; /* bits per table (returned in m) */ register unsigned *p; /* pointer into c[], b[], or v[] */ register huft_t *q; /* points to current table */ huft_t r; /* table entry for structure assignment */ huft_t *u[BMAX]; /* table stack */ unsigned v[N_MAX]; /* values in order of bit length */ register int w; /* bits before this table == (l * h) */ unsigned x[BMAX+1]; /* bit offsets, then code stack */ unsigned *xp; /* pointer into x */ int y; /* number of dummy codes added */ unsigned z; /* number of entries in current table */ /* Generate counts for each bit length */ memset(c, 0, sizeof(c)); p = b; i = n; do { c[*p++]++; /* assume all entries <= BMAX */ } while (--i); if (c[0] == n) /* null input--all zero length codes */ { *t = (huft_t *)NULL; *m = 0; return 0; } /* Find minimum and maximum length, bound *m by those */ l = *m; for (j = 1; j <= BMAX; j++) if (c[j]) break; k = j; /* minimum code length */ if ((unsigned)l < j) l = j; for (i = BMAX; i; i--) if (c[i]) break; g = i; /* maximum code length */ if ((unsigned)l > i) l = i; *m = l; /* Adjust last length count to fill out codes, if needed */ for (y = 1 << j; j < i; j++, y <<= 1) if ((y -= c[j]) < 0) return 2; /* bad input: more codes than bits */ if ((y -= c[i]) < 0) return 2; c[i] += y; /* Generate starting offsets into the value table for each length */ x[1] = j = 0; p = c + 1; xp = x + 2; while (--i) { /* note that i == g from above */ *xp++ = (j += *p++); } /* Make a table of values in order of bit lengths */ p = b; i = 0; do { if ((j = *p++) != 0) v[x[j]++] = i; } while (++i < n); /* Generate the Huffman codes and for each, make the table entries */ x[0] = i = 0; /* first Huffman code is zero */ p = v; /* grab values in bit order */ h = -1; /* no tables yet--level -1 */ w = -l; /* bits decoded == (l * h) */ u[0] = (huft_t *)NULL; /* just to keep compilers happy */ q = (huft_t *)NULL; /* ditto */ z = 0; /* ditto */ /* go through the bit lengths (k already is bits in shortest code) */ for (; k <= g; k++) { a = c[k]; while (a--) { /* here i is the Huffman code of length k bits for value *p */ /* make tables up to required level */ while (k > w + l) { h++; w += l; /* previous table always l bits */ /* compute minimum size table less than or equal to l bits */ z = (z = g - w) > (unsigned)l ? l : z; /* upper limit on table size */ if ((f = 1 << (j = k - w)) > a + 1) /* try a k-w bit table */ { /* too few codes for k-w bit table */ f -= a + 1; /* deduct codes from patterns left */ xp = c + k; while (++j < z) /* try smaller tables up to z bits */ { if ((f <<= 1) <= *++xp) break; /* enough codes to use up j bits */ f -= *xp; /* else deduct codes from patterns */ } } z = 1 << j; /* table entries for j-bit table */ /* allocate and link in new table */ q = (huft_t *)malloc((z + 1)*sizeof(huft_t)); hufts += z + 1; /* track memory usage */ *t = q + 1; /* link to list for huft_free() */ *(t = &(q->v.t)) = (huft_t *)NULL; u[h] = ++q; /* table starts after link */ /* connect to last table, if there is one */ if (h) { x[h] = i; /* save pattern for backing up */ r.b = (uchar_t)l; /* bits to dump before this table */ r.e = (uchar_t)(16 + j);/* bits in this table */ r.v.t = q; /* pointer to this table */ j = i >> (w - l); /* (get around Turbo C bug) */ u[h-1][j] = r; /* connect to last table */ } } /* set up table entry in r */ r.b = (uchar_t)(k - w); if (p >= v + n) r.e = 99;/* out of values--invalid code */ else if (*p < s) { r.e = (uchar_t)(*p < 256 ? 16 : 15);/* 256 is end-of-block code */ r.v.n = *p++; /* simple code is just the value */ } else { r.e = (uchar_t)e[*p - s]; /* non-simple--look up in lists */ r.v.n = d[*p++ - s]; } /* fill code-like entries with r */ f = 1 << (k - w); for (j = i >> w; j < z; j += f) q[j] = r; /* backwards increment the k-bit code i */ for (j = 1 << (k - 1); i & j; j >>= 1) i ^= j; i ^= j; /* backup over finished tables */ while ((i & ((1 << w) - 1)) != x[h]) { h--; /* don't need to update q */ w -= l; } } } /* Return true (1) if we were given an incomplete table */ return y != 0 && g != 1; } /* Free the malloc'ed tables built by huft_build(), which makes a linked * list of the tables it made, with the links in a dummy first entry of * each table. */ int huft_free(t) huft_t *t; /* table to free */ { register huft_t *p, *q; /* Go through linked list, freeing from the malloced (t[-1]) address. */ p = t; while (p != (huft_t *)NULL) { q = (--p)->v.t; free(p); p = q; } return 0; } /* Inflate (decompress) the codes in a deflated (compressed) block. * Return an error code or zero if it all goes ok. */ int inflate_codes(tl, td, bl, bd) huft_t *tl, *td; /* literal/length and distance decoder tables */ int bl, bd; /* number of bits decoded by tl[] and td[] */ { register unsigned e; /* table entry flag/number of extra bits */ unsigned n, d; /* length and index for copy */ unsigned w; /* current window position */ huft_t *t; /* pointer to table entry */ unsigned ml, md; /* masks for bl and bd bits */ register ulong_t b; /* bit buffer */ register unsigned k; /* number of bits in bit buffer */ /* make local copies of globals */ b = bb; /* initialize bit buffer */ k = bk; w = wp; /* initialize window position */ /* inflate the coded data */ ml = mask_bits[bl]; /* precompute masks for speed */ md = mask_bits[bd]; for (;;) /* do until end of block */ { NEEDBITS((unsigned)bl) if ((e = (t = tl + ((unsigned)b & ml))->e) > 16) do { if (e == 99) return 1; DUMPBITS(t->b) e -= 16; NEEDBITS(e) } while ((e = (t = t->v.t + ((unsigned)b & mask_bits[e]))->e) > 16); DUMPBITS(t->b) if (e == 16) /* then it's a literal */ { slide[w++] = (uchar_t)t->v.n; if (w == WSIZE) { flush_output(w); w = 0; } } else /* it's an EOB or a length */ { /* exit if end of block */ if (e == 15) break; /* get length of block to copy */ NEEDBITS(e) n = t->v.n + ((unsigned)b & mask_bits[e]); DUMPBITS(e); /* decode distance of block to copy */ NEEDBITS((unsigned)bd) if ((e = (t = td + ((unsigned)b & md))->e) > 16) do { if (e == 99) return 1; DUMPBITS(t->b) e -= 16; NEEDBITS(e) } while ((e = (t = t->v.t + ((unsigned)b & mask_bits[e]))->e) > 16); DUMPBITS(t->b) NEEDBITS(e) d = w - t->v.n - ((unsigned)b & mask_bits[e]); DUMPBITS(e) /* do the copy */ do { n -= (e = (e = WSIZE - ((d &= WSIZE-1) > w ? d : w)) > n ? n : e); #if !defined(NOMEMCPY) && !defined(DEBUG) if (w - d >= e) /* (this test assumes unsigned comparison) */ { memcpy(slide + w, slide + d, e); w += e; d += e; } else /* do it slow to avoid memcpy() overlap */ #endif /* !NOMEMCPY */ do { slide[w++] = slide[d++]; } while (--e); if (w == WSIZE) { flush_output(w); w = 0; } } while (n); } } /* restore the globals from the locals */ wp = w; /* restore global window pointer */ bb = b; /* restore global bit buffer */ bk = k; /* done */ return 0; } /* "decompress" an inflated type 0 (stored) block. */ int inflate_stored() { unsigned n; /* number of bytes in block */ unsigned w; /* current window position */ register ulong_t b; /* bit buffer */ register unsigned k; /* number of bits in bit buffer */ /* make local copies of globals */ b = bb; /* initialize bit buffer */ k = bk; w = wp; /* initialize window position */ /* go to byte boundary */ n = k & 7; DUMPBITS(n); /* get the length and its complement */ NEEDBITS(16) n = ((unsigned)b & 0xffff); DUMPBITS(16) NEEDBITS(16) if (n != (unsigned)((~b) & 0xffff)) return 1; /* error in compressed data */ DUMPBITS(16) /* read and output the compressed data */ while (n--) { NEEDBITS(8) slide[w++] = (uchar_t)b; if (w == WSIZE) { flush_output(w); w = 0; } DUMPBITS(8) } /* restore the globals from the locals */ wp = w; /* restore global window pointer */ bb = b; /* restore global bit buffer */ bk = k; return 0; } /* Decompress an inflated type 1 (fixed Huffman codes) block. We should * either replace this with a custom decoder, or at least precompute the * Huffman tables. */ int inflate_fixed() { int i; /* temporary variable */ huft_t *tl; /* literal/length code table */ huft_t *td; /* distance code table */ int bl; /* lookup bits for tl */ int bd; /* lookup bits for td */ unsigned l[288]; /* length list for huft_build */ /* set up literal table */ for (i = 0; i < 144; i++) l[i] = 8; for (; i < 256; i++) l[i] = 9; for (; i < 280; i++) l[i] = 7; for (; i < 288; i++) /* make a complete, but wrong code set */ l[i] = 8; bl = 7; if ((i = huft_build(l, 288, 257, cplens, cplext, &tl, &bl)) != 0) return i; /* set up distance table */ for (i = 0; i < 30; i++) /* make an incomplete code set */ l[i] = 5; bd = 5; if ((i = huft_build(l, 30, 0, cpdist, cpdext, &td, &bd)) > 1) { huft_free(tl); return i; } /* decompress until an end-of-block code */ if (inflate_codes(tl, td, bl, bd)) return 1; /* free the decoding tables, return */ huft_free(tl); huft_free(td); return 0; } /* decompress an inflated type 2 (dynamic Huffman codes) block. */ int inflate_dynamic() { int i; /* temporary variables */ unsigned j; unsigned l; /* last length */ unsigned m; /* mask for bit lengths table */ unsigned n; /* number of lengths to get */ huft_t *tl; /* literal/length code table */ huft_t *td; /* distance code table */ int bl; /* lookup bits for tl */ int bd; /* lookup bits for td */ unsigned nb; /* number of bit length codes */ unsigned nl; /* number of literal/length codes */ unsigned nd; /* number of distance codes */ unsigned ll[286+30];/* literal/length and distance code lengths */ register ulong_t b; /* bit buffer */ register unsigned k; /* number of bits in bit buffer */ /* make local bit buffer */ b = bb; k = bk; /* read in table lengths */ NEEDBITS(5) nl = 257 + ((unsigned)b & 0x1f);/* number of literal/length codes */ DUMPBITS(5) NEEDBITS(5) nd = 1 + ((unsigned)b & 0x1f); /* number of distance codes */ DUMPBITS(5) NEEDBITS(4) nb = 4 + ((unsigned)b & 0xf); /* number of bit length codes */ DUMPBITS(4) if (nl > 286 || nd > 30) return 1; /* bad lengths */ /* read in bit-length-code lengths */ for (j = 0; j < nb; j++) { NEEDBITS(3) ll[border[j]] = (unsigned)b & 7; DUMPBITS(3) } for (; j < 19; j++) ll[border[j]] = 0; /* build decoding table for trees--single level, 7 bit lookup */ bl = 7; if ((i = huft_build(ll, 19, 19, NULL, NULL, &tl, &bl)) != 0) { if (i == 1) huft_free(tl); return i; /* incomplete code set */ } /* read in literal and distance code lengths */ n = nl + nd; m = mask_bits[bl]; i = l = 0; while ((unsigned)i < n) { NEEDBITS((unsigned)bl) j = (td = tl + ((unsigned)b & m))->b; DUMPBITS(j) j = td->v.n; if (j < 16) /* length of code in bits (0..15) */ ll[i++] = l = j;/* save last length in l */ else if (j == 16) /* repeat last length 3 to 6 times */ { NEEDBITS(2) j = 3 + ((unsigned)b & 3); DUMPBITS(2) if ((unsigned)i + j > n) return 1; while (j--) ll[i++] = l; } else if (j == 17) /* 3 to 10 zero length codes */ { NEEDBITS(3) j = 3 + ((unsigned)b & 7); DUMPBITS(3) if ((unsigned)i + j > n) return 1; while (j--) ll[i++] = 0; l = 0; } else /* j == 18: 11 to 138 zero length codes */ { NEEDBITS(7) j = 11 + ((unsigned)b & 0x7f); DUMPBITS(7) if ((unsigned)i + j > n) return 1; while (j--) ll[i++] = 0; l = 0; } } /* free decoding table for trees */ huft_free(tl); /* restore the global bit buffer */ bb = b; bk = k; /* build the decoding tables for literal/length and distance codes */ bl = lbits; if ((i = huft_build(ll, nl, 257, cplens, cplext, &tl, &bl)) != 0) { if (i == 1) { error(" incomplete literal tree\n"); huft_free(tl); } return i; /* incomplete code set */ } bd = dbits; if ((i = huft_build(ll + nl, nd, 0, cpdist, cpdext, &td, &bd)) != 0) { if (i == 1) { error(" incomplete distance tree\n"); huft_free(td); } huft_free(tl); return i; /* incomplete code set */ } /* decompress until an end-of-block code */ if (inflate_codes(tl, td, bl, bd)) return 1; /* free the decoding tables, return */ huft_free(tl); huft_free(td); return 0; } /* decompress an inflated block */ int inflate_block(e) int *e; /* last block flag */ { unsigned t; /* block type */ register ulong_t b; /* bit buffer */ register unsigned k; /* number of bits in bit buffer */ /* make local bit buffer */ b = bb; k = bk; /* read in last block bit */ NEEDBITS(1) *e = (int)b & 1; DUMPBITS(1) /* read in block type */ NEEDBITS(2) t = (unsigned)b & 3; DUMPBITS(2) /* restore the global bit buffer */ bb = b; bk = k; /* inflate that block type */ if (t == 2) return inflate_dynamic(); if (t == 0) return inflate_stored(); if (t == 1) return inflate_fixed(); /* bad block type */ return 2; } /* decompress an inflated entry */ int inflate() { int e; /* last block flag */ int r; /* result code */ unsigned h; /* maximum huft_t's malloc'ed */ /* initialize window, bit buffer */ wp = 0; bk = 0; bb = 0; /* decompress until the last block */ h = 0; do { hufts = 0; if ((r = inflate_block(&e)) != 0) return r; if (hufts > h) h = hufts; } while (!e); /* Undo too much lookahead. The next read will be byte aligned so we * can discard unused bits in the last meaningful byte. */ while (bk >= 8) { bk -= 8; /* inptr--;*/ } /* flush out slide */ flush_output(wp); /* return success */ return 0; } /* Process an archive file. This involves reading the blocks one at a time * (uncompressing if necessary as it goes along) and passing them to a untar() * function. */ static void doarchive(filename) char *filename; /* name of the archive file */ { char gunzipname[300]; int ch, len; long pos, datapos; /* open the archive */ inname = filename; infp = fopen(filename, "rb"); if (!infp) { perror(filename); return; } /* if self-extracting, then skip to GZIP data */ if (selfext) { for (len = 0; len < 3; ) { pos = ftell(infp); ch = getc(infp); if (ch == EOF) { fprintf(stderr, "No data in %s\n", filename); return; } else if (ch == MAGIC0) { datapos = pos; len = 1; } else if (ch == MAGIC1 && len == 1) { len = 2; } else if (ch == DEFLATE && len == 2) { len = 3; } else { len = 0; } } fseek(infp, datapos, SEEK_SET); } /* read the first few bytes, so we can determine whether to decompress */ fread(slide, 1, sizeof(gzhdr_t), infp); if (((gzhdr_t *)slide)->magic[0] == MAGIC0 && ((gzhdr_t *)slide)->magic[1] == MAGIC1) { /* COMPRESSED WITH GZIP */ /* Check for unsupported compression types */ if (((gzhdr_t *)slide)->compression != DEFLATE) { fprintf(stderr, "Unsupported compression type\n"); exit(0); } /* If original file name present, skip it */ if (((gzhdr_t *)slide)->flags & NAME) { for (len = 0; (ch = getc(infp)) != '\0'; len++) { gunzipname[len] = ch; } gunzipname[len] = '\0'; } else if (maketar) { /* we need to make up a name */ strcpy(gunzipname, filename); len = strlen(filename); if (len > 3 && (!strcmp(filename + len - 3, ".gz") || !strcmp(filename + len - 3, ".GZ"))) { gunzipname[len - 3] = '\0'; } else if (len > 2 && (!strcmp(filename + len - 2, ".z") || !strcmp(filename + len - 2, ".Z"))) { gunzipname[len - 2] = '\0'; } else if (len > 4 && (!strcmp(filename + len - 4, ".tgz") || !strcmp(filename + len - 4, ".TGZ"))) { strcpy(&gunzipname[len - 4], ".tar"); } else { strcpy(gunzipname, "untar.out"); } } /* if we're writing the gunzip output, then create the output file */ if (maketar) { if (!quiet && listing) { printf("%s: would be gunzipped to %s\n", filename, gunzipname); fclose(infp); return; } /* if not allowed to overwrite and file exists, complain */ if (!force && access(gunzipname, 0) == 0) { fprintf(stderr, "%s: exists, will not overwrite without -f\n", gunzipname); exit(2); } tarfp = fopen(gunzipname, convert ? "w" : "wb"); if (!tarfp) { perror(gunzipname); exit(2); } } /* inflate the blocks */ inflate(); } else { /* UNCOMPRESSED */ /* if we were supposed to just uncompress, complain */ if (maketar) { fprintf(stderr, "%s: isn't gzipped\n", filename); fclose(infp); return; } /* read the rest of the first block */ fread(&slide[sizeof(gzhdr_t)], 1, TSIZE - sizeof(gzhdr_t), infp); /* send each block to the untar() function */ do { untar(slide); } while (fread(slide, 1, TSIZE, infp) > 0); } /* close the archive file. */ fclose(infp); if (tarfp) { fclose(tarfp); tarfp = NULL; if (!quiet) { printf("%s: gunzipped to %s\n", filename, gunzipname); } } } static void usage(argv0) char *argv0; /* name of program */ { /* Give a usage message and exit */ fprintf(stderr, "Usage: %s [options] archive.tgz [filename]...\n", argv0); fprintf(stderr, " or: %s [options] -s [filename]...\n", argv0); fprintf(stderr, " or: %s [options] -u filename...\n", argv0); fprintf(stderr, "\n"); fprintf(stderr, "Options -t test -- list contents but don't extract\n"); fprintf(stderr, " -f force -- allow existing files to be overwritten\n"); fprintf(stderr, " -q quiet -- suppress normal chatter\n"); fprintf(stderr, " -c convert -- convert files to local text format\n"); fprintf(stderr, " -s self extracting -- gzipped archive data is appended to %s\n", argv0); fprintf(stderr, " -u uncompress -- perform \"gunzip\" but not \"tar x\"\n"); fprintf(stderr, "+------------------------------------%.*s---------------------------+\n", strlen(argv0), "--------------------------------------"); fprintf(stderr, "| FOR SELF-EXTRACTING ARCHIVES, USE \"%s -s\" TO EXTRACT THE FILES. |\n", argv0); fprintf(stderr, "+------------------------------------%.*s---------------------------+\n", strlen(argv0), "--------------------------------------"); fprintf(stderr, "This program lists/extracts files from a \"*.tar\" or \"*.tgz\" archive. You can\n"); fprintf(stderr, "optionally specify certain files or directories to list/extract; otherwise it\n"); #ifdef _POSIX_SOURCE fprintf(stderr, "will list/extract them all. File attributes are preserved. This program\n"); #else fprintf(stderr, "will list/extract them all. File attributes are NOT preserved. This program\n"); #endif fprintf(stderr, "can also be used (with -u) to gunzip non-tar files.\n"); fprintf(stderr, "\n"); fprintf(stderr, "THIS PROGRAM IS IN THE PUBLIC DOMAIN, AND IS FREELY REDISTRIBUTABLE.\n"); exit(1); } /* parse command-line arguments, and process each file */ main(argc, argv) int argc; char **argv; { int exitcode = 0; /* value passed to exit() */ int i, j; /* listing? extracting? */ for (i = 1; i < argc && argv[i][0] == '-'; i++) { if (!argv[i][1]) usage(argv[0]); for (j = 1; argv[i][j]; j++) { switch (argv[i][j]) { case 'u': maketar = 1; break; case 't': listing = 1; break; case 'f': force = 1; break; case 'q': quiet = 1; break; case 'c': convert = 1; break; case 's': selfext = 1; break; default: usage(argv[0]); } } } if (i >= argc && !selfext) { usage(argv[0]); } if (maketar) { /* uncompress each argument */ for (; i < argc; i++) { doarchive(argv[i]); } } else if (selfext) { /* detect whether we have an extraction list */ if (i < argc) { only = &argv[i]; nonlys = argc - i; } else { nonlys = 0; } /* list/extract files from self */ doarchive(argv[0]); } else { /* detect whether we have an extraction list */ if (i + 1 < argc) { only = &argv[i + 1]; nonlys = argc - (i + 1); } else { nonlys = 0; } /* list/extract files from archive */ doarchive(argv[i]); } exit(0); }
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.