6 WFLAGS="-ansi -pedantic -W -Wall -Wstrict-prototypes -Wtraditional -Wnested-externs -Winline -Wpointer-arith -Wbad-function-cast -Wcast-qual -Wmissing-prototypes -Wmissing-declarations -Wunused"; \
8 gcc -s -O2 $WFLAGS -DHAVE_ZLIB -DHAVE_BZ2LIB untarka.c -o untarka -lz -lbz2; \
11 * untarka.c -- Display contents and/or extract file from a tar file (possibly
12 * gzip'd, bzip'd or compress'd)
13 * by pts@fazekas.hu Wed Jan 29 00:38:31 CET 2003
14 * Z compiles fine at Wed Jan 29 14:20:32 CET 2003
15 * all run file at Wed Jan 29 15:50:39 CET 2003
16 * 0.34 Win32 runs fine at Wed Jan 29 16:02:57 GMT 2003
18 * Untarka extracts TAR (UNIX Tape ARchive) files without calling any
19 * external programs. It supports and autodetects multiple compression
20 * methods (.tar, .tar.Z, .tar.gz, .tar.bz2, .Z, .gz and .bz2). UNIX
21 * devices, sockets, hard links, symlinks, owners and permissions are
22 * ignored during extraction.
24 * written by "Pedro A. Aranda Guti\irrez" <paag@tid.es>
25 * adaptation to Unix by Jean-loup Gailly <jloup@gzip.org>
26 * adaptation to bzip2 by José Fonseca <em96115@fe.up.pt>
27 * merged comressors by Szabó Péter <pts@fazekas.hu> at Tue Jan 28 23:40:23 CET 2003
28 * compiles on Win32 under MinGW, Linux with gcc.
30 * To get gzip (zlib) support, pass to gcc: -DHAVE_ZLIB -lz
31 * To get bzip2 (bzlib2) support, pass to gcc: -DHAVE_BZ2LIB -lbz2
32 * To get compress (lz) support, relax, since it's the default.
34 * Compile memory-checking with checkergcc -g -ansi -pedantic -W -Wall -Wstrict-prototypes -Wtraditional -Wnested-externs -Winline -Wpointer-arith -Wbad-function-cast -Wcast-qual -Wmissing-prototypes -Wmissing-declarations -Wunused untarka.c -o untarka
37 * Imp: mknod() device, socket
41 * Imp: allow force non-tar gzipped file
42 * Imp: command line options
43 * Imp: uncompress ZIP files
44 * Dat: zlib is able to read uncompressed files, libbz2 isn't
46 * 257 string ustar\0 POSIX tar archive
47 * 257 string ustar\040\040\0 GNU tar archive
48 * 0 string BZh bzip2 compressed data
49 * 0 string \037\213 gzip compressed data
50 * 0 string \037\235 compress'd data
51 * is_tar.c() from file(1)
55 #if defined(WIN32) || defined(__MINGW32__) || defined(__CYGWIN__) || MSC_VER > 1000
58 # undef __STRICT_ANSI__
83 # define mkdir(dirname,mode) _mkdir(dirname)
84 # define unlink(fn) _unlink(fn)
85 # define access(path,mode) _access(path,mode)
87 # define mkdir(dirname,mode) _mkdir(dirname)
91 # include <sys/stat.h> /* mkdir() */
94 #ifndef OF /* function prototypes */
95 # if defined(__STDC__) || defined(__PROTOTYPES__) || defined(__cplusplus)
96 # define OF(args) args
98 # define OF(args) args
102 static void error OF((const char *msg));
104 static unsigned long total_read;
106 /* #define TAR_GZ 1 */
108 typedef struct Readable {
110 /** @return 0 on success, 1 on failure */
111 int (*xOpen4Read)(struct Readable* self, char const* filename);
112 /** @return 0 on success */
113 int (*xClose)(struct Readable* self);
114 /** @return (unsigned)-1 on error */
115 unsigned (*xRead)(struct Readable* self, void* buf, unsigned len);
116 char const* (*xError)(struct Readable* self, int *errnum_ret);
119 enum { FMT_U=1, FMT_Z=2, FMT_GZ=3, FMT_BZ2=4 };
121 /* #define xFILE FILE* */
122 static int xU_Open4Read(struct Readable* self, char const* filename) { total_read=0; return NULL==(self->f=fopen(filename,"rb")); }
123 static int xU_Close(struct Readable* self) { return fclose((FILE*)self->f); }
124 static unsigned xU_Read(struct Readable* self, void* buf, unsigned len) {
125 unsigned got=fread(buf,1,len,(FILE*)self->f);
127 return got>0 ? got : ferror((FILE*)self->f) ? 0U-1 : 0;
129 static char const* xU_Error(struct Readable* self, int *errnum_ret) { return (*errnum_ret=ferror((FILE*)self->f))?"I/O error":"OK"; }
131 /* #define xFILE struct lz_reader_t* */
133 static struct lz_reader_t* lz_read_new(FILE* inf);
134 static int lz_read_init(struct lz_reader_t* reader, FILE* inf);
135 static int lz_close(struct lz_reader_t* reader);
136 static unsigned lz_read(struct lz_reader_t* reader, char*buf, unsigned len);
138 static int xZ_Open4Read(struct Readable* self, char const* filename) {
139 FILE *f=fopen(filename,"rb");
140 if (NULL==f) return 1;
141 return NULL==(self->f=lz_read_new(f));
143 static int xZ_Close(struct Readable* self) {
144 int ret=lz_close((struct lz_reader_t*)self->f);
145 free((struct lz_reader_t*)self->f);
148 static unsigned xZ_Read(struct Readable* self, void* buf, unsigned len) {
149 return lz_read((struct lz_reader_t*)self->f, buf, len);
151 static char const* xZ_Error(struct Readable* self, int *errnum_ret) {
159 /* #define xFILE gzFile */
160 static int xGZ_Open4Read(struct Readable* self, char const* filename) { total_read=0; return NULL==(self->f=gzopen(filename,"rb")); }
161 static int xGZ_Close(struct Readable* self) { return gzclose((gzFile)self->f); }
162 static unsigned xGZ_Read(struct Readable* self, void* buf, unsigned len) { unsigned l=gzread((gzFile)self->f,buf,len); total_read=((z_streamp)self->f)->total_in; return l; }
163 static char const* xGZ_Error(struct Readable* self, int *errnum_ret) { return gzerror((gzFile)self->f, errnum_ret); }
168 /* #define xFILE BZFILE* */
169 static int xBZ2_Open4Read(struct Readable* self, char const* filename) { return NULL==(self->f=BZ2_bzopen(filename,"rb")); }
170 static int xBZ2_Close(struct Readable* self) { BZ2_bzclose((BZFILE*)self->f); return 0; }
171 static unsigned xBZ2_Read(struct Readable* self, void* buf, unsigned len) { return BZ2_bzread((BZFILE*)self->f,buf,len); }
172 static char const* xBZ2_Error(struct Readable* self, int *errnum_ret) { return BZ2_bzerror((BZFILE*)self->f, errnum_ret); }
178 * is_tar() -- figure out whether file is a tar archive.
180 * Stolen (by the author!) from the public domain tar program:
181 * Public Domain version written 26 Aug 1985 John Gilmore (ihnp4!hoptoad!gnu).
183 * @(#)list.c 1.18 9/23/86 Public Domain - gnu
186 * Comments changed and some code/comments reformatted
187 * for file command by Ian Darwin.
190 /* The magic field is filled with this if uname and gname are valid. */
191 #define TMAGIC "ustar " /* 7 chars and a null */
194 * Header block on tape.
196 * I'm going to use traditional DP naming conventions here.
197 * A "block" is a big chunk of stuff that we do I/O on.
198 * A "record" is a piece of info that we care about.
199 * Typically many "record"s fit into a "block".
201 #define RECORDSIZE 512
207 char charptr[RECORDSIZE];
217 char linkname[NAMSIZ];
226 #define isodigit(c) ( ((c) >= '0') && ((c) <= '7') )
228 static int from_oct(int, char *); /* Decode octal number */
232 * 0 if the checksum is bad (i.e., probably not a tar archive),
233 * 1 for old UNIX tar file,
234 * 2 for Unix Std (POSIX) tar file.
237 is_tar(char *buf, unsigned nbytes)
239 union tar_record *header = (union tar_record *)buf;
244 if (nbytes < sizeof(union tar_record))
247 recsum = from_oct(8, header->header.chksum);
251 for (i = sizeof(union tar_record); --i >= 0;) {
253 * We can't use unsigned char here because of old compilers,
259 /* Adjust checksum to count the "chksum" field as blanks. */
260 for (i = sizeof(header->header.chksum); --i >= 0;)
261 sum -= 0xFF & header->header.chksum[i];
262 sum += ' '* sizeof header->header.chksum;
265 return 0; /* Not a tar archive */
267 if (0==strcmp(header->header.magic, TMAGIC))
268 return 2; /* Unix Standard tar archive */
270 return 1; /* Old fashioned tar archive */
275 * Quick and dirty octal conversion.
277 * Result is -1 if the field is invalid (all blank, or nonoctal).
280 from_oct(int digs, char *where)
284 while (*where==' ' || *where=='\f' || *where=='\n' || *where=='\r' || *where=='\t' || *where=='\v') {
287 return -1; /* All blank field */
290 while (digs > 0 && isodigit(*where)) { /* Scan til nonoctal */
291 value = (value << 3) | (*where++ - '0');
295 if (digs > 0 && *where!='\0' && *where!=' ' && *where!='\f' && *where!='\n' && *where!='\r' && *where!='\t' && *where!='\v')
296 return -1; /* Ended on non-space/nul */
305 * @return 0 on success, positive for various failure reasons
307 static int xOpen4Read(struct Readable *self, char const* filename) {
309 char buf[RECORDSIZE];
310 FILE *f=fopen(filename, "rb");
311 if (f==NULL) return 4;
312 i=sizeof(buf); while (i--!=0) buf[i]='\0';
313 if (5>fread(buf, 1, sizeof(buf), f)) return 2;
315 } else if (buf[0]==0102 && buf[1]==0132 && buf[2]==0150) {
318 self->xOpen4Read=xBZ2_Open4Read;
319 self->xClose=xBZ2_Close;
320 self->xRead=xBZ2_Read;
321 self->xError=xBZ2_Error;
322 if (xBZ2_Open4Read(self, filename)!=0) return 1;
324 error("bzip2 compression not compiled in");
326 } else if (buf[0]==0037 && (buf[1]&255)==0213 && (buf[2]&255)<=8) {
329 self->xOpen4Read=xGZ_Open4Read;
330 self->xClose=xGZ_Close;
331 self->xRead=xGZ_Read;
332 self->xError=xGZ_Error;
333 if (xGZ_Open4Read(self, filename)!=0) return 1;
335 error("gzip compression not compiled in");
337 } else if (buf[0]==0037 && (buf[1]&255)==0235) {
339 self->xOpen4Read=xZ_Open4Read;
340 self->xClose=xZ_Close;
342 self->xError=xZ_Error;
343 if (xZ_Open4Read(self, filename)!=0) return 1;
344 } else if ((buf[257]==0165 && buf[258]==0163 && buf[259]==0164
345 && buf[260]==0141 && buf[261]==0162
346 && (buf[262]==0000 || (buf[262]==0040 && buf[263]==0040 && buf[264]==0))
347 ) || is_tar(buf, sizeof(buf))
350 self->f=f; /* shortcut */
351 self->xOpen4Read=xU_Open4Read;
352 self->xClose=xU_Close;
354 self->xError=xU_Error;
359 /* --- .Z LZ uncompression */
362 * (N)compress42.c - File compression ala IEEE Computer, Mar 1992.
363 * Modified by pts@fazekas.hu at Wed Jul 18 17:25:38 CEST 2001.
366 * Spencer W. Thomas (decvax!harpo!utah-cs!utah-gr!thomas)
367 * Jim McKie (decvax!mcvax!jim)
368 * Steve Davies (decvax!vax135!petsd!peora!srd)
369 * Ken Turkowski (decvax!decwrl!turtlevax!ken)
370 * James A. Woods (decvax!ihnp4!ames!jaw)
371 * Joe Orost (decvax!vax135!petsd!joe)
372 * Dave Mack (csu@alembic.acs.com)
373 * Peter Jannesen, Network Communication Systems
376 * Revision 4.2.3 92/03/14 peter@ncs.nl
377 * Optimise compress and decompress function and a lot of cleanups.
378 * New fast hash algoritme added (if more than 800Kb available).
385 #undef DONTPTS /* `#define DONTPTS 1' means original uncompress */
391 #define BITS 16 /* _must_ be able to handle this many bits, anyway */
394 # define ASSERT(x) do { if (!(x)) abort(); } while(0)
400 #include <string.h> /* memcpy(), memset() */
401 #include <stdlib.h> /* abort(), exit() */
403 /* #define fx_write(a,b,c) fwrite((b),1,(c),(a)) */
404 #define fx_read(a,b,c) fread( (b),1,(c),(a))
405 #define fx_stdin stdin
406 #define fx_stdout stdout
407 #define fx_type FILE*
410 #define LARGS(a) () /* Relay on include files for libary func defs. */
411 extern void *malloc LARGS((int));
412 extern void free LARGS((void *));
414 extern int open LARGS((char const *,int,...));
416 extern int close LARGS((int));
417 extern int read LARGS((int,void *,int));
418 extern int write LARGS((int,void const *,int));
419 extern int chmod LARGS((char const *,int));
420 extern int unlink LARGS((char const *));
421 extern int chown LARGS((char const *,int,int));
422 extern int utime LARGS((char const *,struct utimbuf const *));
423 extern char *strcpy LARGS((char *,char const *));
424 extern char *strcat LARGS((char *,char const *));
425 extern int strcmp LARGS((char const *,char const *));
426 extern unsigned strlen LARGS((char const *));
427 extern void *memset LARGS((void *,char,unsigned int));
428 extern void *memcpy LARGS((void *,void const *,unsigned int));
429 extern int atoi LARGS((char const *));
430 extern void exit LARGS((int));
431 extern int isatty LARGS((int));
439 #define min(a,b) ((a>b) ? b : a)
441 #define MAGIC_1 (char_type)'\037'/* First byte of compressed file */
442 #define MAGIC_2 (char_type)'\235'/* Second byte of compressed file */
443 #define BIT_MASK 0x1f /* Mask for 'number of compresssion bits' */
444 /* Masks 0x20 and 0x40 are free. */
445 /* I think 0x20 should mean that there is */
446 /* a fourth header byte (for expansion). */
447 #define BLOCK_MODE 0x80 /* Block compresssion if table is full and */
448 /* compression rate is dropping flush tables */
450 /* the next two codes should not be changed lightly, as they must not */
451 /* lie within the contiguous general code space. */
452 #define FIRST 257 /* first free entry */
453 #define CLEAR 256 /* table clear output code */
455 #define INIT_BITS 9 /* initial number of bits/code */
458 # define BYTEORDER 0000
466 * machine variants which require cc -Dmachine: pdp11, z8000, DOS
469 #ifdef interdata /* Perkin-Elmer */
470 # define SIGNED_COMPARE_SLOW /* signed compare is slower than unsigned */
473 #ifdef MSDOS /* PC/XT/AT (8088) processor */
475 # define BYTEORDER 4321
481 # define O_BINARY 0 /* System has no binary mode */
484 typedef long int code_int;
486 #ifdef SIGNED_COMPARE_SLOW
487 typedef unsigned short int count_short;
488 typedef unsigned long int cmp_code_int; /* Cast to make compare faster */
490 typedef long int cmp_code_int;
493 typedef unsigned char char_type;
495 #define MAXCODE(n) (1L << (n))
498 # define REGISTERS 20
518 # define REG1 register
522 # define REG2 register
526 # define REG3 register
530 # define REG4 register
534 # define REG5 register
538 # define REG6 register
542 # define REG7 register
546 # define REG8 register
550 # define REG9 register
554 # define REG10 register
558 # define REG11 register
562 # define REG12 register
566 # define REG13 register
570 # define REG14 register
574 # define REG15 register
578 # define REG16 register
581 #if BYTEORDER == 4321 && NOALLIGN == 1
582 #define input(b,o,c,n,m){ \
583 (c) = (*(long *)(&(b)[(o)>>3])>>((o)&0x7))&(m); \
587 #define input(b,o,c,n,m){ REG1 char_type *p = &(b)[(o)>>3]; \
588 (c) = ((((long)(p[0]))|((long)(p[1])<<8)| \
589 ((long)(p[2])<<16))>>((o)&0x7))&(m); \
595 * 8086 & 80286 Has a problem with array bigger than 64K so fake the array
596 * For processors with a limited address space and segments.
599 * To save much memory, we overlay the table used by compress() with those
600 * used by lz_decompress(). The tab_prefix table is the same size and type
601 * as the codetab. The tab_suffix table needs 2**BITS characters. We
602 * get this from the beginning of htab. The output stack uses the rest
603 * of htab, and contains characters. There is plenty of room for any
604 * possible stack (stack used to be 8000 characters).
607 #error removed MAXSEG_64K
608 #else /* Normal machine */
609 # define HSIZE (1<<16) /* (1<<15) is few, (1<<16) seems to be OK, (1<<17) is proven safe OK */
611 char_type lz_htab[2*HSIZE]; /* Dat: HSIZE for the codes and HSIZE for de_stack */
612 unsigned short lz_codetab[HSIZE];
614 # define tab_prefixof(i) codetab[i]
615 # define tab_suffixof(i) htab[i]
616 # define de_stack (htab+(sizeof(htab[0])*(2*HSIZE-1)))
617 # define clear_tab_prefixof() memset(codetab, 0, 256*sizeof(codetab[0]));
618 #endif /* MAXSEG_64K */
620 typedef struct lz_reader_t {
621 /* constants (don't change during decompression) */
623 char_type* inbuf; /* [IBUFSIZ+64]; Input buffer */
624 char_type* htab; /* [2*HSIZE]; Dat: HSIZE for the codes and HSIZE for de_stack */
625 unsigned short* codetab; /* [HSIZE]; */
629 /* variables that have to be saved */
646 static struct lz_reader_t* lz_read_new(FILE *inf) {
647 lz_reader_t* reader=(lz_reader_t*)malloc(sizeof(lz_reader_t));
650 if (lz_read_init(reader, inf)!=0) {
652 free(reader); reader=NULL;
657 static int lz_close(struct lz_reader_t* reader) {
658 FILE *fin=reader->fdin;
660 if (reader->inbuf!=NULL) { free(reader->inbuf ); reader->inbuf =NULL; }
661 if (reader->htab!=NULL) { free(reader->htab ); reader->htab =NULL; }
662 if (reader->codetab!=NULL) { free(reader->codetab); reader->codetab=NULL; }
663 if (fin==NULL) return 0;
667 /** @param Zreader uninitialized
668 * @return 0 on success
670 static int lz_read_init(struct lz_reader_t* reader, FILE *inf) {
672 unsigned short* codetab;
675 if (NULL==(reader->inbuf=malloc(IBUFSIZ+67))) return 1;
676 if (NULL==(htab=reader->htab=malloc(2*HSIZE))) return 1; /* Dat: HSIZE for the codes and HSIZE for de_stack */
677 if (NULL==(codetab=reader->codetab=malloc(sizeof(reader->codetab[0])*HSIZE))) return 1;
680 while (reader->insize < 3 && (reader->rsize = fx_read(reader->fdin, reader->inbuf+reader->insize, IBUFSIZ)) > 0)
681 reader->insize += reader->rsize;
683 if (reader->insize < 3
684 || reader->inbuf[0] != (char_type)'\037' /* First byte of compressed file */
685 || reader->inbuf[1] != (char_type)'\235' /* Second byte of compressed file */
686 ) return reader->insize >= 0 ? 2 : 3;
688 reader->maxbits = reader->inbuf[2] & BIT_MASK;
689 reader->blkmode = reader->inbuf[2] & BLOCK_MODE;
690 reader->maycode = MAXCODE(reader->maxbits);
692 if (reader->maxbits > BITS) return 4;
695 "%s: compressed with %d bits, can only handle %d bits\n",
696 ("stdin"), maxbits, BITS);
700 reader->maxcode = MAXCODE(reader->n_bits = INIT_BITS)-1;
701 reader->bitmask = (1<<reader->n_bits)-1;
702 reader->oldcode = -1;
704 reader->posbits = 3<<3;
705 reader->stackp = NULL;
707 reader->incode = -1; /* fake */
708 reader->inbits = 0; /* fake */
710 reader->freeent = ((reader->blkmode) ? FIRST : 256);
712 clear_tab_prefixof(); /* As above, initialize the first 256 entries in the table. */
714 for (codex = 255 ; codex >= 0 ; --codex)
715 tab_suffixof(codex) = (char_type)codex;
716 return 0; /* success */
720 * Decompress stdin to stdout. This routine adapts to the codes in the
721 * file building the "string" table on-the-fly; requiring no table to
722 * be stored in the compressed file. The tables used herein are shared
723 * with those of the compress() routine. See the definitions above.
725 static unsigned lz_read(struct lz_reader_t* reader, char* outbuf, unsigned obufsize) {
726 /* static int lz_decompress(fx_type fdin, fx_type fdout) */
727 REG2 char_type *stackp;
730 REG5 code_int oldcode;
731 REG6 code_int incode;
736 REG12 code_int freeent;
737 REG13 code_int maxcode;
738 REG14 code_int maycode;
745 unsigned short* codetab;
747 REG9 unsigned outpos=0; /* not restored */
750 fprintf(stderr, ":: call rsize=%d oldcode=%d\n", reader->rsize, (int)reader->oldcode);
752 if (reader->rsize<1) return reader->rsize; /* already EOF or error */
754 stackp =reader->stackp;
756 finchar=reader->finchar;
757 oldcode=reader->oldcode;
758 incode =reader->incode;
759 inbits =reader->inbits;
760 posbits=reader->posbits;
761 insize =reader->insize;
762 bitmask=reader->bitmask;
763 freeent=reader->freeent;
764 maxcode=reader->maxcode;
765 maycode=reader->maycode;
766 n_bits =reader->n_bits;
767 rsize =reader->rsize;
768 blkmode=reader->blkmode;
769 maxbits=reader->maxbits;
771 codetab=reader->codetab;
773 inbuf =reader->inbuf;
774 if (oldcode!=-1) goto try_fit; /* lz_read() called again */
783 e = insize-(o = (posbits>>3));
785 for (i = 0 ; i < e ; ++i)
786 inbuf[i] = inbuf[i+o];
792 if ((unsigned)insize < /*sizeof(inbuf)-IBUFSIZ*/ 64) {
794 fprintf(stderr, ":: try read insize=%d\n", insize);
796 if ((rsize = fx_read(fdin, inbuf+insize, IBUFSIZ)) < 0 || ferror(fdin)) return reader->rsize=-1;
798 fprintf(stderr, ":: got rsize=%d\n", rsize);
801 inbuf[insize]=inbuf[insize+1]=inbuf[insize+2]=0;
802 /* ^^^ sentinel, so input() won't produce ``read uninitialized byte(s) in a block.'' */
805 inbits = ((rsize > 0) ? (insize - insize%n_bits)<<3 :
806 (insize<<3)-(n_bits-1));
808 while (inbits > posbits) {
809 if (freeent > maxcode) {
810 posbits = ((posbits-1) + ((n_bits<<3) -
811 (posbits-1+(n_bits<<3))%(n_bits<<3)));
813 if (n_bits == maxbits)
816 maxcode = MAXCODE(n_bits)-1;
818 bitmask = (1<<n_bits)-1;
825 input(inbuf,posbits,code,n_bits,bitmask);
828 outbuf[outpos++] = (char_type)(finchar = (int)(oldcode = code));
831 /* Dat: oldcode will never be -1 again */
833 if (code == CLEAR && blkmode) {
834 clear_tab_prefixof();
836 posbits = ((posbits-1) + ((n_bits<<3) -
837 (posbits-1+(n_bits<<3))%(n_bits<<3)));
838 maxcode = MAXCODE(n_bits = INIT_BITS)-1;
839 bitmask = (1<<n_bits)-1;
846 if (code >= freeent) { /* Special case for KwKwK string. */
847 if (code > freeent) {
851 p = &inbuf[posbits>>3];
854 fprintf(stderr, "uncompress: insize:%d posbits:%d inbuf:%02X %02X %02X %02X %02X (%d)\n", insize, posbits,
855 p[-1],p[0],p[1],p[2],p[3], (posbits&07));
856 fprintf(stderr, "uncompress: corrupt input\n");
859 return reader->rsize=-1;
863 *--stackp = (char_type)finchar;
867 while ((cmp_code_int)code >= (cmp_code_int)256) {
868 /* Generate output characters in reverse order */
869 *--stackp = tab_suffixof(code);
870 code = tab_prefixof(code);
873 fprintf(stderr, ":: to stack code=%d\n", (int)code);
875 *--stackp = (char_type)(finchar = tab_suffixof(code));
876 ASSERT(outpos<=obufsize);
878 /* And put them out in forward order */
882 try_fit: if (outpos+(i = (de_stack-stackp)) >= obufsize) {
883 /* The entire stack doesn't fit into the outbuf */
885 memcpy(outbuf+outpos, stackp, i);
887 /* vvv Dat: blkmode, maycode, inbuf, htab, codetab, fdin need not be saved */
888 reader->stackp =stackp;
890 reader->finchar=finchar;
891 reader->oldcode=oldcode;
892 reader->incode =incode;
893 reader->inbits =inbits;
894 reader->posbits=posbits;
895 reader->insize =insize;
896 reader->bitmask=bitmask;
897 reader->freeent=freeent;
898 reader->maxcode=maxcode;
899 reader->maycode=maycode;
900 reader->n_bits =n_bits;
901 reader->rsize =rsize;
902 reader->blkmode=blkmode;
903 reader->maxbits=maxbits;
905 fprintf(stderr, ":: return obufsize=%d oldcode=%d\n", obufsize, (int)oldcode);
908 /* Dat: co-routine return back to try_fit, with outpos==0, outbuf=... obufsize=... */
910 memcpy(outbuf+outpos, stackp, i);
914 /* Dat: ignore stackp from now */
916 if ((code = freeent) < maycode) { /* Generate the new entry. */
918 fprintf(stderr, ":: new entry code=(%d)\n", (int)code);
920 tab_prefixof(code) = (unsigned short)oldcode;
921 tab_suffixof(code) = (char_type)finchar;
924 oldcode = incode; /* Remember previous code. */
933 /* Values used in typeflag field. */
935 #define REGTYPE '0' /* regular file */
936 #define AREGTYPE '\0' /* regular file */
937 #define LNKTYPE '1' /* link */
938 #define SYMTYPE '2' /* reserved */
939 #define CHRTYPE '3' /* character special */
940 #define BLKTYPE '4' /* block special */
941 #define DIRTYPE '5' /* directory */
942 #define FIFOTYPE '6' /* FIFO special */
943 #define CONTTYPE '7' /* reserved */
945 #define BLOCKSIZE 512
949 char name[100]; /* 0 */
950 char mode[8]; /* 100 */
951 char uid[8]; /* 108 */
952 char gid[8]; /* 116 */
953 char size[12]; /* 124 */
954 char mtime[12]; /* 136 */
955 char chksum[8]; /* 148 */
956 char typeflag; /* 156 */
957 char linkname[100]; /* 157 */
958 char magic[6]; /* 257 */
959 char version[2]; /* 263 */
960 char uname[32]; /* 265 */
961 char gname[32]; /* 297 */
962 char devmajor[8]; /* 329 */
963 char devminor[8]; /* 337 */
964 char prefix[155]; /* 345 */
969 char buffer[BLOCKSIZE];
970 struct tar_header header;
973 enum { TGZ_EXTRACT = 0, TGZ_LIST };
976 static char *TGZfname OF((const char *));
977 void TGZnotfound OF((const char *));
979 int getoct OF((char *, int));
980 char *strtime OF((time_t *));
981 int ExprMatch OF((char *,char *));
983 int makedir OF((char *));
984 int matchname OF((int,int,char **,char *));
986 void error OF((const char *));
987 int tar OF((gzFile, int, int, int, char **));
990 int main OF((int, char **));
995 static void error(const char *msg) {
996 fprintf(stderr, "%s: %s\n", prog, msg);
1000 /* This will give a benign warning */
1002 static char *TGZprefix[] = { "\0", ".tgz", ".tar.gz", ".tar.bz2", ".tar.Z", ".tar", NULL };
1004 /* Return the real name of the TGZ archive */
1005 /* or NULL if it does not exist. */
1007 static char *TGZfname OF((const char *fname))
1009 static char buffer[1024];
1012 strcpy(buffer,fname);
1013 origlen = strlen(buffer);
1015 for (i=0; TGZprefix[i]; i++)
1017 strcpy(buffer+origlen,TGZprefix[i]);
1018 if (access(buffer,F_OK) == 0)
1024 /* error message for the filename */
1026 static void TGZnotfound OF((const char *fname))
1030 fprintf(stderr,"%s : couldn't find ",prog);
1031 for (i=0;TGZprefix[i];i++)
1032 fprintf(stderr,(TGZprefix[i+1]) ? "%s%s, " : "or %s%s\n",
1039 /* help functions */
1041 static int getoct(char *p,int width)
1053 result = result * 8 + (c - '0');
1058 static char *strtime (time_t *t)
1061 static char result[32];
1063 local = localtime(t);
1064 sprintf(result,"%2d/%02d/%4d %02d:%02d:%02d",
1065 local->tm_mday, local->tm_mon+1, local->tm_year+1900,
1066 local->tm_hour, local->tm_min, local->tm_sec);
1071 /* regular expression matching */
1073 #define ISSPECIAL(c) (((c) == '*') || ((c) == '/'))
1075 static int ExprMatch(char *string,char *expr)
1079 if (ISSPECIAL(*expr))
1083 if (*string != '\\' && *string != '/')
1087 else if (*expr == '*')
1091 while (*++string != *expr)
1098 if (*string != *expr)
1107 /* recursive make directory */
1108 /* abort if you get an ENOENT errno somewhere in the middle */
1109 /* e.g. ignore error "mkdir on existing directory" */
1111 /* return 1 if OK */
1114 static int makedir (char *newdir) {
1115 /* avoid calling strdup, since it's not ansi C */
1116 int len = strlen(newdir);
1117 char *p, *buffer = malloc(len+1);
1118 if (buffer==NULL) error("out of memory");
1119 memcpy(buffer,newdir,len+1);
1125 if (buffer[len-1] == '/') {
1126 buffer[len-1] = '\0';
1128 if (mkdir(buffer, 0775) == 0)
1139 while(*p && *p != '\\' && *p != '/')
1143 if ((mkdir(buffer, 0775) == -1) && (errno == ENOENT))
1145 fprintf(stderr,"%s: couldn't create directory %s\n",prog,buffer);
1157 static int matchname (int arg,int argc,char **argv,char *fname)
1159 if (arg == argc) /* no arguments given (untgz tgzarchive) */
1163 if (ExprMatch(fname,argv[arg++]))
1166 return 0; /* ignore this for the moment being */
1170 /* Tar file list or extract */
1172 static int tar (Readable* rin,int action,int arg,int argc,char **argv, char const* TGZfile, int verbose, void (*step)(void *,int), void *data) {
1173 union tar_buffer buffer;
1179 FILE *outfile = NULL;
1180 char fname[BLOCKSIZE];
1182 unsigned long last_read;
1185 while (0<(len=rin->xRead(rin, &buffer, BLOCKSIZE))) {
1186 fwrite(buffer.buffer, 1, len, stdout);
1192 if (action == TGZ_LIST)
1193 printf(" day time size file\n"
1194 " ---------- -------- --------- -------------------------------------\n");
1196 len = rin->xRead(rin, &buffer, BLOCKSIZE);
1198 error (rin->xError(rin, &err));
1199 if (step) { step(data,total_read - last_read); last_read = total_read; }
1200 if (!is_tar_ok && !(is_tar_ok=is_tar(buffer.buffer, len))) {
1201 fprintf(stderr, "%s: compressed file not tared: %s\n", prog, TGZfile);
1202 if (action == TGZ_EXTRACT) {
1204 unsigned len0=strlen(TGZfile), len1=len0;
1205 char *ofn=malloc(len1+5);
1206 if (ofn==NULL) return 1;
1207 memcpy(ofn, TGZfile, len1+1);
1208 while (len1>0 && ofn[len1]!='/' && ofn[len1]!='\\' && ofn[len1]!='.') len1--;
1209 if (ofn[len1]=='.') ofn[len1]='\0'; else strcpy(ofn+len0, ".unc");
1210 /* ^^^ remove last extension, or add `.unc' */
1211 fprintf(stderr, "%s: extracting as: %s\n", prog, ofn);
1212 if (NULL==(of=fopen(ofn, "wb"))) error("fopen write error");
1214 fwrite(buffer.buffer, 1, len, of);
1215 if (ferror(of)) error("write error");
1216 } while (0<(len=rin->xRead(rin, &buffer, BLOCKSIZE))); /* Imp: larger blocks */
1218 if (0!=(len|fclose(of))) error("fclose write error");
1226 * Always expect complete blocks to process
1227 * the tar information.
1229 if (len != BLOCKSIZE)
1230 error("read: incomplete block read");
1233 * If we have to get a tar header
1238 * if we met the end of the tar
1239 * or the end-of-tar block,
1242 if ((len == 0) || (buffer.header.name[0]== 0)) break;
1244 tartime = (time_t)getoct(buffer.header.mtime,12);
1245 strcpy(fname,buffer.header.name);
1247 switch (buffer.header.typeflag)
1250 if (action == TGZ_LIST)
1251 printf(" %s <dir> %s\n",strtime(&tartime),fname);
1252 if (action == TGZ_EXTRACT)
1257 remaining = getoct(buffer.header.size,12);
1258 if (action == TGZ_LIST)
1259 printf(" %s %9d %s\n",strtime(&tartime),remaining,fname);
1260 if (action == TGZ_EXTRACT)
1262 if ((remaining) && (matchname(arg,argc,argv,fname)))
1264 outfile = fopen(fname,"wb");
1265 if (outfile == NULL) {
1266 /* try creating directory */
1267 char *p = strrchr(fname, '/');
1272 outfile = fopen(fname,"wb");
1278 (outfile) ? "Extracting" : "Couldn't create",
1285 * could have no contents
1287 getheader = (remaining) ? 0 : 1;
1290 if (action == TGZ_LIST)
1291 printf(" %s <---> %s\n",strtime(&tartime),fname);
1297 unsigned int bytes = (remaining > BLOCKSIZE) ? BLOCKSIZE : remaining;
1299 if ((action == TGZ_EXTRACT) && (outfile != NULL))
1301 if (fwrite(&buffer,sizeof(char),bytes,outfile) != bytes)
1303 fprintf(stderr,"%s : error writing %s skipping...\n",prog,fname);
1312 if ((action == TGZ_EXTRACT) && (outfile != NULL))
1316 FILETIME ftm,ftLocal;
1322 localt = *localtime(&tartime);
1324 hFile = CreateFile(fname, GENERIC_READ | GENERIC_WRITE,
1325 0, NULL, OPEN_EXISTING, 0, NULL);
1327 st.wYear = (WORD)localt.tm_year+1900;
1328 st.wMonth = (WORD)localt.tm_mon;
1329 st.wDayOfWeek = (WORD)localt.tm_wday;
1330 st.wDay = (WORD)localt.tm_mday;
1331 st.wHour = (WORD)localt.tm_hour;
1332 st.wMinute = (WORD)localt.tm_min;
1333 st.wSecond = (WORD)localt.tm_sec;
1334 st.wMilliseconds = 0;
1335 SystemTimeToFileTime(&st,&ftLocal);
1336 LocalFileTimeToFileTime(&ftLocal,&ftm);
1337 SetFileTime(hFile,&ftm,NULL,&ftm);
1342 struct utimbuf settime;
1344 settime.actime = settime.modtime = tartime;
1348 utime(fname,&settime);
1355 if (rin->xClose(rin))
1356 error("failed gzclose");
1362 /* =========================================================== */
1364 static void help(int exitval)
1367 "untarka v0.34: super untar + untar.Z"
1374 "\ncontains code (C) by pts@fazekas.hu since 2003.01.28\n"
1375 "This program is under GPL >=2.0. There is NO WARRANTY. Use at your own risk!\n\n"
1376 "Usage: untarka [-x] tarfile to extract all files\n"
1377 " untarka -x tarfile fname ... to extract selected files\n"
1378 " untarka -l tarfile to list archive contents\n"
1379 " untarka -h to display this help\n");
1383 /* ====================================================================== */
1386 extern int _CRT_glob;
1387 int _CRT_glob = 0; /* disable globbing of the arguments */
1390 int main(int argc,char **argv) {
1391 int action = TGZ_EXTRACT;
1397 setmode(0, O_BINARY);
1399 prog = strrchr(argv[0],'\\');
1402 prog = strrchr(argv[0],'/');
1405 prog = strrchr(argv[0],':');
1420 if (strcmp(argv[arg],"-l") == 0 || strcmp(argv[arg],"-v") == 0) {
1422 if (argc == ++arg) help(0);
1423 } else if (strcmp(argv[arg],"-x") == 0) {
1424 action = TGZ_EXTRACT;
1425 if (argc == ++arg) help(0);
1426 } else if (strcmp(argv[arg],"-h") == 0) help(0);
1428 if ((TGZfile = TGZfname(argv[arg])) == NULL)
1429 TGZnotfound(argv[arg]);
1432 if ((action == TGZ_LIST) && (arg != argc))
1436 * Process the TGZ file
1441 switch (xOpen4Read(&r,TGZfile)) {
1443 case 1: fprintf(stderr, "%s: cannot decode compressed tar file: %s\n", prog, TGZfile); return 1;
1444 case 2: fprintf(stderr, "%s: tar file too short: %s\n", prog, TGZfile); return 1;
1445 case 3: fprintf(stderr, "%s: not a tar file: %s\n", prog, TGZfile); return 1;
1446 case 4: fprintf(stderr, "%s: cannot open tar file: %s\n", prog, TGZfile); return 1;
1448 return tar(&r, action, arg, argc, argv, TGZfile, 1, 0, 0);
1449 default: error("Unknown option!");
1456 tarextract(char *TGZfile,char *dest,int verbose, void (*step)(void *), void *data)
1459 if (xOpen4Read(&r,TGZfile) == 0)
1465 argv[0] = "fgadmin";
1467 tar(&r, TGZ_EXTRACT, arg, argc, argv, TGZfile, 0, step, data);