[PATCH] libarchive: add a function to unpack embedded data

Ron Yorston rmy at pobox.com
Fri Nov 2 08:34:16 UTC 2018


Similar code to unpack embedded data is used to decompress usage
messages, embedded scripts and the config file (in the non-default
bbconfig applet).

Moving this code to a common function reduces the size of the default
build and hides more of the internals of libarchive.

function                                             old     new   delta
unpack_bz2_data                                        -     135    +135
bb_show_usage                                        137     157     +20
get_script_content                                    32      47     +15
unpack_scripts                                       119       -    -119
unpack_usage_messages                                124       -    -124
------------------------------------------------------------------------------
(add/remove: 1/2 grow/shrink: 2/0 up/down: 170/-243)          Total: -73 bytes

Signed-off-by: Ron Yorston <rmy at pobox.com>
---
 archival/libarchive/decompress_bunzip2.c | 38 +++++++++--
 include/bb_archive.h                     |  7 +-
 libbb/appletlib.c                        | 81 +++++-------------------
 miscutils/bbconfig.c                     | 27 ++------
 4 files changed, 54 insertions(+), 99 deletions(-)

diff --git a/archival/libarchive/decompress_bunzip2.c b/archival/libarchive/decompress_bunzip2.c
index 7ef4e035f..3deb213a8 100644
--- a/archival/libarchive/decompress_bunzip2.c
+++ b/archival/libarchive/decompress_bunzip2.c
@@ -107,7 +107,7 @@ struct bunzip_data {
 	uint8_t selectors[32768];  /* nSelectors=15 bits */
 	struct group_data groups[MAX_GROUPS];  /* Huffman coding tables */
 };
-/* typedef struct bunzip_data bunzip_data; -- done in .h file */
+typedef struct bunzip_data bunzip_data;
 
 
 /* Return the next nnn bits of input.  All reads from the compressed input
@@ -575,7 +575,7 @@ static int get_next_block(bunzip_data *bd)
    in outbuf. IOW: on EOF returns len ("all bytes are not filled"), not 0.
    (Why? This allows to get rid of one local variable)
 */
-int FAST_FUNC read_bunzip(bunzip_data *bd, char *outbuf, int len)
+static int FAST_FUNC read_bunzip(bunzip_data *bd, char *outbuf, int len)
 {
 	const uint32_t *dbuf;
 	int pos, current, previous;
@@ -699,7 +699,7 @@ int FAST_FUNC read_bunzip(bunzip_data *bd, char *outbuf, int len)
 /* Because bunzip2 is used for help text unpacking, and because bb_show_usage()
    should work for NOFORK applets too, we must be extremely careful to not leak
    any allocations! */
-int FAST_FUNC start_bunzip(
+static int FAST_FUNC start_bunzip(
 		void *jmpbuf,
 		bunzip_data **bdp,
 		int in_fd,
@@ -759,7 +759,7 @@ int FAST_FUNC start_bunzip(
 	return RETVAL_OK;
 }
 
-void FAST_FUNC dealloc_bunzip(bunzip_data *bd)
+static void FAST_FUNC dealloc_bunzip(bunzip_data *bd)
 {
 	free(bd->dbuf);
 	free(bd);
@@ -847,6 +847,36 @@ unpack_bz2_stream(transformer_state_t *xstate)
 	return i ? i : IF_DESKTOP(total_written) + 0;
 }
 
+const char * FAST_FUNC
+unpack_bz2_data(const char *packed, int packed_len, int unpacked_len)
+{
+	char *outbuf = NULL;
+	bunzip_data *bd;
+	int i;
+	jmp_buf jmpbuf;
+
+	/* Setup for I/O error handling via longjmp */
+	i = setjmp(jmpbuf);
+	if (i == 0) {
+		i = start_bunzip(&jmpbuf,
+			&bd,
+			/* src_fd: */ -1,
+			/* inbuf:  */ packed,
+			/* len:    */ packed_len
+		);
+	}
+	/* read_bunzip can longjmp and end up here with i != 0
+	 * on read data errors! Not trivial */
+	if (i == 0) {
+		/* Cannot use xmalloc: will leak bd in NOFORK case! */
+		outbuf = malloc_or_warn(unpacked_len);
+		if (outbuf)
+			read_bunzip(bd, outbuf, unpacked_len);
+	}
+	dealloc_bunzip(bd);
+	return outbuf;
+}
+
 #ifdef TESTING
 
 static char *const bunzip_errors[] = {
diff --git a/include/bb_archive.h b/include/bb_archive.h
index d2022336b..0dbe17496 100644
--- a/include/bb_archive.h
+++ b/include/bb_archive.h
@@ -214,12 +214,7 @@ const llist_t *find_list_entry(const llist_t *list, const char *filename) FAST_F
 const llist_t *find_list_entry2(const llist_t *list, const char *filename) FAST_FUNC;
 
 /* A bit of bunzip2 internals are exposed for compressed help support: */
-typedef struct bunzip_data bunzip_data;
-int start_bunzip(void *, bunzip_data **bdp, int in_fd, const void *inbuf, int len) FAST_FUNC;
-/* NB: read_bunzip returns < 0 on error, or the number of *unfilled* bytes
- * in outbuf. IOW: on EOF returns len ("all bytes are not filled"), not 0: */
-int read_bunzip(bunzip_data *bd, char *outbuf, int len) FAST_FUNC;
-void dealloc_bunzip(bunzip_data *bd) FAST_FUNC;
+const char *unpack_bz2_data(const char *packed, int packed_len, int unpacked_len) FAST_FUNC;
 
 /* Meaning and direction (input/output) of the fields are transformer-specific */
 typedef struct transformer_state_t {
diff --git a/libbb/appletlib.c b/libbb/appletlib.c
index d48b2ea60..6dfaf1f41 100644
--- a/libbb/appletlib.c
+++ b/libbb/appletlib.c
@@ -107,34 +107,8 @@ static const char usage_messages[] ALIGN1 = UNPACKED_USAGE;
 
 static const char packed_usage[] ALIGN1 = { PACKED_USAGE };
 # include "bb_archive.h"
-static const char *unpack_usage_messages(void)
-{
-	char *outbuf = NULL;
-	bunzip_data *bd;
-	int i;
-	jmp_buf jmpbuf;
-
-	/* Setup for I/O error handling via longjmp */
-	i = setjmp(jmpbuf);
-	if (i == 0) {
-		i = start_bunzip(&jmpbuf,
-			&bd,
-			/* src_fd: */ -1,
-			/* inbuf:  */ packed_usage,
-			/* len:    */ sizeof(packed_usage)
-		);
-	}
-	/* read_bunzip can longjmp and end up here with i != 0
-	 * on read data errors! Not trivial */
-	if (i == 0) {
-		/* Cannot use xmalloc: will leak bd in NOFORK case! */
-		outbuf = malloc_or_warn(sizeof(UNPACKED_USAGE));
-		if (outbuf)
-			read_bunzip(bd, outbuf, sizeof(UNPACKED_USAGE));
-	}
-	dealloc_bunzip(bd);
-	return outbuf;
-}
+# define unpack_usage_messages() \
+	unpack_bz2_data(packed_usage, sizeof(packed_usage), sizeof(UNPACKED_USAGE))
 # define dealloc_usage_messages(s) free(s)
 
 #else
@@ -152,21 +126,23 @@ void FAST_FUNC bb_show_usage(void)
 		/* Imagine that this applet is "true". Dont suck in printf! */
 		const char *usage_string = unpack_usage_messages();
 
-		if (*usage_string == '\b') {
-			full_write2_str("No help available.\n\n");
-		} else {
-			full_write2_str("Usage: "SINGLE_APPLET_STR" ");
-			full_write2_str(usage_string);
-			full_write2_str("\n\n");
+		if (usage_string) {
+			if (*usage_string == '\b') {
+				full_write2_str("No help available.\n\n");
+			} else {
+				full_write2_str("Usage: "SINGLE_APPLET_STR" ");
+				full_write2_str(usage_string);
+				full_write2_str("\n\n");
+			}
+			if (ENABLE_FEATURE_CLEAN_UP)
+				dealloc_usage_messages((char*)usage_string);
 		}
-		if (ENABLE_FEATURE_CLEAN_UP)
-			dealloc_usage_messages((char*)usage_string);
 #else
 		const char *p;
 		const char *usage_string = p = unpack_usage_messages();
 		int ap = find_applet_by_name(applet_name);
 
-		if (ap < 0) /* never happens, paranoia */
+		if (ap < 0 || usage_string == NULL)
 			xfunc_die();
 		while (ap) {
 			while (*p++) continue;
@@ -986,38 +962,11 @@ find_script_by_name(const char *name)
 	return -0x10000; /* make it so that NUM_APPLETS + <error> is still < 0 */
 }
 
-static char *
-unpack_scripts(void)
-{
-	char *outbuf = NULL;
-	bunzip_data *bd;
-	int i;
-	jmp_buf jmpbuf;
-
-	/* Setup for I/O error handling via longjmp */
-	i = setjmp(jmpbuf);
-	if (i == 0) {
-		i = start_bunzip(&jmpbuf,
-			&bd,
-			/* src_fd: */ -1,
-			/* inbuf:  */ packed_scripts,
-			/* len:    */ sizeof(packed_scripts)
-		);
-	}
-	/* read_bunzip can longjmp and end up here with i != 0
-	 * on read data errors! Not trivial */
-	if (i == 0) {
-		outbuf = xmalloc(UNPACKED_SCRIPTS_LENGTH);
-		read_bunzip(bd, outbuf, UNPACKED_SCRIPTS_LENGTH);
-	}
-	dealloc_bunzip(bd);
-	return outbuf;
-}
-
 char* FAST_FUNC
 get_script_content(unsigned n)
 {
-	char *t = unpack_scripts();
+	char *t = unpack_bz2_data(packed_scripts, sizeof(packed_scripts),
+					UNPACKED_SCRIPTS_LENGTH);
 	if (t) {
 		while (n != 0) {
 			while (*t++ != '\0')
diff --git a/miscutils/bbconfig.c b/miscutils/bbconfig.c
index 501349548..11698de94 100644
--- a/miscutils/bbconfig.c
+++ b/miscutils/bbconfig.c
@@ -43,29 +43,10 @@ int bbconfig_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
 int bbconfig_main(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
 {
 #if ENABLE_FEATURE_COMPRESS_BBCONFIG
-	bunzip_data *bd;
-	int i;
-	jmp_buf jmpbuf;
-
-	/* Setup for I/O error handling via longjmp */
-	i = setjmp(jmpbuf);
-	if (i == 0) {
-		i = start_bunzip(&jmpbuf,
-			&bd,
-			/* src_fd: */ -1,
-			/* inbuf:  */ bbconfig_config_bz2,
-			/* len:    */ sizeof(bbconfig_config_bz2)
-		);
-	}
-	/* read_bunzip can longjmp and end up here with i != 0
-	 * on read data errors! Not trivial */
-	if (i == 0) {
-		/* Cannot use xmalloc: will leak bd in NOFORK case! */
-		char *outbuf = malloc_or_warn(sizeof(bbconfig_config));
-		if (outbuf) {
-			read_bunzip(bd, outbuf, sizeof(bbconfig_config));
-			full_write1_str(outbuf);
-		}
+	const char *outbuf = unpack_bz2_data(bbconfig_config_bz2,
+					sizeof(bbconfig_config_bz2), sizeof(bbconfig_config));
+	if (outbuf) {
+		full_write1_str(outbuf);
 	}
 #else
 	full_write1_str(bbconfig_config);
-- 
2.19.1



More information about the busybox mailing list