summaryrefslogtreecommitdiff
path: root/contrib/untgz/untgz.c
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/untgz/untgz.c')
-rw-r--r--contrib/untgz/untgz.c212
1 files changed, 125 insertions, 87 deletions
diff --git a/contrib/untgz/untgz.c b/contrib/untgz/untgz.c
index 478d744..d748b69 100644
--- a/contrib/untgz/untgz.c
+++ b/contrib/untgz/untgz.c
@@ -1,8 +1,9 @@
1/* 1/*
2 * untgz.c -- Display contents and/or extract file from 2 * untgz.c -- Display contents and extract files from a gzip'd TAR file
3 * a gzip'd TAR file 3 *
4 * written by "Pedro A. Aranda Guti\irrez" <paag@tid.es> 4 * written by "Pedro A. Aranda Guti\irrez" <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 */ 7 */
7 8
8#include <stdio.h> 9#include <stdio.h>
@@ -10,7 +11,9 @@
10#include <string.h> 11#include <string.h>
11#include <time.h> 12#include <time.h>
12#include <errno.h> 13#include <errno.h>
13#include <fcntl.h> 14
15#include "zlib.h"
16
14#ifdef unix 17#ifdef unix
15# include <unistd.h> 18# include <unistd.h>
16#else 19#else
@@ -18,27 +21,22 @@
18# include <io.h> 21# include <io.h>
19#endif 22#endif
20 23
21#include "zlib.h"
22
23#ifdef WIN32 24#ifdef WIN32
24#include <windows.h> 25#include <windows.h>
25# ifndef F_OK 26# ifndef F_OK
26# define F_OK (0) 27# define F_OK 0
27# endif 28# endif
29# define mkdir(dirname,mode) _mkdir(dirname)
28# ifdef _MSC_VER 30# ifdef _MSC_VER
29# define mkdir(dirname,mode) _mkdir(dirname)
30# define strdup(str) _strdup(str) 31# define strdup(str) _strdup(str)
31# define unlink(fn) _unlink(fn)
32# define access(path,mode) _access(path,mode) 32# define access(path,mode) _access(path,mode)
33# else
34# define mkdir(dirname,mode) _mkdir(dirname)
35# endif 33# endif
36#else 34#else
37# include <utime.h> 35# include <utime.h>
38#endif 36#endif
39 37
40 38
41/* Values used in typeflag field. */ 39/* values used in typeflag field */
42 40
43#define REGTYPE '0' /* regular file */ 41#define REGTYPE '0' /* regular file */
44#define AREGTYPE '\0' /* regular file */ 42#define AREGTYPE '\0' /* regular file */
@@ -78,40 +76,38 @@ union tar_buffer {
78 struct tar_header header; 76 struct tar_header header;
79}; 77};
80 78
81enum { TGZ_EXTRACT = 0, TGZ_LIST }; 79enum { TGZ_EXTRACT, TGZ_LIST, TGZ_INVALID };
82 80
83static char *TGZfname OF((const char *)); 81char *TGZfname OF((const char *));
84void TGZnotfound OF((const char *)); 82void TGZnotfound OF((const char *));
85 83
86int getoct OF((char *, int)); 84int getoct OF((char *, int));
87char *strtime OF((time_t *)); 85char *strtime OF((time_t *));
88int setftime OF((char *, time_t)); 86int setfiletime OF((char *, time_t));
89int ExprMatch OF((char *, char *)); 87int ExprMatch OF((char *, char *));
90 88
91int makedir OF((char *)); 89int makedir OF((char *));
92int matchname OF((int, int, char **, char *)); 90int matchname OF((int, int, char **, char *));
93 91
94void error OF((const char *)); 92void error OF((const char *));
95int tar OF((gzFile, int, int, int, char **)); 93int tar OF((gzFile, int, int, int, char **));
96 94
97void help OF((int)); 95void help OF((int));
98int main OF((int, char **)); 96int main OF((int, char **));
99 97
100char *prog; 98char *prog;
101 99
102/* This will give a benign warning */ 100const char *TGZsuffix[] = { "\0", ".tar", ".tar.gz", ".taz", ".tgz", NULL };
103
104static char *TGZsuffix[] = { "\0", ".tar", ".tar.gz", ".taz", ".tgz", NULL };
105 101
106/* Return the real name of the TGZ archive */ 102/* return the file name of the TGZ archive */
107/* or NULL if it does not exist. */ 103/* or NULL if it does not exist */
108 104
109static char *TGZfname (const char *fname) 105char *TGZfname (const char *arcname)
110{ 106{
111 static char buffer[1024]; 107 static char buffer[1024];
112 int origlen,i; 108 int origlen,i;
113 109
114 strcpy(buffer,fname); 110 strcpy(buffer,arcname);
115 origlen = strlen(buffer); 111 origlen = strlen(buffer);
116 112
117 for (i=0; TGZsuffix[i]; i++) 113 for (i=0; TGZsuffix[i]; i++)
@@ -123,55 +119,67 @@ static char *TGZfname (const char *fname)
123 return NULL; 119 return NULL;
124} 120}
125 121
122
126/* error message for the filename */ 123/* error message for the filename */
127 124
128void TGZnotfound (const char *fname) 125void TGZnotfound (const char *arcname)
129{ 126{
130 int i; 127 int i;
131 128
132 fprintf(stderr,"%s : couldn't find ",prog); 129 fprintf(stderr,"%s: Couldn't find ",prog);
133 for (i=0;TGZsuffix[i];i++) 130 for (i=0;TGZsuffix[i];i++)
134 fprintf(stderr,(TGZsuffix[i+1]) ? "%s%s, " : "or %s%s\n", 131 fprintf(stderr,(TGZsuffix[i+1]) ? "%s%s, " : "or %s%s\n",
135 fname, 132 arcname,
136 TGZsuffix[i]); 133 TGZsuffix[i]);
137 exit(1); 134 exit(1);
138} 135}
139 136
140 137
141/* help functions */ 138/* convert octal digits to int */
139/* on error return -1 */
142 140
143int getoct (char *p,int width) 141int getoct (char *p,int width)
144{ 142{
145 int result = 0; 143 int result = 0;
146 char c; 144 char c;
147 145
148 while (width --) 146 while (width--)
149 { 147 {
150 c = *p++; 148 c = *p++;
151 if (c == ' ')
152 continue;
153 if (c == 0) 149 if (c == 0)
154 break; 150 break;
151 if (c == ' ')
152 continue;
153 if (c < '0' || c > '7')
154 return -1;
155 result = result * 8 + (c - '0'); 155 result = result * 8 + (c - '0');
156 } 156 }
157 return result; 157 return result;
158} 158}
159 159
160
161/* convert time_t to string */
162/* use the "YYYY/MM/DD hh:mm:ss" format */
163
160char *strtime (time_t *t) 164char *strtime (time_t *t)
161{ 165{
162 struct tm *local; 166 struct tm *local;
163 static char result[32]; 167 static char result[32];
164 168
165 local = localtime(t); 169 local = localtime(t);
166 sprintf(result,"%2d/%02d/%4d %02d:%02d:%02d", 170 sprintf(result,"%4d/%02d/%02d %02d:%02d:%02d",
167 local->tm_mday, local->tm_mon+1, local->tm_year+1900, 171 local->tm_year+1900, local->tm_mon+1, local->tm_mday,
168 local->tm_hour, local->tm_min, local->tm_sec); 172 local->tm_hour, local->tm_min, local->tm_sec);
169 return result; 173 return result;
170} 174}
171 175
172int setftime (char *fname,time_t ftime) 176
177/* set file time */
178
179int setfiletime (char *fname,time_t ftime)
173{ 180{
174#ifdef WIN32 181#ifdef WIN32
182 static int isWinNT = -1;
175 SYSTEMTIME st; 183 SYSTEMTIME st;
176 FILETIME locft, modft; 184 FILETIME locft, modft;
177 struct tm *loctm; 185 struct tm *loctm;
@@ -194,8 +202,11 @@ int setftime (char *fname,time_t ftime)
194 !LocalFileTimeToFileTime(&locft, &modft)) 202 !LocalFileTimeToFileTime(&locft, &modft))
195 return -1; 203 return -1;
196 204
197 hFile = CreateFile(fname, GENERIC_READ | GENERIC_WRITE, 205 if (isWinNT < 0)
198 0, NULL, OPEN_EXISTING, 0, 0); 206 isWinNT = (GetVersion() < 0x80000000) ? 1 : 0;
207 hFile = CreateFile(fname, GENERIC_WRITE, 0, NULL, OPEN_EXISTING,
208 (isWinNT ? FILE_FLAG_BACKUP_SEMANTICS : 0),
209 NULL);
199 if (hFile == INVALID_HANDLE_VALUE) 210 if (hFile == INVALID_HANDLE_VALUE)
200 return -1; 211 return -1;
201 result = SetFileTime(hFile, NULL, NULL, &modft) ? 0 : -1; 212 result = SetFileTime(hFile, NULL, NULL, &modft) ? 0 : -1;
@@ -246,10 +257,9 @@ int ExprMatch (char *string,char *expr)
246 } 257 }
247} 258}
248 259
249/* recursive make directory */ 260
250/* abort if you get an ENOENT errno somewhere in the middle */ 261/* recursive mkdir */
251/* e.g. ignore error "mkdir on existing directory" */ 262/* abort on ENOENT; ignore other errors like "directory already exists" */
252/* */
253/* return 1 if OK */ 263/* return 1 if OK */
254/* 0 on error */ 264/* 0 on error */
255 265
@@ -266,7 +276,7 @@ int makedir (char *newdir)
266 if (buffer[len-1] == '/') { 276 if (buffer[len-1] == '/') {
267 buffer[len-1] = '\0'; 277 buffer[len-1] = '\0';
268 } 278 }
269 if (mkdir(buffer, 0775) == 0) 279 if (mkdir(buffer, 0755) == 0)
270 { 280 {
271 free(buffer); 281 free(buffer);
272 return 1; 282 return 1;
@@ -281,9 +291,9 @@ int makedir (char *newdir)
281 p++; 291 p++;
282 hold = *p; 292 hold = *p;
283 *p = 0; 293 *p = 0;
284 if ((mkdir(buffer, 0775) == -1) && (errno == ENOENT)) 294 if ((mkdir(buffer, 0755) == -1) && (errno == ENOENT))
285 { 295 {
286 fprintf(stderr,"%s: couldn't create directory %s\n",prog,buffer); 296 fprintf(stderr,"%s: Couldn't create directory %s\n",prog,buffer);
287 free(buffer); 297 free(buffer);
288 return 0; 298 return 0;
289 } 299 }
@@ -295,9 +305,10 @@ int makedir (char *newdir)
295 return 1; 305 return 1;
296} 306}
297 307
308
298int matchname (int arg,int argc,char **argv,char *fname) 309int matchname (int arg,int argc,char **argv,char *fname)
299{ 310{
300 if (arg == argc) /* no arguments given (untgz tgzarchive) */ 311 if (arg == argc) /* no arguments given (untgz tgzarchive) */
301 return 1; 312 return 1;
302 313
303 while (arg < argc) 314 while (arg < argc)
@@ -308,7 +319,7 @@ int matchname (int arg,int argc,char **argv,char *fname)
308} 319}
309 320
310 321
311/* Tar file list or extract */ 322/* tar file list or extract */
312 323
313int tar (gzFile in,int action,int arg,int argc,char **argv) 324int tar (gzFile in,int action,int arg,int argc,char **argv)
314{ 325{
@@ -319,22 +330,26 @@ int tar (gzFile in,int action,int arg,int argc,char **argv)
319 int remaining = 0; 330 int remaining = 0;
320 FILE *outfile = NULL; 331 FILE *outfile = NULL;
321 char fname[BLOCKSIZE]; 332 char fname[BLOCKSIZE];
333 int tarmode;
322 time_t tartime; 334 time_t tartime;
323 335
324 if (action == TGZ_LIST) 336 if (action == TGZ_LIST)
325 printf(" day time size file\n" 337 printf(" date time size file\n"
326 " ---------- -------- --------- -------------------------------------\n"); 338 " ---------- -------- --------- -------------------------------------\n");
327 while (1) 339 while (1)
328 { 340 {
329 len = gzread(in, &buffer, BLOCKSIZE); 341 len = gzread(in, &buffer, BLOCKSIZE);
330 if (len < 0) 342 if (len < 0)
331 error (gzerror(in, &err)); 343 error(gzerror(in, &err));
332 /* 344 /*
333 * Always expect complete blocks to process 345 * Always expect complete blocks to process
334 * the tar information. 346 * the tar information.
335 */ 347 */
336 if (len != BLOCKSIZE) 348 if (len != BLOCKSIZE)
337 error("gzread: incomplete block read"); 349 {
350 action = TGZ_INVALID; /* force error exit */
351 remaining = 0; /* force I/O cleanup */
352 }
338 353
339 /* 354 /*
340 * If we have to get a tar header 355 * If we have to get a tar header
@@ -346,9 +361,16 @@ int tar (gzFile in,int action,int arg,int argc,char **argv)
346 * or the end-of-tar block, 361 * or the end-of-tar block,
347 * we are done 362 * we are done
348 */ 363 */
349 if ((len == 0) || (buffer.header.name[0]== 0)) break; 364 if ((len == 0) || (buffer.header.name[0] == 0)) break;
350 365
366 tarmode = getoct(buffer.header.mode,8);
351 tartime = (time_t)getoct(buffer.header.mtime,12); 367 tartime = (time_t)getoct(buffer.header.mtime,12);
368 if (tarmode == -1 || tartime == (time_t)-1)
369 {
370 buffer.header.name[0] = 0;
371 action = TGZ_INVALID;
372 }
373
352 strcpy(fname,buffer.header.name); 374 strcpy(fname,buffer.header.name);
353 375
354 switch (buffer.header.typeflag) 376 switch (buffer.header.typeflag)
@@ -357,16 +379,24 @@ int tar (gzFile in,int action,int arg,int argc,char **argv)
357 if (action == TGZ_LIST) 379 if (action == TGZ_LIST)
358 printf(" %s <dir> %s\n",strtime(&tartime),fname); 380 printf(" %s <dir> %s\n",strtime(&tartime),fname);
359 if (action == TGZ_EXTRACT) 381 if (action == TGZ_EXTRACT)
360 makedir(fname); 382 {
383 makedir(fname);
384 setfiletime(fname,tartime);
385 }
361 break; 386 break;
362 case REGTYPE: 387 case REGTYPE:
363 case AREGTYPE: 388 case AREGTYPE:
364 remaining = getoct(buffer.header.size,12); 389 remaining = getoct(buffer.header.size,12);
390 if (remaining == -1)
391 {
392 action = TGZ_INVALID;
393 break;
394 }
365 if (action == TGZ_LIST) 395 if (action == TGZ_LIST)
366 printf(" %s %9d %s\n",strtime(&tartime),remaining,fname); 396 printf(" %s %9d %s\n",strtime(&tartime),remaining,fname);
367 if (action == TGZ_EXTRACT) 397 else if (action == TGZ_EXTRACT)
368 { 398 {
369 if ((remaining) && (matchname(arg,argc,argv,fname))) 399 if (matchname(arg,argc,argv,fname))
370 { 400 {
371 outfile = fopen(fname,"wb"); 401 outfile = fopen(fname,"wb");
372 if (outfile == NULL) { 402 if (outfile == NULL) {
@@ -379,18 +409,15 @@ int tar (gzFile in,int action,int arg,int argc,char **argv)
379 outfile = fopen(fname,"wb"); 409 outfile = fopen(fname,"wb");
380 } 410 }
381 } 411 }
382 fprintf(stderr, 412 if (outfile != NULL)
383 "%s %s\n", 413 printf("Extracting %s\n",fname);
384 (outfile) ? "Extracting" : "Couldn't create", 414 else
385 fname); 415 fprintf(stderr, "%s: Couldn't create %s",prog,fname);
386 } 416 }
387 else 417 else
388 outfile = NULL; 418 outfile = NULL;
389 } 419 }
390 /* 420 getheader = 0;
391 * could have no contents
392 */
393 getheader = (remaining) ? 0 : 1;
394 break; 421 break;
395 default: 422 default:
396 if (action == TGZ_LIST) 423 if (action == TGZ_LIST)
@@ -402,27 +429,39 @@ int tar (gzFile in,int action,int arg,int argc,char **argv)
402 { 429 {
403 unsigned int bytes = (remaining > BLOCKSIZE) ? BLOCKSIZE : remaining; 430 unsigned int bytes = (remaining > BLOCKSIZE) ? BLOCKSIZE : remaining;
404 431
405 if ((action == TGZ_EXTRACT) && (outfile != NULL)) 432 if (outfile != NULL)
406 { 433 {
407 if (fwrite(&buffer,sizeof(char),bytes,outfile) != bytes) 434 if (fwrite(&buffer,sizeof(char),bytes,outfile) != bytes)
408 { 435 {
409 fprintf(stderr,"%s : error writing %s skipping...\n",prog,fname); 436 fprintf(stderr,"%s: Error writing %s -- skipping\n",prog,fname);
410 fclose(outfile); 437 fclose(outfile);
411 unlink(fname); 438 outfile = NULL;
439 remove(fname);
412 } 440 }
413 } 441 }
414 remaining -= bytes; 442 remaining -= bytes;
415 if (remaining == 0) 443 }
444
445 if (remaining == 0)
446 {
447 getheader = 1;
448 if (outfile != NULL)
416 { 449 {
417 getheader = 1; 450 fclose(outfile);
418 if ((action == TGZ_EXTRACT) && (outfile != NULL)) 451 outfile = NULL;
419 { 452 if (action != TGZ_INVALID)
420 fclose(outfile); 453 setfiletime(fname,tartime);
421 outfile = NULL;
422 setftime(fname,tartime);
423 }
424 } 454 }
425 } 455 }
456
457 /*
458 * Abandon if errors are found
459 */
460 if (action == TGZ_INVALID)
461 {
462 error("broken archive");
463 break;
464 }
426 } 465 }
427 466
428 if (gzclose(in) != Z_OK) 467 if (gzclose(in) != Z_OK)
@@ -432,30 +471,32 @@ int tar (gzFile in,int action,int arg,int argc,char **argv)
432} 471}
433 472
434 473
435/* =========================================================== */ 474/* ============================================================ */
436 475
437void help(int exitval) 476void help(int exitval)
438{ 477{
439 fprintf(stderr, 478 printf("untgz version 0.2\n"
440 "untgz version 0.1\n" 479 " using zlib version %s\n\n",
441 " a sample application of zlib\n\n" 480 zlibVersion());
442 "Usage : untgz file.tgz to extract all files\n" 481 printf("Usage: untgz file.tgz extract all files\n"
443 " untgz file.tgz fname ... to extract selected files\n" 482 " untgz file.tgz fname ... extract selected files\n"
444 " untgz -l file.tgz to list archive contents\n" 483 " untgz -l file.tgz list archive contents\n"
445 " untgz -h to display this help\n\n"); 484 " untgz -h display this help\n");
446 exit(exitval); 485 exit(exitval);
447} 486}
448 487
449void error(const char *msg) 488void error(const char *msg)
450{ 489{
451 fprintf(stderr, "%s: %s\n", prog, msg); 490 fprintf(stderr, "%s: %s\n", prog, msg);
452 exit(1); 491 exit(1);
453} 492}
454 493
455 494
456/* ====================================================================== */ 495/* ============================================================ */
457 496
458int _CRT_glob = 0; /* disable globbing of the arguments */ 497#if defined(WIN32) && defined(__GNUC__)
498int _CRT_glob = 0; /* disable argument globbing in MinGW */
499#endif
459 500
460int main(int argc,char **argv) 501int main(int argc,char **argv)
461{ 502{
@@ -464,7 +505,6 @@ int main(int argc,char **argv)
464 char *TGZfile; 505 char *TGZfile;
465 gzFile *f; 506 gzFile *f;
466 507
467
468 prog = strrchr(argv[0],'\\'); 508 prog = strrchr(argv[0],'\\');
469 if (prog == NULL) 509 if (prog == NULL)
470 { 510 {
@@ -514,16 +554,14 @@ int main(int argc,char **argv)
514 f = gzopen(TGZfile,"rb"); 554 f = gzopen(TGZfile,"rb");
515 if (f == NULL) 555 if (f == NULL)
516 { 556 {
517 fprintf(stderr,"%s: Couldn't gzopen %s\n", 557 fprintf(stderr,"%s: Couldn't gzopen %s\n",prog,TGZfile);
518 prog,
519 TGZfile);
520 return 1; 558 return 1;
521 } 559 }
522 exit(tar(f, action, arg, argc, argv)); 560 exit(tar(f, action, arg, argc, argv));
523 break; 561 break;
524 562
525 default: 563 default:
526 error("Unknown option!"); 564 error("Unknown option");
527 exit(1); 565 exit(1);
528 } 566 }
529 567