untgz.c revision 1.1.1.1.76.1 1 1.1 christos /*
2 1.1 christos * untgz.c -- Display contents and extract files from a gzip'd TAR file
3 1.1 christos *
4 1.1 christos * written by Pedro A. Aranda Gutierrez <paag (at) tid.es>
5 1.1 christos * adaptation to Unix by Jean-loup Gailly <jloup (at) gzip.org>
6 1.1 christos * various fixes by Cosmin Truta <cosmint (at) cs.ubbcluj.ro>
7 1.1 christos */
8 1.1 christos
9 1.1 christos #include <stdio.h>
10 1.1 christos #include <stdlib.h>
11 1.1 christos #include <string.h>
12 1.1 christos #include <time.h>
13 1.1 christos #include <errno.h>
14 1.1 christos
15 1.1 christos #include "zlib.h"
16 1.1 christos
17 1.1 christos #ifdef unix
18 1.1 christos # include <unistd.h>
19 1.1 christos #else
20 1.1 christos # include <direct.h>
21 1.1 christos # include <io.h>
22 1.1 christos #endif
23 1.1 christos
24 1.1 christos #ifdef WIN32
25 1.1 christos #include <windows.h>
26 1.1 christos # ifndef F_OK
27 1.1 christos # define F_OK 0
28 1.1 christos # endif
29 1.1 christos # define mkdir(dirname,mode) _mkdir(dirname)
30 1.1 christos # ifdef _MSC_VER
31 1.1 christos # define access(path,mode) _access(path,mode)
32 1.1 christos # define chmod(path,mode) _chmod(path,mode)
33 1.1 christos # define strdup(str) _strdup(str)
34 1.1 christos # endif
35 1.1 christos #else
36 1.1 christos # include <utime.h>
37 1.1 christos #endif
38 1.1 christos
39 1.1 christos
40 1.1 christos /* values used in typeflag field */
41 1.1 christos
42 1.1 christos #define REGTYPE '0' /* regular file */
43 1.1 christos #define AREGTYPE '\0' /* regular file */
44 1.1 christos #define LNKTYPE '1' /* link */
45 1.1 christos #define SYMTYPE '2' /* reserved */
46 1.1 christos #define CHRTYPE '3' /* character special */
47 1.1 christos #define BLKTYPE '4' /* block special */
48 1.1 christos #define DIRTYPE '5' /* directory */
49 1.1 christos #define FIFOTYPE '6' /* FIFO special */
50 1.1 christos #define CONTTYPE '7' /* reserved */
51 1.1 christos
52 1.1 christos /* GNU tar extensions */
53 1.1 christos
54 1.1 christos #define GNUTYPE_DUMPDIR 'D' /* file names from dumped directory */
55 1.1 christos #define GNUTYPE_LONGLINK 'K' /* long link name */
56 1.1 christos #define GNUTYPE_LONGNAME 'L' /* long file name */
57 1.1 christos #define GNUTYPE_MULTIVOL 'M' /* continuation of file from another volume */
58 1.1 christos #define GNUTYPE_NAMES 'N' /* file name that does not fit into main hdr */
59 1.1 christos #define GNUTYPE_SPARSE 'S' /* sparse file */
60 1.1 christos #define GNUTYPE_VOLHDR 'V' /* tape/volume header */
61 1.1 christos
62 1.1 christos
63 1.1 christos /* tar header */
64 1.1 christos
65 1.1 christos #define BLOCKSIZE 512
66 1.1 christos #define SHORTNAMESIZE 100
67 1.1 christos
68 1.1 christos struct tar_header
69 1.1 christos { /* byte offset */
70 1.1 christos char name[100]; /* 0 */
71 1.1 christos char mode[8]; /* 100 */
72 1.1 christos char uid[8]; /* 108 */
73 1.1 christos char gid[8]; /* 116 */
74 1.1 christos char size[12]; /* 124 */
75 1.1 christos char mtime[12]; /* 136 */
76 1.1 christos char chksum[8]; /* 148 */
77 1.1 christos char typeflag; /* 156 */
78 1.1 christos char linkname[100]; /* 157 */
79 1.1 christos char magic[6]; /* 257 */
80 1.1 christos char version[2]; /* 263 */
81 1.1 christos char uname[32]; /* 265 */
82 1.1 christos char gname[32]; /* 297 */
83 1.1 christos char devmajor[8]; /* 329 */
84 1.1 christos char devminor[8]; /* 337 */
85 1.1 christos char prefix[155]; /* 345 */
86 1.1 christos /* 500 */
87 1.1 christos };
88 1.1 christos
89 1.1 christos union tar_buffer
90 1.1 christos {
91 1.1 christos char buffer[BLOCKSIZE];
92 1.1 christos struct tar_header header;
93 1.1 christos };
94 1.1 christos
95 1.1 christos struct attr_item
96 1.1 christos {
97 1.1 christos struct attr_item *next;
98 1.1 christos char *fname;
99 1.1 christos int mode;
100 1.1 christos time_t time;
101 1.1 christos };
102 1.1 christos
103 1.1 christos enum { TGZ_EXTRACT, TGZ_LIST, TGZ_INVALID };
104 1.1 christos
105 1.1 christos char *TGZfname OF((const char *));
106 1.1 christos void TGZnotfound OF((const char *));
107 1.1 christos
108 1.1 christos int getoct OF((char *, int));
109 1.1 christos char *strtime OF((time_t *));
110 1.1 christos int setfiletime OF((char *, time_t));
111 1.1 christos void push_attr OF((struct attr_item **, char *, int, time_t));
112 1.1 christos void restore_attr OF((struct attr_item **));
113 1.1 christos
114 1.1 christos int ExprMatch OF((char *, char *));
115 1.1 christos
116 1.1 christos int makedir OF((char *));
117 1.1 christos int matchname OF((int, int, char **, char *));
118 1.1 christos
119 1.1 christos void error OF((const char *));
120 1.1 christos int tar OF((gzFile, int, int, int, char **));
121 1.1 christos
122 1.1 christos void help OF((int));
123 1.1 christos int main OF((int, char **));
124 1.1 christos
125 1.1 christos char *prog;
126 1.1 christos
127 1.1 christos const char *TGZsuffix[] = { "\0", ".tar", ".tar.gz", ".taz", ".tgz", NULL };
128 1.1 christos
129 1.1 christos /* return the file name of the TGZ archive */
130 1.1 christos /* or NULL if it does not exist */
131 1.1 christos
132 1.1 christos char *TGZfname (const char *arcname)
133 1.1 christos {
134 1.1 christos static char buffer[1024];
135 1.1 christos int origlen,i;
136 1.1 christos
137 1.1 christos strcpy(buffer,arcname);
138 1.1 christos origlen = strlen(buffer);
139 1.1 christos
140 1.1 christos for (i=0; TGZsuffix[i]; i++)
141 1.1 christos {
142 1.1 christos strcpy(buffer+origlen,TGZsuffix[i]);
143 1.1 christos if (access(buffer,F_OK) == 0)
144 1.1 christos return buffer;
145 1.1 christos }
146 1.1 christos return NULL;
147 1.1 christos }
148 1.1 christos
149 1.1 christos
150 1.1 christos /* error message for the filename */
151 1.1 christos
152 1.1 christos void TGZnotfound (const char *arcname)
153 1.1 christos {
154 1.1 christos int i;
155 1.1 christos
156 1.1 christos fprintf(stderr,"%s: Couldn't find ",prog);
157 1.1 christos for (i=0;TGZsuffix[i];i++)
158 1.1 christos fprintf(stderr,(TGZsuffix[i+1]) ? "%s%s, " : "or %s%s\n",
159 1.1 christos arcname,
160 1.1 christos TGZsuffix[i]);
161 1.1 christos exit(1);
162 1.1 christos }
163 1.1 christos
164 1.1 christos
165 1.1 christos /* convert octal digits to int */
166 1.1 christos /* on error return -1 */
167 1.1 christos
168 1.1 christos int getoct (char *p,int width)
169 1.1 christos {
170 1.1 christos int result = 0;
171 1.1 christos char c;
172 1.1 christos
173 1.1 christos while (width--)
174 1.1 christos {
175 1.1 christos c = *p++;
176 1.1 christos if (c == 0)
177 1.1 christos break;
178 1.1 christos if (c == ' ')
179 1.1 christos continue;
180 1.1 christos if (c < '0' || c > '7')
181 1.1 christos return -1;
182 1.1 christos result = result * 8 + (c - '0');
183 1.1 christos }
184 1.1 christos return result;
185 1.1 christos }
186 1.1 christos
187 1.1 christos
188 1.1 christos /* convert time_t to string */
189 1.1 christos /* use the "YYYY/MM/DD hh:mm:ss" format */
190 1.1 christos
191 1.1 christos char *strtime (time_t *t)
192 1.1 christos {
193 1.1 christos struct tm *local;
194 1.1 christos static char result[32];
195 1.1 christos
196 1.1 christos local = localtime(t);
197 1.1 christos sprintf(result,"%4d/%02d/%02d %02d:%02d:%02d",
198 1.1 christos local->tm_year+1900, local->tm_mon+1, local->tm_mday,
199 1.1 christos local->tm_hour, local->tm_min, local->tm_sec);
200 1.1 christos return result;
201 1.1 christos }
202 1.1 christos
203 1.1 christos
204 1.1 christos /* set file time */
205 1.1 christos
206 1.1 christos int setfiletime (char *fname,time_t ftime)
207 1.1 christos {
208 1.1 christos #ifdef WIN32
209 1.1 christos static int isWinNT = -1;
210 1.1 christos SYSTEMTIME st;
211 1.1 christos FILETIME locft, modft;
212 1.1 christos struct tm *loctm;
213 1.1 christos HANDLE hFile;
214 1.1 christos int result;
215 1.1 christos
216 1.1 christos loctm = localtime(&ftime);
217 1.1 christos if (loctm == NULL)
218 1.1 christos return -1;
219 1.1 christos
220 1.1 christos st.wYear = (WORD)loctm->tm_year + 1900;
221 1.1 christos st.wMonth = (WORD)loctm->tm_mon + 1;
222 1.1 christos st.wDayOfWeek = (WORD)loctm->tm_wday;
223 1.1 christos st.wDay = (WORD)loctm->tm_mday;
224 1.1 christos st.wHour = (WORD)loctm->tm_hour;
225 1.1 christos st.wMinute = (WORD)loctm->tm_min;
226 1.1 christos st.wSecond = (WORD)loctm->tm_sec;
227 1.1 christos st.wMilliseconds = 0;
228 1.1 christos if (!SystemTimeToFileTime(&st, &locft) ||
229 1.1 christos !LocalFileTimeToFileTime(&locft, &modft))
230 1.1 christos return -1;
231 1.1 christos
232 1.1 christos if (isWinNT < 0)
233 1.1 christos isWinNT = (GetVersion() < 0x80000000) ? 1 : 0;
234 1.1 christos hFile = CreateFile(fname, GENERIC_WRITE, 0, NULL, OPEN_EXISTING,
235 1.1 christos (isWinNT ? FILE_FLAG_BACKUP_SEMANTICS : 0),
236 1.1 christos NULL);
237 1.1 christos if (hFile == INVALID_HANDLE_VALUE)
238 1.1 christos return -1;
239 1.1 christos result = SetFileTime(hFile, NULL, NULL, &modft) ? 0 : -1;
240 1.1 christos CloseHandle(hFile);
241 1.1 christos return result;
242 1.1 christos #else
243 1.1 christos struct utimbuf settime;
244 1.1 christos
245 1.1 christos settime.actime = settime.modtime = ftime;
246 1.1 christos return utime(fname,&settime);
247 1.1 christos #endif
248 1.1 christos }
249 1.1 christos
250 1.1 christos
251 1.1 christos /* push file attributes */
252 1.1 christos
253 1.1 christos void push_attr(struct attr_item **list,char *fname,int mode,time_t time)
254 1.1 christos {
255 1.1 christos struct attr_item *item;
256 1.1 christos
257 1.1 christos item = (struct attr_item *)malloc(sizeof(struct attr_item));
258 1.1 christos if (item == NULL)
259 1.1 christos error("Out of memory");
260 1.1 christos item->fname = strdup(fname);
261 1.1 christos item->mode = mode;
262 1.1 christos item->time = time;
263 1.1 christos item->next = *list;
264 1.1 christos *list = item;
265 1.1 christos }
266 1.1 christos
267 1.1 christos
268 1.1 christos /* restore file attributes */
269 1.1 christos
270 1.1 christos void restore_attr(struct attr_item **list)
271 1.1 christos {
272 1.1 christos struct attr_item *item, *prev;
273 1.1 christos
274 1.1 christos for (item = *list; item != NULL; )
275 1.1 christos {
276 1.1 christos setfiletime(item->fname,item->time);
277 1.1 christos chmod(item->fname,item->mode);
278 1.1 christos prev = item;
279 1.1 christos item = item->next;
280 1.1 christos free(prev);
281 1.1 christos }
282 1.1 christos *list = NULL;
283 1.1 christos }
284 1.1 christos
285 1.1 christos
286 1.1 christos /* match regular expression */
287 1.1 christos
288 1.1 christos #define ISSPECIAL(c) (((c) == '*') || ((c) == '/'))
289 1.1 christos
290 1.1 christos int ExprMatch (char *string,char *expr)
291 1.1 christos {
292 1.1 christos while (1)
293 1.1 christos {
294 1.1 christos if (ISSPECIAL(*expr))
295 1.1 christos {
296 1.1 christos if (*expr == '/')
297 1.1 christos {
298 1.1 christos if (*string != '\\' && *string != '/')
299 1.1 christos return 0;
300 1.1 christos string ++; expr++;
301 1.1 christos }
302 1.1 christos else if (*expr == '*')
303 1.1 christos {
304 1.1 christos if (*expr ++ == 0)
305 1.1 christos return 1;
306 1.1 christos while (*++string != *expr)
307 1.1 christos if (*string == 0)
308 1.1 christos return 0;
309 1.1 christos }
310 1.1 christos }
311 1.1 christos else
312 1.1 christos {
313 1.1 christos if (*string != *expr)
314 1.1 christos return 0;
315 1.1 christos if (*expr++ == 0)
316 1.1 christos return 1;
317 1.1 christos string++;
318 1.1 christos }
319 1.1 christos }
320 1.1 christos }
321 1.1 christos
322 1.1 christos
323 1.1 christos /* recursive mkdir */
324 1.1 christos /* abort on ENOENT; ignore other errors like "directory already exists" */
325 1.1 christos /* return 1 if OK */
326 1.1 christos /* 0 on error */
327 1.1 christos
328 1.1 christos int makedir (char *newdir)
329 1.1 christos {
330 1.1 christos char *buffer = strdup(newdir);
331 1.1 christos char *p;
332 1.1 christos int len = strlen(buffer);
333 1.1 christos
334 1.1 christos if (len <= 0) {
335 1.1 christos free(buffer);
336 1.1 christos return 0;
337 1.1 christos }
338 1.1 christos if (buffer[len-1] == '/') {
339 1.1 christos buffer[len-1] = '\0';
340 1.1 christos }
341 1.1 christos if (mkdir(buffer, 0755) == 0)
342 1.1 christos {
343 1.1 christos free(buffer);
344 1.1 christos return 1;
345 1.1 christos }
346 1.1 christos
347 1.1 christos p = buffer+1;
348 1.1 christos while (1)
349 1.1 christos {
350 1.1 christos char hold;
351 1.1 christos
352 1.1 christos while(*p && *p != '\\' && *p != '/')
353 1.1 christos p++;
354 1.1 christos hold = *p;
355 1.1 christos *p = 0;
356 1.1 christos if ((mkdir(buffer, 0755) == -1) && (errno == ENOENT))
357 1.1 christos {
358 1.1 christos fprintf(stderr,"%s: Couldn't create directory %s\n",prog,buffer);
359 1.1 christos free(buffer);
360 1.1 christos return 0;
361 1.1 christos }
362 1.1 christos if (hold == 0)
363 1.1 christos break;
364 1.1 christos *p++ = hold;
365 1.1 christos }
366 1.1 christos free(buffer);
367 1.1 christos return 1;
368 1.1 christos }
369 1.1 christos
370 1.1 christos
371 1.1 christos int matchname (int arg,int argc,char **argv,char *fname)
372 1.1 christos {
373 1.1 christos if (arg == argc) /* no arguments given (untgz tgzarchive) */
374 1.1 christos return 1;
375 1.1 christos
376 1.1 christos while (arg < argc)
377 1.1 christos if (ExprMatch(fname,argv[arg++]))
378 1.1 christos return 1;
379 1.1 christos
380 1.1 christos return 0; /* ignore this for the moment being */
381 1.1 christos }
382 1.1 christos
383 1.1 christos
384 1.1 christos /* tar file list or extract */
385 1.1 christos
386 1.1 christos int tar (gzFile in,int action,int arg,int argc,char **argv)
387 1.1 christos {
388 1.1 christos union tar_buffer buffer;
389 1.1 christos int len;
390 1.1 christos int err;
391 1.1 christos int getheader = 1;
392 1.1 christos int remaining = 0;
393 1.1 christos FILE *outfile = NULL;
394 1.1 christos char fname[BLOCKSIZE];
395 1.1 christos int tarmode;
396 1.1 christos time_t tartime;
397 1.1 christos struct attr_item *attributes = NULL;
398 1.1 christos
399 1.1 christos if (action == TGZ_LIST)
400 1.1 christos printf(" date time size file\n"
401 1.1 christos " ---------- -------- --------- -------------------------------------\n");
402 1.1 christos while (1)
403 1.1 christos {
404 1.1 christos len = gzread(in, &buffer, BLOCKSIZE);
405 1.1 christos if (len < 0)
406 1.1 christos error(gzerror(in, &err));
407 1.1 christos /*
408 1.1 christos * Always expect complete blocks to process
409 1.1 christos * the tar information.
410 1.1 christos */
411 1.1 christos if (len != BLOCKSIZE)
412 1.1 christos {
413 1.1 christos action = TGZ_INVALID; /* force error exit */
414 1.1 christos remaining = 0; /* force I/O cleanup */
415 1.1 christos }
416 1.1 christos
417 1.1 christos /*
418 1.1 christos * If we have to get a tar header
419 1.1 christos */
420 1.1 christos if (getheader >= 1)
421 1.1 christos {
422 1.1 christos /*
423 1.1 christos * if we met the end of the tar
424 1.1 christos * or the end-of-tar block,
425 1.1 christos * we are done
426 1.1 christos */
427 1.1 christos if (len == 0 || buffer.header.name[0] == 0)
428 1.1 christos break;
429 1.1 christos
430 1.1 christos tarmode = getoct(buffer.header.mode,8);
431 1.1 christos tartime = (time_t)getoct(buffer.header.mtime,12);
432 1.1 christos if (tarmode == -1 || tartime == (time_t)-1)
433 1.1 christos {
434 1.1 christos buffer.header.name[0] = 0;
435 1.1 christos action = TGZ_INVALID;
436 1.1 christos }
437 1.1 christos
438 1.1 christos if (getheader == 1)
439 1.1 christos {
440 1.1 christos strncpy(fname,buffer.header.name,SHORTNAMESIZE);
441 1.1 christos if (fname[SHORTNAMESIZE-1] != 0)
442 1.1 christos fname[SHORTNAMESIZE] = 0;
443 1.1 christos }
444 1.1 christos else
445 1.1 christos {
446 1.1 christos /*
447 1.1 christos * The file name is longer than SHORTNAMESIZE
448 1.1 christos */
449 1.1 christos if (strncmp(fname,buffer.header.name,SHORTNAMESIZE-1) != 0)
450 1.1 christos error("bad long name");
451 1.1 christos getheader = 1;
452 1.1 christos }
453 1.1 christos
454 1.1 christos /*
455 1.1 christos * Act according to the type flag
456 1.1 christos */
457 1.1 christos switch (buffer.header.typeflag)
458 1.1 christos {
459 1.1 christos case DIRTYPE:
460 1.1 christos if (action == TGZ_LIST)
461 1.1 christos printf(" %s <dir> %s\n",strtime(&tartime),fname);
462 1.1 christos if (action == TGZ_EXTRACT)
463 1.1 christos {
464 1.1 christos makedir(fname);
465 1.1 christos push_attr(&attributes,fname,tarmode,tartime);
466 1.1 christos }
467 1.1 christos break;
468 1.1 christos case REGTYPE:
469 1.1 christos case AREGTYPE:
470 1.1 christos remaining = getoct(buffer.header.size,12);
471 1.1 christos if (remaining == -1)
472 1.1 christos {
473 1.1 christos action = TGZ_INVALID;
474 1.1 christos break;
475 1.1 christos }
476 1.1 christos if (action == TGZ_LIST)
477 1.1 christos printf(" %s %9d %s\n",strtime(&tartime),remaining,fname);
478 1.1 christos else if (action == TGZ_EXTRACT)
479 1.1 christos {
480 1.1 christos if (matchname(arg,argc,argv,fname))
481 1.1 christos {
482 1.1 christos outfile = fopen(fname,"wb");
483 1.1 christos if (outfile == NULL) {
484 1.1 christos /* try creating directory */
485 1.1 christos char *p = strrchr(fname, '/');
486 1.1 christos if (p != NULL) {
487 1.1 christos *p = '\0';
488 1.1 christos makedir(fname);
489 1.1 christos *p = '/';
490 1.1 christos outfile = fopen(fname,"wb");
491 1.1 christos }
492 1.1 christos }
493 1.1 christos if (outfile != NULL)
494 1.1 christos printf("Extracting %s\n",fname);
495 1.1 christos else
496 1.1 christos fprintf(stderr, "%s: Couldn't create %s",prog,fname);
497 1.1 christos }
498 1.1 christos else
499 1.1 christos outfile = NULL;
500 1.1 christos }
501 1.1 christos getheader = 0;
502 1.1 christos break;
503 1.1 christos case GNUTYPE_LONGLINK:
504 1.1 christos case GNUTYPE_LONGNAME:
505 1.1 christos remaining = getoct(buffer.header.size,12);
506 1.1 christos if (remaining < 0 || remaining >= BLOCKSIZE)
507 1.1 christos {
508 1.1 christos action = TGZ_INVALID;
509 1.1 christos break;
510 1.1 christos }
511 1.1 christos len = gzread(in, fname, BLOCKSIZE);
512 1.1 christos if (len < 0)
513 1.1 christos error(gzerror(in, &err));
514 1.1 christos if (fname[BLOCKSIZE-1] != 0 || (int)strlen(fname) > remaining)
515 1.1 christos {
516 1.1 christos action = TGZ_INVALID;
517 1.1 christos break;
518 1.1 christos }
519 1.1 christos getheader = 2;
520 1.1 christos break;
521 1.1 christos default:
522 1.1 christos if (action == TGZ_LIST)
523 1.1 christos printf(" %s <---> %s\n",strtime(&tartime),fname);
524 1.1 christos break;
525 1.1 christos }
526 1.1 christos }
527 1.1 christos else
528 1.1 christos {
529 1.1 christos unsigned int bytes = (remaining > BLOCKSIZE) ? BLOCKSIZE : remaining;
530 1.1 christos
531 1.1 christos if (outfile != NULL)
532 1.1 christos {
533 1.1 christos if (fwrite(&buffer,sizeof(char),bytes,outfile) != bytes)
534 1.1 christos {
535 1.1 christos fprintf(stderr,
536 1.1 christos "%s: Error writing %s -- skipping\n",prog,fname);
537 1.1 christos fclose(outfile);
538 1.1 christos outfile = NULL;
539 1.1 christos remove(fname);
540 1.1 christos }
541 1.1 christos }
542 1.1 christos remaining -= bytes;
543 1.1 christos }
544 1.1 christos
545 1.1 christos if (remaining == 0)
546 1.1 christos {
547 1.1 christos getheader = 1;
548 1.1 christos if (outfile != NULL)
549 1.1 christos {
550 1.1 christos fclose(outfile);
551 1.1 christos outfile = NULL;
552 1.1 christos if (action != TGZ_INVALID)
553 1.1 christos push_attr(&attributes,fname,tarmode,tartime);
554 1.1 christos }
555 1.1 christos }
556 1.1 christos
557 1.1 christos /*
558 1.1 christos * Abandon if errors are found
559 1.1 christos */
560 1.1 christos if (action == TGZ_INVALID)
561 1.1 christos {
562 1.1 christos error("broken archive");
563 1.1 christos break;
564 1.1 christos }
565 1.1 christos }
566 1.1 christos
567 1.1 christos /*
568 1.1 christos * Restore file modes and time stamps
569 1.1 christos */
570 1.1 christos restore_attr(&attributes);
571 1.1 christos
572 1.1 christos if (gzclose(in) != Z_OK)
573 1.1 christos error("failed gzclose");
574 1.1 christos
575 1.1 christos return 0;
576 1.1 christos }
577 1.1 christos
578 1.1 christos
579 1.1 christos /* ============================================================ */
580 1.1 christos
581 1.1 christos void help(int exitval)
582 1.1 christos {
583 1.1 christos printf("untgz version 0.2.1\n"
584 1.1 christos " using zlib version %s\n\n",
585 1.1 christos zlibVersion());
586 1.1 christos printf("Usage: untgz file.tgz extract all files\n"
587 1.1 christos " untgz file.tgz fname ... extract selected files\n"
588 1.1 christos " untgz -l file.tgz list archive contents\n"
589 1.1 christos " untgz -h display this help\n");
590 1.1 christos exit(exitval);
591 1.1 christos }
592 1.1 christos
593 1.1 christos void error(const char *msg)
594 1.1 christos {
595 1.1 christos fprintf(stderr, "%s: %s\n", prog, msg);
596 1.1 christos exit(1);
597 1.1 christos }
598 1.1 christos
599 1.1 christos
600 1.1 christos /* ============================================================ */
601 1.1 christos
602 1.1 christos #if defined(WIN32) && defined(__GNUC__)
603 1.1 christos int _CRT_glob = 0; /* disable argument globbing in MinGW */
604 1.1 christos #endif
605 1.1 christos
606 1.1 christos int main(int argc,char **argv)
607 1.1 christos {
608 1.1 christos int action = TGZ_EXTRACT;
609 1.1 christos int arg = 1;
610 1.1 christos char *TGZfile;
611 1.1 christos gzFile *f;
612 1.1 christos
613 1.1 christos prog = strrchr(argv[0],'\\');
614 1.1 christos if (prog == NULL)
615 1.1 christos {
616 1.1 christos prog = strrchr(argv[0],'/');
617 1.1 christos if (prog == NULL)
618 1.1 christos {
619 1.1 christos prog = strrchr(argv[0],':');
620 1.1 christos if (prog == NULL)
621 1.1 christos prog = argv[0];
622 1.1 christos else
623 1.1 christos prog++;
624 1.1 christos }
625 1.1 christos else
626 1.1 christos prog++;
627 1.1 christos }
628 1.1 christos else
629 1.1 christos prog++;
630 1.1 christos
631 1.1 christos if (argc == 1)
632 1.1 christos help(0);
633 1.1 christos
634 1.1 christos if (strcmp(argv[arg],"-l") == 0)
635 1.1 christos {
636 1.1 christos action = TGZ_LIST;
637 1.1 christos if (argc == ++arg)
638 1.1 christos help(0);
639 1.1 christos }
640 1.1 christos else if (strcmp(argv[arg],"-h") == 0)
641 1.1 christos {
642 1.1 christos help(0);
643 1.1 christos }
644 1.1 christos
645 1.1 christos if ((TGZfile = TGZfname(argv[arg])) == NULL)
646 1.1 christos TGZnotfound(argv[arg]);
647 1.1 christos
648 1.1 christos ++arg;
649 1.1 christos if ((action == TGZ_LIST) && (arg != argc))
650 1.1 christos help(1);
651 1.1 christos
652 1.1 christos /*
653 1.1 christos * Process the TGZ file
654 1.1 christos */
655 1.1 christos switch(action)
656 1.1 christos {
657 1.1 christos case TGZ_LIST:
658 1.1 christos case TGZ_EXTRACT:
659 1.1 christos f = gzopen(TGZfile,"rb");
660 1.1 christos if (f == NULL)
661 1.1 christos {
662 1.1 christos fprintf(stderr,"%s: Couldn't gzopen %s\n",prog,TGZfile);
663 1.1 christos return 1;
664 1.1 christos }
665 1.1 christos exit(tar(f, action, arg, argc, argv));
666 1.1 christos break;
667 1.1 christos
668 1.1 christos default:
669 1.1 christos error("Unknown option");
670 1.1 christos exit(1);
671 1.1 christos }
672 1.1 christos
673 1.1 christos return 0;
674 1.1 christos }
675