[git commit master] rpm: code shrink. Now uses open_zipped's logic (factored out into setup_unzip_on_fd())

Denys Vlasenko vda.linux at googlemail.com
Thu May 6 14:19:19 UTC 2010


commit: http://git.busybox.net/busybox/commit/?id=27653adc8b7ebe44bd357511de53d0c14eef0894
branch: http://git.busybox.net/busybox/commit/?id=refs/heads/master

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 at googlemail.com>
---
 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 6c1e341..77679c2 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 0000000..f7c6fc2
--- /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 5403aee..4ed5b02 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 976120e..2f67c7f 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 06ce297..503216e 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*/);
 		}
 	}
 
-- 
1.6.3.3



More information about the busybox-cvs mailing list