|
|
1.1 ! root 1: /* $Source: /newbits/usr/bin/pax/shipping/extract.c,v $ ! 2: * ! 3: * $Revision: 1.1 $ ! 4: * ! 5: * extract.c - Extract files from a tar archive. ! 6: * ! 7: * DESCRIPTION ! 8: * ! 9: * AUTHOR ! 10: * ! 11: * Mark H. Colburn, NAPS International ([email protected]) ! 12: * ! 13: * Sponsored by The USENIX Association for public distribution. ! 14: * ! 15: * Copyright (c) 1989 Mark H. Colburn. ! 16: * All rights reserved. ! 17: * ! 18: * Redistribution and use in source and binary forms are permitted ! 19: * provided that the above copyright notice is duplicated in all such ! 20: * forms and that any documentation, advertising materials, and other ! 21: * materials related to such distribution and use acknowledge that the ! 22: * software was developed * by Mark H. Colburn and sponsored by The ! 23: * USENIX Association. ! 24: * ! 25: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR ! 26: * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED ! 27: * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. ! 28: * ! 29: * $Log: /newbits/usr/bin/pax/shipping/extract.c,v $ ! 30: * Revision 1.1 91/02/05 11:55:52 bin ! 31: * Initial revision ! 32: * ! 33: * Revision 1.3 89/02/12 10:29:43 mark ! 34: * Fixed misspelling of Replstr ! 35: * ! 36: * Revision 1.2 89/02/12 10:04:24 mark ! 37: * 1.2 release fixes ! 38: * ! 39: * Revision 1.1 88/12/23 18:02:07 mark ! 40: * Initial revision ! 41: * ! 42: */ ! 43: ! 44: #ifndef lint ! 45: static char *ident = "$Id: extract.c,v 1.3 89/02/12 10:29:43 mark Exp Locker: mark $"; ! 46: static char *copyright = "Copyright (c) 1989 Mark H. Colburn.\nAll rights reserved.\n"; ! 47: #endif /* ! lint */ ! 48: ! 49: ! 50: /* Headers */ ! 51: ! 52: #include "pax.h" ! 53: ! 54: ! 55: /* Defines */ ! 56: ! 57: /* ! 58: * Swap bytes. ! 59: */ ! 60: #define SWAB(n) ((((ushort)(n) >> 8) & 0xff) | (((ushort)(n) << 8) & 0xff00)) ! 61: ! 62: ! 63: /* Function Prototypes */ ! 64: ! 65: #if __STDC__ ! 66: ! 67: static int inbinary(char *, char *, Stat *); ! 68: static int inascii(char *, char *, Stat *); ! 69: static int inswab(char *, char *, Stat *); ! 70: static int readtar(char *, Stat *); ! 71: static int readcpio(char *, Stat *); ! 72: ! 73: #else /* !__STDC__ */ ! 74: ! 75: static int inbinary(); ! 76: static int inascii(); ! 77: static int inswab(); ! 78: static int readtar(); ! 79: static int readcpio(); ! 80: ! 81: #endif /* __STDC__ */ ! 82: ! 83: ! 84: /* read_archive - read in an archive ! 85: * ! 86: * DESCRIPTION ! 87: * ! 88: * Read_archive is the central entry point for reading archives. ! 89: * Read_archive determines the proper archive functions to call ! 90: * based upon the archive type being processed. ! 91: * ! 92: * RETURNS ! 93: * ! 94: */ ! 95: ! 96: #if __STDC__ ! 97: ! 98: int read_archive(void) ! 99: ! 100: #else ! 101: ! 102: int read_archive() ! 103: ! 104: #endif ! 105: { ! 106: Stat sb; ! 107: char name[PATH_MAX + 1]; ! 108: int match; ! 109: int pad; ! 110: ! 111: name_gather(); /* get names from command line */ ! 112: name[0] = '\0'; ! 113: while (get_header(name, &sb) == 0) { ! 114: match = name_match(name) ^ f_reverse_match; ! 115: if (f_list) { /* only wanted a table of contents */ ! 116: if (match) { ! 117: print_entry(name, &sb); ! 118: } ! 119: if (((ar_format == TAR) ! 120: ? buf_skip(ROUNDUP((OFFSET) sb.sb_size, BLOCKSIZE)) ! 121: : buf_skip((OFFSET) sb.sb_size)) < 0) { ! 122: warn(name, "File data is corrupt"); ! 123: } ! 124: } else if (match) { ! 125: if (rplhead != (Replstr *)NULL) { ! 126: rpl_name(name); ! 127: if (strlen(name) == 0) { ! 128: continue; ! 129: } ! 130: } ! 131: if (get_disposition("extract", name) || ! 132: get_newname(name, sizeof(name))) { ! 133: /* skip file... */ ! 134: if (((ar_format == TAR) ! 135: ? buf_skip(ROUNDUP((OFFSET) sb.sb_size, BLOCKSIZE)) ! 136: : buf_skip((OFFSET) sb.sb_size)) < 0) { ! 137: warn(name, "File data is corrupt"); ! 138: } ! 139: continue; ! 140: } ! 141: if (inentry(name, &sb) < 0) { ! 142: warn(name, "File data is corrupt"); ! 143: } ! 144: if (f_verbose) { ! 145: print_entry(name, &sb); ! 146: } ! 147: if (ar_format == TAR && sb.sb_nlink > 1) { ! 148: /* ! 149: * This kludge makes sure that the link table is cleared ! 150: * before attempting to process any other links. ! 151: */ ! 152: if (sb.sb_nlink > 1) { ! 153: linkfrom(name, &sb); ! 154: } ! 155: } ! 156: if (ar_format == TAR && (pad = sb.sb_size % BLOCKSIZE) != 0) { ! 157: pad = BLOCKSIZE - pad; ! 158: buf_skip((OFFSET) pad); ! 159: } ! 160: } else { ! 161: if (((ar_format == TAR) ! 162: ? buf_skip(ROUNDUP((OFFSET) sb.sb_size, BLOCKSIZE)) ! 163: : buf_skip((OFFSET) sb.sb_size)) < 0) { ! 164: warn(name, "File data is corrupt"); ! 165: } ! 166: } ! 167: } ! 168: close_archive(); ! 169: } ! 170: ! 171: ! 172: ! 173: /* get_header - figures which type of header needs to be read. ! 174: * ! 175: * DESCRIPTION ! 176: * ! 177: * This is merely a single entry point for the two types of archive ! 178: * headers which are supported. The correct header is selected ! 179: * depending on the archive type. ! 180: * ! 181: * PARAMETERS ! 182: * ! 183: * char *name - name of the file (passed to header routine) ! 184: * Stat *asb - Stat block for the file (passed to header routine) ! 185: * ! 186: * RETURNS ! 187: * ! 188: * Returns the value which was returned by the proper header ! 189: * function. ! 190: */ ! 191: ! 192: #if __STDC__ ! 193: ! 194: int get_header(char *name, Stat *asb) ! 195: ! 196: #else ! 197: ! 198: int get_header(name, asb) ! 199: char *name; ! 200: Stat *asb; ! 201: ! 202: #endif ! 203: { ! 204: if (ar_format == TAR) { ! 205: return(readtar(name, asb)); ! 206: } else { ! 207: return(readcpio(name, asb)); ! 208: } ! 209: } ! 210: ! 211: ! 212: /* readtar - read a tar header ! 213: * ! 214: * DESCRIPTION ! 215: * ! 216: * Tar_head read a tar format header from the archive. The name ! 217: * and asb parameters are modified as appropriate for the file listed ! 218: * in the header. Name is assumed to be a pointer to an array of ! 219: * at least PATH_MAX bytes. ! 220: * ! 221: * PARAMETERS ! 222: * ! 223: * char *name - name of the file for which the header is ! 224: * for. This is modified and passed back to ! 225: * the caller. ! 226: * Stat *asb - Stat block for the file for which the header ! 227: * is for. The fields of the stat structure are ! 228: * extracted from the archive header. This is ! 229: * also passed back to the caller. ! 230: * ! 231: * RETURNS ! 232: * ! 233: * Returns 0 if a valid header was found, or -1 if EOF is ! 234: * encountered. ! 235: */ ! 236: ! 237: #if __STDC__ ! 238: ! 239: static int readtar(char *name, Stat *asb) ! 240: ! 241: #else ! 242: ! 243: static int readtar(name, asb) ! 244: char *name; ! 245: Stat *asb; ! 246: ! 247: #endif ! 248: { ! 249: int status = 3; /* Initial status at start of archive */ ! 250: static int prev_status; ! 251: ! 252: for (;;) { ! 253: prev_status = status; ! 254: status = read_header(name, asb); ! 255: switch (status) { ! 256: case 1: /* Valid header */ ! 257: return(0); ! 258: case 0: /* Invalid header */ ! 259: switch (prev_status) { ! 260: case 3: /* Error on first record */ ! 261: warn(ar_file, "This doesn't look like a tar archive"); ! 262: /* FALLTHRU */ ! 263: case 2: /* Error after record of zeroes */ ! 264: case 1: /* Error after header rec */ ! 265: warn(ar_file, "Skipping to next file..."); ! 266: /* FALLTHRU */ ! 267: default: ! 268: case 0: /* Error after error */ ! 269: break; ! 270: } ! 271: break; ! 272: ! 273: case 2: /* Record of zeroes */ ! 274: case EOF: /* End of archive */ ! 275: default: ! 276: return(-1); ! 277: } ! 278: } ! 279: } ! 280: ! 281: ! 282: /* readcpio - read a CPIO header ! 283: * ! 284: * DESCRIPTION ! 285: * ! 286: * Read in a cpio header. Understands how to determine and read ASCII, ! 287: * binary and byte-swapped binary headers. Quietly translates ! 288: * old-fashioned binary cpio headers (and arranges to skip the possible ! 289: * alignment byte). Returns zero if successful, -1 upon archive trailer. ! 290: * ! 291: * PARAMETERS ! 292: * ! 293: * char *name - name of the file for which the header is ! 294: * for. This is modified and passed back to ! 295: * the caller. ! 296: * Stat *asb - Stat block for the file for which the header ! 297: * is for. The fields of the stat structure are ! 298: * extracted from the archive header. This is ! 299: * also passed back to the caller. ! 300: * ! 301: * RETURNS ! 302: * ! 303: * Returns 0 if a valid header was found, or -1 if EOF is ! 304: * encountered. ! 305: */ ! 306: ! 307: #if __STDC__ ! 308: ! 309: static int readcpio(char *name, Stat *asb) ! 310: ! 311: #else ! 312: ! 313: static int readcpio(name, asb) ! 314: char *name; ! 315: Stat *asb; ! 316: ! 317: #endif ! 318: { ! 319: OFFSET skipped; ! 320: char magic[M_STRLEN]; ! 321: static int align; ! 322: ! 323: if (align > 0) { ! 324: buf_skip((OFFSET) align); ! 325: } ! 326: align = 0; ! 327: for (;;) { ! 328: buf_read(magic, M_STRLEN); ! 329: skipped = 0; ! 330: while ((align = inascii(magic, name, asb)) < 0 ! 331: && (align = inbinary(magic, name, asb)) < 0 ! 332: && (align = inswab(magic, name, asb)) < 0) { ! 333: if (++skipped == 1) { ! 334: if (total - sizeof(magic) == 0) { ! 335: fatal("Unrecognizable archive"); ! 336: } ! 337: warnarch("Bad magic number", (OFFSET) sizeof(magic)); ! 338: if (name[0]) { ! 339: warn(name, "May be corrupt"); ! 340: } ! 341: } ! 342: memcpy(magic, magic + 1, sizeof(magic) - 1); ! 343: buf_read(magic + sizeof(magic) - 1, 1); ! 344: } ! 345: if (skipped) { ! 346: warnarch("Apparently resynchronized", (OFFSET) sizeof(magic)); ! 347: warn(name, "Continuing"); ! 348: } ! 349: if (strcmp(name, TRAILER) == 0) { ! 350: return (-1); ! 351: } ! 352: if (nameopt(name) >= 0) { ! 353: break; ! 354: } ! 355: buf_skip((OFFSET) asb->sb_size + align); ! 356: } ! 357: #ifdef S_IFLNK ! 358: if ((asb->sb_mode & S_IFMT) == S_IFLNK) { ! 359: if (buf_read(asb->sb_link, (uint) asb->sb_size) < 0) { ! 360: warn(name, "Corrupt symbolic link"); ! 361: return (readcpio(name, asb)); ! 362: } ! 363: asb->sb_link[asb->sb_size] = '\0'; ! 364: asb->sb_size = 0; ! 365: } ! 366: #endif /* S_IFLNK */ ! 367: ! 368: /* destroy absolute pathnames for security reasons */ ! 369: if (name[0] == '/') { ! 370: if (name[1]) { ! 371: while (name[0] = name[1]) { ! 372: ++name; ! 373: } ! 374: } else { ! 375: name[0] = '.'; ! 376: } ! 377: } ! 378: asb->sb_atime = asb->sb_ctime = asb->sb_mtime; ! 379: if (asb->sb_nlink > 1) { ! 380: linkto(name, asb); ! 381: } ! 382: return (0); ! 383: } ! 384: ! 385: ! 386: /* inswab - read a reversed by order binary header ! 387: * ! 388: * DESCRIPTIONS ! 389: * ! 390: * Reads a byte-swapped CPIO binary archive header ! 391: * ! 392: * PARMAMETERS ! 393: * ! 394: * char *magic - magic number to match ! 395: * char *name - name of the file which is stored in the header. ! 396: * (modified and passed back to caller). ! 397: * Stat *asb - stat block for the file (modified and passed back ! 398: * to the caller). ! 399: * ! 400: * ! 401: * RETURNS ! 402: * ! 403: * Returns the number of trailing alignment bytes to skip; -1 if ! 404: * unsuccessful. ! 405: * ! 406: */ ! 407: ! 408: #if __STDC__ ! 409: ! 410: static int inswab(char *magic, char *name, Stat *asb) ! 411: ! 412: #else ! 413: ! 414: static int inswab(magic, name, asb) ! 415: char *magic; ! 416: char *name; ! 417: Stat *asb; ! 418: ! 419: #endif ! 420: { ! 421: ushort namesize; ! 422: uint namefull; ! 423: Binary binary; ! 424: ! 425: if (*((ushort *) magic) != SWAB(M_BINARY)) { ! 426: return (-1); ! 427: } ! 428: memcpy((char *) &binary, ! 429: magic + sizeof(ushort), ! 430: M_STRLEN - sizeof(ushort)); ! 431: if (buf_read((char *) &binary + M_STRLEN - sizeof(ushort), ! 432: sizeof(binary) - (M_STRLEN - sizeof(ushort))) < 0) { ! 433: warnarch("Corrupt swapped header", ! 434: (OFFSET) sizeof(binary) - (M_STRLEN - sizeof(ushort))); ! 435: return (-1); ! 436: } ! 437: asb->sb_dev = (dev_t) SWAB(binary.b_dev); ! 438: asb->sb_ino = (ino_t) SWAB(binary.b_ino); ! 439: asb->sb_mode = SWAB(binary.b_mode); ! 440: asb->sb_uid = SWAB(binary.b_uid); ! 441: asb->sb_gid = SWAB(binary.b_gid); ! 442: asb->sb_nlink = SWAB(binary.b_nlink); ! 443: asb->sb_rdev = (dev_t) SWAB(binary.b_rdev); ! 444: asb->sb_mtime = SWAB(binary.b_mtime[0]) << 16 | SWAB(binary.b_mtime[1]); ! 445: asb->sb_size = SWAB(binary.b_size[0]) << 16 | SWAB(binary.b_size[1]); ! 446: if ((namesize = SWAB(binary.b_name)) == 0 || namesize >= PATH_MAX) { ! 447: warnarch("Bad swapped pathname length", ! 448: (OFFSET) sizeof(binary) - (M_STRLEN - sizeof(ushort))); ! 449: return (-1); ! 450: } ! 451: if (buf_read(name, namefull = namesize + namesize % 2) < 0) { ! 452: warnarch("Corrupt swapped pathname", (OFFSET) namefull); ! 453: return (-1); ! 454: } ! 455: if (name[namesize - 1] != '\0') { ! 456: warnarch("Bad swapped pathname", (OFFSET) namefull); ! 457: return (-1); ! 458: } ! 459: return (asb->sb_size % 2); ! 460: } ! 461: ! 462: ! 463: /* inascii - read in an ASCII cpio header ! 464: * ! 465: * DESCRIPTION ! 466: * ! 467: * Reads an ASCII format cpio header ! 468: * ! 469: * PARAMETERS ! 470: * ! 471: * char *magic - magic number to match ! 472: * char *name - name of the file which is stored in the header. ! 473: * (modified and passed back to caller). ! 474: * Stat *asb - stat block for the file (modified and passed back ! 475: * to the caller). ! 476: * ! 477: * RETURNS ! 478: * ! 479: * Returns zero if successful; -1 otherwise. Assumes that the entire ! 480: * magic number has been read. ! 481: */ ! 482: ! 483: #if __STDC__ ! 484: ! 485: static int inascii(char *magic, char *name, Stat *asb) ! 486: ! 487: #else ! 488: ! 489: static int inascii(magic, name, asb) ! 490: char *magic; ! 491: char *name; ! 492: Stat *asb; ! 493: ! 494: #endif ! 495: { ! 496: uint namelen; ! 497: char header[H_STRLEN + 1]; ! 498: ! 499: if (strncmp(magic, M_ASCII, M_STRLEN) != 0) { ! 500: return (-1); ! 501: } ! 502: if (buf_read(header, H_STRLEN) < 0) { ! 503: warnarch("Corrupt ASCII header", (OFFSET) H_STRLEN); ! 504: return (-1); ! 505: } ! 506: header[H_STRLEN] = '\0'; ! 507: if (sscanf(header, H_SCAN, &asb->sb_dev, ! 508: &asb->sb_ino, &asb->sb_mode, &asb->sb_uid, ! 509: &asb->sb_gid, &asb->sb_nlink, &asb->sb_rdev, ! 510: &asb->sb_mtime, &namelen, &asb->sb_size) != H_COUNT) { ! 511: warnarch("Bad ASCII header", (OFFSET) H_STRLEN); ! 512: return (-1); ! 513: } ! 514: if (namelen == 0 || namelen >= PATH_MAX) { ! 515: warnarch("Bad ASCII pathname length", (OFFSET) H_STRLEN); ! 516: return (-1); ! 517: } ! 518: if (buf_read(name, namelen) < 0) { ! 519: warnarch("Corrupt ASCII pathname", (OFFSET) namelen); ! 520: return (-1); ! 521: } ! 522: if (name[namelen - 1] != '\0') { ! 523: warnarch("Bad ASCII pathname", (OFFSET) namelen); ! 524: return (-1); ! 525: } ! 526: return (0); ! 527: } ! 528: ! 529: ! 530: /* inbinary - read a binary header ! 531: * ! 532: * DESCRIPTION ! 533: * ! 534: * Reads a CPIO format binary header. ! 535: * ! 536: * PARAMETERS ! 537: * ! 538: * char *magic - magic number to match ! 539: * char *name - name of the file which is stored in the header. ! 540: * (modified and passed back to caller). ! 541: * Stat *asb - stat block for the file (modified and passed back ! 542: * to the caller). ! 543: * ! 544: * RETURNS ! 545: * ! 546: * Returns the number of trailing alignment bytes to skip; -1 if ! 547: * unsuccessful. ! 548: */ ! 549: ! 550: #if __STDC__ ! 551: ! 552: static int inbinary(char *magic, char *name, Stat *asb) ! 553: ! 554: #else ! 555: ! 556: static int inbinary(magic, name, asb) ! 557: char *magic; ! 558: char *name; ! 559: Stat *asb; ! 560: ! 561: #endif ! 562: { ! 563: uint namefull; ! 564: Binary binary; ! 565: ! 566: if (*((ushort *) magic) != M_BINARY) { ! 567: return (-1); ! 568: } ! 569: memcpy((char *) &binary, ! 570: magic + sizeof(ushort), ! 571: M_STRLEN - sizeof(ushort)); ! 572: if (buf_read((char *) &binary + M_STRLEN - sizeof(ushort), ! 573: sizeof(binary) - (M_STRLEN - sizeof(ushort))) < 0) { ! 574: warnarch("Corrupt binary header", ! 575: (OFFSET) sizeof(binary) - (M_STRLEN - sizeof(ushort))); ! 576: return (-1); ! 577: } ! 578: asb->sb_dev = binary.b_dev; ! 579: asb->sb_ino = binary.b_ino; ! 580: asb->sb_mode = binary.b_mode; ! 581: asb->sb_uid = binary.b_uid; ! 582: asb->sb_gid = binary.b_gid; ! 583: asb->sb_nlink = binary.b_nlink; ! 584: asb->sb_rdev = binary.b_rdev; ! 585: asb->sb_mtime = binary.b_mtime[0] << 16 | binary.b_mtime[1]; ! 586: asb->sb_size = binary.b_size[0] << 16 | binary.b_size[1]; ! 587: if (binary.b_name == 0 || binary.b_name >= PATH_MAX) { ! 588: warnarch("Bad binary pathname length", ! 589: (OFFSET) sizeof(binary) - (M_STRLEN - sizeof(ushort))); ! 590: return (-1); ! 591: } ! 592: if (buf_read(name, namefull = binary.b_name + binary.b_name % 2) < 0) { ! 593: warnarch("Corrupt binary pathname", (OFFSET) namefull); ! 594: return (-1); ! 595: } ! 596: if (name[binary.b_name - 1] != '\0') { ! 597: warnarch("Bad binary pathname", (OFFSET) namefull); ! 598: return (-1); ! 599: } ! 600: return (asb->sb_size % 2); ! 601: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.