rpm: code shrink. Now uses open_zipped's logic (factored out into setup_unzip_on_fd())
authorDenys Vlasenko <vda.linux@googlemail.com>
Thu, 6 May 2010 14:19:19 +0000 (14:19 +0000)
committerDenys Vlasenko <vda.linux@googlemail.com>
Thu, 6 May 2010 14:19:19 +0000 (14:19 +0000)
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 <vda.linux@googlemail.com>
archival/rpm.c
archival/rpm.h [new file with mode: 0644]
archival/rpm2cpio.c
include/libbb.h
libbb/read.c

index 6c1e341cdbfad41c44731a14c2e1030b27973c2c..77679c275f288ae4d4987621951ac02288e7f58e 100644 (file)
@@ -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 (file)
index 0000000..f7c6fc2
--- /dev/null
@@ -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"
index 5403aee0221eefacd3b39ef80c8cc8bf44aac333..4ed5b023be2147b9ffae5dd25aded81dfceec039 100644 (file)
@@ -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);
index 976120e7239b4bb6ed2b3159d4a74b0cd9a5e49d..2f67c7f7233d37e5124cffa421508f959f7fb085 100644 (file)
@@ -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;
index 06ce29718e9e5bb24219a01be9a67a2116074037..503216eb5a99399edc24fc28ff861824408612b4 100644 (file)
@@ -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*/);
                }
        }