1*aaf4ece6Schristos /*
2*aaf4ece6Schristos * untgz.c -- Display contents and extract files from a gzip'd TAR file
3*aaf4ece6Schristos *
4*aaf4ece6Schristos * written by Pedro A. Aranda Gutierrez <paag@tid.es>
5*aaf4ece6Schristos * adaptation to Unix by Jean-loup Gailly <jloup@gzip.org>
6*aaf4ece6Schristos * various fixes by Cosmin Truta <cosmint@cs.ubbcluj.ro>
7*aaf4ece6Schristos */
8*aaf4ece6Schristos
9*aaf4ece6Schristos #include <stdio.h>
10*aaf4ece6Schristos #include <stdlib.h>
11*aaf4ece6Schristos #include <string.h>
12*aaf4ece6Schristos #include <time.h>
13*aaf4ece6Schristos #include <errno.h>
14*aaf4ece6Schristos
15*aaf4ece6Schristos #include "zlib.h"
16*aaf4ece6Schristos
17*aaf4ece6Schristos #ifdef unix
18*aaf4ece6Schristos # include <unistd.h>
19*aaf4ece6Schristos #else
20*aaf4ece6Schristos # include <direct.h>
21*aaf4ece6Schristos # include <io.h>
22*aaf4ece6Schristos #endif
23*aaf4ece6Schristos
24*aaf4ece6Schristos #ifdef WIN32
25*aaf4ece6Schristos #include <windows.h>
26*aaf4ece6Schristos # ifndef F_OK
27*aaf4ece6Schristos # define F_OK 0
28*aaf4ece6Schristos # endif
29*aaf4ece6Schristos # define mkdir(dirname,mode) _mkdir(dirname)
30*aaf4ece6Schristos # ifdef _MSC_VER
31*aaf4ece6Schristos # define access(path,mode) _access(path,mode)
32*aaf4ece6Schristos # define chmod(path,mode) _chmod(path,mode)
33*aaf4ece6Schristos # define strdup(str) _strdup(str)
34*aaf4ece6Schristos # endif
35*aaf4ece6Schristos #else
36*aaf4ece6Schristos # include <utime.h>
37*aaf4ece6Schristos #endif
38*aaf4ece6Schristos
39*aaf4ece6Schristos
40*aaf4ece6Schristos /* values used in typeflag field */
41*aaf4ece6Schristos
42*aaf4ece6Schristos #define REGTYPE '0' /* regular file */
43*aaf4ece6Schristos #define AREGTYPE '\0' /* regular file */
44*aaf4ece6Schristos #define LNKTYPE '1' /* link */
45*aaf4ece6Schristos #define SYMTYPE '2' /* reserved */
46*aaf4ece6Schristos #define CHRTYPE '3' /* character special */
47*aaf4ece6Schristos #define BLKTYPE '4' /* block special */
48*aaf4ece6Schristos #define DIRTYPE '5' /* directory */
49*aaf4ece6Schristos #define FIFOTYPE '6' /* FIFO special */
50*aaf4ece6Schristos #define CONTTYPE '7' /* reserved */
51*aaf4ece6Schristos
52*aaf4ece6Schristos /* GNU tar extensions */
53*aaf4ece6Schristos
54*aaf4ece6Schristos #define GNUTYPE_DUMPDIR 'D' /* file names from dumped directory */
55*aaf4ece6Schristos #define GNUTYPE_LONGLINK 'K' /* long link name */
56*aaf4ece6Schristos #define GNUTYPE_LONGNAME 'L' /* long file name */
57*aaf4ece6Schristos #define GNUTYPE_MULTIVOL 'M' /* continuation of file from another volume */
58*aaf4ece6Schristos #define GNUTYPE_NAMES 'N' /* file name that does not fit into main hdr */
59*aaf4ece6Schristos #define GNUTYPE_SPARSE 'S' /* sparse file */
60*aaf4ece6Schristos #define GNUTYPE_VOLHDR 'V' /* tape/volume header */
61*aaf4ece6Schristos
62*aaf4ece6Schristos
63*aaf4ece6Schristos /* tar header */
64*aaf4ece6Schristos
65*aaf4ece6Schristos #define BLOCKSIZE 512
66*aaf4ece6Schristos #define SHORTNAMESIZE 100
67*aaf4ece6Schristos
68*aaf4ece6Schristos struct tar_header
69*aaf4ece6Schristos { /* byte offset */
70*aaf4ece6Schristos char name[100]; /* 0 */
71*aaf4ece6Schristos char mode[8]; /* 100 */
72*aaf4ece6Schristos char uid[8]; /* 108 */
73*aaf4ece6Schristos char gid[8]; /* 116 */
74*aaf4ece6Schristos char size[12]; /* 124 */
75*aaf4ece6Schristos char mtime[12]; /* 136 */
76*aaf4ece6Schristos char chksum[8]; /* 148 */
77*aaf4ece6Schristos char typeflag; /* 156 */
78*aaf4ece6Schristos char linkname[100]; /* 157 */
79*aaf4ece6Schristos char magic[6]; /* 257 */
80*aaf4ece6Schristos char version[2]; /* 263 */
81*aaf4ece6Schristos char uname[32]; /* 265 */
82*aaf4ece6Schristos char gname[32]; /* 297 */
83*aaf4ece6Schristos char devmajor[8]; /* 329 */
84*aaf4ece6Schristos char devminor[8]; /* 337 */
85*aaf4ece6Schristos char prefix[155]; /* 345 */
86*aaf4ece6Schristos /* 500 */
87*aaf4ece6Schristos };
88*aaf4ece6Schristos
89*aaf4ece6Schristos union tar_buffer
90*aaf4ece6Schristos {
91*aaf4ece6Schristos char buffer[BLOCKSIZE];
92*aaf4ece6Schristos struct tar_header header;
93*aaf4ece6Schristos };
94*aaf4ece6Schristos
95*aaf4ece6Schristos struct attr_item
96*aaf4ece6Schristos {
97*aaf4ece6Schristos struct attr_item *next;
98*aaf4ece6Schristos char *fname;
99*aaf4ece6Schristos int mode;
100*aaf4ece6Schristos time_t time;
101*aaf4ece6Schristos };
102*aaf4ece6Schristos
103*aaf4ece6Schristos enum { TGZ_EXTRACT, TGZ_LIST, TGZ_INVALID };
104*aaf4ece6Schristos
105*aaf4ece6Schristos char *TGZfname OF((const char *));
106*aaf4ece6Schristos void TGZnotfound OF((const char *));
107*aaf4ece6Schristos
108*aaf4ece6Schristos int getoct OF((char *, int));
109*aaf4ece6Schristos char *strtime OF((time_t *));
110*aaf4ece6Schristos int setfiletime OF((char *, time_t));
111*aaf4ece6Schristos void push_attr OF((struct attr_item **, char *, int, time_t));
112*aaf4ece6Schristos void restore_attr OF((struct attr_item **));
113*aaf4ece6Schristos
114*aaf4ece6Schristos int ExprMatch OF((char *, char *));
115*aaf4ece6Schristos
116*aaf4ece6Schristos int makedir OF((char *));
117*aaf4ece6Schristos int matchname OF((int, int, char **, char *));
118*aaf4ece6Schristos
119*aaf4ece6Schristos void error OF((const char *));
120*aaf4ece6Schristos int tar OF((gzFile, int, int, int, char **));
121*aaf4ece6Schristos
122*aaf4ece6Schristos void help OF((int));
123*aaf4ece6Schristos int main OF((int, char **));
124*aaf4ece6Schristos
125*aaf4ece6Schristos char *prog;
126*aaf4ece6Schristos
127*aaf4ece6Schristos const char *TGZsuffix[] = { "\0", ".tar", ".tar.gz", ".taz", ".tgz", NULL };
128*aaf4ece6Schristos
129*aaf4ece6Schristos /* return the file name of the TGZ archive */
130*aaf4ece6Schristos /* or NULL if it does not exist */
131*aaf4ece6Schristos
TGZfname(const char * arcname)132*aaf4ece6Schristos char *TGZfname (const char *arcname)
133*aaf4ece6Schristos {
134*aaf4ece6Schristos static char buffer[1024];
135*aaf4ece6Schristos int origlen,i;
136*aaf4ece6Schristos
137*aaf4ece6Schristos strcpy(buffer,arcname);
138*aaf4ece6Schristos origlen = strlen(buffer);
139*aaf4ece6Schristos
140*aaf4ece6Schristos for (i=0; TGZsuffix[i]; i++)
141*aaf4ece6Schristos {
142*aaf4ece6Schristos strcpy(buffer+origlen,TGZsuffix[i]);
143*aaf4ece6Schristos if (access(buffer,F_OK) == 0)
144*aaf4ece6Schristos return buffer;
145*aaf4ece6Schristos }
146*aaf4ece6Schristos return NULL;
147*aaf4ece6Schristos }
148*aaf4ece6Schristos
149*aaf4ece6Schristos
150*aaf4ece6Schristos /* error message for the filename */
151*aaf4ece6Schristos
TGZnotfound(const char * arcname)152*aaf4ece6Schristos void TGZnotfound (const char *arcname)
153*aaf4ece6Schristos {
154*aaf4ece6Schristos int i;
155*aaf4ece6Schristos
156*aaf4ece6Schristos fprintf(stderr,"%s: Couldn't find ",prog);
157*aaf4ece6Schristos for (i=0;TGZsuffix[i];i++)
158*aaf4ece6Schristos fprintf(stderr,(TGZsuffix[i+1]) ? "%s%s, " : "or %s%s\n",
159*aaf4ece6Schristos arcname,
160*aaf4ece6Schristos TGZsuffix[i]);
161*aaf4ece6Schristos exit(1);
162*aaf4ece6Schristos }
163*aaf4ece6Schristos
164*aaf4ece6Schristos
165*aaf4ece6Schristos /* convert octal digits to int */
166*aaf4ece6Schristos /* on error return -1 */
167*aaf4ece6Schristos
getoct(char * p,int width)168*aaf4ece6Schristos int getoct (char *p,int width)
169*aaf4ece6Schristos {
170*aaf4ece6Schristos int result = 0;
171*aaf4ece6Schristos char c;
172*aaf4ece6Schristos
173*aaf4ece6Schristos while (width--)
174*aaf4ece6Schristos {
175*aaf4ece6Schristos c = *p++;
176*aaf4ece6Schristos if (c == 0)
177*aaf4ece6Schristos break;
178*aaf4ece6Schristos if (c == ' ')
179*aaf4ece6Schristos continue;
180*aaf4ece6Schristos if (c < '0' || c > '7')
181*aaf4ece6Schristos return -1;
182*aaf4ece6Schristos result = result * 8 + (c - '0');
183*aaf4ece6Schristos }
184*aaf4ece6Schristos return result;
185*aaf4ece6Schristos }
186*aaf4ece6Schristos
187*aaf4ece6Schristos
188*aaf4ece6Schristos /* convert time_t to string */
189*aaf4ece6Schristos /* use the "YYYY/MM/DD hh:mm:ss" format */
190*aaf4ece6Schristos
strtime(time_t * t)191*aaf4ece6Schristos char *strtime (time_t *t)
192*aaf4ece6Schristos {
193*aaf4ece6Schristos struct tm *local;
194*aaf4ece6Schristos static char result[32];
195*aaf4ece6Schristos
196*aaf4ece6Schristos local = localtime(t);
197*aaf4ece6Schristos sprintf(result,"%4d/%02d/%02d %02d:%02d:%02d",
198*aaf4ece6Schristos local->tm_year+1900, local->tm_mon+1, local->tm_mday,
199*aaf4ece6Schristos local->tm_hour, local->tm_min, local->tm_sec);
200*aaf4ece6Schristos return result;
201*aaf4ece6Schristos }
202*aaf4ece6Schristos
203*aaf4ece6Schristos
204*aaf4ece6Schristos /* set file time */
205*aaf4ece6Schristos
setfiletime(char * fname,time_t ftime)206*aaf4ece6Schristos int setfiletime (char *fname,time_t ftime)
207*aaf4ece6Schristos {
208*aaf4ece6Schristos #ifdef WIN32
209*aaf4ece6Schristos static int isWinNT = -1;
210*aaf4ece6Schristos SYSTEMTIME st;
211*aaf4ece6Schristos FILETIME locft, modft;
212*aaf4ece6Schristos struct tm *loctm;
213*aaf4ece6Schristos HANDLE hFile;
214*aaf4ece6Schristos int result;
215*aaf4ece6Schristos
216*aaf4ece6Schristos loctm = localtime(&ftime);
217*aaf4ece6Schristos if (loctm == NULL)
218*aaf4ece6Schristos return -1;
219*aaf4ece6Schristos
220*aaf4ece6Schristos st.wYear = (WORD)loctm->tm_year + 1900;
221*aaf4ece6Schristos st.wMonth = (WORD)loctm->tm_mon + 1;
222*aaf4ece6Schristos st.wDayOfWeek = (WORD)loctm->tm_wday;
223*aaf4ece6Schristos st.wDay = (WORD)loctm->tm_mday;
224*aaf4ece6Schristos st.wHour = (WORD)loctm->tm_hour;
225*aaf4ece6Schristos st.wMinute = (WORD)loctm->tm_min;
226*aaf4ece6Schristos st.wSecond = (WORD)loctm->tm_sec;
227*aaf4ece6Schristos st.wMilliseconds = 0;
228*aaf4ece6Schristos if (!SystemTimeToFileTime(&st, &locft) ||
229*aaf4ece6Schristos !LocalFileTimeToFileTime(&locft, &modft))
230*aaf4ece6Schristos return -1;
231*aaf4ece6Schristos
232*aaf4ece6Schristos if (isWinNT < 0)
233*aaf4ece6Schristos isWinNT = (GetVersion() < 0x80000000) ? 1 : 0;
234*aaf4ece6Schristos hFile = CreateFile(fname, GENERIC_WRITE, 0, NULL, OPEN_EXISTING,
235*aaf4ece6Schristos (isWinNT ? FILE_FLAG_BACKUP_SEMANTICS : 0),
236*aaf4ece6Schristos NULL);
237*aaf4ece6Schristos if (hFile == INVALID_HANDLE_VALUE)
238*aaf4ece6Schristos return -1;
239*aaf4ece6Schristos result = SetFileTime(hFile, NULL, NULL, &modft) ? 0 : -1;
240*aaf4ece6Schristos CloseHandle(hFile);
241*aaf4ece6Schristos return result;
242*aaf4ece6Schristos #else
243*aaf4ece6Schristos struct utimbuf settime;
244*aaf4ece6Schristos
245*aaf4ece6Schristos settime.actime = settime.modtime = ftime;
246*aaf4ece6Schristos return utime(fname,&settime);
247*aaf4ece6Schristos #endif
248*aaf4ece6Schristos }
249*aaf4ece6Schristos
250*aaf4ece6Schristos
251*aaf4ece6Schristos /* push file attributes */
252*aaf4ece6Schristos
push_attr(struct attr_item ** list,char * fname,int mode,time_t time)253*aaf4ece6Schristos void push_attr(struct attr_item **list,char *fname,int mode,time_t time)
254*aaf4ece6Schristos {
255*aaf4ece6Schristos struct attr_item *item;
256*aaf4ece6Schristos
257*aaf4ece6Schristos item = (struct attr_item *)malloc(sizeof(struct attr_item));
258*aaf4ece6Schristos if (item == NULL)
259*aaf4ece6Schristos error("Out of memory");
260*aaf4ece6Schristos item->fname = strdup(fname);
261*aaf4ece6Schristos item->mode = mode;
262*aaf4ece6Schristos item->time = time;
263*aaf4ece6Schristos item->next = *list;
264*aaf4ece6Schristos *list = item;
265*aaf4ece6Schristos }
266*aaf4ece6Schristos
267*aaf4ece6Schristos
268*aaf4ece6Schristos /* restore file attributes */
269*aaf4ece6Schristos
restore_attr(struct attr_item ** list)270*aaf4ece6Schristos void restore_attr(struct attr_item **list)
271*aaf4ece6Schristos {
272*aaf4ece6Schristos struct attr_item *item, *prev;
273*aaf4ece6Schristos
274*aaf4ece6Schristos for (item = *list; item != NULL; )
275*aaf4ece6Schristos {
276*aaf4ece6Schristos setfiletime(item->fname,item->time);
277*aaf4ece6Schristos chmod(item->fname,item->mode);
278*aaf4ece6Schristos prev = item;
279*aaf4ece6Schristos item = item->next;
280*aaf4ece6Schristos free(prev);
281*aaf4ece6Schristos }
282*aaf4ece6Schristos *list = NULL;
283*aaf4ece6Schristos }
284*aaf4ece6Schristos
285*aaf4ece6Schristos
286*aaf4ece6Schristos /* match regular expression */
287*aaf4ece6Schristos
288*aaf4ece6Schristos #define ISSPECIAL(c) (((c) == '*') || ((c) == '/'))
289*aaf4ece6Schristos
ExprMatch(char * string,char * expr)290*aaf4ece6Schristos int ExprMatch (char *string,char *expr)
291*aaf4ece6Schristos {
292*aaf4ece6Schristos while (1)
293*aaf4ece6Schristos {
294*aaf4ece6Schristos if (ISSPECIAL(*expr))
295*aaf4ece6Schristos {
296*aaf4ece6Schristos if (*expr == '/')
297*aaf4ece6Schristos {
298*aaf4ece6Schristos if (*string != '\\' && *string != '/')
299*aaf4ece6Schristos return 0;
300*aaf4ece6Schristos string ++; expr++;
301*aaf4ece6Schristos }
302*aaf4ece6Schristos else if (*expr == '*')
303*aaf4ece6Schristos {
304*aaf4ece6Schristos if (*expr ++ == 0)
305*aaf4ece6Schristos return 1;
306*aaf4ece6Schristos while (*++string != *expr)
307*aaf4ece6Schristos if (*string == 0)
308*aaf4ece6Schristos return 0;
309*aaf4ece6Schristos }
310*aaf4ece6Schristos }
311*aaf4ece6Schristos else
312*aaf4ece6Schristos {
313*aaf4ece6Schristos if (*string != *expr)
314*aaf4ece6Schristos return 0;
315*aaf4ece6Schristos if (*expr++ == 0)
316*aaf4ece6Schristos return 1;
317*aaf4ece6Schristos string++;
318*aaf4ece6Schristos }
319*aaf4ece6Schristos }
320*aaf4ece6Schristos }
321*aaf4ece6Schristos
322*aaf4ece6Schristos
323*aaf4ece6Schristos /* recursive mkdir */
324*aaf4ece6Schristos /* abort on ENOENT; ignore other errors like "directory already exists" */
325*aaf4ece6Schristos /* return 1 if OK */
326*aaf4ece6Schristos /* 0 on error */
327*aaf4ece6Schristos
makedir(char * newdir)328*aaf4ece6Schristos int makedir (char *newdir)
329*aaf4ece6Schristos {
330*aaf4ece6Schristos char *buffer = strdup(newdir);
331*aaf4ece6Schristos char *p;
332*aaf4ece6Schristos int len = strlen(buffer);
333*aaf4ece6Schristos
334*aaf4ece6Schristos if (len <= 0) {
335*aaf4ece6Schristos free(buffer);
336*aaf4ece6Schristos return 0;
337*aaf4ece6Schristos }
338*aaf4ece6Schristos if (buffer[len-1] == '/') {
339*aaf4ece6Schristos buffer[len-1] = '\0';
340*aaf4ece6Schristos }
341*aaf4ece6Schristos if (mkdir(buffer, 0755) == 0)
342*aaf4ece6Schristos {
343*aaf4ece6Schristos free(buffer);
344*aaf4ece6Schristos return 1;
345*aaf4ece6Schristos }
346*aaf4ece6Schristos
347*aaf4ece6Schristos p = buffer+1;
348*aaf4ece6Schristos while (1)
349*aaf4ece6Schristos {
350*aaf4ece6Schristos char hold;
351*aaf4ece6Schristos
352*aaf4ece6Schristos while(*p && *p != '\\' && *p != '/')
353*aaf4ece6Schristos p++;
354*aaf4ece6Schristos hold = *p;
355*aaf4ece6Schristos *p = 0;
356*aaf4ece6Schristos if ((mkdir(buffer, 0755) == -1) && (errno == ENOENT))
357*aaf4ece6Schristos {
358*aaf4ece6Schristos fprintf(stderr,"%s: Couldn't create directory %s\n",prog,buffer);
359*aaf4ece6Schristos free(buffer);
360*aaf4ece6Schristos return 0;
361*aaf4ece6Schristos }
362*aaf4ece6Schristos if (hold == 0)
363*aaf4ece6Schristos break;
364*aaf4ece6Schristos *p++ = hold;
365*aaf4ece6Schristos }
366*aaf4ece6Schristos free(buffer);
367*aaf4ece6Schristos return 1;
368*aaf4ece6Schristos }
369*aaf4ece6Schristos
370*aaf4ece6Schristos
matchname(int arg,int argc,char ** argv,char * fname)371*aaf4ece6Schristos int matchname (int arg,int argc,char **argv,char *fname)
372*aaf4ece6Schristos {
373*aaf4ece6Schristos if (arg == argc) /* no arguments given (untgz tgzarchive) */
374*aaf4ece6Schristos return 1;
375*aaf4ece6Schristos
376*aaf4ece6Schristos while (arg < argc)
377*aaf4ece6Schristos if (ExprMatch(fname,argv[arg++]))
378*aaf4ece6Schristos return 1;
379*aaf4ece6Schristos
380*aaf4ece6Schristos return 0; /* ignore this for the moment being */
381*aaf4ece6Schristos }
382*aaf4ece6Schristos
383*aaf4ece6Schristos
384*aaf4ece6Schristos /* tar file list or extract */
385*aaf4ece6Schristos
tar(gzFile in,int action,int arg,int argc,char ** argv)386*aaf4ece6Schristos int tar (gzFile in,int action,int arg,int argc,char **argv)
387*aaf4ece6Schristos {
388*aaf4ece6Schristos union tar_buffer buffer;
389*aaf4ece6Schristos int len;
390*aaf4ece6Schristos int err;
391*aaf4ece6Schristos int getheader = 1;
392*aaf4ece6Schristos int remaining = 0;
393*aaf4ece6Schristos FILE *outfile = NULL;
394*aaf4ece6Schristos char fname[BLOCKSIZE];
395*aaf4ece6Schristos int tarmode;
396*aaf4ece6Schristos time_t tartime;
397*aaf4ece6Schristos struct attr_item *attributes = NULL;
398*aaf4ece6Schristos
399*aaf4ece6Schristos if (action == TGZ_LIST)
400*aaf4ece6Schristos printf(" date time size file\n"
401*aaf4ece6Schristos " ---------- -------- --------- -------------------------------------\n");
402*aaf4ece6Schristos while (1)
403*aaf4ece6Schristos {
404*aaf4ece6Schristos len = gzread(in, &buffer, BLOCKSIZE);
405*aaf4ece6Schristos if (len < 0)
406*aaf4ece6Schristos error(gzerror(in, &err));
407*aaf4ece6Schristos /*
408*aaf4ece6Schristos * Always expect complete blocks to process
409*aaf4ece6Schristos * the tar information.
410*aaf4ece6Schristos */
411*aaf4ece6Schristos if (len != BLOCKSIZE)
412*aaf4ece6Schristos {
413*aaf4ece6Schristos action = TGZ_INVALID; /* force error exit */
414*aaf4ece6Schristos remaining = 0; /* force I/O cleanup */
415*aaf4ece6Schristos }
416*aaf4ece6Schristos
417*aaf4ece6Schristos /*
418*aaf4ece6Schristos * If we have to get a tar header
419*aaf4ece6Schristos */
420*aaf4ece6Schristos if (getheader >= 1)
421*aaf4ece6Schristos {
422*aaf4ece6Schristos /*
423*aaf4ece6Schristos * if we met the end of the tar
424*aaf4ece6Schristos * or the end-of-tar block,
425*aaf4ece6Schristos * we are done
426*aaf4ece6Schristos */
427*aaf4ece6Schristos if (len == 0 || buffer.header.name[0] == 0)
428*aaf4ece6Schristos break;
429*aaf4ece6Schristos
430*aaf4ece6Schristos tarmode = getoct(buffer.header.mode,8);
431*aaf4ece6Schristos tartime = (time_t)getoct(buffer.header.mtime,12);
432*aaf4ece6Schristos if (tarmode == -1 || tartime == (time_t)-1)
433*aaf4ece6Schristos {
434*aaf4ece6Schristos buffer.header.name[0] = 0;
435*aaf4ece6Schristos action = TGZ_INVALID;
436*aaf4ece6Schristos }
437*aaf4ece6Schristos
438*aaf4ece6Schristos if (getheader == 1)
439*aaf4ece6Schristos {
440*aaf4ece6Schristos strncpy(fname,buffer.header.name,SHORTNAMESIZE);
441*aaf4ece6Schristos if (fname[SHORTNAMESIZE-1] != 0)
442*aaf4ece6Schristos fname[SHORTNAMESIZE] = 0;
443*aaf4ece6Schristos }
444*aaf4ece6Schristos else
445*aaf4ece6Schristos {
446*aaf4ece6Schristos /*
447*aaf4ece6Schristos * The file name is longer than SHORTNAMESIZE
448*aaf4ece6Schristos */
449*aaf4ece6Schristos if (strncmp(fname,buffer.header.name,SHORTNAMESIZE-1) != 0)
450*aaf4ece6Schristos error("bad long name");
451*aaf4ece6Schristos getheader = 1;
452*aaf4ece6Schristos }
453*aaf4ece6Schristos
454*aaf4ece6Schristos /*
455*aaf4ece6Schristos * Act according to the type flag
456*aaf4ece6Schristos */
457*aaf4ece6Schristos switch (buffer.header.typeflag)
458*aaf4ece6Schristos {
459*aaf4ece6Schristos case DIRTYPE:
460*aaf4ece6Schristos if (action == TGZ_LIST)
461*aaf4ece6Schristos printf(" %s <dir> %s\n",strtime(&tartime),fname);
462*aaf4ece6Schristos if (action == TGZ_EXTRACT)
463*aaf4ece6Schristos {
464*aaf4ece6Schristos makedir(fname);
465*aaf4ece6Schristos push_attr(&attributes,fname,tarmode,tartime);
466*aaf4ece6Schristos }
467*aaf4ece6Schristos break;
468*aaf4ece6Schristos case REGTYPE:
469*aaf4ece6Schristos case AREGTYPE:
470*aaf4ece6Schristos remaining = getoct(buffer.header.size,12);
471*aaf4ece6Schristos if (remaining == -1)
472*aaf4ece6Schristos {
473*aaf4ece6Schristos action = TGZ_INVALID;
474*aaf4ece6Schristos break;
475*aaf4ece6Schristos }
476*aaf4ece6Schristos if (action == TGZ_LIST)
477*aaf4ece6Schristos printf(" %s %9d %s\n",strtime(&tartime),remaining,fname);
478*aaf4ece6Schristos else if (action == TGZ_EXTRACT)
479*aaf4ece6Schristos {
480*aaf4ece6Schristos if (matchname(arg,argc,argv,fname))
481*aaf4ece6Schristos {
482*aaf4ece6Schristos outfile = fopen(fname,"wb");
483*aaf4ece6Schristos if (outfile == NULL) {
484*aaf4ece6Schristos /* try creating directory */
485*aaf4ece6Schristos char *p = strrchr(fname, '/');
486*aaf4ece6Schristos if (p != NULL) {
487*aaf4ece6Schristos *p = '\0';
488*aaf4ece6Schristos makedir(fname);
489*aaf4ece6Schristos *p = '/';
490*aaf4ece6Schristos outfile = fopen(fname,"wb");
491*aaf4ece6Schristos }
492*aaf4ece6Schristos }
493*aaf4ece6Schristos if (outfile != NULL)
494*aaf4ece6Schristos printf("Extracting %s\n",fname);
495*aaf4ece6Schristos else
496*aaf4ece6Schristos fprintf(stderr, "%s: Couldn't create %s",prog,fname);
497*aaf4ece6Schristos }
498*aaf4ece6Schristos else
499*aaf4ece6Schristos outfile = NULL;
500*aaf4ece6Schristos }
501*aaf4ece6Schristos getheader = 0;
502*aaf4ece6Schristos break;
503*aaf4ece6Schristos case GNUTYPE_LONGLINK:
504*aaf4ece6Schristos case GNUTYPE_LONGNAME:
505*aaf4ece6Schristos remaining = getoct(buffer.header.size,12);
506*aaf4ece6Schristos if (remaining < 0 || remaining >= BLOCKSIZE)
507*aaf4ece6Schristos {
508*aaf4ece6Schristos action = TGZ_INVALID;
509*aaf4ece6Schristos break;
510*aaf4ece6Schristos }
511*aaf4ece6Schristos len = gzread(in, fname, BLOCKSIZE);
512*aaf4ece6Schristos if (len < 0)
513*aaf4ece6Schristos error(gzerror(in, &err));
514*aaf4ece6Schristos if (fname[BLOCKSIZE-1] != 0 || (int)strlen(fname) > remaining)
515*aaf4ece6Schristos {
516*aaf4ece6Schristos action = TGZ_INVALID;
517*aaf4ece6Schristos break;
518*aaf4ece6Schristos }
519*aaf4ece6Schristos getheader = 2;
520*aaf4ece6Schristos break;
521*aaf4ece6Schristos default:
522*aaf4ece6Schristos if (action == TGZ_LIST)
523*aaf4ece6Schristos printf(" %s <---> %s\n",strtime(&tartime),fname);
524*aaf4ece6Schristos break;
525*aaf4ece6Schristos }
526*aaf4ece6Schristos }
527*aaf4ece6Schristos else
528*aaf4ece6Schristos {
529*aaf4ece6Schristos unsigned int bytes = (remaining > BLOCKSIZE) ? BLOCKSIZE : remaining;
530*aaf4ece6Schristos
531*aaf4ece6Schristos if (outfile != NULL)
532*aaf4ece6Schristos {
533*aaf4ece6Schristos if (fwrite(&buffer,sizeof(char),bytes,outfile) != bytes)
534*aaf4ece6Schristos {
535*aaf4ece6Schristos fprintf(stderr,
536*aaf4ece6Schristos "%s: Error writing %s -- skipping\n",prog,fname);
537*aaf4ece6Schristos fclose(outfile);
538*aaf4ece6Schristos outfile = NULL;
539*aaf4ece6Schristos remove(fname);
540*aaf4ece6Schristos }
541*aaf4ece6Schristos }
542*aaf4ece6Schristos remaining -= bytes;
543*aaf4ece6Schristos }
544*aaf4ece6Schristos
545*aaf4ece6Schristos if (remaining == 0)
546*aaf4ece6Schristos {
547*aaf4ece6Schristos getheader = 1;
548*aaf4ece6Schristos if (outfile != NULL)
549*aaf4ece6Schristos {
550*aaf4ece6Schristos fclose(outfile);
551*aaf4ece6Schristos outfile = NULL;
552*aaf4ece6Schristos if (action != TGZ_INVALID)
553*aaf4ece6Schristos push_attr(&attributes,fname,tarmode,tartime);
554*aaf4ece6Schristos }
555*aaf4ece6Schristos }
556*aaf4ece6Schristos
557*aaf4ece6Schristos /*
558*aaf4ece6Schristos * Abandon if errors are found
559*aaf4ece6Schristos */
560*aaf4ece6Schristos if (action == TGZ_INVALID)
561*aaf4ece6Schristos {
562*aaf4ece6Schristos error("broken archive");
563*aaf4ece6Schristos break;
564*aaf4ece6Schristos }
565*aaf4ece6Schristos }
566*aaf4ece6Schristos
567*aaf4ece6Schristos /*
568*aaf4ece6Schristos * Restore file modes and time stamps
569*aaf4ece6Schristos */
570*aaf4ece6Schristos restore_attr(&attributes);
571*aaf4ece6Schristos
572*aaf4ece6Schristos if (gzclose(in) != Z_OK)
573*aaf4ece6Schristos error("failed gzclose");
574*aaf4ece6Schristos
575*aaf4ece6Schristos return 0;
576*aaf4ece6Schristos }
577*aaf4ece6Schristos
578*aaf4ece6Schristos
579*aaf4ece6Schristos /* ============================================================ */
580*aaf4ece6Schristos
help(int exitval)581*aaf4ece6Schristos void help(int exitval)
582*aaf4ece6Schristos {
583*aaf4ece6Schristos printf("untgz version 0.2.1\n"
584*aaf4ece6Schristos " using zlib version %s\n\n",
585*aaf4ece6Schristos zlibVersion());
586*aaf4ece6Schristos printf("Usage: untgz file.tgz extract all files\n"
587*aaf4ece6Schristos " untgz file.tgz fname ... extract selected files\n"
588*aaf4ece6Schristos " untgz -l file.tgz list archive contents\n"
589*aaf4ece6Schristos " untgz -h display this help\n");
590*aaf4ece6Schristos exit(exitval);
591*aaf4ece6Schristos }
592*aaf4ece6Schristos
error(const char * msg)593*aaf4ece6Schristos void error(const char *msg)
594*aaf4ece6Schristos {
595*aaf4ece6Schristos fprintf(stderr, "%s: %s\n", prog, msg);
596*aaf4ece6Schristos exit(1);
597*aaf4ece6Schristos }
598*aaf4ece6Schristos
599*aaf4ece6Schristos
600*aaf4ece6Schristos /* ============================================================ */
601*aaf4ece6Schristos
602*aaf4ece6Schristos #if defined(WIN32) && defined(__GNUC__)
603*aaf4ece6Schristos int _CRT_glob = 0; /* disable argument globbing in MinGW */
604*aaf4ece6Schristos #endif
605*aaf4ece6Schristos
main(int argc,char ** argv)606*aaf4ece6Schristos int main(int argc,char **argv)
607*aaf4ece6Schristos {
608*aaf4ece6Schristos int action = TGZ_EXTRACT;
609*aaf4ece6Schristos int arg = 1;
610*aaf4ece6Schristos char *TGZfile;
611*aaf4ece6Schristos gzFile *f;
612*aaf4ece6Schristos
613*aaf4ece6Schristos prog = strrchr(argv[0],'\\');
614*aaf4ece6Schristos if (prog == NULL)
615*aaf4ece6Schristos {
616*aaf4ece6Schristos prog = strrchr(argv[0],'/');
617*aaf4ece6Schristos if (prog == NULL)
618*aaf4ece6Schristos {
619*aaf4ece6Schristos prog = strrchr(argv[0],':');
620*aaf4ece6Schristos if (prog == NULL)
621*aaf4ece6Schristos prog = argv[0];
622*aaf4ece6Schristos else
623*aaf4ece6Schristos prog++;
624*aaf4ece6Schristos }
625*aaf4ece6Schristos else
626*aaf4ece6Schristos prog++;
627*aaf4ece6Schristos }
628*aaf4ece6Schristos else
629*aaf4ece6Schristos prog++;
630*aaf4ece6Schristos
631*aaf4ece6Schristos if (argc == 1)
632*aaf4ece6Schristos help(0);
633*aaf4ece6Schristos
634*aaf4ece6Schristos if (strcmp(argv[arg],"-l") == 0)
635*aaf4ece6Schristos {
636*aaf4ece6Schristos action = TGZ_LIST;
637*aaf4ece6Schristos if (argc == ++arg)
638*aaf4ece6Schristos help(0);
639*aaf4ece6Schristos }
640*aaf4ece6Schristos else if (strcmp(argv[arg],"-h") == 0)
641*aaf4ece6Schristos {
642*aaf4ece6Schristos help(0);
643*aaf4ece6Schristos }
644*aaf4ece6Schristos
645*aaf4ece6Schristos if ((TGZfile = TGZfname(argv[arg])) == NULL)
646*aaf4ece6Schristos TGZnotfound(argv[arg]);
647*aaf4ece6Schristos
648*aaf4ece6Schristos ++arg;
649*aaf4ece6Schristos if ((action == TGZ_LIST) && (arg != argc))
650*aaf4ece6Schristos help(1);
651*aaf4ece6Schristos
652*aaf4ece6Schristos /*
653*aaf4ece6Schristos * Process the TGZ file
654*aaf4ece6Schristos */
655*aaf4ece6Schristos switch(action)
656*aaf4ece6Schristos {
657*aaf4ece6Schristos case TGZ_LIST:
658*aaf4ece6Schristos case TGZ_EXTRACT:
659*aaf4ece6Schristos f = gzopen(TGZfile,"rb");
660*aaf4ece6Schristos if (f == NULL)
661*aaf4ece6Schristos {
662*aaf4ece6Schristos fprintf(stderr,"%s: Couldn't gzopen %s\n",prog,TGZfile);
663*aaf4ece6Schristos return 1;
664*aaf4ece6Schristos }
665*aaf4ece6Schristos exit(tar(f, action, arg, argc, argv));
666*aaf4ece6Schristos break;
667*aaf4ece6Schristos
668*aaf4ece6Schristos default:
669*aaf4ece6Schristos error("Unknown option");
670*aaf4ece6Schristos exit(1);
671*aaf4ece6Schristos }
672*aaf4ece6Schristos
673*aaf4ece6Schristos return 0;
674*aaf4ece6Schristos }
675