busybox/archival/libarchive/get_header_ar.c
<<
>>
Prefs
   1/* vi: set sw=4 ts=4: */
   2/* Copyright 2001 Glenn McGrath.
   3 *
   4 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
   5 */
   6
   7#include "libbb.h"
   8#include "archive.h"
   9#include "ar.h"
  10
  11static unsigned read_num(const char *str, int base)
  12{
  13        /* This code works because
  14         * on misformatted numbers bb_strtou returns all-ones */
  15        int err = bb_strtou(str, NULL, base);
  16        if (err == -1)
  17                bb_error_msg_and_die("invalid ar header");
  18        return err;
  19}
  20
  21char FAST_FUNC get_header_ar(archive_handle_t *archive_handle)
  22{
  23        file_header_t *typed = archive_handle->file_header;
  24        unsigned size;
  25        union {
  26                char raw[60];
  27                struct ar_header formatted;
  28        } ar;
  29#if ENABLE_FEATURE_AR_LONG_FILENAMES
  30        static char *ar_long_names;
  31        static unsigned ar_long_name_size;
  32#endif
  33
  34        /* dont use xread as we want to handle the error ourself */
  35        if (read(archive_handle->src_fd, ar.raw, 60) != 60) {
  36                /* End Of File */
  37                return EXIT_FAILURE;
  38        }
  39
  40        /* ar header starts on an even byte (2 byte aligned)
  41         * '\n' is used for padding
  42         */
  43        if (ar.raw[0] == '\n') {
  44                /* fix up the header, we started reading 1 byte too early */
  45                memmove(ar.raw, &ar.raw[1], 59);
  46                ar.raw[59] = xread_char(archive_handle->src_fd);
  47                archive_handle->offset++;
  48        }
  49        archive_handle->offset += 60;
  50
  51        if (ar.formatted.magic[0] != '`' || ar.formatted.magic[1] != '\n')
  52                bb_error_msg_and_die("invalid ar header");
  53
  54        /* FIXME: more thorough routine would be in order here
  55         * (we have something like that in tar)
  56         * but for now we are lax. */
  57        ar.formatted.magic[0] = '\0'; /* else 4G-2 file will have size="4294967294`\n..." */
  58        typed->size = size = read_num(ar.formatted.size, 10);
  59
  60        /* special filenames have '/' as the first character */
  61        if (ar.formatted.name[0] == '/') {
  62                if (ar.formatted.name[1] == ' ') {
  63                        /* This is the index of symbols in the file for compilers */
  64                        data_skip(archive_handle);
  65                        archive_handle->offset += size;
  66                        return get_header_ar(archive_handle); /* Return next header */
  67                }
  68#if ENABLE_FEATURE_AR_LONG_FILENAMES
  69                if (ar.formatted.name[1] == '/') {
  70                        /* If the second char is a '/' then this entries data section
  71                         * stores long filename for multiple entries, they are stored
  72                         * in static variable long_names for use in future entries
  73                         */
  74                        ar_long_name_size = size;
  75                        free(ar_long_names);
  76                        ar_long_names = xmalloc(size);
  77                        xread(archive_handle->src_fd, ar_long_names, size);
  78                        archive_handle->offset += size;
  79                        /* Return next header */
  80                        return get_header_ar(archive_handle);
  81                }
  82#else
  83                bb_error_msg_and_die("long filenames not supported");
  84#endif
  85        }
  86        /* Only size is always present, the rest may be missing in
  87         * long filename pseudo file. Thus we decode the rest
  88         * after dealing with long filename pseudo file.
  89         */
  90        typed->mode = read_num(ar.formatted.mode, 8);
  91        typed->mtime = read_num(ar.formatted.date, 10);
  92        typed->uid = read_num(ar.formatted.uid, 10);
  93        typed->gid = read_num(ar.formatted.gid, 10);
  94
  95#if ENABLE_FEATURE_AR_LONG_FILENAMES
  96        if (ar.formatted.name[0] == '/') {
  97                unsigned long_offset;
  98
  99                /* The number after the '/' indicates the offset in the ar data section
 100                 * (saved in ar_long_names) that conatains the real filename */
 101                long_offset = read_num(&ar.formatted.name[1], 10);
 102                if (long_offset >= ar_long_name_size) {
 103                        bb_error_msg_and_die("can't resolve long filename");
 104                }
 105                typed->name = xstrdup(ar_long_names + long_offset);
 106        } else
 107#endif
 108        {
 109                /* short filenames */
 110                typed->name = xstrndup(ar.formatted.name, 16);
 111        }
 112
 113        typed->name[strcspn(typed->name, " /")] = '\0';
 114
 115        if (archive_handle->filter(archive_handle) == EXIT_SUCCESS) {
 116                archive_handle->action_header(typed);
 117#if ENABLE_DPKG || ENABLE_DPKG_DEB
 118                if (archive_handle->dpkg__sub_archive) {
 119                        while (archive_handle->dpkg__action_data_subarchive(archive_handle->dpkg__sub_archive) == EXIT_SUCCESS)
 120                                continue;
 121                } else
 122#endif
 123                        archive_handle->action_data(archive_handle);
 124        } else {
 125                data_skip(archive_handle);
 126        }
 127
 128        archive_handle->offset += typed->size;
 129        /* Set the file pointer to the correct spot, we may have been reading a compressed file */
 130        lseek(archive_handle->src_fd, archive_handle->offset, SEEK_SET);
 131
 132        return EXIT_SUCCESS;
 133}
 134