source: trunk/gcc/zlib/contrib/untgz/untgz.c

Last change on this file was 2, checked in by bird, 22 years ago

Initial revision

  • Property cvs2svn:cvs-rev set to 1.1
  • Property svn:eol-style set to native
  • Property svn:executable set to *
File size: 10.6 KB
Line 
1/*
2 * untgz.c -- Display contents and/or extract file from
3 * a gzip'd TAR file
4 * written by "Pedro A. Aranda Guti\irrez" <paag@tid.es>
5 * adaptation to Unix by Jean-loup Gailly <jloup@gzip.org>
6 */
7
8#include <stdio.h>
9#include <stdlib.h>
10#include <string.h>
11#include <time.h>
12#include <errno.h>
13#include <fcntl.h>
14#ifdef unix
15# include <unistd.h>
16#else
17# include <direct.h>
18# include <io.h>
19#endif
20
21#include "zlib.h"
22
23#ifdef WIN32
24# ifndef F_OK
25# define F_OK (0)
26# endif
27# ifdef _MSC_VER
28# define mkdir(dirname,mode) _mkdir(dirname)
29# define strdup(str) _strdup(str)
30# define unlink(fn) _unlink(fn)
31# define access(path,mode) _access(path,mode)
32# else
33# define mkdir(dirname,mode) _mkdir(dirname)
34# endif
35#else
36# include <utime.h>
37#endif
38
39
40/* Values used in typeflag field. */
41
42#define REGTYPE '0' /* regular file */
43#define AREGTYPE '\0' /* regular file */
44#define LNKTYPE '1' /* link */
45#define SYMTYPE '2' /* reserved */
46#define CHRTYPE '3' /* character special */
47#define BLKTYPE '4' /* block special */
48#define DIRTYPE '5' /* directory */
49#define FIFOTYPE '6' /* FIFO special */
50#define CONTTYPE '7' /* reserved */
51
52#define BLOCKSIZE 512
53
54struct tar_header
55{ /* byte offset */
56 char name[100]; /* 0 */
57 char mode[8]; /* 100 */
58 char uid[8]; /* 108 */
59 char gid[8]; /* 116 */
60 char size[12]; /* 124 */
61 char mtime[12]; /* 136 */
62 char chksum[8]; /* 148 */
63 char typeflag; /* 156 */
64 char linkname[100]; /* 157 */
65 char magic[6]; /* 257 */
66 char version[2]; /* 263 */
67 char uname[32]; /* 265 */
68 char gname[32]; /* 297 */
69 char devmajor[8]; /* 329 */
70 char devminor[8]; /* 337 */
71 char prefix[155]; /* 345 */
72 /* 500 */
73};
74
75union tar_buffer {
76 char buffer[BLOCKSIZE];
77 struct tar_header header;
78};
79
80enum { TGZ_EXTRACT = 0, TGZ_LIST };
81
82static char *TGZfname OF((const char *));
83void TGZnotfound OF((const char *));
84
85int getoct OF((char *, int));
86char *strtime OF((time_t *));
87int ExprMatch OF((char *,char *));
88
89int makedir OF((char *));
90int matchname OF((int,int,char **,char *));
91
92void error OF((const char *));
93int tar OF((gzFile, int, int, int, char **));
94
95void help OF((int));
96int main OF((int, char **));
97
98char *prog;
99
100/* This will give a benign warning */
101
102static char *TGZprefix[] = { "\0", ".tgz", ".tar.gz", ".tar", NULL };
103
104/* Return the real name of the TGZ archive */
105/* or NULL if it does not exist. */
106
107static char *TGZfname OF((const char *fname))
108{
109 static char buffer[1024];
110 int origlen,i;
111
112 strcpy(buffer,fname);
113 origlen = strlen(buffer);
114
115 for (i=0; TGZprefix[i]; i++)
116 {
117 strcpy(buffer+origlen,TGZprefix[i]);
118 if (access(buffer,F_OK) == 0)
119 return buffer;
120 }
121 return NULL;
122}
123
124/* error message for the filename */
125
126void TGZnotfound OF((const char *fname))
127{
128 int i;
129
130 fprintf(stderr,"%s : couldn't find ",prog);
131 for (i=0;TGZprefix[i];i++)
132 fprintf(stderr,(TGZprefix[i+1]) ? "%s%s, " : "or %s%s\n",
133 fname,
134 TGZprefix[i]);
135 exit(1);
136}
137
138
139/* help functions */
140
141int getoct(char *p,int width)
142{
143 int result = 0;
144 char c;
145
146 while (width --)
147 {
148 c = *p++;
149 if (c == ' ')
150 continue;
151 if (c == 0)
152 break;
153 result = result * 8 + (c - '0');
154 }
155 return result;
156}
157
158char *strtime (time_t *t)
159{
160 struct tm *local;
161 static char result[32];
162
163 local = localtime(t);
164 sprintf(result,"%2d/%02d/%4d %02d:%02d:%02d",
165 local->tm_mday, local->tm_mon+1, local->tm_year+1900,
166 local->tm_hour, local->tm_min, local->tm_sec);
167 return result;
168}
169
170
171/* regular expression matching */
172
173#define ISSPECIAL(c) (((c) == '*') || ((c) == '/'))
174
175int ExprMatch(char *string,char *expr)
176{
177 while (1)
178 {
179 if (ISSPECIAL(*expr))
180 {
181 if (*expr == '/')
182 {
183 if (*string != '\\' && *string != '/')
184 return 0;
185 string ++; expr++;
186 }
187 else if (*expr == '*')
188 {
189 if (*expr ++ == 0)
190 return 1;
191 while (*++string != *expr)
192 if (*string == 0)
193 return 0;
194 }
195 }
196 else
197 {
198 if (*string != *expr)
199 return 0;
200 if (*expr++ == 0)
201 return 1;
202 string++;
203 }
204 }
205}
206
207/* recursive make directory */
208/* abort if you get an ENOENT errno somewhere in the middle */
209/* e.g. ignore error "mkdir on existing directory" */
210/* */
211/* return 1 if OK */
212/* 0 on error */
213
214int makedir (char *newdir)
215{
216 char *buffer = strdup(newdir);
217 char *p;
218 int len = strlen(buffer);
219
220 if (len <= 0) {
221 free(buffer);
222 return 0;
223 }
224 if (buffer[len-1] == '/') {
225 buffer[len-1] = '\0';
226 }
227 if (mkdir(buffer, 0775) == 0)
228 {
229 free(buffer);
230 return 1;
231 }
232
233 p = buffer+1;
234 while (1)
235 {
236 char hold;
237
238 while(*p && *p != '\\' && *p != '/')
239 p++;
240 hold = *p;
241 *p = 0;
242 if ((mkdir(buffer, 0775) == -1) && (errno == ENOENT))
243 {
244 fprintf(stderr,"%s: couldn't create directory %s\n",prog,buffer);
245 free(buffer);
246 return 0;
247 }
248 if (hold == 0)
249 break;
250 *p++ = hold;
251 }
252 free(buffer);
253 return 1;
254}
255
256int matchname (int arg,int argc,char **argv,char *fname)
257{
258 if (arg == argc) /* no arguments given (untgz tgzarchive) */
259 return 1;
260
261 while (arg < argc)
262 if (ExprMatch(fname,argv[arg++]))
263 return 1;
264
265 return 0; /* ignore this for the moment being */
266}
267
268
269/* Tar file list or extract */
270
271int tar (gzFile in,int action,int arg,int argc,char **argv)
272{
273 union tar_buffer buffer;
274 int len;
275 int err;
276 int getheader = 1;
277 int remaining = 0;
278 FILE *outfile = NULL;
279 char fname[BLOCKSIZE];
280 time_t tartime;
281
282 if (action == TGZ_LIST)
283 printf(" day time size file\n"
284 " ---------- -------- --------- -------------------------------------\n");
285 while (1)
286 {
287 len = gzread(in, &buffer, BLOCKSIZE);
288 if (len < 0)
289 error (gzerror(in, &err));
290 /*
291 * Always expect complete blocks to process
292 * the tar information.
293 */
294 if (len != BLOCKSIZE)
295 error("gzread: incomplete block read");
296
297 /*
298 * If we have to get a tar header
299 */
300 if (getheader == 1)
301 {
302 /*
303 * if we met the end of the tar
304 * or the end-of-tar block,
305 * we are done
306 */
307 if ((len == 0) || (buffer.header.name[0]== 0)) break;
308
309 tartime = (time_t)getoct(buffer.header.mtime,12);
310 strcpy(fname,buffer.header.name);
311
312 switch (buffer.header.typeflag)
313 {
314 case DIRTYPE:
315 if (action == TGZ_LIST)
316 printf(" %s <dir> %s\n",strtime(&tartime),fname);
317 if (action == TGZ_EXTRACT)
318 makedir(fname);
319 break;
320 case REGTYPE:
321 case AREGTYPE:
322 remaining = getoct(buffer.header.size,12);
323 if (action == TGZ_LIST)
324 printf(" %s %9d %s\n",strtime(&tartime),remaining,fname);
325 if (action == TGZ_EXTRACT)
326 {
327 if ((remaining) && (matchname(arg,argc,argv,fname)))
328 {
329 outfile = fopen(fname,"wb");
330 if (outfile == NULL) {
331 /* try creating directory */
332 char *p = strrchr(fname, '/');
333 if (p != NULL) {
334 *p = '\0';
335 makedir(fname);
336 *p = '/';
337 outfile = fopen(fname,"wb");
338 }
339 }
340 fprintf(stderr,
341 "%s %s\n",
342 (outfile) ? "Extracting" : "Couldn't create",
343 fname);
344 }
345 else
346 outfile = NULL;
347 }
348 /*
349 * could have no contents
350 */
351 getheader = (remaining) ? 0 : 1;
352 break;
353 default:
354 if (action == TGZ_LIST)
355 printf(" %s <---> %s\n",strtime(&tartime),fname);
356 break;
357 }
358 }
359 else
360 {
361 unsigned int bytes = (remaining > BLOCKSIZE) ? BLOCKSIZE : remaining;
362
363 if ((action == TGZ_EXTRACT) && (outfile != NULL))
364 {
365 if (fwrite(&buffer,sizeof(char),bytes,outfile) != bytes)
366 {
367 fprintf(stderr,"%s : error writing %s skipping...\n",prog,fname);
368 fclose(outfile);
369 unlink(fname);
370 }
371 }
372 remaining -= bytes;
373 if (remaining == 0)
374 {
375 getheader = 1;
376 if ((action == TGZ_EXTRACT) && (outfile != NULL))
377 {
378#ifdef WIN32
379 HANDLE hFile;
380 FILETIME ftm,ftLocal;
381 SYSTEMTIME st;
382 struct tm localt;
383
384 fclose(outfile);
385
386 localt = *localtime(&tartime);
387
388 hFile = CreateFile(fname, GENERIC_READ | GENERIC_WRITE,
389 0, NULL, OPEN_EXISTING, 0, NULL);
390
391 st.wYear = (WORD)localt.tm_year+1900;
392 st.wMonth = (WORD)localt.tm_mon;
393 st.wDayOfWeek = (WORD)localt.tm_wday;
394 st.wDay = (WORD)localt.tm_mday;
395 st.wHour = (WORD)localt.tm_hour;
396 st.wMinute = (WORD)localt.tm_min;
397 st.wSecond = (WORD)localt.tm_sec;
398 st.wMilliseconds = 0;
399 SystemTimeToFileTime(&st,&ftLocal);
400 LocalFileTimeToFileTime(&ftLocal,&ftm);
401 SetFileTime(hFile,&ftm,NULL,&ftm);
402 CloseHandle(hFile);
403
404 outfile = NULL;
405#else
406 struct utimbuf settime;
407
408 settime.actime = settime.modtime = tartime;
409
410 fclose(outfile);
411 outfile = NULL;
412 utime(fname,&settime);
413#endif
414 }
415 }
416 }
417 }
418
419 if (gzclose(in) != Z_OK)
420 error("failed gzclose");
421
422 return 0;
423}
424
425
426/* =========================================================== */
427
428void help(int exitval)
429{
430 fprintf(stderr,
431 "untgz v 0.1\n"
432 " an sample application of zlib 1.0.4\n\n"
433 "Usage : untgz TGZfile to extract all files\n"
434 " untgz TGZfile fname ... to extract selected files\n"
435 " untgz -l TGZfile to list archive contents\n"
436 " untgz -h to display this help\n\n");
437 exit(exitval);
438}
439
440void error(const char *msg)
441{
442 fprintf(stderr, "%s: %s\n", prog, msg);
443 exit(1);
444}
445
446
447/* ====================================================================== */
448
449int _CRT_glob = 0; /* disable globbing of the arguments */
450
451int main(int argc,char **argv)
452{
453 int action = TGZ_EXTRACT;
454 int arg = 1;
455 char *TGZfile;
456 gzFile *f;
457
458
459 prog = strrchr(argv[0],'\\');
460 if (prog == NULL)
461 {
462 prog = strrchr(argv[0],'/');
463 if (prog == NULL)
464 {
465 prog = strrchr(argv[0],':');
466 if (prog == NULL)
467 prog = argv[0];
468 else
469 prog++;
470 }
471 else
472 prog++;
473 }
474 else
475 prog++;
476
477 if (argc == 1)
478 help(0);
479
480 if (strcmp(argv[arg],"-l") == 0)
481 {
482 action = TGZ_LIST;
483 if (argc == ++arg)
484 help(0);
485 }
486 else if (strcmp(argv[arg],"-h") == 0)
487 {
488 help(0);
489 }
490
491 if ((TGZfile = TGZfname(argv[arg])) == NULL)
492 TGZnotfound(argv[arg]);
493
494 ++arg;
495 if ((action == TGZ_LIST) && (arg != argc))
496 help(1);
497
498/*
499 * Process the TGZ file
500 */
501 switch(action)
502 {
503 case TGZ_LIST:
504 case TGZ_EXTRACT:
505 f = gzopen(TGZfile,"rb");
506 if (f == NULL)
507 {
508 fprintf(stderr,"%s: Couldn't gzopen %s\n",
509 prog,
510 TGZfile);
511 return 1;
512 }
513 exit(tar(f, action, arg, argc, argv));
514 break;
515
516 default:
517 error("Unknown option!");
518 exit(1);
519 }
520
521 return 0;
522}
Note: See TracBrowser for help on using the repository browser.