The SWORD Project  1.9.0
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
untgz.c
Go to the documentation of this file.
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 <errno.h>
13 #include <fcntl.h>
14 #ifdef unix
15 #include <unistd.h>
16 #include <sys/stat.h>
17 #include <sys/types.h>
18 
19 #else
20 # include <direct.h>
21 # include <io.h>
22 #endif
23 
24 #include "zlib.h"
25 
26 #ifdef WIN32
27 # include <windows.h>
28 # ifndef F_OK
29 # define F_OK (0)
30 # endif
31 # ifdef _MSC_VER
32 # define mkdir(dirname,mode) _mkdir(dirname)
33 # define strdup(str) _strdup(str)
34 # define unlink(fn) _unlink(fn)
35 # define access(path,mode) _access(path,mode)
36 # else
37 # define mkdir(dirname,mode) _mkdir(dirname)
38 # endif
39 #else
40 # include <utime.h>
41 #endif
42 
43 
44 /* Values used in typeflag field. */
45 
46 #define REGTYPE '0' /* regular file */
47 #define AREGTYPE '\0' /* regular file */
48 #define LNKTYPE '1' /* link */
49 #define SYMTYPE '2' /* reserved */
50 #define CHRTYPE '3' /* character special */
51 #define BLKTYPE '4' /* block special */
52 #define DIRTYPE '5' /* directory */
53 #define FIFOTYPE '6' /* FIFO special */
54 #define CONTTYPE '7' /* reserved */
55 
56 #define BLOCKSIZE 512
57 
58 struct tar_header
59 { /* byte offset */
60  char name[100]; /* 0 */
61  char mode[8]; /* 100 */
62  char uid[8]; /* 108 */
63  char gid[8]; /* 116 */
64  char size[12]; /* 124 */
65  char mtime[12]; /* 136 */
66  char chksum[8]; /* 148 */
67  char typeflag; /* 156 */
68  char linkname[100]; /* 157 */
69  char magic[6]; /* 257 */
70  char version[2]; /* 263 */
71  char uname[32]; /* 265 */
72  char gname[32]; /* 297 */
73  char devmajor[8]; /* 329 */
74  char devminor[8]; /* 337 */
75  char prefix[155]; /* 345 */
76  /* 500 */
77 };
78 
79 union tar_buffer {
81  struct tar_header header;
82 };
83 
84 enum { TGZ_EXTRACT = 0, TGZ_LIST };
85 
86 void TGZnotfound OF((const char *));
87 
88 int getoct OF((char *, int));
89 char *strtime OF((time_t *));
90 int ExprMatch OF((char *,char *));
91 
92 int makedir OF((char *));
93 int matchname OF((int,int,char **,char *));
94 
95 void error OF((const char *));
96 int tar OF((gzFile, int, int, int, char **));
97 
98 void help OF((int));
99 int main OF((int, char **));
100 
101 char *prog;
102 
103 /* This will give a benign warning */
104 
105 static char *TGZprefix[] = { "\0", ".tgz", ".tar.gz", ".tar", NULL };
106 
107 /* Return the real name of the TGZ archive */
108 /* or NULL if it does not exist. */
109 
110 /* error message for the filename */
111 
112 void TGZnotfound OF((const char *fname))
113 {
114  int i;
115 
116  fprintf(stderr,"%s : couldn't find ",prog);
117  for (i=0;TGZprefix[i];i++)
118  fprintf(stderr,(TGZprefix[i+1]) ? "%s%s, " : "or %s%s\n",
119  fname,
120  TGZprefix[i]);
121  exit(1);
122 }
123 
124 
125 /* help functions */
126 
127 int getoct(char *p,int width)
128 {
129  int result = 0;
130  char c;
131 
132  while (width --)
133  {
134  c = *p++;
135  if (c == ' ')
136  continue;
137  if (c == 0)
138  break;
139  result = result * 8 + (c - '0');
140  }
141  return result;
142 }
143 
144 char *strtime (time_t *t)
145 {
146  struct tm *local;
147  static char result[32];
148 
149  local = localtime(t);
150  sprintf(result,"%2d/%02d/%4d %02d:%02d:%02d",
151  local->tm_mday, local->tm_mon+1, local->tm_year+1900,
152  local->tm_hour, local->tm_min, local->tm_sec);
153  return result;
154 }
155 
156 
157 /* regular expression matching */
158 
159 #define ISSPECIAL(c) (((c) == '*') || ((c) == '/'))
160 
161 int ExprMatch(char *string,char *expr)
162 {
163  while (1)
164  {
165  if (ISSPECIAL(*expr))
166  {
167  if (*expr == '/')
168  {
169  if (*string != '\\' && *string != '/')
170  return 0;
171  string ++; expr++;
172  }
173  else if (*expr == '*')
174  {
175  if (*expr ++ == 0)
176  return 1;
177  while (*++string != *expr)
178  if (*string == 0)
179  return 0;
180  }
181  }
182  else
183  {
184  if (*string != *expr)
185  return 0;
186  if (*expr++ == 0)
187  return 1;
188  string++;
189  }
190  }
191 }
192 
193 /* recursive make directory */
194 /* abort if you get an ENOENT errno somewhere in the middle */
195 /* e.g. ignore error "mkdir on existing directory" */
196 /* */
197 /* return 1 if OK */
198 /* 0 on error */
199 
200 int makedir (char *newdir)
201 {
202  char *buffer = strdup(newdir);
203  char *p;
204  int len = (int)strlen(buffer);
205 
206  if (len <= 0) {
207  free(buffer);
208  return 0;
209  }
210  if (buffer[len-1] == '/') {
211  buffer[len-1] = '\0';
212  }
213  if (mkdir(buffer, 0775) == 0)
214  {
215  free(buffer);
216  return 1;
217  }
218 
219  p = buffer+1;
220  while (1)
221  {
222  char hold;
223 
224  while(*p && *p != '\\' && *p != '/')
225  p++;
226  hold = *p;
227  *p = 0;
228  if ((mkdir(buffer, 0775) == -1) && (errno == ENOENT))
229  {
230  fprintf(stderr,"%s: couldn't create directory %s\n",prog,buffer);
231  free(buffer);
232  return 0;
233  }
234  if (hold == 0)
235  break;
236  *p++ = hold;
237  }
238  free(buffer);
239  return 1;
240 }
241 
242 int matchname (int arg,int argc,char **argv,char *fname)
243 {
244  if (arg == argc) /* no arguments given (untgz tgzarchive) */
245  return 1;
246 
247  while (arg < argc)
248  if (ExprMatch(fname,argv[arg++]))
249  return 1;
250 
251  return 0; /* ignore this for the moment being */
252 }
253 
254 
255 /* Tar file list or extract */
256 
257 int untar (gzFile in, const char *dest) {
258  union tar_buffer buffer;
259  int len;
260  int err;
261  int getheader = 1;
262  int remaining = 0;
263  FILE *outfile = NULL;
264  char fname[BLOCKSIZE];
265  time_t tartime;
266 
267  while (1) {
268  len = gzread(in, &buffer, BLOCKSIZE);
269  if (len < 0)
270  error (gzerror(in, &err));
271  /*
272  * Always expect complete blocks to process
273  * the tar information.
274  */
275  if (len != BLOCKSIZE)
276  error("gzread: incomplete block read");
277 
278  /*
279  * If we have to get a tar header
280  */
281  if (getheader == 1) {
282  /*
283  * if we met the end of the tar
284  * or the end-of-tar block,
285  * we are done
286  */
287  if ((len == 0) || (buffer.header.name[0]== 0)) break;
288 
289  tartime = (time_t)getoct(buffer.header.mtime,12);
290  strcpy(fname, dest);
291  if ((fname[strlen(fname)-1] != '/') && (fname[strlen(fname)-1] != '\\'))
292  strcat(fname, "/");
293  strcat(fname, buffer.header.name);
294 
295  switch (buffer.header.typeflag) {
296  case DIRTYPE:
297  makedir(fname);
298  break;
299  case REGTYPE:
300  case AREGTYPE:
301  remaining = getoct(buffer.header.size,12);
302  if (remaining) {
303  outfile = fopen(fname,"wb");
304  if (outfile == NULL) {
305  // try creating directory
306  char *p = strrchr(fname, '/');
307  if (p != NULL) {
308  *p = '\0';
309  makedir(fname);
310  *p = '/';
311  outfile = fopen(fname,"wb");
312  }
313  }
314 /*
315  fprintf(stderr,
316  "%s %s\n",
317  (outfile) ? "Extracting" : "Couldn't create",
318  fname);
319 */
320  }
321  else
322  outfile = NULL;
323  /*
324  * could have no contents
325  */
326  getheader = (remaining) ? 0 : 1;
327  break;
328  default:
329  break;
330  }
331  }
332  else {
333  unsigned int bytes = (remaining > BLOCKSIZE) ? BLOCKSIZE : remaining;
334 
335  if (outfile != NULL) {
336  if (fwrite(&buffer,sizeof(char),bytes,outfile) != bytes) {
337  fprintf(stderr,"%s : error writing %s skipping...\n",prog,fname);
338  fclose(outfile);
339  unlink(fname);
340  }
341  }
342  remaining -= bytes;
343  if (remaining == 0) {
344  getheader = 1;
345  if (outfile != NULL) {
346 #ifdef WIN32
347  HANDLE hFile;
348  FILETIME ftm,ftLocal;
349  SYSTEMTIME st;
350  struct tm localt;
351 
352  fclose(outfile);
353 
354  localt = *localtime(&tartime);
355 
356  hFile = CreateFile(fname, GENERIC_READ | GENERIC_WRITE,
357  0, NULL, OPEN_EXISTING, 0, NULL);
358 
359  st.wYear = (WORD)localt.tm_year+1900;
360  st.wMonth = (WORD)localt.tm_mon;
361  st.wDayOfWeek = (WORD)localt.tm_wday;
362  st.wDay = (WORD)localt.tm_mday;
363  st.wHour = (WORD)localt.tm_hour;
364  st.wMinute = (WORD)localt.tm_min;
365  st.wSecond = (WORD)localt.tm_sec;
366  st.wMilliseconds = 0;
367  SystemTimeToFileTime(&st,&ftLocal);
368  LocalFileTimeToFileTime(&ftLocal,&ftm);
369  SetFileTime(hFile,&ftm,NULL,&ftm);
370  CloseHandle(hFile);
371 
372  outfile = NULL;
373 #else
374  struct utimbuf settime;
375 
376  settime.actime = settime.modtime = tartime;
377 
378  fclose(outfile);
379  outfile = NULL;
380  utime(fname,&settime);
381 #endif
382  }
383  }
384  }
385  }
386  return 0;
387 }
388 
389 
390 /* =========================================================== */
391 
392 void help(int exitval)
393 {
394  fprintf(stderr,
395  "untgz v 0.1\n"
396  " an sample application of zlib 1.0.4\n\n"
397  "Usage : untgz TGZfile to extract all files\n"
398  " untgz TGZfile fname ... to extract selected files\n"
399  " untgz -l TGZfile to list archive contents\n"
400  " untgz -h to display this help\n\n");
401  exit(exitval);
402 }
403 
404 void error(const char *msg)
405 {
406  fprintf(stderr, "%s: %s\n", prog, msg);
407 // exit(1); // don't exit on error
408 }
409 
410 
411 int untargz(int fd, const char *dest) {
412  gzFile f;
413 
414  f = gzdopen(fd, "rb");
415  if (f == NULL) {
416  fprintf(stderr,"%s: Couldn't gzopen file\n", prog);
417  return 1;
418  }
419 
420  return untar(f, dest);
421 }
#define AREGTYPE
Definition: untgz.c:47
struct tar_header header
Definition: untgz.c:81
int matchname(int arg, int argc, char **argv, char *fname)
Definition: untgz.c:242
Definition: untgz.c:84
char * prog
Definition: untgz.c:101
char devminor[8]
Definition: untgz.c:74
int makedir(char *newdir)
Definition: untgz.c:200
char gid[8]
Definition: untgz.c:63
char name[100]
Definition: untgz.c:60
char devmajor[8]
Definition: untgz.c:73
char mode[8]
Definition: untgz.c:61
char linkname[100]
Definition: untgz.c:68
preg buffer
Definition: regex.c:8089
int main(int argc, char **argv)
Definition: addcomment.cpp:32
void help(int exitval)
Definition: untgz.c:392
static char * TGZprefix[]
Definition: untgz.c:105
#define DIRTYPE
Definition: untgz.c:52
#define OF(args)
Definition: zconf.h:269
#define REGTYPE
Definition: untgz.c:46
char chksum[8]
Definition: untgz.c:66
char * strtime(time_t *t)
Definition: untgz.c:144
#define BLOCKSIZE
Definition: untgz.c:56
return NULL
Definition: regex.c:7953
free(preg->fastmap)
void error(const char *msg)
Definition: untgz.c:404
char uid[8]
Definition: untgz.c:62
gzFile ZEXPORT gzdopen(int fd, const char *mode)
Definition: gzlib.c:292
#define local
Definition: adler32.c:10
char version[2]
Definition: untgz.c:70
#define ISSPECIAL(c)
Definition: untgz.c:159
int size
Definition: regex.c:5043
char typeflag
Definition: untgz.c:67
const char *ZEXPORT gzerror(gzFile file, int *errnum)
Definition: gzlib.c:536
int getoct(char *p, int width)
Definition: untgz.c:127
result
Definition: regex.c:5545
int ExprMatch(char *string, char *expr)
Definition: untgz.c:161
int untargz(int fd, const char *dest)
Definition: untgz.c:411
char mtime[12]
Definition: untgz.c:65
char prefix[155]
Definition: untgz.c:75
int ZEXPORT gzread(gzFile file, voidp buf, unsigned len)
Definition: gzread.c:295
int untar(gzFile in, const char *dest)
Definition: untgz.c:257
char uname[32]
Definition: untgz.c:71
char magic[6]
Definition: untgz.c:69
char gname[32]
Definition: untgz.c:72