aboutsummaryrefslogtreecommitdiff
path: root/zlib/contrib/untgz/untgz.c
diff options
context:
space:
mode:
Diffstat (limited to 'zlib/contrib/untgz/untgz.c')
-rw-r--r--zlib/contrib/untgz/untgz.c135
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"