libarchive: add a function to unpack embedded data

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@pobox.com>
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
This commit is contained in:
Ron Yorston 2018-11-02 14:14:31 +01:00 committed by Denys Vlasenko
parent 0df289f427
commit c339c7f7b3
4 changed files with 54 additions and 99 deletions

View File

@ -107,7 +107,7 @@ struct bunzip_data {
uint8_t selectors[32768]; /* nSelectors=15 bits */ uint8_t selectors[32768]; /* nSelectors=15 bits */
struct group_data groups[MAX_GROUPS]; /* Huffman coding tables */ 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 /* 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. in outbuf. IOW: on EOF returns len ("all bytes are not filled"), not 0.
(Why? This allows to get rid of one local variable) (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; const uint32_t *dbuf;
int pos, current, previous; 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() /* 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 should work for NOFORK applets too, we must be extremely careful to not leak
any allocations! */ any allocations! */
int FAST_FUNC start_bunzip( static int FAST_FUNC start_bunzip(
void *jmpbuf, void *jmpbuf,
bunzip_data **bdp, bunzip_data **bdp,
int in_fd, int in_fd,
@ -759,7 +759,7 @@ int FAST_FUNC start_bunzip(
return RETVAL_OK; 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->dbuf);
free(bd); free(bd);
@ -847,6 +847,36 @@ unpack_bz2_stream(transformer_state_t *xstate)
return i ? i : IF_DESKTOP(total_written) + 0; return i ? i : IF_DESKTOP(total_written) + 0;
} }
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 #ifdef TESTING
static char *const bunzip_errors[] = { static char *const bunzip_errors[] = {

View File

@ -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; 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: */ /* A bit of bunzip2 internals are exposed for compressed help support: */
typedef struct bunzip_data bunzip_data; char *unpack_bz2_data(const char *packed, int packed_len, int unpacked_len) FAST_FUNC;
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;
/* Meaning and direction (input/output) of the fields are transformer-specific */ /* Meaning and direction (input/output) of the fields are transformer-specific */
typedef struct transformer_state_t { typedef struct transformer_state_t {

View File

@ -107,34 +107,8 @@ static const char usage_messages[] ALIGN1 = UNPACKED_USAGE;
static const char packed_usage[] ALIGN1 = { PACKED_USAGE }; static const char packed_usage[] ALIGN1 = { PACKED_USAGE };
# include "bb_archive.h" # include "bb_archive.h"
static const char *unpack_usage_messages(void) # define unpack_usage_messages() \
{ unpack_bz2_data(packed_usage, sizeof(packed_usage), sizeof(UNPACKED_USAGE))
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 dealloc_usage_messages(s) free(s) # define dealloc_usage_messages(s) free(s)
#else #else
@ -152,6 +126,7 @@ void FAST_FUNC bb_show_usage(void)
/* Imagine that this applet is "true". Dont suck in printf! */ /* Imagine that this applet is "true". Dont suck in printf! */
const char *usage_string = unpack_usage_messages(); const char *usage_string = unpack_usage_messages();
if (usage_string) {
if (*usage_string == '\b') { if (*usage_string == '\b') {
full_write2_str("No help available.\n\n"); full_write2_str("No help available.\n\n");
} else { } else {
@ -161,12 +136,13 @@ void FAST_FUNC bb_show_usage(void)
} }
if (ENABLE_FEATURE_CLEAN_UP) if (ENABLE_FEATURE_CLEAN_UP)
dealloc_usage_messages((char*)usage_string); dealloc_usage_messages((char*)usage_string);
}
#else #else
const char *p; const char *p;
const char *usage_string = p = unpack_usage_messages(); const char *usage_string = p = unpack_usage_messages();
int ap = find_applet_by_name(applet_name); int ap = find_applet_by_name(applet_name);
if (ap < 0) /* never happens, paranoia */ if (ap < 0 || usage_string == NULL)
xfunc_die(); xfunc_die();
while (ap) { while (ap) {
while (*p++) continue; 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 */ 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 char* FAST_FUNC
get_script_content(unsigned n) get_script_content(unsigned n)
{ {
char *t = unpack_scripts(); char *t = unpack_bz2_data(packed_scripts, sizeof(packed_scripts),
UNPACKED_SCRIPTS_LENGTH);
if (t) { if (t) {
while (n != 0) { while (n != 0) {
while (*t++ != '\0') while (*t++ != '\0')

View File

@ -43,30 +43,11 @@ int bbconfig_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
int bbconfig_main(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) int bbconfig_main(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
{ {
#if ENABLE_FEATURE_COMPRESS_BBCONFIG #if ENABLE_FEATURE_COMPRESS_BBCONFIG
bunzip_data *bd; const char *outbuf = unpack_bz2_data(bbconfig_config_bz2,
int i; sizeof(bbconfig_config_bz2), sizeof(bbconfig_config));
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) { if (outbuf) {
read_bunzip(bd, outbuf, sizeof(bbconfig_config));
full_write1_str(outbuf); full_write1_str(outbuf);
} }
}
#else #else
full_write1_str(bbconfig_config); full_write1_str(bbconfig_config);
#endif #endif