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!");