summaryrefslogtreecommitdiff
path: root/contrib/untgz/untgz.c
diff options
context:
space:
mode:
authorMark Adler <madler@alumni.caltech.edu>2011-09-09 23:23:45 -0700
committerMark Adler <madler@alumni.caltech.edu>2011-09-09 23:23:45 -0700
commit7a6955760ba950eb82f57929f8f6c9847c65f0af (patch)
treee2cd657aca6d606e0b28bf57fe45e914717a334c /contrib/untgz/untgz.c
parentf0e76a6634eb26e3ddc6dfc6f2489553eff8c8f4 (diff)
downloadzlib-1.2.1.2.tar.gz
zlib-1.2.1.2.tar.bz2
zlib-1.2.1.2.zip
zlib 1.2.1.2v1.2.1.2
Diffstat (limited to 'contrib/untgz/untgz.c')
-rw-r--r--contrib/untgz/untgz.c135
1 files changed, 120 insertions, 15 deletions
diff --git a/contrib/untgz/untgz.c b/contrib/untgz/untgz.c
index d748b69..3a30768 100644
--- a/contrib/untgz/untgz.c
+++ b/contrib/untgz/untgz.c
@@ -1,7 +1,7 @@
1/* 1/*
2 * untgz.c -- Display contents and extract files from a gzip'd TAR file 2 * untgz.c -- Display contents and extract files from a gzip'd TAR file
3 * 3 *
4 * written by "Pedro A. Aranda Guti\irrez" <paag@tid.es> 4 * written by Pedro A. Aranda Gutierrez <paag@tid.es>
5 * adaptation to Unix by Jean-loup Gailly <jloup@gzip.org> 5 * adaptation to Unix by Jean-loup Gailly <jloup@gzip.org>
6 * various fixes by Cosmin Truta <cosmint@cs.ubbcluj.ro> 6 * various fixes by Cosmin Truta <cosmint@cs.ubbcluj.ro>
7 */ 7 */
@@ -15,10 +15,10 @@
15#include "zlib.h" 15#include "zlib.h"
16 16
17#ifdef unix 17#ifdef unix
18# include <unistd.h> 18# include <unistd.h>
19#else 19#else
20# include <direct.h> 20# include <direct.h>
21# include <io.h> 21# include <io.h>
22#endif 22#endif
23 23
24#ifdef WIN32 24#ifdef WIN32
@@ -28,8 +28,9 @@
28# endif 28# endif
29# define mkdir(dirname,mode) _mkdir(dirname) 29# define mkdir(dirname,mode) _mkdir(dirname)
30# ifdef _MSC_VER 30# ifdef _MSC_VER
31# define strdup(str) _strdup(str)
32# define access(path,mode) _access(path,mode) 31# define access(path,mode) _access(path,mode)
32# define chmod(path,mode) _chmod(path,mode)
33# define strdup(str) _strdup(str)
33# endif 34# endif
34#else 35#else
35# include <utime.h> 36# include <utime.h>
@@ -48,7 +49,21 @@
48#define FIFOTYPE '6' /* FIFO special */ 49#define FIFOTYPE '6' /* FIFO special */
49#define CONTTYPE '7' /* reserved */ 50#define CONTTYPE '7' /* reserved */
50 51
51#define BLOCKSIZE 512 52/* GNU tar extensions */
53
54#define GNUTYPE_DUMPDIR 'D' /* file names from dumped directory */
55#define GNUTYPE_LONGLINK 'K' /* long link name */
56#define GNUTYPE_LONGNAME 'L' /* long file name */
57#define GNUTYPE_MULTIVOL 'M' /* continuation of file from another volume */
58#define GNUTYPE_NAMES 'N' /* file name that does not fit into main hdr */
59#define GNUTYPE_SPARSE 'S' /* sparse file */
60#define GNUTYPE_VOLHDR 'V' /* tape/volume header */
61
62
63/* tar header */
64
65#define BLOCKSIZE 512
66#define SHORTNAMESIZE 100
52 67
53struct tar_header 68struct tar_header
54{ /* byte offset */ 69{ /* byte offset */
@@ -71,11 +86,20 @@ struct tar_header
71 /* 500 */ 86 /* 500 */
72}; 87};
73 88
74union tar_buffer { 89union tar_buffer
90{
75 char buffer[BLOCKSIZE]; 91 char buffer[BLOCKSIZE];
76 struct tar_header header; 92 struct tar_header header;
77}; 93};
78 94
95struct attr_item
96{
97 struct attr_item *next;
98 char *fname;
99 int mode;
100 time_t time;
101};
102
79enum { TGZ_EXTRACT, TGZ_LIST, TGZ_INVALID }; 103enum { TGZ_EXTRACT, TGZ_LIST, TGZ_INVALID };
80 104
81char *TGZfname OF((const char *)); 105char *TGZfname OF((const char *));
@@ -84,6 +108,9 @@ void TGZnotfound OF((const char *));
84int getoct OF((char *, int)); 108int getoct OF((char *, int));
85char *strtime OF((time_t *)); 109char *strtime OF((time_t *));
86int setfiletime OF((char *, time_t)); 110int setfiletime OF((char *, time_t));
111void push_attr OF((struct attr_item **, char *, int, time_t));
112void restore_attr OF((struct attr_item **));
113
87int ExprMatch OF((char *, char *)); 114int ExprMatch OF((char *, char *));
88 115
89int makedir OF((char *)); 116int makedir OF((char *));
@@ -221,7 +248,42 @@ int setfiletime (char *fname,time_t ftime)
221} 248}
222 249
223 250
224/* regular expression matching */ 251/* push file attributes */
252
253void push_attr(struct attr_item **list,char *fname,int mode,time_t time)
254{
255 struct attr_item *item;
256
257 item = (struct attr_item *)malloc(sizeof(struct attr_item));
258 if (item == NULL)
259 error("Out of memory");
260 item->fname = strdup(fname);
261 item->mode = mode;
262 item->time = time;
263 item->next = *list;
264 *list = item;
265}
266
267
268/* restore file attributes */
269
270void restore_attr(struct attr_item **list)
271{
272 struct attr_item *item, *prev;
273
274 for (item = *list; item != NULL; )
275 {
276 setfiletime(item->fname,item->time);
277 chmod(item->fname,item->mode);
278 prev = item;
279 item = item->next;
280 free(prev);
281 }
282 *list = NULL;
283}
284
285
286/* match regular expression */
225 287
226#define ISSPECIAL(c) (((c) == '*') || ((c) == '/')) 288#define ISSPECIAL(c) (((c) == '*') || ((c) == '/'))
227 289
@@ -332,6 +394,7 @@ int tar (gzFile in,int action,int arg,int argc,char **argv)
332 char fname[BLOCKSIZE]; 394 char fname[BLOCKSIZE];
333 int tarmode; 395 int tarmode;
334 time_t tartime; 396 time_t tartime;
397 struct attr_item *attributes = NULL;
335 398
336 if (action == TGZ_LIST) 399 if (action == TGZ_LIST)
337 printf(" date time size file\n" 400 printf(" date time size file\n"
@@ -354,14 +417,15 @@ int tar (gzFile in,int action,int arg,int argc,char **argv)
354 /* 417 /*
355 * If we have to get a tar header 418 * If we have to get a tar header
356 */ 419 */
357 if (getheader == 1) 420 if (getheader >= 1)
358 { 421 {
359 /* 422 /*
360 * if we met the end of the tar 423 * if we met the end of the tar
361 * or the end-of-tar block, 424 * or the end-of-tar block,
362 * we are done 425 * we are done
363 */ 426 */
364 if ((len == 0) || (buffer.header.name[0] == 0)) break; 427 if (len == 0 || buffer.header.name[0] == 0)
428 break;
365 429
366 tarmode = getoct(buffer.header.mode,8); 430 tarmode = getoct(buffer.header.mode,8);
367 tartime = (time_t)getoct(buffer.header.mtime,12); 431 tartime = (time_t)getoct(buffer.header.mtime,12);
@@ -371,8 +435,25 @@ int tar (gzFile in,int action,int arg,int argc,char **argv)
371 action = TGZ_INVALID; 435 action = TGZ_INVALID;
372 } 436 }
373 437
374 strcpy(fname,buffer.header.name); 438 if (getheader == 1)
439 {
440 strncpy(fname,buffer.header.name,SHORTNAMESIZE);
441 if (fname[SHORTNAMESIZE-1] != 0)
442 fname[SHORTNAMESIZE] = 0;
443 }
444 else
445 {
446 /*
447 * The file name is longer than SHORTNAMESIZE
448 */
449 if (strncmp(fname,buffer.header.name,SHORTNAMESIZE-1) != 0)
450 error("bad long name");
451 getheader = 1;
452 }
375 453
454 /*
455 * Act according to the type flag
456 */
376 switch (buffer.header.typeflag) 457 switch (buffer.header.typeflag)
377 { 458 {
378 case DIRTYPE: 459 case DIRTYPE:
@@ -381,7 +462,7 @@ int tar (gzFile in,int action,int arg,int argc,char **argv)
381 if (action == TGZ_EXTRACT) 462 if (action == TGZ_EXTRACT)
382 { 463 {
383 makedir(fname); 464 makedir(fname);
384 setfiletime(fname,tartime); 465 push_attr(&attributes,fname,tarmode,tartime);
385 } 466 }
386 break; 467 break;
387 case REGTYPE: 468 case REGTYPE:
@@ -419,6 +500,24 @@ int tar (gzFile in,int action,int arg,int argc,char **argv)
419 } 500 }
420 getheader = 0; 501 getheader = 0;
421 break; 502 break;
503 case GNUTYPE_LONGLINK:
504 case GNUTYPE_LONGNAME:
505 remaining = getoct(buffer.header.size,12);
506 if (remaining < 0 || remaining >= BLOCKSIZE)
507 {
508 action = TGZ_INVALID;
509 break;
510 }
511 len = gzread(in, fname, BLOCKSIZE);
512 if (len < 0)
513 error(gzerror(in, &err));
514 if (fname[BLOCKSIZE-1] != 0 || (int)strlen(fname) > remaining)
515 {
516 action = TGZ_INVALID;
517 break;
518 }
519 getheader = 2;
520 break;
422 default: 521 default:
423 if (action == TGZ_LIST) 522 if (action == TGZ_LIST)
424 printf(" %s <---> %s\n",strtime(&tartime),fname); 523 printf(" %s <---> %s\n",strtime(&tartime),fname);
@@ -433,7 +532,8 @@ int tar (gzFile in,int action,int arg,int argc,char **argv)
433 { 532 {
434 if (fwrite(&buffer,sizeof(char),bytes,outfile) != bytes) 533 if (fwrite(&buffer,sizeof(char),bytes,outfile) != bytes)
435 { 534 {
436 fprintf(stderr,"%s: Error writing %s -- skipping\n",prog,fname); 535 fprintf(stderr,
536 "%s: Error writing %s -- skipping\n",prog,fname);
437 fclose(outfile); 537 fclose(outfile);
438 outfile = NULL; 538 outfile = NULL;
439 remove(fname); 539 remove(fname);
@@ -450,7 +550,7 @@ int tar (gzFile in,int action,int arg,int argc,char **argv)
450 fclose(outfile); 550 fclose(outfile);
451 outfile = NULL; 551 outfile = NULL;
452 if (action != TGZ_INVALID) 552 if (action != TGZ_INVALID)
453 setfiletime(fname,tartime); 553 push_attr(&attributes,fname,tarmode,tartime);
454 } 554 }
455 } 555 }
456 556
@@ -464,6 +564,11 @@ int tar (gzFile in,int action,int arg,int argc,char **argv)
464 } 564 }
465 } 565 }
466 566
567 /*
568 * Restore file modes and time stamps
569 */
570 restore_attr(&attributes);
571
467 if (gzclose(in) != Z_OK) 572 if (gzclose(in) != Z_OK)
468 error("failed gzclose"); 573 error("failed gzclose");
469 574
@@ -475,7 +580,7 @@ int tar (gzFile in,int action,int arg,int argc,char **argv)
475 580
476void help(int exitval) 581void help(int exitval)
477{ 582{
478 printf("untgz version 0.2\n" 583 printf("untgz version 0.2.1\n"
479 " using zlib version %s\n\n", 584 " using zlib version %s\n\n",
480 zlibVersion()); 585 zlibVersion());
481 printf("Usage: untgz file.tgz extract all files\n" 586 printf("Usage: untgz file.tgz extract all files\n"