Ignore:
Timestamp:
Nov 4, 2007, 3:16:40 AM (16 years ago)
Author:
Bruno Cornec
Message:

Update to busybox 1.7.2

File:
1 edited

Legend:

Unmodified
Added
Removed
  • branches/2.2.5/mindi-busybox/archival/libunarchive/get_header_tar.c

    r821 r1765  
     1/* vi: set sw=4 ts=4: */
    12/* Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
    23 *
     
    1112 */
    1213
    13 #include <stdio.h>
    14 #include <stdlib.h>
    15 #include <string.h>
    16 #include <sys/sysmacros.h>  /* For makedev */
     14#include "libbb.h"
    1715#include "unarchive.h"
    18 #include "libbb.h"
    19 
    20 #ifdef CONFIG_FEATURE_TAR_GNU_EXTENSIONS
    21 static char *longname = NULL;
    22 static char *linkname = NULL;
    23 #endif
    24 
     16
     17#if ENABLE_FEATURE_TAR_GNU_EXTENSIONS
     18static char *longname;
     19static char *linkname;
     20#else
     21enum {
     22    longname = 0,
     23    linkname = 0,
     24};
     25#endif
     26
     27/* NB: _DESTROYS_ str[len] character! */
     28static unsigned long long getOctal(char *str, int len)
     29{
     30    unsigned long long v;
     31    /* Actually, tar header allows leading spaces also.
     32     * Oh well, we will be liberal and skip this...
     33     * The only downside probably is that we allow "-123" too :)
     34    if (*str < '0' || *str > '7')
     35        bb_error_msg_and_die("corrupted octal value in tar header");
     36    */
     37    str[len] = '\0';
     38    v = strtoull(str, &str, 8);
     39    if (*str && (!ENABLE_FEATURE_TAR_OLDGNU_COMPATIBILITY || *str != ' '))
     40        bb_error_msg_and_die("corrupted octal value in tar header");
     41    return v;
     42}
     43#define GET_OCTAL(a) getOctal((a), sizeof(a))
     44
     45void BUG_tar_header_size(void);
    2546char get_header_tar(archive_handle_t *archive_handle)
    2647{
     48    static smallint end;
     49
    2750    file_header_t *file_header = archive_handle->file_header;
    28     union {
     51    struct {
    2952        /* ustar header, Posix 1003.1 */
    30         unsigned char raw[512];
    31         struct {
    32             char name[100]; /*   0-99 */
    33             char mode[8];   /* 100-107 */
    34             char uid[8];    /* 108-115 */
    35             char gid[8];    /* 116-123 */
    36             char size[12];  /* 124-135 */
    37             char mtime[12]; /* 136-147 */
    38             char chksum[8]; /* 148-155 */
    39             char typeflag;  /* 156-156 */
    40             char linkname[100]; /* 157-256 */
    41             char magic[6];  /* 257-262 */
    42             char version[2];    /* 263-264 */
    43             char uname[32]; /* 265-296 */
    44             char gname[32]; /* 297-328 */
    45             char devmajor[8];   /* 329-336 */
    46             char devminor[8];   /* 337-344 */
    47             char prefix[155];   /* 345-499 */
    48             char padding[12];   /* 500-512 */
    49         } formated;
     53        char name[100];     /*   0-99 */
     54        char mode[8];       /* 100-107 */
     55        char uid[8];        /* 108-115 */
     56        char gid[8];        /* 116-123 */
     57        char size[12];      /* 124-135 */
     58        char mtime[12];     /* 136-147 */
     59        char chksum[8];     /* 148-155 */
     60        char typeflag;      /* 156-156 */
     61        char linkname[100]; /* 157-256 */
     62        char magic[6];      /* 257-262 */
     63        char version[2];    /* 263-264 */
     64        char uname[32];     /* 265-296 */
     65        char gname[32];     /* 297-328 */
     66        char devmajor[8];   /* 329-336 */
     67        char devminor[8];   /* 337-344 */
     68        char prefix[155];   /* 345-499 */
     69        char padding[12];   /* 500-512 */
    5070    } tar;
    51     long sum = 0;
    52     long i;
    53     static int end = 0;
    54 
     71    char *cp;
     72    int i, sum_u, sum;
     73#if ENABLE_FEATURE_TAR_OLDSUN_COMPATIBILITY
     74    int sum_s;
     75#endif
     76    int parse_names;
     77
     78    if (sizeof(tar) != 512)
     79        BUG_tar_header_size();
     80
     81#if ENABLE_FEATURE_TAR_GNU_EXTENSIONS
     82 again:
     83#endif
    5584    /* Align header */
    5685    data_align(archive_handle, 512);
    5786
    58     if (bb_full_read(archive_handle->src_fd, tar.raw, 512) != 512) {
    59         /* Assume end of file */
    60         bb_error_msg_and_die("Short header");
    61         //return(EXIT_FAILURE);
    62     }
     87 again_after_align:
     88
     89    xread(archive_handle->src_fd, &tar, 512);
    6390    archive_handle->offset += 512;
    6491
    6592    /* If there is no filename its an empty header */
    66     if (tar.formated.name[0] == 0) {
     93    if (tar.name[0] == 0) {
    6794        if (end) {
    6895            /* This is the second consecutive empty header! End of archive!
    6996             * Read until the end to empty the pipe from gz or bz2
    7097             */
    71             while (bb_full_read(archive_handle->src_fd, tar.raw, 512) == 512);
    72             return(EXIT_FAILURE);
     98            while (full_read(archive_handle->src_fd, &tar, 512) == 512)
     99                /* repeat */;
     100            return EXIT_FAILURE;
    73101        }
    74102        end = 1;
    75         return(EXIT_SUCCESS);
     103        return EXIT_SUCCESS;
    76104    }
    77105    end = 0;
     
    80108     * 0's are for the old tar format
    81109     */
    82     if (strncmp(tar.formated.magic, "ustar", 5) != 0) {
    83 #ifdef CONFIG_FEATURE_TAR_OLDGNU_COMPATIBILITY
    84         if (strncmp(tar.formated.magic, "\0\0\0\0\0", 5) != 0)
    85 #endif
    86             bb_error_msg_and_die("Invalid tar magic");
    87     }
    88     /* Do checksum on headers */
    89     for (i =  0; i < 148 ; i++) {
    90         sum += tar.raw[i];
    91     }
    92     sum += ' ' * 8;
    93     for (i =  156; i < 512 ; i++) {
    94         sum += tar.raw[i];
    95     }
    96     if (sum != strtol(tar.formated.chksum, NULL, 8)) {
    97         bb_error_msg("Invalid tar header checksum");
    98         return(EXIT_FAILURE);
    99     }
    100 
    101 #ifdef CONFIG_FEATURE_TAR_GNU_EXTENSIONS
     110    if (strncmp(tar.magic, "ustar", 5) != 0) {
     111#if ENABLE_FEATURE_TAR_OLDGNU_COMPATIBILITY
     112        if (memcmp(tar.magic, "\0\0\0\0", 5) != 0)
     113#endif
     114            bb_error_msg_and_die("invalid tar magic");
     115    }
     116
     117    /* Do checksum on headers.
     118     * POSIX says that checksum is done on unsigned bytes, but
     119     * Sun and HP-UX gets it wrong... more details in
     120     * GNU tar source. */
     121#if ENABLE_FEATURE_TAR_OLDSUN_COMPATIBILITY
     122    sum_s = ' ' * sizeof(tar.chksum);
     123#endif
     124    sum_u = ' ' * sizeof(tar.chksum);
     125    for (i = 0; i < 148; i++) {
     126        sum_u += ((unsigned char*)&tar)[i];
     127#if ENABLE_FEATURE_TAR_OLDSUN_COMPATIBILITY
     128        sum_s += ((signed char*)&tar)[i];
     129#endif
     130    }
     131    for (i = 156; i < 512; i++) {
     132        sum_u += ((unsigned char*)&tar)[i];
     133#if ENABLE_FEATURE_TAR_OLDSUN_COMPATIBILITY
     134        sum_s += ((signed char*)&tar)[i];
     135#endif
     136    }
     137#if ENABLE_FEATURE_TAR_OLDGNU_COMPATIBILITY
     138    sum = strtoul(tar.chksum, &cp, 8);
     139    if ((*cp && *cp != ' ')
     140     || (sum_u != sum USE_FEATURE_TAR_OLDSUN_COMPATIBILITY(&& sum_s != sum))
     141    ) {
     142        bb_error_msg_and_die("invalid tar header checksum");
     143    }
     144#else
     145    /* This field does not need special treatment (getOctal) */
     146    sum = xstrtoul(tar.chksum, 8);
     147    if (sum_u != sum USE_FEATURE_TAR_OLDSUN_COMPATIBILITY(&& sum_s != sum)) {
     148        bb_error_msg_and_die("invalid tar header checksum");
     149    }
     150#endif
     151
     152    /* 0 is reserved for high perf file, treat as normal file */
     153    if (!tar.typeflag) tar.typeflag = '0';
     154    parse_names = (tar.typeflag >= '0' && tar.typeflag <= '7');
     155
     156    /* getOctal trashes subsequent field, therefore we call it
     157     * on fields in reverse order */
     158    if (tar.devmajor[0]) {
     159        unsigned minor = GET_OCTAL(tar.devminor);
     160        unsigned major = GET_OCTAL(tar.devmajor);
     161        file_header->device = makedev(major, minor);
     162    }
     163    file_header->link_target = NULL;
     164    if (!linkname && parse_names && tar.linkname[0]) {
     165        /* we trash magic[0] here, it's ok */
     166        tar.linkname[sizeof(tar.linkname)] = '\0';
     167        file_header->link_target = xstrdup(tar.linkname);
     168        /* FIXME: what if we have non-link object with link_target? */
     169        /* Will link_target be free()ed? */
     170    }
     171    file_header->mtime = GET_OCTAL(tar.mtime);
     172    file_header->size = GET_OCTAL(tar.size);
     173    file_header->gid = GET_OCTAL(tar.gid);
     174    file_header->uid = GET_OCTAL(tar.uid);
     175    /* Set bits 0-11 of the files mode */
     176    file_header->mode = 07777 & GET_OCTAL(tar.mode);
     177
     178    file_header->name = NULL;
     179    if (!longname && parse_names) {
     180        /* we trash mode[0] here, it's ok */
     181        tar.name[sizeof(tar.name)] = '\0';
     182        if (tar.prefix[0]) {
     183            /* and padding[0] */
     184            tar.prefix[sizeof(tar.prefix)] = '\0';
     185            file_header->name = concat_path_file(tar.prefix, tar.name);
     186        } else
     187            file_header->name = xstrdup(tar.name);
     188    }
     189
     190    /* Set bits 12-15 of the files mode */
     191    /* (typeflag was not trashed because chksum does not use getOctal) */
     192    switch (tar.typeflag) {
     193    /* busybox identifies hard links as being regular files with 0 size and a link name */
     194    case '1':
     195        file_header->mode |= S_IFREG;
     196        break;
     197    case '7':
     198    /* case 0: */
     199    case '0':
     200#if ENABLE_FEATURE_TAR_OLDGNU_COMPATIBILITY
     201        if (last_char_is(file_header->name, '/')) {
     202            file_header->mode |= S_IFDIR;
     203        } else
     204#endif
     205        file_header->mode |= S_IFREG;
     206        break;
     207    case '2':
     208        file_header->mode |= S_IFLNK;
     209        break;
     210    case '3':
     211        file_header->mode |= S_IFCHR;
     212        break;
     213    case '4':
     214        file_header->mode |= S_IFBLK;
     215        break;
     216    case '5':
     217        file_header->mode |= S_IFDIR;
     218        break;
     219    case '6':
     220        file_header->mode |= S_IFIFO;
     221        break;
     222#if ENABLE_FEATURE_TAR_GNU_EXTENSIONS
     223    case 'L':
     224        /* free: paranoia: tar with several consecutive longnames */
     225        free(longname);
     226        /* For paranoia reasons we allocate extra NUL char */
     227        longname = xzalloc(file_header->size + 1);
     228        /* We read ASCIZ string, including NUL */
     229        xread(archive_handle->src_fd, longname, file_header->size);
     230        archive_handle->offset += file_header->size;
     231        /* return get_header_tar(archive_handle); */
     232        /* gcc 4.1.1 didn't optimize it into jump */
     233        /* so we will do it ourself, this also saves stack */
     234        goto again;
     235    case 'K':
     236        free(linkname);
     237        linkname = xzalloc(file_header->size + 1);
     238        xread(archive_handle->src_fd, linkname, file_header->size);
     239        archive_handle->offset += file_header->size;
     240        /* return get_header_tar(archive_handle); */
     241        goto again;
     242    case 'D':   /* GNU dump dir */
     243    case 'M':   /* Continuation of multi volume archive */
     244    case 'N':   /* Old GNU for names > 100 characters */
     245    case 'S':   /* Sparse file */
     246    case 'V':   /* Volume header */
     247#endif
     248    case 'g':   /* pax global header */
     249    case 'x': { /* pax extended header */
     250        off_t sz;
     251        bb_error_msg("warning: skipping header '%c'", tar.typeflag);
     252        sz = (file_header->size + 511) & ~(off_t)511;
     253        archive_handle->offset += sz;
     254        sz >>= 9; /* sz /= 512 but w/o contortions for signed div */
     255        while (sz--)
     256            xread(archive_handle->src_fd, &tar, 512);
     257        /* return get_header_tar(archive_handle); */
     258        goto again_after_align;
     259    }
     260    default:
     261        bb_error_msg_and_die("unknown typeflag: 0x%x", tar.typeflag);
     262    }
     263
     264#if ENABLE_FEATURE_TAR_GNU_EXTENSIONS
    102265    if (longname) {
    103266        file_header->name = longname;
    104267        longname = NULL;
    105268    }
    106     else if (linkname) {
    107         file_header->name = linkname;
     269    if (linkname) {
     270        file_header->link_target = linkname;
    108271        linkname = NULL;
    109     } else
    110 #endif
    111     {
    112         file_header->name = bb_xstrndup(tar.formated.name,100);
    113 
    114         if (tar.formated.prefix[0]) {
    115             char *temp = file_header->name;
    116             file_header->name = concat_path_file(tar.formated.prefix, temp);
    117             free(temp);
    118         }
    119     }
    120 
    121     file_header->uid = strtol(tar.formated.uid, NULL, 8);
    122     file_header->gid = strtol(tar.formated.gid, NULL, 8);
    123     file_header->size = strtol(tar.formated.size, NULL, 8);
    124     file_header->mtime = strtol(tar.formated.mtime, NULL, 8);
    125     file_header->link_name = (tar.formated.linkname[0] != '\0') ?
    126         bb_xstrdup(tar.formated.linkname) : NULL;
    127     file_header->device = makedev(strtol(tar.formated.devmajor, NULL, 8),
    128         strtol(tar.formated.devminor, NULL, 8));
    129 
    130     /* Set bits 0-11 of the files mode */
    131     file_header->mode = 07777 & strtol(tar.formated.mode, NULL, 8);
    132 
    133     /* Set bits 12-15 of the files mode */
    134     switch (tar.formated.typeflag) {
    135     /* busybox identifies hard links as being regular files with 0 size and a link name */
    136     case '1':
    137         file_header->mode |= S_IFREG;
    138         break;
    139     case '7':
    140         /* Reserved for high performance files, treat as normal file */
    141     case 0:
    142     case '0':
    143 #ifdef CONFIG_FEATURE_TAR_OLDGNU_COMPATIBILITY
    144         if (last_char_is(file_header->name, '/')) {
    145             file_header->mode |= S_IFDIR;
    146         } else
    147 #endif
    148             file_header->mode |= S_IFREG;
    149         break;
    150     case '2':
    151         file_header->mode |= S_IFLNK;
    152         break;
    153     case '3':
    154         file_header->mode |= S_IFCHR;
    155         break;
    156     case '4':
    157         file_header->mode |= S_IFBLK;
    158         break;
    159     case '5':
    160         file_header->mode |= S_IFDIR;
    161         break;
    162     case '6':
    163         file_header->mode |= S_IFIFO;
    164         break;
    165 #ifdef CONFIG_FEATURE_TAR_GNU_EXTENSIONS
    166     case 'L': {
    167             longname = xzalloc(file_header->size + 1);
    168             archive_xread_all(archive_handle, longname, file_header->size);
    169             archive_handle->offset += file_header->size;
    170 
    171             return(get_header_tar(archive_handle));
    172         }
    173     case 'K': {
    174             linkname = xzalloc(file_header->size + 1);
    175             archive_xread_all(archive_handle, linkname, file_header->size);
    176             archive_handle->offset += file_header->size;
    177 
    178             file_header->name = linkname;
    179             return(get_header_tar(archive_handle));
    180         }
    181     case 'D':   /* GNU dump dir */
    182     case 'M':   /* Continuation of multi volume archive*/
    183     case 'N':   /* Old GNU for names > 100 characters */
    184     case 'S':   /* Sparse file */
    185     case 'V':   /* Volume header */
    186 #endif
    187     case 'g':   /* pax global header */
    188     case 'x':   /* pax extended header */
    189         bb_error_msg("Ignoring extension type %c", tar.formated.typeflag);
    190         break;
    191     default:
    192         bb_error_msg("Unknown typeflag: 0x%x", tar.formated.typeflag);
    193     }
    194     {   /* Strip trailing '/' in directories */
    195         /* Must be done after mode is set as '/' is used to check if its a directory */
    196         char *tmp = last_char_is(file_header->name, '/');
    197         if (tmp) {
    198             *tmp = '\0';
    199         }
    200     }
     272    }
     273#endif
     274    if (!strncmp(file_header->name, "/../"+1, 3)
     275     || strstr(file_header->name, "/../")
     276    ) {
     277        bb_error_msg_and_die("name with '..' encountered: '%s'",
     278                file_header->name);
     279    }
     280
     281    /* Strip trailing '/' in directories */
     282    /* Must be done after mode is set as '/' is used to check if it's a directory */
     283    cp = last_char_is(file_header->name, '/');
    201284
    202285    if (archive_handle->filter(archive_handle) == EXIT_SUCCESS) {
    203286        archive_handle->action_header(archive_handle->file_header);
     287        /* Note that we kill the '/' only after action_header() */
     288        /* (like GNU tar 1.15.1: verbose mode outputs "dir/dir/") */
     289        if (cp) *cp = '\0';
    204290        archive_handle->flags |= ARCHIVE_EXTRACT_QUIET;
    205291        archive_handle->action_data(archive_handle);
     
    207293    } else {
    208294        data_skip(archive_handle);
     295        free(file_header->name);
    209296    }
    210297    archive_handle->offset += file_header->size;
    211298
    212     free(file_header->link_name);
    213 
    214     return(EXIT_SUCCESS);
     299    free(file_header->link_target);
     300    /* Do not free(file_header->name)! */
     301
     302    return EXIT_SUCCESS;
    215303}
Note: See TracChangeset for help on using the changeset viewer.