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