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