| 1 /* untar.c */ |
|
| 2 |
|
| 3 /*#define VERSION "1.4"*/ |
|
| 4 |
|
| 5 /* DESCRIPTION: |
|
| 6 * Untar extracts files from an uncompressed tar archive, or one which |
|
| 7 * has been compressed with gzip. Usually such archives will have file |
|
| 8 * names that end with ".tar" or ".tgz" respectively, although untar |
|
| 9 * doesn't depend on any naming conventions. For a summary of the |
|
| 10 * command-line options, run untar with no arguments. |
|
| 11 * |
|
| 12 * HOW TO COMPILE: |
|
| 13 * Untar doesn't require any special libraries or compile-time flags. |
|
| 14 * A simple "cc untar.c -o untar" (or the local equivalent) is |
|
| 15 * sufficient. Even "make untar" works, without needing a Makefile. |
|
| 16 * For Microsoft Visual C++, the command is "cl /D_WEAK_POSIX untar.c" |
|
| 17 * (for 32 bit compilers) or "cl /F 1400 untar.c" (for 16-bit). |
|
| 18 * |
|
| 19 * IF YOU SEE COMPILER WARNINGS, THAT'S NORMAL; you can ignore them. |
|
| 20 * Most of the warnings could be eliminated by adding #include <string.h> |
|
| 21 * but that isn't portable -- some systems require <strings.h> and |
|
| 22 * <malloc.h>, for example. Because <string.h> isn't quite portable, |
|
| 23 * and isn't really necessary in the context of this program, it isn't |
|
| 24 * included. |
|
| 25 * |
|
| 26 * PORTABILITY: |
|
| 27 * Untar only requires the <stdio.h> header. It uses old-style function |
|
| 28 * definitions. It opens all files in binary mode. Taken together, |
|
| 29 * this means that untar should compile & run on just about anything. |
|
| 30 * |
|
| 31 * If your system supports the POSIX chmod(2), utime(2), link(2), and |
|
| 32 * symlink(2) calls, then you may wish to compile with -D_POSIX_SOURCE, |
|
| 33 * which will enable untar to use those system calls to restore the |
|
| 34 * timestamp and permissions of the extracted files, and restore links. |
|
| 35 * (For Linux, _POSIX_SOURCE is always defined.) |
|
| 36 * |
|
| 37 * For systems which support some POSIX features but not enough to support |
|
| 38 * -D_POSIX_SOURCE, you might be able to use -D_WEAK_POSIX. This allows |
|
| 39 * untar to restore time stamps and file permissions, but not links. |
|
| 40 * This should work for Microsoft systems, and hopefully others as well. |
|
| 41 * |
|
| 42 * AUTHOR & COPYRIGHT INFO: |
|
| 43 * Written by Steve Kirkendall, kirkenda@cs.pdx.edu |
|
| 44 * Placed in public domain, 6 October 1995 |
|
| 45 * |
|
| 46 * Portions derived from inflate.c -- Not copyrighted 1992 by Mark Adler |
|
| 47 * version c10p1, 10 January 1993 |
|
| 48 * |
|
| 49 * Altered by Herman Bloggs <hermanator12002@yahoo.com> |
|
| 50 * April 4, 2003 |
|
| 51 * Changes: Stripped out gz compression code, added better interface for |
|
| 52 * untar. |
|
| 53 */ |
|
| 54 #include <windows.h> |
|
| 55 #include <stdio.h> |
|
| 56 #include <io.h> |
|
| 57 #include <string.h> |
|
| 58 #include <stdlib.h> |
|
| 59 #ifndef SEEK_SET |
|
| 60 # define SEEK_SET 0 |
|
| 61 #endif |
|
| 62 |
|
| 63 #ifdef _WEAK_POSIX |
|
| 64 # ifndef _POSIX_SOURCE |
|
| 65 # define _POSIX_SOURCE |
|
| 66 # endif |
|
| 67 #endif |
|
| 68 |
|
| 69 #ifdef _POSIX_SOURCE |
|
| 70 # include <sys/types.h> |
|
| 71 # include <sys/stat.h> |
|
| 72 # include <sys/utime.h> |
|
| 73 # ifdef _WEAK_POSIX |
|
| 74 # define mode_t int |
|
| 75 # else |
|
| 76 # include <unistd.h> |
|
| 77 # endif |
|
| 78 #endif |
|
| 79 #include "debug.h" |
|
| 80 #include "untar.h" |
|
| 81 #include <glib.h> |
|
| 82 |
|
| 83 #if GLIB_CHECK_VERSION(2,6,0) |
|
| 84 # include <glib/gstdio.h> |
|
| 85 #else |
|
| 86 #define mkdir(a,b) _mkdir((a)) |
|
| 87 #define g_mkdir mkdir |
|
| 88 #define g_fopen fopen |
|
| 89 #define g_unlink unlink |
|
| 90 #endif |
|
| 91 |
|
| 92 #define untar_error( error, args... ) gaim_debug(GAIM_DEBUG_ERROR, "untar", error, ## args ) |
|
| 93 #define untar_warning( warning, args... ) gaim_debug(GAIM_DEBUG_WARNING, "untar", warning, ## args ) |
|
| 94 #define untar_verbose( args... ) gaim_debug(GAIM_DEBUG_INFO, "untar", ## args ) |
|
| 95 |
|
| 96 #define WSIZE 32768 /* size of decompression buffer */ |
|
| 97 #define TSIZE 512 /* size of a "tape" block */ |
|
| 98 #define CR 13 /* carriage-return character */ |
|
| 99 #define LF 10 /* line-feed character */ |
|
| 100 |
|
| 101 typedef unsigned char Uchar_t; |
|
| 102 typedef unsigned short Ushort_t; |
|
| 103 typedef unsigned long Ulong_t; |
|
| 104 |
|
| 105 typedef struct |
|
| 106 { |
|
| 107 char filename[100]; /* 0 name of next file */ |
|
| 108 char mode[8]; /* 100 Permissions and type (octal digits) */ |
|
| 109 char owner[8]; /* 108 Owner ID (ignored) */ |
|
| 110 char group[8]; /* 116 Group ID (ignored) */ |
|
| 111 char size[12]; /* 124 Bytes in file (octal digits) */ |
|
| 112 char mtime[12]; /* 136 Modification time stamp (octal digits)*/ |
|
| 113 char checksum[8]; /* 148 Header checksum (ignored) */ |
|
| 114 char type; /* 156 File type (see below) */ |
|
| 115 char linkto[100]; /* 157 Linked-to name */ |
|
| 116 char brand[8]; /* 257 Identifies tar version (ignored) */ |
|
| 117 char ownername[32]; /* 265 Name of owner (ignored) */ |
|
| 118 char groupname[32]; /* 297 Name of group (ignored) */ |
|
| 119 char devmajor[8]; /* 329 Device major number (ignored) */ |
|
| 120 char defminor[8]; /* 337 Device minor number (ignored) */ |
|
| 121 char prefix[155]; /* 345 Prefix of name (optional) */ |
|
| 122 char RESERVED[12]; /* 500 Pad header size to 512 bytes */ |
|
| 123 } tar_t; |
|
| 124 #define ISREGULAR(hdr) ((hdr).type < '1' || (hdr).type > '6') |
|
| 125 |
|
| 126 Uchar_t slide[WSIZE]; |
|
| 127 |
|
| 128 static const char *inname = NULL; /* name of input archive */ |
|
| 129 static FILE *infp = NULL; /* input byte stream */ |
|
| 130 static FILE *outfp = NULL; /* output stream, for file currently being extracted */ |
|
| 131 static Ulong_t outsize = 0; /* number of bytes remainin in file currently being extracted */ |
|
| 132 static char **only = NULL; /* array of filenames to extract/list */ |
|
| 133 static int nonlys = 0; /* number of filenames in "only" array; 0=extract all */ |
|
| 134 static int didabs = 0; /* were any filenames affected by the absence of -p? */ |
|
| 135 |
|
| 136 static untar_opt untarops = 0; /* Untar options */ |
|
| 137 |
|
| 138 /* Options checked during untar process */ |
|
| 139 #define LISTING (untarops & UNTAR_LISTING) /* 1 if listing, 0 if extracting */ |
|
| 140 #define QUIET (untarops & UNTAR_QUIET) /* 1 to write nothing to stdout, 0 for normal chatter */ |
|
| 141 #define VERBOSE (untarops & UNTAR_VERBOSE) /* 1 to write extra information to stdout */ |
|
| 142 #define FORCE (untarops & UNTAR_FORCE) /* 1 to overwrite existing files, 0 to skip them */ |
|
| 143 #define ABSPATH (untarops & UNTAR_ABSPATH) /* 1 to allow leading '/', 0 to strip leading '/' */ |
|
| 144 #define CONVERT (untarops & UNTAR_CONVERT) /* 1 to convert newlines, 0 to leave unchanged */ |
|
| 145 |
|
| 146 /*----------------------------------------------------------------------------*/ |
|
| 147 |
|
| 148 /* create a file for writing. If necessary, create the directories leading up |
|
| 149 * to that file as well. |
|
| 150 */ |
|
| 151 static FILE *createpath(name) |
|
| 152 char *name; /* pathname of file to create */ |
|
| 153 { |
|
| 154 FILE *fp; |
|
| 155 int i; |
|
| 156 |
|
| 157 /* if we aren't allowed to overwrite and this file exists, return NULL */ |
|
| 158 if (!FORCE && access(name, 0) == 0) |
|
| 159 { |
|
| 160 untar_warning("%s: exists, will not overwrite without \"FORCE option\"\n", name); |
|
| 161 return NULL; |
|
| 162 } |
|
| 163 |
|
| 164 /* first try creating it the easy way */ |
|
| 165 fp = g_fopen(name, CONVERT ? "w" : "wb"); |
|
| 166 if (fp) |
|
| 167 return fp; |
|
| 168 |
|
| 169 /* Else try making all of its directories, and then try creating |
|
| 170 * the file again. |
|
| 171 */ |
|
| 172 for (i = 0; name[i]; i++) |
|
| 173 { |
|
| 174 /* If this is a slash, then temporarily replace the '/' |
|
| 175 * with a '\0' and do a mkdir() on the resulting string. |
|
| 176 * Ignore errors for now. |
|
| 177 */ |
|
| 178 if (name[i] == '/') |
|
| 179 { |
|
| 180 name[i] = '\0'; |
|
| 181 (void)g_mkdir(name, 0777); |
|
| 182 name[i] = '/'; |
|
| 183 } |
|
| 184 } |
|
| 185 fp = g_fopen(name, CONVERT ? "w" : "wb"); |
|
| 186 if (!fp) |
|
| 187 untar_error("Error opening: %s\n", name); |
|
| 188 return fp; |
|
| 189 } |
|
| 190 |
|
| 191 /* Create a link, or copy a file. If the file is copied (not linked) then |
|
| 192 * give a warning. |
|
| 193 */ |
|
| 194 static void linkorcopy(src, dst, sym) |
|
| 195 char *src; /* name of existing source file */ |
|
| 196 char *dst; /* name of new destination file */ |
|
| 197 int sym; /* use symlink instead of link */ |
|
| 198 { |
|
| 199 FILE *fpsrc; |
|
| 200 FILE *fpdst; |
|
| 201 int c; |
|
| 202 |
|
| 203 /* Open the source file. We do this first to make sure it exists */ |
|
| 204 fpsrc = g_fopen(src, "rb"); |
|
| 205 if (!fpsrc) |
|
| 206 { |
|
| 207 untar_error("Error opening: %s\n", src); |
|
| 208 return; |
|
| 209 } |
|
| 210 |
|
| 211 /* Create the destination file. On POSIX systems, this is just to |
|
| 212 * make sure the directory path exists. |
|
| 213 */ |
|
| 214 fpdst = createpath(dst); |
|
| 215 if (!fpdst) |
|
| 216 /* error message already given */ |
|
| 217 return; |
|
| 218 |
|
| 219 #ifdef _POSIX_SOURCE |
|
| 220 # ifndef _WEAK_POSIX |
|
| 221 /* first try to link it over, instead of copying */ |
|
| 222 fclose(fpdst); |
|
| 223 g_unlink(dst); |
|
| 224 if (sym) |
|
| 225 { |
|
| 226 if (symlink(src, dst)) |
|
| 227 { |
|
| 228 perror(dst); |
|
| 229 } |
|
| 230 fclose(fpsrc); |
|
| 231 return; |
|
| 232 } |
|
| 233 if (!link(src, dst)) |
|
| 234 { |
|
| 235 /* This story had a happy ending */ |
|
| 236 fclose(fpsrc); |
|
| 237 return; |
|
| 238 } |
|
| 239 |
|
| 240 /* Dang. Reopen the destination again */ |
|
| 241 fpdst = g_fopen(dst, "wb"); |
|
| 242 /* This *can't* fail */ |
|
| 243 |
|
| 244 # endif /* _WEAK_POSIX */ |
|
| 245 #endif /* _POSIX_SOURCE */ |
|
| 246 |
|
| 247 /* Copy characters */ |
|
| 248 while ((c = getc(fpsrc)) != EOF) |
|
| 249 putc(c, fpdst); |
|
| 250 |
|
| 251 /* Close the files */ |
|
| 252 fclose(fpsrc); |
|
| 253 fclose(fpdst); |
|
| 254 |
|
| 255 /* Give a warning */ |
|
| 256 untar_warning("%s: copy instead of link\n", dst); |
|
| 257 } |
|
| 258 |
|
| 259 /* This calls fwrite(), possibly after converting CR-LF to LF */ |
|
| 260 static void cvtwrite(blk, size, fp) |
|
| 261 Uchar_t *blk; /* the block to be written */ |
|
| 262 Ulong_t size; /* number of characters to be written */ |
|
| 263 FILE *fp; /* file to write to */ |
|
| 264 { |
|
| 265 int i, j; |
|
| 266 static Uchar_t mod[TSIZE]; |
|
| 267 |
|
| 268 if (CONVERT) |
|
| 269 { |
|
| 270 for (i = j = 0; i < size; i++) |
|
| 271 { |
|
| 272 /* convert LF to local newline convention */ |
|
| 273 if (blk[i] == LF) |
|
| 274 mod[j++] = '\n'; |
|
| 275 /* If CR-LF pair, then delete the CR */ |
|
| 276 else if (blk[i] == CR && (i+1 >= size || blk[i+1] == LF)) |
|
| 277 ; |
|
| 278 /* other characters copied literally */ |
|
| 279 else |
|
| 280 mod[j++] = blk[i]; |
|
| 281 } |
|
| 282 size = j; |
|
| 283 blk = mod; |
|
| 284 } |
|
| 285 |
|
| 286 fwrite(blk, (size_t)size, sizeof(Uchar_t), fp); |
|
| 287 } |
|
| 288 |
|
| 289 |
|
| 290 /* Compute the checksum of a tar header block, and return it as a long int. |
|
| 291 * The checksum can be computed using either POSIX rules (unsigned bytes) |
|
| 292 * or Sun rules (signed bytes). |
|
| 293 */ |
|
| 294 static long checksum(tblk, sunny) |
|
| 295 tar_t *tblk; /* buffer containing the tar header block */ |
|
| 296 int sunny; /* Boolean: Sun-style checksums? (else POSIX) */ |
|
| 297 { |
|
| 298 long sum; |
|
| 299 char *scan; |
|
| 300 |
|
| 301 /* compute the sum of the first 148 bytes -- everything up to but not |
|
| 302 * including the checksum field itself. |
|
| 303 */ |
|
| 304 sum = 0L; |
|
| 305 for (scan = (char *)tblk; scan < tblk->checksum; scan++) |
|
| 306 { |
|
| 307 sum += (*scan) & 0xff; |
|
| 308 if (sunny && (*scan & 0x80) != 0) |
|
| 309 sum -= 256; |
|
| 310 } |
|
| 311 |
|
| 312 /* for the 8 bytes of the checksum field, add blanks to the sum */ |
|
| 313 sum += ' ' * sizeof tblk->checksum; |
|
| 314 scan += sizeof tblk->checksum; |
|
| 315 |
|
| 316 /* finish counting the sum of the rest of the block */ |
|
| 317 for (; scan < (char *)tblk + sizeof *tblk; scan++) |
|
| 318 { |
|
| 319 sum += (*scan) & 0xff; |
|
| 320 if (sunny && (*scan & 0x80) != 0) |
|
| 321 sum -= 256; |
|
| 322 } |
|
| 323 |
|
| 324 return sum; |
|
| 325 } |
|
| 326 |
|
| 327 |
|
| 328 |
|
| 329 /* list files in an archive, and optionally extract them as well */ |
|
| 330 static int untar_block(Uchar_t *blk) { |
|
| 331 static char nbuf[256];/* storage space for prefix+name, combined */ |
|
| 332 static char *name,*n2;/* prefix and name, combined */ |
|
| 333 static int first = 1;/* Boolean: first block of archive? */ |
|
| 334 long sum; /* checksum for this block */ |
|
| 335 int i; |
|
| 336 tar_t tblk[1]; |
|
| 337 |
|
| 338 #ifdef _POSIX_SOURCE |
|
| 339 static mode_t mode; /* file permissions */ |
|
| 340 static struct utimbuf timestamp; /* file timestamp */ |
|
| 341 #endif |
|
| 342 |
|
| 343 /* make a local copy of the block, and treat it as a tar header */ |
|
| 344 tblk[0] = *(tar_t *)blk; |
|
| 345 |
|
| 346 /* process each type of tape block differently */ |
|
| 347 if (outsize > TSIZE) |
|
| 348 { |
|
| 349 /* data block, but not the last one */ |
|
| 350 if (outfp) |
|
| 351 cvtwrite(blk, (Ulong_t)TSIZE, outfp); |
|
| 352 outsize -= TSIZE; |
|
| 353 } |
|
| 354 else if (outsize > 0) |
|
| 355 { |
|
| 356 /* last data block of current file */ |
|
| 357 if (outfp) |
|
| 358 { |
|
| 359 cvtwrite(blk, outsize, outfp); |
|
| 360 fclose(outfp); |
|
| 361 outfp = NULL; |
|
| 362 #ifdef _POSIX_SOURCE |
|
| 363 utime(nbuf, ×tamp); |
|
| 364 chmod(nbuf, mode); |
|
| 365 #endif |
|
| 366 } |
|
| 367 outsize = 0; |
|
| 368 } |
|
| 369 else if ((tblk)->filename[0] == '\0') |
|
| 370 { |
|
| 371 /* end-of-archive marker */ |
|
| 372 if (didabs) |
|
| 373 untar_warning("Removed leading slashes because \"ABSPATH option\" wasn't given.\n"); |
|
| 374 return 1; |
|
| 375 } |
|
| 376 else |
|
| 377 { |
|
| 378 /* file header */ |
|
| 379 |
|
| 380 /* half-assed verification -- does it look like header? */ |
|
| 381 if ((tblk)->filename[99] != '\0' |
|
| 382 || ((tblk)->size[0] < '0' |
|
| 383 && (tblk)->size[0] != ' ') |
|
| 384 || (tblk)->size[0] > '9') |
|
| 385 { |
|
| 386 if (first) |
|
| 387 { |
|
| 388 untar_error("%s: not a valid tar file\n", inname); |
|
| 389 return 0; |
|
| 390 } |
|
| 391 else |
|
| 392 { |
|
| 393 untar_error("Garbage detected; preceding file may be damaged\n"); |
|
| 394 return 0; |
|
| 395 } |
|
| 396 } |
|
| 397 |
|
| 398 /* combine prefix and filename */ |
|
| 399 memset(nbuf, 0, sizeof nbuf); |
|
| 400 name = nbuf; |
|
| 401 if ((tblk)->prefix[0]) |
|
| 402 { |
|
| 403 strncpy(name, (tblk)->prefix, sizeof (tblk)->prefix); |
|
| 404 strcat(name, "/"); |
|
| 405 strncat(name + strlen(name), (tblk)->filename, |
|
| 406 sizeof (tblk)->filename); |
|
| 407 } |
|
| 408 else |
|
| 409 { |
|
| 410 strncpy(name, (tblk)->filename, |
|
| 411 sizeof (tblk)->filename); |
|
| 412 } |
|
| 413 |
|
| 414 /* Convert any backslashes to forward slashes, and guard |
|
| 415 * against doubled-up slashes. (Some DOS versions of "tar" |
|
| 416 * get this wrong.) Also strip off leading slashes. |
|
| 417 */ |
|
| 418 if (!ABSPATH && (*name == '/' || *name == '\\')) |
|
| 419 didabs = 1; |
|
| 420 for (n2 = nbuf; *name; name++) |
|
| 421 { |
|
| 422 if (*name == '\\') |
|
| 423 *name = '/'; |
|
| 424 if (*name != '/' |
|
| 425 || (ABSPATH && n2 == nbuf) |
|
| 426 || (n2 != nbuf && n2[-1] != '/')) |
|
| 427 *n2++ = *name; |
|
| 428 } |
|
| 429 if (n2 == nbuf) |
|
| 430 *n2++ = '/'; |
|
| 431 *n2 = '\0'; |
|
| 432 |
|
| 433 /* verify the checksum */ |
|
| 434 for (sum = 0L, i = 0; i < sizeof((tblk)->checksum); i++) |
|
| 435 { |
|
| 436 if ((tblk)->checksum[i] >= '0' |
|
| 437 && (tblk)->checksum[i] <= '7') |
|
| 438 sum = sum * 8 + (tblk)->checksum[i] - '0'; |
|
| 439 } |
|
| 440 if (sum != checksum(tblk, 0) && sum != checksum(tblk, 1)) |
|
| 441 { |
|
| 442 if (!first) |
|
| 443 untar_error("Garbage detected; preceding file may be damaged\n"); |
|
| 444 untar_error("%s: header has bad checksum for %s\n", inname, nbuf); |
|
| 445 return 0; |
|
| 446 } |
|
| 447 |
|
| 448 /* From this point on, we don't care whether this is the first |
|
| 449 * block or not. Might as well reset the "first" flag now. |
|
| 450 */ |
|
| 451 first = 0; |
|
| 452 |
|
| 453 /* if last character of name is '/' then assume directory */ |
|
| 454 if (*nbuf && nbuf[strlen(nbuf) - 1] == '/') |
|
| 455 (tblk)->type = '5'; |
|
| 456 |
|
| 457 /* convert file size */ |
|
| 458 for (outsize = 0L, i = 0; i < sizeof((tblk)->size); i++) |
|
| 459 { |
|
| 460 if ((tblk)->size[i] >= '0' && (tblk)->size[i] <= '7') |
|
| 461 outsize = outsize * 8 + (tblk)->size[i] - '0'; |
|
| 462 } |
|
| 463 |
|
| 464 #ifdef _POSIX_SOURCE |
|
| 465 /* convert file timestamp */ |
|
| 466 for (timestamp.modtime=0L, i=0; i < sizeof((tblk)->mtime); i++) |
|
| 467 { |
|
| 468 if ((tblk)->mtime[i] >= '0' && (tblk)->mtime[i] <= '7') |
|
| 469 timestamp.modtime = timestamp.modtime * 8 |
|
| 470 + (tblk)->mtime[i] - '0'; |
|
| 471 } |
|
| 472 timestamp.actime = timestamp.modtime; |
|
| 473 |
|
| 474 /* convert file permissions */ |
|
| 475 for (mode = i = 0; i < sizeof((tblk)->mode); i++) |
|
| 476 { |
|
| 477 if ((tblk)->mode[i] >= '0' && (tblk)->mode[i] <= '7') |
|
| 478 mode = mode * 8 + (tblk)->mode[i] - '0'; |
|
| 479 } |
|
| 480 #endif |
|
| 481 |
|
| 482 /* If we have an "only" list, and this file isn't in it, |
|
| 483 * then skip it. |
|
| 484 */ |
|
| 485 if (nonlys > 0) |
|
| 486 { |
|
| 487 for (i = 0; |
|
| 488 i < nonlys |
|
| 489 && strcmp(only[i], nbuf) |
|
| 490 && (strncmp(only[i], nbuf, strlen(only[i])) |
|
| 491 || nbuf[strlen(only[i])] != '/'); |
|
| 492 i++) |
|
| 493 { |
|
| 494 } |
|
| 495 if (i >= nonlys) |
|
| 496 { |
|
| 497 outfp = NULL; |
|
| 498 return 1; |
|
| 499 } |
|
| 500 } |
|
| 501 |
|
| 502 /* list the file */ |
|
| 503 if (VERBOSE) |
|
| 504 untar_verbose("%c %s", |
|
| 505 ISREGULAR(*tblk) ? '-' : ("hlcbdp"[(tblk)->type - '1']), |
|
| 506 nbuf); |
|
| 507 else if (!QUIET) |
|
| 508 untar_verbose("%s\n", nbuf); |
|
| 509 |
|
| 510 /* if link, then do the link-or-copy thing */ |
|
| 511 if (tblk->type == '1' || tblk->type == '2') |
|
| 512 { |
|
| 513 if (VERBOSE) |
|
| 514 untar_verbose(" -> %s\n", tblk->linkto); |
|
| 515 if (!LISTING) |
|
| 516 linkorcopy(tblk->linkto, nbuf, tblk->type == '2'); |
|
| 517 outsize = 0L; |
|
| 518 return 1; |
|
| 519 } |
|
| 520 |
|
| 521 /* If directory, then make a weak attempt to create it. |
|
| 522 * Ideally we would do the "create path" thing, but that |
|
| 523 * seems like more trouble than it's worth since traditional |
|
| 524 * tar archives don't contain directories anyway. |
|
| 525 */ |
|
| 526 if (tblk->type == '5') |
|
| 527 { |
|
| 528 if (LISTING) |
|
| 529 n2 = " directory"; |
|
| 530 #ifdef _POSIX_SOURCE |
|
| 531 else if (mkdir(nbuf, mode) == 0) |
|
| 532 #else |
|
| 533 else if (g_mkdir(nbuf, 0755) == 0) |
|
| 534 #endif |
|
| 535 n2 = " created"; |
|
| 536 else |
|
| 537 n2 = " ignored"; |
|
| 538 if (VERBOSE) |
|
| 539 untar_verbose("%s\n", n2); |
|
| 540 return 1; |
|
| 541 } |
|
| 542 |
|
| 543 /* if not a regular file, then skip it */ |
|
| 544 if (!ISREGULAR(*tblk)) |
|
| 545 { |
|
| 546 if (VERBOSE) |
|
| 547 untar_verbose(" ignored\n"); |
|
| 548 outsize = 0L; |
|
| 549 return 1; |
|
| 550 } |
|
| 551 |
|
| 552 /* print file statistics */ |
|
| 553 if (VERBOSE) |
|
| 554 { |
|
| 555 untar_verbose(" (%ld byte%s, %ld tape block%s)\n", |
|
| 556 outsize, |
|
| 557 outsize == 1 ? "" : "s", |
|
| 558 (outsize + TSIZE - 1) / TSIZE, |
|
| 559 (outsize > 0 && outsize <= TSIZE) ? "" : "s"); |
|
| 560 } |
|
| 561 |
|
| 562 /* if extracting, then try to create the file */ |
|
| 563 if (!LISTING) |
|
| 564 outfp = createpath(nbuf); |
|
| 565 else |
|
| 566 outfp = NULL; |
|
| 567 |
|
| 568 /* if file is 0 bytes long, then we're done already! */ |
|
| 569 if (outsize == 0 && outfp) |
|
| 570 { |
|
| 571 fclose(outfp); |
|
| 572 #ifdef _POSIX_SOURCE |
|
| 573 utime(nbuf, ×tamp); |
|
| 574 chmod(nbuf, mode); |
|
| 575 #endif |
|
| 576 } |
|
| 577 } |
|
| 578 return 1; |
|
| 579 } |
|
| 580 |
|
| 581 /* Process an archive file. This involves reading the blocks one at a time |
|
| 582 * and passing them to a untar() function. |
|
| 583 */ |
|
| 584 int untar(const char *filename, const char* destdir, untar_opt options) { |
|
| 585 int ret=1; |
|
| 586 char curdir[_MAX_PATH]; |
|
| 587 untarops = options; |
|
| 588 /* open the archive */ |
|
| 589 inname = filename; |
|
| 590 infp = g_fopen(filename, "rb"); |
|
| 591 if (!infp) |
|
| 592 { |
|
| 593 untar_error("Error opening: %s\n", filename); |
|
| 594 return 0; |
|
| 595 } |
|
| 596 |
|
| 597 /* Set current directory */ |
|
| 598 if(!GetCurrentDirectory(_MAX_PATH, curdir)) { |
|
| 599 untar_error("Could not get current directory (error %d).\n", GetLastError()); |
|
| 600 fclose(infp); |
|
| 601 return 0; |
|
| 602 } |
|
| 603 if(!SetCurrentDirectory(destdir)) { |
|
| 604 untar_error("Could not set current directory to (error %d): %s\n", GetLastError(), destdir); |
|
| 605 fclose(infp); |
|
| 606 return 0; |
|
| 607 } else { |
|
| 608 /* UNCOMPRESSED */ |
|
| 609 /* send each block to the untar_block() function */ |
|
| 610 while (fread(slide, 1, TSIZE, infp) == TSIZE) { |
|
| 611 if(!untar_block(slide)) { |
|
| 612 untar_error("untar failure: %s\n", filename); |
|
| 613 fclose(infp); |
|
| 614 ret=0; |
|
| 615 } |
|
| 616 } |
|
| 617 if (outsize > 0 && ret) { |
|
| 618 untar_warning("Last file might be truncated!\n"); |
|
| 619 fclose(outfp); |
|
| 620 outfp = NULL; |
|
| 621 } |
|
| 622 if(!SetCurrentDirectory(curdir)) { |
|
| 623 untar_error("Could not set current dir back to original (error %d).\n", GetLastError()); |
|
| 624 ret=0; |
|
| 625 } |
|
| 626 } |
|
| 627 |
|
| 628 /* close the archive file. */ |
|
| 629 fclose(infp); |
|
| 630 |
|
| 631 return ret; |
|
| 632 } |
|
| 633 |
|