diff options
Diffstat (limited to 'zlib/contrib/untgz/untgz.c')
-rw-r--r-- | zlib/contrib/untgz/untgz.c | 135 |
1 files changed, 120 insertions, 15 deletions
diff --git a/zlib/contrib/untgz/untgz.c b/zlib/contrib/untgz/untgz.c index d748b6905bb..2c391e59867 100644 --- a/zlib/contrib/untgz/untgz.c +++ b/zlib/contrib/untgz/untgz.c @@ -1,7 +1,7 @@ /* * untgz.c -- Display contents and extract files from a gzip'd TAR file * - * written by "Pedro A. Aranda Guti\irrez" <paag@tid.es> + * written by Pedro A. Aranda Gutierrez <paag@tid.es> * adaptation to Unix by Jean-loup Gailly <jloup@gzip.org> * various fixes by Cosmin Truta <cosmint@cs.ubbcluj.ro> */ @@ -15,10 +15,10 @@ #include "zlib.h" #ifdef unix -# include <unistd.h> +# include <unistd.h> #else -# include <direct.h> -# include <io.h> +# include <direct.h> +# include <io.h> #endif #ifdef WIN32 @@ -28,8 +28,9 @@ # endif # define mkdir(dirname,mode) _mkdir(dirname) # ifdef _MSC_VER -# define strdup(str) _strdup(str) # define access(path,mode) _access(path,mode) +# define chmod(path,mode) _chmod(path,mode) +# define strdup(str) _strdup(str) # endif #else # include <utime.h> @@ -48,7 +49,21 @@ #define FIFOTYPE '6' /* FIFO special */ #define CONTTYPE '7' /* reserved */ -#define BLOCKSIZE 512 +/* GNU tar extensions */ + +#define GNUTYPE_DUMPDIR 'D' /* file names from dumped directory */ +#define GNUTYPE_LONGLINK 'K' /* long link name */ +#define GNUTYPE_LONGNAME 'L' /* long file name */ +#define GNUTYPE_MULTIVOL 'M' /* continuation of file from another volume */ +#define GNUTYPE_NAMES 'N' /* file name that does not fit into main hdr */ +#define GNUTYPE_SPARSE 'S' /* sparse file */ +#define GNUTYPE_VOLHDR 'V' /* tape/volume header */ + + +/* tar header */ + +#define BLOCKSIZE 512 +#define SHORTNAMESIZE 100 struct tar_header { /* byte offset */ @@ -71,11 +86,20 @@ struct tar_header /* 500 */ }; -union tar_buffer { +union tar_buffer +{ char buffer[BLOCKSIZE]; struct tar_header header; }; +struct attr_item +{ + struct attr_item *next; + char *fname; + int mode; + time_t time; +}; + enum { TGZ_EXTRACT, TGZ_LIST, TGZ_INVALID }; char *TGZfname OF((const char *)); @@ -84,6 +108,9 @@ void TGZnotfound OF((const char *)); int getoct OF((char *, int)); char *strtime OF((time_t *)); int setfiletime OF((char *, time_t)); +void push_attr OF((struct attr_item **, char *, int, time_t)); +void restore_attr OF((struct attr_item **)); + int ExprMatch OF((char *, char *)); int makedir OF((char *)); @@ -221,7 +248,42 @@ int setfiletime (char *fname,time_t ftime) } -/* regular expression matching */ +/* push file attributes */ + +void push_attr(struct attr_item **list,char *fname,int mode,time_t time) +{ + struct attr_item *item; + + item = (struct attr_item *)malloc(sizeof(struct attr_item)); + if (item == NULL) + error("Out of memory"); + item->fname = strdup(fname); + item->mode = mode; + item->time = time; + item->next = *list; + *list = item; +} + + +/* restore file attributes */ + +void restore_attr(struct attr_item **list) +{ + struct attr_item *item, *prev; + + for (item = *list; item != NULL; ) + { + setfiletime(item->fname,item->time); + chmod(item->fname,item->mode); + prev = item; + item = item->next; + free(prev); + } + *list = NULL; +} + + +/* match regular expression */ #define ISSPECIAL(c) (((c) == '*') || ((c) == '/')) @@ -332,6 +394,7 @@ int tar (gzFile in,int action,int arg,int argc,char **argv) char fname[BLOCKSIZE]; int tarmode; time_t tartime; + struct attr_item *attributes = NULL; if (action == TGZ_LIST) printf(" date time size file\n" @@ -354,14 +417,15 @@ int tar (gzFile in,int action,int arg,int argc,char **argv) /* * If we have to get a tar header */ - if (getheader == 1) + if (getheader >= 1) { /* * if we met the end of the tar * or the end-of-tar block, * we are done */ - if ((len == 0) || (buffer.header.name[0] == 0)) break; + if (len == 0 || buffer.header.name[0] == 0) + break; tarmode = getoct(buffer.header.mode,8); tartime = (time_t)getoct(buffer.header.mtime,12); @@ -371,8 +435,25 @@ int tar (gzFile in,int action,int arg,int argc,char **argv) action = TGZ_INVALID; } - strcpy(fname,buffer.header.name); + if (getheader == 1) + { + strncpy(fname,buffer.header.name,SHORTNAMESIZE); + if (fname[SHORTNAMESIZE-1] != 0) + fname[SHORTNAMESIZE] = 0; + } + else + { + /* + * The file name is longer than SHORTNAMESIZE + */ + if (strncmp(fname,buffer.header.name,SHORTNAMESIZE-1) != 0) + error("bad long name"); + getheader = 1; + } + /* + * Act according to the type flag + */ switch (buffer.header.typeflag) { case DIRTYPE: @@ -381,7 +462,7 @@ int tar (gzFile in,int action,int arg,int argc,char **argv) if (action == TGZ_EXTRACT) { makedir(fname); - setfiletime(fname,tartime); + push_attr(&attributes,fname,tarmode,tartime); } break; case REGTYPE: @@ -419,6 +500,24 @@ int tar (gzFile in,int action,int arg,int argc,char **argv) } getheader = 0; break; + case GNUTYPE_LONGLINK: + case GNUTYPE_LONGNAME: + remaining = getoct(buffer.header.size,12); + if (remaining < 0 || remaining >= BLOCKSIZE) + { + action = TGZ_INVALID; + break; + } + len = gzread(in, fname, BLOCKSIZE); + if (len < 0) + error(gzerror(in, &err)); + if (fname[BLOCKSIZE-1] != 0 || (int)strlen(fname) > remaining) + { + action = TGZ_INVALID; + break; + } + getheader = 2; + break; default: if (action == TGZ_LIST) printf(" %s <---> %s\n",strtime(&tartime),fname); @@ -433,7 +532,8 @@ int tar (gzFile in,int action,int arg,int argc,char **argv) { if (fwrite(&buffer,sizeof(char),bytes,outfile) != bytes) { - fprintf(stderr,"%s: Error writing %s -- skipping\n",prog,fname); + fprintf(stderr, + "%s: Error writing %s -- skipping\n",prog,fname); fclose(outfile); outfile = NULL; remove(fname); @@ -450,7 +550,7 @@ int tar (gzFile in,int action,int arg,int argc,char **argv) fclose(outfile); outfile = NULL; if (action != TGZ_INVALID) - setfiletime(fname,tartime); + push_attr(&attributes,fname,tarmode,tartime); } } @@ -464,6 +564,11 @@ int tar (gzFile in,int action,int arg,int argc,char **argv) } } + /* + * Restore file modes and time stamps + */ + restore_attr(&attributes); + if (gzclose(in) != Z_OK) error("failed gzclose"); @@ -475,7 +580,7 @@ int tar (gzFile in,int action,int arg,int argc,char **argv) void help(int exitval) { - printf("untgz version 0.2\n" + printf("untgz version 0.2.1\n" " using zlib version %s\n\n", zlibVersion()); printf("Usage: untgz file.tgz extract all files\n" |