summaryrefslogtreecommitdiff
path: root/contrib/untgz/untgz.c
diff options
context:
space:
mode:
authorMark Adler <madler@alumni.caltech.edu>2011-09-09 23:17:33 -0700
committerMark Adler <madler@alumni.caltech.edu>2011-09-09 23:17:33 -0700
commit7850e4e406dce1f7a819297eeb151d1ca18e7cd9 (patch)
treed4befddacae46b06c4924193904de533099610b4 /contrib/untgz/untgz.c
parentebd3c2c0e734fc99a1360014ea52ed04fe6aade4 (diff)
downloadzlib-1.0.7.tar.gz
zlib-1.0.7.tar.bz2
zlib-1.0.7.zip
zlib 1.0.7v1.0.7
Diffstat (limited to 'contrib/untgz/untgz.c')
-rw-r--r--contrib/untgz/untgz.c478
1 files changed, 478 insertions, 0 deletions
diff --git a/contrib/untgz/untgz.c b/contrib/untgz/untgz.c
new file mode 100644
index 0000000..6fa9a5d
--- /dev/null
+++ b/contrib/untgz/untgz.c
@@ -0,0 +1,478 @@
1/*
2 * untgz.c -- Display contents and/or extract file from
3 * a gzip'd TAR file
4 * written by "Pedro A. Aranda Guti\irrez" <paag@tid.es>
5 * adaptation to Unix by Jean-loup Gailly <jloup@gzip.org>
6 */
7
8#include <stdio.h>
9#include <stdlib.h>
10#include <string.h>
11#include <time.h>
12#include <utime.h>
13#include <errno.h>
14#include <fcntl.h>
15#ifdef unix
16# include <unistd.h>
17#else
18# include <direct.h>
19# include <io.h>
20#endif
21
22#include "zlib.h"
23
24/* Values used in typeflag field. */
25
26#define REGTYPE '0' /* regular file */
27#define AREGTYPE '\0' /* regular file */
28#define LNKTYPE '1' /* link */
29#define SYMTYPE '2' /* reserved */
30#define CHRTYPE '3' /* character special */
31#define BLKTYPE '4' /* block special */
32#define DIRTYPE '5' /* directory */
33#define FIFOTYPE '6' /* FIFO special */
34#define CONTTYPE '7' /* reserved */
35
36#define BLOCKSIZE 512
37
38struct tar_header
39{ /* byte offset */
40 char name[100]; /* 0 */
41 char mode[8]; /* 100 */
42 char uid[8]; /* 108 */
43 char gid[8]; /* 116 */
44 char size[12]; /* 124 */
45 char mtime[12]; /* 136 */
46 char chksum[8]; /* 148 */
47 char typeflag; /* 156 */
48 char linkname[100]; /* 157 */
49 char magic[6]; /* 257 */
50 char version[2]; /* 263 */
51 char uname[32]; /* 265 */
52 char gname[32]; /* 297 */
53 char devmajor[8]; /* 329 */
54 char devminor[8]; /* 337 */
55 char prefix[155]; /* 345 */
56 /* 500 */
57};
58
59union tar_buffer {
60 char buffer[BLOCKSIZE];
61 struct tar_header header;
62};
63
64enum { TGZ_EXTRACT = 0, TGZ_LIST };
65
66static char *TGZfname OF((const char *));
67void TGZnotfound OF((const char *));
68
69int getoct OF((char *, int));
70char *strtime OF((time_t *));
71int ExprMatch OF((char *,char *));
72
73int makedir OF((char *));
74int matchname OF((int,int,char **,char *));
75
76void error OF((const char *));
77int tar OF((gzFile, int, int, int, char **));
78
79void help OF((int));
80int main OF((int, char **));
81
82char *prog;
83
84/* This will give a benign warning */
85
86static char *TGZprefix[] = { "\0", ".tgz", ".tar.gz", NULL };
87
88/* Return the real name of the TGZ archive */
89/* or NULL if it does not exist. */
90
91static char *TGZfname OF((const char *fname))
92{
93 static char buffer[1024];
94 int origlen,i;
95
96 strcpy(buffer,fname);
97 origlen = strlen(buffer);
98
99 for (i=0; TGZprefix[i]; i++)
100 {
101 strcpy(buffer+origlen,TGZprefix[i]);
102 if (access(buffer,F_OK) == 0)
103 return buffer;
104 }
105 return NULL;
106}
107
108/* error message for the filename */
109
110void TGZnotfound OF((const char *fname))
111{
112 int i;
113
114 fprintf(stderr,"%s : couldn't find ",prog);
115 for (i=0;TGZprefix[i];i++)
116 fprintf(stderr,(TGZprefix[i+1]) ? "%s%s, " : "or %s%s\n",
117 fname,
118 TGZprefix[i]);
119 exit(1);
120}
121
122
123/* help functions */
124
125int getoct(char *p,int width)
126{
127 int result = 0;
128 char c;
129
130 while (width --)
131 {
132 c = *p++;
133 if (c == ' ')
134 continue;
135 if (c == 0)
136 break;
137 result = result * 8 + (c - '0');
138 }
139 return result;
140}
141
142char *strtime (time_t *t)
143{
144 struct tm *local;
145 static char result[32];
146
147 local = localtime(t);
148 sprintf(result,"%2d/%02d/%4d %02d:%02d:%02d",
149 local->tm_mday, local->tm_mon+1, local->tm_year+1900,
150 local->tm_hour, local->tm_min, local->tm_sec);
151 return result;
152}
153
154
155/* regular expression matching */
156
157#define ISSPECIAL(c) (((c) == '*') || ((c) == '/'))
158
159int ExprMatch(char *string,char *expr)
160{
161 while (1)
162 {
163 if (ISSPECIAL(*expr))
164 {
165 if (*expr == '/')
166 {
167 if (*string != '\\' && *string != '/')
168 return 0;
169 string ++; expr++;
170 }
171 else if (*expr == '*')
172 {
173 if (*expr ++ == 0)
174 return 1;
175 while (*++string != *expr)
176 if (*string == 0)
177 return 0;
178 }
179 }
180 else
181 {
182 if (*string != *expr)
183 return 0;
184 if (*expr++ == 0)
185 return 1;
186 string++;
187 }
188 }
189}
190
191/* recursive make directory */
192/* abort if you get an ENOENT errno somewhere in the middle */
193/* e.g. ignore error "mkdir on existing directory" */
194/* */
195/* return 1 if OK */
196/* 0 on error */
197
198int makedir (char *newdir)
199{
200 char *buffer = strdup(newdir);
201 char *p;
202 int len = strlen(buffer);
203
204 if (len <= 0) {
205 free(buffer);
206 return 0;
207 }
208 if (buffer[len-1] == '/') {
209 buffer[len-1] = '\0';
210 }
211 if (mkdir(buffer, 0775) == 0)
212 {
213 free(buffer);
214 return 1;
215 }
216
217 p = buffer+1;
218 while (1)
219 {
220 char hold;
221
222 while(*p && *p != '\\' && *p != '/')
223 p++;
224 hold = *p;
225 *p = 0;
226 if ((mkdir(buffer, 0775) == -1) && (errno == ENOENT))
227 {
228 fprintf(stderr,"%s: couldn't create directory %s\n",prog,buffer);
229 free(buffer);
230 return 0;
231 }
232 if (hold == 0)
233 break;
234 *p++ = hold;
235 }
236 free(buffer);
237 return 1;
238}
239
240int matchname (int arg,int argc,char **argv,char *fname)
241{
242 if (arg == argc) /* no arguments given (untgz tgzarchive) */
243 return 1;
244
245 while (arg < argc)
246 if (ExprMatch(fname,argv[arg++]))
247 return 1;
248
249 return 0; /* ignore this for the moment being */
250}
251
252
253/* Tar file list or extract */
254
255int tar (gzFile in,int action,int arg,int argc,char **argv)
256{
257 union tar_buffer buffer;
258 int len;
259 int err;
260 int getheader = 1;
261 int remaining = 0;
262 FILE *outfile = NULL;
263 char fname[BLOCKSIZE];
264 time_t tartime;
265
266 if (action == TGZ_LIST)
267 printf(" day time size file\n"
268 " ---------- -------- --------- -------------------------------------\n");
269 while (1)
270 {
271 len = gzread(in, &buffer, BLOCKSIZE);
272 if (len < 0)
273 error (gzerror(in, &err));
274 /*
275 * if we met the end of the tar
276 * or the end-of-tar block,
277 * we are done
278 */
279 if ((len == 0) || (buffer.header.name[0]== 0))
280 break;
281
282 /*
283 * Always expect complete blocks to process
284 * the tar information.
285 */
286 if (len != BLOCKSIZE)
287 error("gzread: incomplete block read");
288
289 /*
290 * If we have to get a tar header
291 */
292 if (getheader == 1)
293 {
294 tartime = (time_t)getoct(buffer.header.mtime,12);
295 strcpy(fname,buffer.header.name);
296
297 switch (buffer.header.typeflag)
298 {
299 case DIRTYPE:
300 if (action == TGZ_LIST)
301 printf(" %s <dir> %s\n",strtime(&tartime),fname);
302 if (action == TGZ_EXTRACT)
303 makedir(fname);
304 break;
305 case REGTYPE:
306 case AREGTYPE:
307 remaining = getoct(buffer.header.size,12);
308 if (action == TGZ_LIST)
309 printf(" %s %9d %s\n",strtime(&tartime),remaining,fname);
310 if (action == TGZ_EXTRACT)
311 {
312 if ((remaining) && (matchname(arg,argc,argv,fname)))
313 {
314 outfile = fopen(fname,"wb");
315 if (outfile == NULL) {
316 /* try creating directory */
317 char *p = strrchr(fname, '/');
318 if (p != NULL) {
319 *p = '\0';
320 makedir(fname);
321 *p = '/';
322 outfile = fopen(fname,"wb");
323 }
324 }
325 fprintf(stderr,
326 "%s %s\n",
327 (outfile) ? "Extracting" : "Couldn't create",
328 fname);
329 }
330 else
331 outfile = NULL;
332 }
333 /*
334 * could have no contents
335 */
336 getheader = (remaining) ? 0 : 1;
337 break;
338 default:
339 if (action == TGZ_LIST)
340 printf(" %s <---> %s\n",strtime(&tartime),fname);
341 break;
342 }
343 }
344 else
345 {
346 unsigned int bytes = (remaining > BLOCKSIZE) ? BLOCKSIZE : remaining;
347
348 if ((action == TGZ_EXTRACT) && (outfile != NULL))
349 {
350 if (fwrite(&buffer,sizeof(char),bytes,outfile) != bytes)
351 {
352 fprintf(stderr,"%s : error writing %s skipping...\n",prog,fname);
353 fclose(outfile);
354 unlink(fname);
355 }
356 }
357 remaining -= bytes;
358 if (remaining == 0)
359 {
360 getheader = 1;
361 if ((action == TGZ_EXTRACT) && (outfile != NULL))
362 {
363 struct utimbuf settime;
364
365 settime.actime = settime.modtime = tartime;
366
367 fclose(outfile);
368 outfile = NULL;
369 utime(fname,&settime);
370 }
371 }
372 }
373 }
374
375 if (gzclose(in) != Z_OK)
376 error("failed gzclose");
377
378 return 0;
379}
380
381
382/* =========================================================== */
383
384void help(int exitval)
385{
386 fprintf(stderr,
387 "untgz v 0.1\n"
388 " an sample application of zlib 1.0.4\n\n"
389 "Usage : untgz TGZfile to extract all files\n"
390 " untgz TGZfile fname ... to extract selected files\n"
391 " untgz -l TGZfile to list archive contents\n"
392 " untgz -h to display this help\n\n");
393 exit(exitval);
394}
395
396void error(const char *msg)
397{
398 fprintf(stderr, "%s: %s\n", prog, msg);
399 exit(1);
400}
401
402
403/* ====================================================================== */
404
405int _CRT_glob = 0; /* disable globbing of the arguments */
406
407int main(int argc,char **argv)
408{
409 int action = TGZ_EXTRACT;
410 int arg = 1;
411 char *TGZfile;
412 gzFile *f;
413
414
415 prog = strrchr(argv[0],'\\');
416 if (prog == NULL)
417 {
418 prog = strrchr(argv[0],'/');
419 if (prog == NULL)
420 {
421 prog = strrchr(argv[0],':');
422 if (prog == NULL)
423 prog = argv[0];
424 else
425 prog++;
426 }
427 else
428 prog++;
429 }
430 else
431 prog++;
432
433 if (argc == 1)
434 help(0);
435
436 if (strcmp(argv[arg],"-l") == 0)
437 {
438 action = TGZ_LIST;
439 if (argc == ++arg)
440 help(0);
441 }
442 else if (strcmp(argv[arg],"-h") == 0)
443 {
444 help(0);
445 }
446
447 if ((TGZfile = TGZfname(argv[arg])) == NULL)
448 TGZnotfound(argv[arg]);
449
450 ++arg;
451 if ((action == TGZ_LIST) && (arg != argc))
452 help(1);
453
454/*
455 * Process the TGZ file
456 */
457 switch(action)
458 {
459 case TGZ_LIST:
460 case TGZ_EXTRACT:
461 f = gzopen(TGZfile,"rb");
462 if (f == NULL)
463 {
464 fprintf(stderr,"%s: Couldn't gzopen %s\n",
465 prog,
466 TGZfile);
467 return 1;
468 }
469 exit(tar(f, action, arg, argc, argv));
470 break;
471
472 default:
473 error("Unknown option!");
474 exit(1);
475 }
476
477 return 0;
478}