home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 9 Archive / 09-Archive.zip / PAX20.ZIP / EXTRACT.C < prev    next >
C/C++ Source or Header  |  1990-11-12  |  16KB  |  631 lines

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