2
* untgz.c -- Display contents and/or extract file from
4
* written by "Pedro A. Aranda Guti\irrez" <paag@tid.es>
5
* adaptation to Unix by Jean-loup Gailly <jloup@gzip.org>
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)
33
# define mkdir(dirname,mode) _mkdir(dirname)
40
/* Values used in typeflag field. */
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 */
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 */
76
char buffer[BLOCKSIZE];
77
struct tar_header header;
80
enum { TGZ_EXTRACT = 0, TGZ_LIST };
82
static char *TGZfname OF((const char *));
83
void TGZnotfound OF((const char *));
85
int getoct OF((char *, int));
86
char *strtime OF((time_t *));
87
int ExprMatch OF((char *,char *));
89
int makedir OF((char *));
90
int matchname OF((int,int,char **,char *));
92
void error OF((const char *));
93
int tar OF((gzFile, int, int, int, char **));
96
int main OF((int, char **));
100
/* This will give a benign warning */
102
static char *TGZprefix[] = { "\0", ".tgz", ".tar.gz", ".tar", NULL };
104
/* Return the real name of the TGZ archive */
105
/* or NULL if it does not exist. */
107
static char *TGZfname OF((const char *fname))
109
static char buffer[1024];
112
strcpy(buffer,fname);
113
origlen = strlen(buffer);
115
for (i=0; TGZprefix[i]; i++)
117
strcpy(buffer+origlen,TGZprefix[i]);
118
if (access(buffer,F_OK) == 0)
124
/* error message for the filename */
126
void TGZnotfound OF((const char *fname))
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",
141
int getoct(char *p,int width)
153
result = result * 8 + (c - '0');
158
char *strtime (time_t *t)
161
static char result[32];
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);
171
/* regular expression matching */
173
#define ISSPECIAL(c) (((c) == '*') || ((c) == '/'))
175
int ExprMatch(char *string,char *expr)
179
if (ISSPECIAL(*expr))
183
if (*string != '\\' && *string != '/')
187
else if (*expr == '*')
191
while (*++string != *expr)
198
if (*string != *expr)
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" */
214
int makedir (char *newdir)
216
char *buffer = strdup(newdir);
218
int len = strlen(buffer);
224
if (buffer[len-1] == '/') {
225
buffer[len-1] = '\0';
227
if (mkdir(buffer, 0775) == 0)
238
while(*p && *p != '\\' && *p != '/')
242
if ((mkdir(buffer, 0775) == -1) && (errno == ENOENT))
244
fprintf(stderr,"%s: couldn't create directory %s\n",prog,buffer);
256
int matchname (int arg,int argc,char **argv,char *fname)
258
if (arg == argc) /* no arguments given (untgz tgzarchive) */
262
if (ExprMatch(fname,argv[arg++]))
265
return 0; /* ignore this for the moment being */
269
/* Tar file list or extract */
271
int tar (gzFile in,int action,int arg,int argc,char **argv)
273
union tar_buffer buffer;
278
FILE *outfile = NULL;
279
char fname[BLOCKSIZE];
282
if (action == TGZ_LIST)
283
printf(" day time size file\n"
284
" ---------- -------- --------- -------------------------------------\n");
287
len = gzread(in, &buffer, BLOCKSIZE);
289
error (gzerror(in, &err));
291
* Always expect complete blocks to process
292
* the tar information.
294
if (len != BLOCKSIZE)
295
error("gzread: incomplete block read");
298
* If we have to get a tar header
303
* if we met the end of the tar
304
* or the end-of-tar block,
307
if ((len == 0) || (buffer.header.name[0]== 0)) break;
309
tartime = (time_t)getoct(buffer.header.mtime,12);
310
strcpy(fname,buffer.header.name);
312
switch (buffer.header.typeflag)
315
if (action == TGZ_LIST)
316
printf(" %s <dir> %s\n",strtime(&tartime),fname);
317
if (action == TGZ_EXTRACT)
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)
327
if ((remaining) && (matchname(arg,argc,argv,fname)))
329
outfile = fopen(fname,"wb");
330
if (outfile == NULL) {
331
/* try creating directory */
332
char *p = strrchr(fname, '/');
337
outfile = fopen(fname,"wb");
342
(outfile) ? "Extracting" : "Couldn't create",
349
* could have no contents
351
getheader = (remaining) ? 0 : 1;
354
if (action == TGZ_LIST)
355
printf(" %s <---> %s\n",strtime(&tartime),fname);
361
unsigned int bytes = (remaining > BLOCKSIZE) ? BLOCKSIZE : remaining;
363
if ((action == TGZ_EXTRACT) && (outfile != NULL))
365
if (fwrite(&buffer,sizeof(char),bytes,outfile) != bytes)
367
fprintf(stderr,"%s : error writing %s skipping...\n",prog,fname);
376
if ((action == TGZ_EXTRACT) && (outfile != NULL))
380
FILETIME ftm,ftLocal;
386
localt = *localtime(&tartime);
388
hFile = CreateFile(fname, GENERIC_READ | GENERIC_WRITE,
389
0, NULL, OPEN_EXISTING, 0, NULL);
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);
406
struct utimbuf settime;
408
settime.actime = settime.modtime = tartime;
412
utime(fname,&settime);
419
if (gzclose(in) != Z_OK)
420
error("failed gzclose");
426
/* =========================================================== */
428
void help(int exitval)
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");
440
void error(const char *msg)
442
fprintf(stderr, "%s: %s\n", prog, msg);
447
/* ====================================================================== */
449
int _CRT_glob = 0; /* disable globbing of the arguments */
451
int main(int argc,char **argv)
453
int action = TGZ_EXTRACT;
459
prog = strrchr(argv[0],'\\');
462
prog = strrchr(argv[0],'/');
465
prog = strrchr(argv[0],':');
480
if (strcmp(argv[arg],"-l") == 0)
486
else if (strcmp(argv[arg],"-h") == 0)
491
if ((TGZfile = TGZfname(argv[arg])) == NULL)
492
TGZnotfound(argv[arg]);
495
if ((action == TGZ_LIST) && (arg != argc))
499
* Process the TGZ file
505
f = gzopen(TGZfile,"rb");
508
fprintf(stderr,"%s: Couldn't gzopen %s\n",
513
exit(tar(f, action, arg, argc, argv));
517
error("Unknown option!");