VirtualBox

source: vbox/trunk/src/libs/zlib-1.2.1/contrib/untgz/untgz.c@ 34079

Last change on this file since 34079 was 6392, checked in by vboxsync, 17 years ago

export libpng and zlib so Windows and OS/2 builds cleanly.

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

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette