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