From 27653adc8b7ebe44bd357511de53d0c14eef0894 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Thu, 6 May 2010 14:19:19 +0000 Subject: [PATCH] rpm: code shrink. Now uses open_zipped's logic (factored out into setup_unzip_on_fd()) function old new delta setup_unzip_on_fd - 80 +80 open_zipped 176 113 -63 rpm_main 1672 1355 -317 ------------------------------------------------------------------------------ (add/remove: 1/0 grow/shrink: 0/2 up/down: 80/-380) Total: -300 bytes Signed-off-by: Denys Vlasenko --- archival/rpm.c | 97 +++++++++++++++------------------------------ archival/rpm.h | 38 ++++++++++++++++++ archival/rpm2cpio.c | 69 +++++++++++++------------------- include/libbb.h | 9 +++++ libbb/read.c | 97 +++++++++++++++++++++++++-------------------- 5 files changed, 161 insertions(+), 149 deletions(-) create mode 100644 archival/rpm.h diff --git a/archival/rpm.c b/archival/rpm.c index 6c1e341cd..77679c275 100644 --- a/archival/rpm.c +++ b/archival/rpm.c @@ -9,8 +9,8 @@ #include "libbb.h" #include "unarchive.h" +#include "rpm.h" -#define RPM_HEADER_MAGIC "\216\255\350" #define RPM_CHAR_TYPE 1 #define RPM_INT8_TYPE 2 #define RPM_INT16_TYPE 3 @@ -46,6 +46,7 @@ #define TAG_DIRINDEXES 1116 #define TAG_BASENAMES 1117 #define TAG_DIRNAMES 1118 + #define RPMFILE_CONFIG (1 << 0) #define RPMFILE_DOC (1 << 1) @@ -147,8 +148,14 @@ int rpm_main(int argc, char **argv) time_t bdate_time; struct tm *bdate_ptm; char bdatestring[50]; - printf("Name : %-29sRelocations: %s\n", rpm_getstr(TAG_NAME, 0), rpm_getstr(TAG_PREFIXS, 0) ? rpm_getstr(TAG_PREFIXS, 0) : "(not relocateable)"); - printf("Version : %-34sVendor: %s\n", rpm_getstr(TAG_VERSION, 0), rpm_getstr(TAG_VENDOR, 0) ? rpm_getstr(TAG_VENDOR, 0) : "(none)"); + const char *p; + + p = rpm_getstr(TAG_PREFIXS, 0); + if (!p) p = "(not relocateable)"; + printf("Name : %-29sRelocations: %s\n", rpm_getstr(TAG_NAME, 0), p); + p = rpm_getstr(TAG_VENDOR, 0); + if (!p) p = "(none)"; + printf("Version : %-34sVendor: %s\n", rpm_getstr(TAG_VERSION, 0), p); bdate_time = rpm_getint(TAG_BUILDTIME, 0); bdate_ptm = localtime(&bdate_time); strftime(bdatestring, 50, "%a %d %b %Y %T %Z", bdate_ptm); @@ -190,20 +197,15 @@ int rpm_main(int argc, char **argv) static void extract_cpio_gz(int fd) { archive_handle_t *archive_handle; - unsigned char magic[2]; -#if BB_MMU - IF_DESKTOP(long long) int FAST_FUNC (*xformer)(int src_fd, int dst_fd); - enum { xformer_prog = 0 }; -#else - enum { xformer = 0 }; - const char *xformer_prog; -#endif /* Initialize */ archive_handle = init_handle(); archive_handle->seek = seek_by_read; - //archive_handle->action_header = header_list; archive_handle->action_data = data_extract_all; +#if 0 /* For testing (rpm -i only lists the files in internal cpio): */ + archive_handle->action_header = header_list; + archive_handle->action_data = data_skip; +#endif archive_handle->ah_flags = ARCHIVE_RESTORE_DATE | ARCHIVE_CREATE_LEADING_DIRS /* compat: overwrite existing files. * try "rpm -i foo.src.rpm" few times in a row - @@ -213,46 +215,15 @@ static void extract_cpio_gz(int fd) archive_handle->src_fd = fd; /*archive_handle->offset = 0; - init_handle() did it */ -// TODO: open_zipped does the same - - xread(archive_handle->src_fd, &magic, 2); -#if BB_MMU - xformer = unpack_gz_stream; -#else - xformer_prog = "gunzip"; -#endif - if (magic[0] != 0x1f || magic[1] != 0x8b) { - if (!ENABLE_FEATURE_SEAMLESS_BZ2 - || magic[0] != 'B' || magic[1] != 'Z' - ) { - bb_error_msg_and_die("no gzip" - IF_FEATURE_SEAMLESS_BZ2("/bzip2") - " magic"); - } -#if BB_MMU - xformer = unpack_bz2_stream; -#else - xformer_prog = "bunzip2"; -#endif - } else { -#if !BB_MMU - /* NOMMU version of open_transformer execs an external unzipper that should - * have the file position at the start of the file */ - xlseek(archive_handle->src_fd, 0, SEEK_SET); -#endif - } - xchdir("/"); /* Install RPM's to root */ - open_transformer(archive_handle->src_fd, xformer, xformer_prog); - archive_handle->offset = 0; + setup_unzip_on_fd(archive_handle->src_fd /*, fail_if_not_detected: 1*/); while (get_header_cpio(archive_handle) == EXIT_SUCCESS) continue; } - static rpm_index **rpm_gettags(int fd, int *num_tags) { - /* We should never need mode than 200, and realloc later */ + /* We should never need more than 200 (shrink via realloc later) */ rpm_index **tags = xzalloc(200 * sizeof(tags[0])); int pass, tagindex = 0; @@ -260,27 +231,16 @@ static rpm_index **rpm_gettags(int fd, int *num_tags) /* 1st pass is the signature headers, 2nd is the main stuff */ for (pass = 0; pass < 2; pass++) { - struct { - char magic[3]; /* 3 byte magic: 0x8e 0xad 0xe8 */ - uint8_t version; /* 1 byte version number */ - uint32_t reserved; /* 4 bytes reserved */ - uint32_t entries; /* Number of entries in header (4 bytes) */ - uint32_t size; /* Size of store (4 bytes) */ - } header; - struct BUG_header { - char BUG_header[sizeof(header) == 16 ? 1 : -1]; - }; + struct rpm_header header; rpm_index *tmpindex; int storepos; xread(fd, &header, sizeof(header)); - if (strncmp((char *) &header.magic, RPM_HEADER_MAGIC, 3) != 0) - return NULL; /* Invalid magic */ - if (header.version != 1) - return NULL; /* This program only supports v1 headers */ + if (header.magic_and_ver != htonl(RPM_HEADER_MAGICnVER)) + return NULL; /* Invalid magic, or not version 1 */ header.size = ntohl(header.size); header.entries = ntohl(header.entries); - storepos = xlseek(fd,0,SEEK_CUR) + header.entries * 16; + storepos = xlseek(fd, 0, SEEK_CUR) + header.entries * 16; while (header.entries--) { tmpindex = tags[tagindex++] = xmalloc(sizeof(*tmpindex)); @@ -292,14 +252,16 @@ static rpm_index **rpm_gettags(int fd, int *num_tags) if (pass == 0) tmpindex->tag -= 743; } - xlseek(fd, header.size, SEEK_CUR); /* Seek past store */ + storepos = xlseek(fd, header.size, SEEK_CUR); /* Seek past store */ /* Skip padding to 8 byte boundary after reading signature headers */ if (pass == 0) - xlseek(fd, (8 - (xlseek(fd,0,SEEK_CUR) % 8)) % 8, SEEK_CUR); + xlseek(fd, (-storepos) & 0x7, SEEK_CUR); } - tags = xrealloc(tags, tagindex * sizeof(tags[0])); /* realloc tags to save space */ + /* realloc tags to save space */ + tags = xrealloc(tags, tagindex * sizeof(tags[0])); *num_tags = tagindex; - return tags; /* All done, leave the file at the start of the gzipped cpio archive */ + /* All done, leave the file at the start of the gzipped cpio archive */ + return tags; } static int bsearch_rpmtag(const void *key, const void *item) @@ -324,10 +286,13 @@ static char *rpm_getstr(int tag, int itemindex) found = bsearch(&tag, mytags, tagcount, sizeof(struct rpmtag *), bsearch_rpmtag); if (!found || itemindex >= found[0]->count) return NULL; - if (found[0]->type == RPM_STRING_TYPE || found[0]->type == RPM_I18NSTRING_TYPE || found[0]->type == RPM_STRING_ARRAY_TYPE) { + if (found[0]->type == RPM_STRING_TYPE + || found[0]->type == RPM_I18NSTRING_TYPE + || found[0]->type == RPM_STRING_ARRAY_TYPE + ) { int n; char *tmpstr = (char *) map + found[0]->offset; - for (n=0; n < itemindex; n++) + for (n = 0; n < itemindex; n++) tmpstr = tmpstr + strlen(tmpstr) + 1; return tmpstr; } diff --git a/archival/rpm.h b/archival/rpm.h new file mode 100644 index 000000000..f7c6fc2fa --- /dev/null +++ b/archival/rpm.h @@ -0,0 +1,38 @@ +/* vi: set sw=4 ts=4: */ +/* + * RPM structs and consts + * + * Copyright (C) 2001 by Laurence Anderson + * + * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + */ + +/* RPM file starts with this struct: */ +struct rpm_lead { + uint32_t magic; + uint8_t major, minor; + uint16_t type; + uint16_t archnum; + char name[66]; + uint16_t osnum; + uint16_t signature_type; + char reserved[16]; +}; +struct BUG_rpm_lead { + char bug[sizeof(struct rpm_lead) == 96 ? 1 : -1]; +}; +#define RPM_LEAD_MAGIC 0xedabeedb +#define RPM_LEAD_MAGIC_STR "\355\253\356\333" + +/* Then follows the header: */ +struct rpm_header { + uint32_t magic_and_ver; /* 3 byte magic: 0x8e 0xad 0xe8; 1 byte version: 0x01 */ + uint32_t reserved; /* 4 bytes reserved */ + uint32_t entries; /* Number of entries in header (4 bytes) */ + uint32_t size; /* Size of store (4 bytes) */ +}; +struct BUG_rpm_header { + char bug[sizeof(struct rpm_header) == 16 ? 1 : -1]; +}; +#define RPM_HEADER_MAGICnVER 0x8eade801 +#define RPM_HEADER_MAGIC_STR "\216\255\350" diff --git a/archival/rpm2cpio.c b/archival/rpm2cpio.c index 5403aee02..4ed5b023b 100644 --- a/archival/rpm2cpio.c +++ b/archival/rpm2cpio.c @@ -8,30 +8,7 @@ */ #include "libbb.h" #include "unarchive.h" - -#define RPM_MAGIC 0xedabeedb -#define RPM_MAGIC_STR "\355\253\356\333" - -struct rpm_lead { - uint32_t magic; - uint8_t major, minor; - uint16_t type; - uint16_t archnum; - char name[66]; - uint16_t osnum; - uint16_t signature_type; - char reserved[16]; -}; - -#define RPM_HEADER_MAGICnVER 0x8eade801 -#define RPM_HEADER_MAGIC_STR "\216\255\350" - -struct rpm_header { - uint32_t magic_and_ver; /* 3 byte magic: 0x8e 0xad 0xe8; 1 byte version */ - uint32_t reserved; /* 4 bytes reserved */ - uint32_t entries; /* Number of entries in header (4 bytes) */ - uint32_t size; /* Size of store (4 bytes) */ -}; +#include "rpm.h" enum { rpm_fd = STDIN_FILENO }; @@ -65,8 +42,6 @@ int rpm2cpio_main(int argc UNUSED_PARAM, char **argv) { struct rpm_lead lead; unsigned pos; - unsigned char magic[2]; - IF_DESKTOP(long long) int FAST_FUNC (*unpack)(int src_fd, int dst_fd); if (argv[1]) { xmove_fd(xopen(argv[1], O_RDONLY), rpm_fd); @@ -74,33 +49,45 @@ int rpm2cpio_main(int argc UNUSED_PARAM, char **argv) xread(rpm_fd, &lead, sizeof(lead)); /* Just check the magic, the rest is irrelevant */ - if (lead.magic != htonl(RPM_MAGIC)) { + if (lead.magic != htonl(RPM_LEAD_MAGIC)) { bb_error_msg_and_die("invalid RPM magic"); } /* Skip the signature header, align to 8 bytes */ pos = skip_header(); - seek_by_jump(rpm_fd, (8 - pos) & 7); + seek_by_jump(rpm_fd, (-(int)pos) & 7); /* Skip the main header */ skip_header(); - xread(rpm_fd, &magic, 2); - unpack = unpack_gz_stream; - if (magic[0] != 0x1f || magic[1] != 0x8b) { - if (!ENABLE_FEATURE_SEAMLESS_BZ2 - || magic[0] != 'B' || magic[1] != 'Z' - ) { - bb_error_msg_and_die("invalid gzip" - IF_FEATURE_SEAMLESS_BZ2("/bzip2") - " magic"); +#if 0 + /* This works, but doesn't report uncompress errors (they happen in child) */ + setup_unzip_on_fd(rpm_fd /*fail_if_not_detected: 1*/); + if (bb_copyfd_eof(rpm_fd, STDOUT_FILENO) < 0) + bb_error_msg_and_die("error unpacking"); +#else + /* BLOAT */ + { + unsigned char magic[2]; + IF_DESKTOP(long long) int FAST_FUNC (*unpack)(int src_fd, int dst_fd); + + xread(rpm_fd, &magic, 2); + unpack = unpack_gz_stream; + if (magic[0] != 0x1f || magic[1] != 0x8b) { + if (!ENABLE_FEATURE_SEAMLESS_BZ2 + || magic[0] != 'B' || magic[1] != 'Z' + ) { + bb_error_msg_and_die("invalid gzip" + IF_FEATURE_SEAMLESS_BZ2("/bzip2") + " magic"); + } + unpack = unpack_bz2_stream; } - unpack = unpack_bz2_stream; - } - if (unpack(rpm_fd, STDOUT_FILENO) < 0) { - bb_error_msg_and_die("error unpacking"); + if (unpack(rpm_fd, STDOUT_FILENO) < 0) + bb_error_msg_and_die("error unpacking"); } +#endif if (ENABLE_FEATURE_CLEAN_UP) { close(rpm_fd); diff --git a/include/libbb.h b/include/libbb.h index 976120e72..2f67c7f72 100644 --- a/include/libbb.h +++ b/include/libbb.h @@ -651,6 +651,15 @@ extern char *xmalloc_reads(int fd, char *pfx, size_t *maxsz_p) FAST_FUNC; extern void *xmalloc_read(int fd, size_t *maxsz_p) FAST_FUNC RETURNS_MALLOC; /* Returns NULL if file can't be opened (default max size: INT_MAX - 4095) */ extern void *xmalloc_open_read_close(const char *filename, size_t *maxsz_p) FAST_FUNC RETURNS_MALLOC; +/* Autodetects gzip/bzip2 formats. fd may be in the middle of the file! */ +#if ENABLE_FEATURE_SEAMLESS_LZMA \ + || ENABLE_FEATURE_SEAMLESS_BZ2 \ + || ENABLE_FEATURE_SEAMLESS_GZ \ + /* || ENABLE_FEATURE_SEAMLESS_Z */ +extern int setup_unzip_on_fd(int fd /*, int fail_if_not_detected*/) FAST_FUNC; +#else +# define setup_unzip_on_fd(...) ((void)0) +#endif /* Autodetects .gz etc */ extern int open_zipped(const char *fname) FAST_FUNC; extern void *xmalloc_open_zipped_read_close(const char *fname, size_t *maxsz_p) FAST_FUNC RETURNS_MALLOC; diff --git a/libbb/read.c b/libbb/read.c index 06ce29718..503216eb5 100644 --- a/libbb/read.c +++ b/libbb/read.c @@ -6,7 +6,6 @@ * * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. */ - #include "libbb.h" #define ZIPPED (ENABLE_FEATURE_SEAMLESS_LZMA \ @@ -16,7 +15,7 @@ ) #if ZIPPED -#include "unarchive.h" +# include "unarchive.h" #endif ssize_t FAST_FUNC safe_read(int fd, void *buf, size_t count) @@ -306,14 +305,11 @@ void* FAST_FUNC xmalloc_xopen_read_close(const char *filename, size_t *maxsz_p) return buf; } -int FAST_FUNC open_zipped(const char *fname) +#if ZIPPED +int FAST_FUNC setup_unzip_on_fd(int fd /*, int fail_if_not_detected*/) { -#if !ZIPPED - return open(fname, O_RDONLY); -#else + const int fail_if_not_detected = 1; unsigned char magic[2]; - char *sfx; - int fd; #if BB_MMU IF_DESKTOP(long long) int FAST_FUNC (*xformer)(int src_fd, int dst_fd); enum { xformer_prog = 0 }; @@ -322,6 +318,56 @@ int FAST_FUNC open_zipped(const char *fname) const char *xformer_prog; #endif + /* .gz and .bz2 both have 2-byte signature, and their + * unpack_XXX_stream wants this header skipped. */ + xread(fd, &magic, 2); +#if ENABLE_FEATURE_SEAMLESS_GZ +# if BB_MMU + xformer = unpack_gz_stream; +# else + xformer_prog = "gunzip"; +# endif +#endif + if (!ENABLE_FEATURE_SEAMLESS_GZ + || magic[0] != 0x1f || magic[1] != 0x8b + ) { + if (!ENABLE_FEATURE_SEAMLESS_BZ2 + || magic[0] != 'B' || magic[1] != 'Z' + ) { + if (fail_if_not_detected) + bb_error_msg_and_die("no gzip" + IF_FEATURE_SEAMLESS_BZ2("/bzip2") + " magic"); + xlseek(fd, -2, SEEK_CUR); + return fd; + } +#if BB_MMU + xformer = unpack_bz2_stream; +#else + xformer_prog = "bunzip2"; +#endif + } else { +#if !BB_MMU + /* NOMMU version of open_transformer execs + * an external unzipper that wants + * file position at the start of the file */ + xlseek(fd, -2, SEEK_CUR); +#endif + } + open_transformer(fd, xformer, xformer_prog); + + return fd; +} +#endif /* ZIPPED */ + +int FAST_FUNC open_zipped(const char *fname) +{ +#if !ZIPPED + return open(fname, O_RDONLY); +#else + char *sfx; + int fd; + fd = open(fname, O_RDONLY); if (fd < 0) return fd; @@ -335,40 +381,7 @@ int FAST_FUNC open_zipped(const char *fname) if ((ENABLE_FEATURE_SEAMLESS_GZ && strcmp(sfx, ".gz") == 0) || (ENABLE_FEATURE_SEAMLESS_BZ2 && strcmp(sfx, ".bz2") == 0) ) { - /* .gz and .bz2 both have 2-byte signature, and their - * unpack_XXX_stream wants this header skipped. */ - xread(fd, &magic, 2); -#if ENABLE_FEATURE_SEAMLESS_GZ -#if BB_MMU - xformer = unpack_gz_stream; -#else - xformer_prog = "gunzip"; -#endif -#endif - if (!ENABLE_FEATURE_SEAMLESS_GZ - || magic[0] != 0x1f || magic[1] != 0x8b - ) { - if (!ENABLE_FEATURE_SEAMLESS_BZ2 - || magic[0] != 'B' || magic[1] != 'Z' - ) { - bb_error_msg_and_die("no gzip" - IF_FEATURE_SEAMLESS_BZ2("/bzip2") - " magic"); - } -#if BB_MMU - xformer = unpack_bz2_stream; -#else - xformer_prog = "bunzip2"; -#endif - } else { -#if !BB_MMU - /* NOMMU version of open_transformer execs - * an external unzipper that wants - * file position at the start of the file */ - xlseek(fd, 0, SEEK_SET); -#endif - } - open_transformer(fd, xformer, xformer_prog); + setup_unzip_on_fd(fd /*, fail_if_not_detected: 1*/); } } -- 2.25.1