From 756e95e7822182f0bb75fc33284123c9b73f3d8f Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Thu, 28 Oct 2010 19:10:46 +0200 Subject: ipcrm: small code shrink Signed-off-by: Denys Vlasenko --- util-linux/ipcrm.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/util-linux/ipcrm.c b/util-linux/ipcrm.c index 731216c06..e597ed637 100644 --- a/util-linux/ipcrm.c +++ b/util-linux/ipcrm.c @@ -40,7 +40,7 @@ typedef enum type_id { MSG } type_id; -static int remove_ids(type_id type, int argc, char **argv) +static int remove_ids(type_id type, char **argv) { unsigned long id; int nb_errors = 0; @@ -48,7 +48,7 @@ static int remove_ids(type_id type, int argc, char **argv) arg.val = 0; - while (argc) { + while (argv[0]) { id = bb_strtoul(argv[0], NULL, 10); if (errno || id > INT_MAX) { bb_error_msg("invalid id: %s", argv[0]); @@ -67,7 +67,6 @@ static int remove_ids(type_id type, int argc, char **argv) nb_errors++; } } - argc--; argv++; } @@ -109,7 +108,7 @@ int ipcrm_main(int argc, char **argv) else if (w == 'e') what = SEM; - if (remove_ids(what, argc-2, &argv[2])) + if (remove_ids(what, &argv[2])) fflush_stdout_and_exit(EXIT_FAILURE); printf("resource(s) deleted\n"); return 0; -- cgit v1.2.3-55-g6feb From b27d62af8bd83f482506271510bfa6e873b953ab Mon Sep 17 00:00:00 2001 From: Holger Blasum Date: Thu, 28 Oct 2010 20:37:05 +0200 Subject: update docs/new-applet-HOWTO.txt Signed-off-by: Holger Blasum Signed-off-by: Denys Vlasenko --- docs/new-applet-HOWTO.txt | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/docs/new-applet-HOWTO.txt b/docs/new-applet-HOWTO.txt index 2f237564d..8a825b998 100644 --- a/docs/new-applet-HOWTO.txt +++ b/docs/new-applet-HOWTO.txt @@ -99,14 +99,14 @@ int function(char *a) ----end example code------ Add .o in the right alphabetically sorted place -in libbb/Kbuild. You should look at the conditional part of -libbb/Kbuild aswell. +in libbb/Kbuild.src. You should look at the conditional part of +libbb/Kbuild.src as well. You should also try to find a suitable place in include/libbb.h for the function declaration. If not, add it somewhere anyway, with or without ifdefs to include or not. -You can look at libbb/Config.in and try to find out if the function is +You can look at libbb/Config.src and try to find out if the function is tunable and add it there if it is. @@ -118,11 +118,11 @@ Find the appropriate directory for your new applet. Make sure you find the appropriate places in the files, the applets are sorted alphabetically. -Add the applet to Kbuild in the chosen directory: +Add the applet to Kbuild.src in the chosen directory: lib-$(CONFIG_MU) += mu.o -Add the applet to Config.in in the chosen directory: +Add the applet to Config.src in the chosen directory: config MU bool "MU" @@ -134,7 +134,7 @@ config MU Usage String(s) --------------- -Next, add usage information for you applet to include/usage.h. +Next, add usage information for you applet to include/usage.src.h. This should look like the following: #define mu_trivial_usage \ @@ -149,17 +149,17 @@ This should look like the following: If your program supports flags, the flags should be mentioned on the first line (-[abcde]) and a detailed description of each flag should go in the mu_full_usage section, one flag per line. (Numerous examples of this -currently exist in usage.h.) +currently exist in usage.src.h.) Header Files ------------ -Next, add an entry to include/applets.h. Be *sure* to keep the list +Next, add an entry to include/applets.src.h. Be *sure* to keep the list in alphabetical order, or else it will break the binary-search lookup algorithm in busybox.c and the Gods of BusyBox smite you. Yea, verily: -Be sure to read the top of applets.h before adding your applet. +Be sure to read the top of applets.src.h before adding your applet. /* all programs above here are alphabetically "less than" 'mu' */ IF_MU(APPLET(mu, _BB_DIR_USR_BIN, _BB_SUID_DROP)) -- cgit v1.2.3-55-g6feb From 02788ac7e2a44eee889aa1005e89076f928e964a Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Thu, 28 Oct 2010 20:45:37 +0200 Subject: scripts: remove bitrotted scripts/individual Signed-off-by: Denys Vlasenko --- docs/new-applet-HOWTO.txt | 3 +- scripts/individual | 129 ---------------------------------------------- scripts/mkdiff_obj | 23 ++++++--- 3 files changed, 16 insertions(+), 139 deletions(-) delete mode 100755 scripts/individual diff --git a/docs/new-applet-HOWTO.txt b/docs/new-applet-HOWTO.txt index 8a825b998..bb29999cf 100644 --- a/docs/new-applet-HOWTO.txt +++ b/docs/new-applet-HOWTO.txt @@ -19,8 +19,7 @@ such as who you stole the code from and so forth. Also include the mini-GPL boilerplate. Be sure to name the main function _main instead of main. And be sure to put it in .c. Usage does not have to be taken care of by your applet. -Make sure to #include "libbb.h" as the first include file in your applet so -the bb_config.h and appropriate platform specific files are included properly. +Make sure to #include "libbb.h" as the first include file in your applet. For a new applet mu, here is the code that would go in mu.c: diff --git a/scripts/individual b/scripts/individual deleted file mode 100755 index e93ca5552..000000000 --- a/scripts/individual +++ /dev/null @@ -1,129 +0,0 @@ -#!/bin/sh - -# Compile individual versions of each busybox applet. - -if [ $# -eq 0 ] -then - -# Clear out the build directory. (Make clean should do this instead of here.) - -rm -rf build -mkdir build - -# Make our prerequisites. - -make busybox.links include/bb_config.h $(pwd)/{libbb/libbb.a,archival/libunarchive/libunarchive.a,coreutils/libcoreutils/libcoreutils.a,networking/libiproute/libiproute.a} - -else -# Could very well be that we want to build an individual applet but have no -# 'build' dir yet.. - -test -d ./build || mkdir build - -fi - -# About 3/5 of the applets build from one .c file (with the same name as the -# corresponding applet), and all it needs to link against. However, to build -# them all we need more than that. - -# Figure out which applets need extra libraries added to their command line. - -function substithing() -{ - if [ "${1/ $3 //}" != "$1" ] - then - echo $2 - fi -} - -function extra_libraries() -{ - # gzip needs gunzip.c (when gunzip is enabled, anyway). - substithing " gzip " "archival/gunzip.c archival/uncompress.c" "$1" - - # init needs init_shared.c - substithing " init " "init/init_shared.c" "$1" - - # ifconfig needs interface.c - substithing " ifconfig " "networking/interface.c" "$1" - - # Applets that need libunarchive.a - substithing " ar bunzip2 unlzma cpio dpkg gunzip rpm2cpio rpm tar uncompress unzip dpkg_deb gzip " "archival/libunarchive/libunarchive.a" "$1" - - # Applets that need libcoreutils.a - substithing " cp mv " "coreutils/libcoreutils/libcoreutils.a" "$1" - - # Applets that need libiproute.a - substithing " ip " "networking/libiproute/libiproute.a" "$1" - - # What needs -libm? - substithing " awk dc " "-lm" "$1" - - # What needs -lcrypt? - substithing " httpd vlock " "-lcrypt" "$1" -} - -# Query applets.h to figure out which applets need special treatment - -strange_names=`sed -rn -e 's/\#.*//' -e 's/.*APPLET_NOUSAGE\(([^,]*),([^,]*),.*/\1 \2/p' -e 's/.*APPLET_ODDNAME\(([^,]*),([^,]*),.*, *([^)]*).*/\1 \2@\3/p' include/applets.h` - -function bonkname() -{ - while [ $# -gt 0 ] - do - if [ "$APPLET" == "$1" ] - then - APPFILT="${2/@*/}" - if [ "${APPFILT}" == "$2" ] - then - HELPNAME='"nousage\n"' # These should be _fixed_. - else - HELPNAME="${2/*@/}"_full_usage - fi - break - fi - shift 2 - done -#echo APPLET=${APPLET} APPFILT=${APPFILT} HELPNAME=${HELPNAME} 2=${2} -} - -# Iterate through every name in busybox.links - -function buildit () -{ - export APPLET="$1" - export APPFILT=${APPLET} - export HELPNAME=${APPLET}_full_usage - - bonkname $strange_names - - j=`find archival console-tools coreutils debianutils editors findutils init loginutils miscutils modutils networking procps shell sysklogd util-linux -name "${APPFILT}.c"` - if [ -z "$j" ] - then - echo no file for $APPLET - else - echo "Building $APPLET" - gcc -Os -o build/$APPLET applets/individual.c $j \ - `extra_libraries $APPFILT` libbb/libbb.a -Iinclude \ - -DBUILD_INDIVIDUAL \ - '-Drun_applet_and_exit(...)' '-Dfind_applet_by_name(...)=0' \ - -DAPPLET_main=${APPFILT}_main -DAPPLET_full_usage=${HELPNAME} - if [ $? -ne 0 ]; - then - echo "Failed $APPLET" - fi - fi -} - -if [ $# -eq 0 ] -then - for APPLET in `sed 's .*/ ' busybox.links` - do - buildit "$APPLET" - done -else - buildit "$1" -fi - - -strip build/* diff --git a/scripts/mkdiff_obj b/scripts/mkdiff_obj index a6ec5e602..f783491af 100755 --- a/scripts/mkdiff_obj +++ b/scripts/mkdiff_obj @@ -1,28 +1,35 @@ #!/bin/sh +usage() { + echo "Usage: ${0##*/} DIR1 DIR2" + echo + echo "Compares all object files recursivelty found in DIR1 and DIR2." + echo "Prints diff of their disassembly." + echo + exit $1 +} + filter() { # sed removes " address: " prefixes which mess up diff sed $'s/^\\(\t*\\)[ ]*[0-9a-f][0-9a-f]*:[ \t]*/\\1/' \ | sed 's/__GI_//g' } -test -d "$1" || exit 1 -test -d "$2" || exit 1 +test -d "$1" || usage 1 +test -d "$2" || usage 1 { ( cd "$1" || exit 1 - find -name '*.o' -o -name '*.os' # -o -name '*.so' + find -name '*.o' # -o -name '*.os' # -o -name '*.so' ) ( cd "$2" || exit 1 - find -name '*.o' -o -name '*.os' # -o -name '*.so' + find -name '*.o' # -o -name '*.os' # -o -name '*.so' ) } | sed 's:^\./::' | sort | uniq | \ -tee LST | \ ( -IFS='' -while read -r oname; do +while IFS='' read -r oname; do if ! test -f "$1/$oname"; then echo "Only $2/$oname" continue @@ -34,6 +41,6 @@ while read -r oname; do diff -q -- "$1/$oname" "$2/$oname" >/dev/null && continue (cd "$1"; objdump -dr "$oname" | filter >"$oname.disasm") (cd "$2"; objdump -dr "$oname" | filter >"$oname.disasm") - diff -u "$1/$oname.disasm" "$2/$oname.disasm" + diff -u -- "$1/$oname.disasm" "$2/$oname.disasm" done ) -- cgit v1.2.3-55-g6feb From 7b18107384d950358e146d42bf02b391fab5ffd6 Mon Sep 17 00:00:00 2001 From: Marek Polacek Date: Thu, 28 Oct 2010 21:34:56 +0200 Subject: *: use _exit() in sighandlers; showkey: do not use exit-thru-sighandler While at it, make ESC sequences more readable; and removed check for isatty(stdin) in reset. Code shrink: text data bss dec hex filename 884771 936 17216 902923 dc70b busybox_old 884723 936 17216 902875 dc6db busybox_unstripped Signed-off-by: Marek Polacek Signed-off-by: Denys Vlasenko --- console-tools/reset.c | 12 ++++---- console-tools/resize.c | 2 +- console-tools/showkey.c | 73 ++++++++++++++++++++++--------------------------- libbb/lineedit.c | 20 ++++++++------ miscutils/conspy.c | 13 +++++---- miscutils/less.c | 14 ++++++---- miscutils/watchdog.c | 2 +- util-linux/more.c | 14 ++++++---- 8 files changed, 78 insertions(+), 72 deletions(-) diff --git a/console-tools/reset.c b/console-tools/reset.c index 7dffdea18..1806ce742 100644 --- a/console-tools/reset.c +++ b/console-tools/reset.c @@ -8,11 +8,13 @@ * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ -#include "libbb.h" - /* BTW, which "standard" package has this utility? It doesn't seem * to be ncurses, coreutils, console-tools... then what? */ +#include "libbb.h" + +#define ESC "\033" + #if ENABLE_STTY int stty_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; #endif @@ -26,15 +28,15 @@ int reset_main(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) /* no options, no getopt */ - if (isatty(STDIN_FILENO) && isatty(STDOUT_FILENO)) { + if (/*isatty(STDIN_FILENO) &&*/ isatty(STDOUT_FILENO)) { /* See 'man 4 console_codes' for details: * "ESC c" -- Reset * "ESC ( K" -- Select user mapping - * "ESC [ J" -- Erase to the end of screen * "ESC [ 0 m" -- Reset all display attributes + * "ESC [ J" -- Erase to the end of screen * "ESC [ ? 25 h" -- Make cursor visible */ - printf("\033c\033(K\033[J\033[0m\033[?25h"); + printf(ESC"c" ESC"(K" ESC"[0m" ESC"[J" ESC"[?25h"); /* http://bugs.busybox.net/view.php?id=1414: * people want it to reset echo etc: */ #if ENABLE_STTY diff --git a/console-tools/resize.c b/console-tools/resize.c index 12e50a116..fdfe2a6a0 100644 --- a/console-tools/resize.c +++ b/console-tools/resize.c @@ -17,7 +17,7 @@ static void onintr(int sig UNUSED_PARAM) { tcsetattr(STDERR_FILENO, TCSANOW, old_termios_p); - exit(EXIT_FAILURE); + _exit(EXIT_FAILURE); } int resize_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; diff --git a/console-tools/showkey.c b/console-tools/showkey.c index 149ea6465..b29c84d6a 100644 --- a/console-tools/showkey.c +++ b/console-tools/showkey.c @@ -10,27 +10,7 @@ #include "libbb.h" #include -// set raw tty mode -// also used by microcom -// libbb candidates? -static void xget1(struct termios *t, struct termios *oldt) -{ - tcgetattr(STDIN_FILENO, oldt); - *t = *oldt; - cfmakeraw(t); -} - -static void xset1(struct termios *tio) -{ - int ret = tcsetattr(STDIN_FILENO, TCSAFLUSH, tio); - if (ret) { - bb_perror_msg("can't tcsetattr for stdin"); - } -} -/* - * GLOBALS - */ struct globals { int kbmode; struct termios tio, tio0; @@ -44,13 +24,22 @@ struct globals { } while (0) -static void signal_handler(int signo) +// set raw tty mode +// also used by microcom +// libbb candidates? +static void xget1(struct termios *t, struct termios *oldt) { - // restore keyboard and console settings - xset1(&tio0); - xioctl(STDIN_FILENO, KDSKBMODE, (void *)(ptrdiff_t)kbmode); - // alarmed? -> exit 0 - exit(SIGALRM == signo); + tcgetattr(STDIN_FILENO, oldt); + *t = *oldt; + cfmakeraw(t); +} + +static void xset1(struct termios *t) +{ + int ret = tcsetattr(STDIN_FILENO, TCSAFLUSH, t); + if (ret) { + bb_perror_msg("can't tcsetattr for stdin"); + } } int showkey_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; @@ -62,20 +51,21 @@ int showkey_main(int argc UNUSED_PARAM, char **argv) OPT_s = (1<<2), // display only the raw scan-codes }; + INIT_G(); + // FIXME: aks are all mutually exclusive getopt32(argv, "aks"); - INIT_G(); - // get keyboard settings xioctl(STDIN_FILENO, KDGKBMODE, &kbmode); printf("kb mode was %s\n\nPress any keys. Program terminates %s\n\n", kbmode == K_RAW ? "RAW" : (kbmode == K_XLATE ? "XLATE" : (kbmode == K_MEDIUMRAW ? "MEDIUMRAW" : - (kbmode == K_UNICODE ? "UNICODE" : "?UNKNOWN?"))) - , (option_mask32 & OPT_a) ? "when CTRL+D pressed" : "10s after last keypress" + (kbmode == K_UNICODE ? "UNICODE" : "UNKNOWN"))) + , (option_mask32 & OPT_a) ? "on EOF (ctrl-D)" : "10s after last keypress" ); + // prepare for raw mode xget1(&tio, &tio0); // put stdin in raw mode @@ -83,34 +73,37 @@ int showkey_main(int argc UNUSED_PARAM, char **argv) if (option_mask32 & OPT_a) { unsigned char c; + // just read stdin char by char - while (1 == safe_read(STDIN_FILENO, &c, 1)) { + while (1 == read(STDIN_FILENO, &c, 1)) { printf("%3u 0%03o 0x%02x\r\n", c, c, c); if (04 /*CTRL-D*/ == c) break; } } else { - // we should exit on any signal - bb_signals(BB_FATAL_SIGS, signal_handler); // set raw keyboard mode xioctl(STDIN_FILENO, KDSKBMODE, (void *)(ptrdiff_t)((option_mask32 & OPT_k) ? K_MEDIUMRAW : K_RAW)); + // we should exit on any signal; signals should interrupt read + bb_signals_recursive_norestart(BB_FATAL_SIGS, record_signo); + // read and show scancodes - while (1) { + while (!bb_got_signal) { char buf[18]; int i, n; + // setup 10s watchdog alarm(10); // read scancodes n = read(STDIN_FILENO, buf, sizeof(buf)); i = 0; while (i < n) { - char c = buf[i]; - // show raw scancodes ordered? -> if (option_mask32 & OPT_s) { + // show raw scancodes printf("0x%02x ", buf[i++]); - // show interpreted scancodes (default) ? -> } else { + // show interpreted scancodes (default) + char c = buf[i]; int kc; if (i+2 < n && (c & 0x7f) == 0 @@ -130,9 +123,9 @@ int showkey_main(int argc UNUSED_PARAM, char **argv) } } - // cleanup - signal_handler(SIGALRM); + // restore keyboard and console settings + xset1(&tio0); + xioctl(STDIN_FILENO, KDSKBMODE, (void *)(ptrdiff_t)kbmode); - // should never be here! return EXIT_SUCCESS; } diff --git a/libbb/lineedit.c b/libbb/lineedit.c index 066b569f6..68006ffba 100644 --- a/libbb/lineedit.c +++ b/libbb/lineedit.c @@ -94,8 +94,10 @@ static bool BB_ispunct(CHAR_T c) { return ((unsigned)c < 256 && ispunct(c)); } #endif -#define SEQ_CLEAR_TILL_END_OF_SCREEN "\033[J" -//#define SEQ_CLEAR_TILL_END_OF_LINE "\033[K" +#define ESC "\033" + +#define SEQ_CLEAR_TILL_END_OF_SCREEN ESC"[J" +//#define SEQ_CLEAR_TILL_END_OF_LINE ESC"[K" enum { @@ -446,7 +448,7 @@ static void input_backward(unsigned num) } while (--num); return; } - printf("\033[%uD", num); + printf(ESC"[%uD", num); return; } @@ -471,7 +473,7 @@ static void input_backward(unsigned num) */ unsigned sv_cursor; /* go to 1st column; go up to first line */ - printf("\r" "\033[%uA", cmdedit_y); + printf("\r" ESC"[%uA", cmdedit_y); cmdedit_y = 0; sv_cursor = cursor; put_prompt(); /* sets cursor to 0 */ @@ -488,12 +490,12 @@ static void input_backward(unsigned num) cmdedit_x = (width * cmdedit_y - num) % width; cmdedit_y -= lines_up; /* go to 1st column; go up */ - printf("\r" "\033[%uA", lines_up); + printf("\r" ESC"[%uA", lines_up); /* go to correct column. * xterm, konsole, Linux VT interpret 0 as 1 below! wow. * need to *make sure* we skip it if cmdedit_x == 0 */ if (cmdedit_x) - printf("\033[%uC", cmdedit_x); + printf(ESC"[%uC", cmdedit_x); } } @@ -501,7 +503,7 @@ static void input_backward(unsigned num) static void redraw(int y, int back_cursor) { if (y > 0) /* up y lines */ - printf("\033[%uA", y); + printf(ESC"[%uA", y); bb_putchar('\r'); put_prompt(); put_till_end_and_adv_cursor(); @@ -1626,7 +1628,7 @@ static void ask_terminal(void) pfd.events = POLLIN; if (safe_poll(&pfd, 1, 0) == 0) { S.sent_ESC_br6n = 1; - fputs("\033" "[6n", stdout); + fputs(ESC"[6n", stdout); fflush_all(); /* make terminal see it ASAP! */ } } @@ -2074,7 +2076,7 @@ int FAST_FUNC read_line_input(const char *prompt, char *command, int maxsize, li case CTRL('L'): vi_case(CTRL('L')|VI_CMDMODE_BIT:) /* Control-l -- clear screen */ - printf("\033[H"); /* cursor to top,left */ + printf(ESC"[H"); /* cursor to top,left */ redraw(0, command_len - cursor); break; #if MAX_HISTORY > 0 diff --git a/miscutils/conspy.c b/miscutils/conspy.c index 01928b35f..040fa86f3 100644 --- a/miscutils/conspy.c +++ b/miscutils/conspy.c @@ -43,6 +43,9 @@ #include "libbb.h" #include + +#define ESC "\033" + struct screen_info { unsigned char lines, cols, cursor_x, cursor_y; }; @@ -70,7 +73,7 @@ struct globals { unsigned col; unsigned line; smallint curoff; // unknown:0 cursor on:-1 cursor off:1 - char attrbuf[sizeof("\033[0;1;5;30;40m")]; + char attrbuf[sizeof(ESC"[0;1;5;30;40m")]; // remote console struct screen_info remote; // saved local tty terminfo @@ -101,7 +104,7 @@ enum { static void clrscr(void) { // Home, clear till end of screen - fputs("\033[1;1H" "\033[J", stdout); + fputs(ESC"[1;1H" ESC"[J", stdout); G.col = G.line = 0; } @@ -109,7 +112,7 @@ static void set_cursor(int state) { if (G.curoff != state) { G.curoff = state; - fputs("\033[?25", stdout); + fputs(ESC"[?25", stdout); bb_putchar("h?l"[1 + state]); } } @@ -119,7 +122,7 @@ static void gotoxy(int col, int line) if (G.col != col || G.line != line) { G.col = col; G.line = line; - printf("\033[%u;%uH", line + 1, col + 1); + printf(ESC"[%u;%uH", line + 1, col + 1); } } @@ -132,7 +135,7 @@ static void cleanup(int code) } // Reset attributes if (!BW) - fputs("\033[0m", stdout); + fputs(ESC"[0m", stdout); bb_putchar('\n'); if (code > 1) kill_myself_with_sig(code); diff --git a/miscutils/less.c b/miscutils/less.c index 500059d2a..9e12c11a7 100644 --- a/miscutils/less.c +++ b/miscutils/less.c @@ -28,13 +28,15 @@ #include "xregex.h" #endif + +#define ESC "\033" /* The escape codes for highlighted and normal text */ -#define HIGHLIGHT "\033[7m" -#define NORMAL "\033[0m" +#define HIGHLIGHT ESC"[7m" +#define NORMAL ESC"[0m" /* The escape code to home and clear to the end of screen */ -#define CLEAR "\033[H\033[J" +#define CLEAR ESC"[H\033[J" /* The escape code to clear to the end of line */ -#define CLEAR_2_EOL "\033[K" +#define CLEAR_2_EOL ESC"[K" enum { /* Absolute max of lines eaten */ @@ -165,12 +167,12 @@ static void set_tty_cooked(void) top-left corner of the console */ static void move_cursor(int line, int row) { - printf("\033[%u;%uH", line, row); + printf(ESC"[%u;%uH", line, row); } static void clear_line(void) { - printf("\033[%u;0H" CLEAR_2_EOL, max_displayed_line + 2); + printf(ESC"[%u;0H" CLEAR_2_EOL, max_displayed_line + 2); } static void print_hilite(const char *str) diff --git a/miscutils/watchdog.c b/miscutils/watchdog.c index 36902a214..630782660 100644 --- a/miscutils/watchdog.c +++ b/miscutils/watchdog.c @@ -24,7 +24,7 @@ static void watchdog_shutdown(int sig UNUSED_PARAM) write(3, &V, 1); /* Magic, see watchdog-api.txt in kernel */ if (ENABLE_FEATURE_CLEAN_UP) close(3); - exit(EXIT_SUCCESS); + _exit(EXIT_SUCCESS); } int watchdog_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; diff --git a/util-linux/more.c b/util-linux/more.c index 1fd6f9ee8..788609a08 100644 --- a/util-linux/more.c +++ b/util-linux/more.c @@ -29,16 +29,20 @@ struct globals { #define new_settings (G.new_settings ) #define cin_fileno (G.cin_fileno ) -#define setTermSettings(fd, argp) do { \ - if (ENABLE_FEATURE_USE_TERMIOS) tcsetattr(fd, TCSANOW, argp); \ - } while (0) +#define setTermSettings(fd, argp) \ +do { \ + if (ENABLE_FEATURE_USE_TERMIOS) \ + tcsetattr(fd, TCSANOW, argp); \ +} while (0) #define getTermSettings(fd, argp) tcgetattr(fd, argp) static void gotsig(int sig UNUSED_PARAM) { - bb_putchar('\n'); + /* bb_putchar_stderr doesn't use stdio buffering, + * therefore it is safe in signal handler */ + bb_putchar_stderr('\n'); setTermSettings(cin_fileno, &initial_settings); - exit(EXIT_FAILURE); + _exit(EXIT_FAILURE); } #define CONVERTED_TAB_SIZE 8 -- cgit v1.2.3-55-g6feb From 8410ac1a073272affe8acdb0da67e5753ea051f8 Mon Sep 17 00:00:00 2001 From: Marek Polacek Date: Tue, 26 Oct 2010 02:34:36 +0200 Subject: bloat-o-meter: make it python3 compliant Python 3 doesn't support the iterkeys() method anymore. Use iter(foo.keys()) instead of foo.iterkeys(). Signed-off-by: Marek Polacek Signed-off-by: Denys Vlasenko --- scripts/bloat-o-meter | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/bloat-o-meter b/scripts/bloat-o-meter index 95cbbe6b8..91374c1ca 100755 --- a/scripts/bloat-o-meter +++ b/scripts/bloat-o-meter @@ -63,7 +63,7 @@ def getsizes(file): else: sym[name] = {"addr" : value, "size": size} lut[(value, size)] = 0 - for addr, sz in alias.iterkeys(): + for addr, sz in iter(alias.keys()): # If the non-GLOBAL sym has an implementation elsewhere then # it's an alias, disregard it. if not (addr, sz) in lut: @@ -92,7 +92,7 @@ if flag_timing: grow, shrink, add, remove, up, down = 0, 0, 0, 0, 0, 0 delta, common = [], {} -for name in old.iterkeys(): +for name in iter(old.keys()): if name in new: common[name] = 1 -- cgit v1.2.3-55-g6feb From caddfc83399ab783f032dbe23f3b10a5bd85414f Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Thu, 28 Oct 2010 23:08:53 +0200 Subject: decompress_bunzip2: handle concatenated .bz2 files function old new delta unpack_bz2_stream 207 307 +100 start_bunzip 199 209 +10 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 2/0 up/down: 110/0) Total: 110 bytes Signed-off-by: Denys Vlasenko --- archival/libunarchive/decompress_bunzip2.c | 74 ++++++++++++++++++++---------- include/unarchive.h | 2 +- libbb/appletlib.c | 2 +- miscutils/bbconfig.c | 2 +- testsuite/bunzip2.tests | 31 ++++++++++++- 5 files changed, 81 insertions(+), 30 deletions(-) diff --git a/archival/libunarchive/decompress_bunzip2.c b/archival/libunarchive/decompress_bunzip2.c index 22015683c..549c8b19f 100644 --- a/archival/libunarchive/decompress_bunzip2.c +++ b/archival/libunarchive/decompress_bunzip2.c @@ -44,7 +44,7 @@ #define RETVAL_LAST_BLOCK (-1) #define RETVAL_NOT_BZIP_DATA (-2) #define RETVAL_UNEXPECTED_INPUT_EOF (-3) -#define RETVAL_SHORT_WRITE (-4) +//#define RETVAL_SHORT_WRITE (-4) #define RETVAL_DATA_ERROR (-5) #define RETVAL_OUT_OF_MEMORY (-6) #define RETVAL_OBSOLETE_INPUT (-7) @@ -584,8 +584,8 @@ 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(bunzip_data **bdp, int in_fd, const unsigned char *inbuf, - int len) +int FAST_FUNC start_bunzip(bunzip_data **bdp, int in_fd, + const void *inbuf, int len) { bunzip_data *bd; unsigned i; @@ -606,9 +606,11 @@ int FAST_FUNC start_bunzip(bunzip_data **bdp, int in_fd, const unsigned char *in if (-1 == in_fd) { /* in this case, bd->inbuf is read-only */ bd->inbuf = (void*)inbuf; /* cast away const-ness */ - bd->inbufCount = len; - } else + } else { bd->inbuf = (unsigned char *)(bd + 1); + memcpy(bd->inbuf, inbuf, len); + } + bd->inbufCount = len; /* Init the CRC32 table (big endian) */ crc32_filltable(bd->crc32Table, 1); @@ -652,37 +654,59 @@ IF_DESKTOP(long long) int FAST_FUNC unpack_bz2_stream(int src_fd, int dst_fd) { IF_DESKTOP(long long total_written = 0;) + bunzip_data *bd; char *outbuf; - bunzip_data *bd; int i; + unsigned len; outbuf = xmalloc(IOBUF_SIZE); - i = start_bunzip(&bd, src_fd, NULL, 0); - if (!i) { - for (;;) { - i = read_bunzip(bd, outbuf, IOBUF_SIZE); - if (i <= 0) break; - if (i != full_write(dst_fd, outbuf, i)) { - i = RETVAL_SHORT_WRITE; - break; + len = 0; + while (1) { /* "Process one BZ... stream" loop */ + + i = start_bunzip(&bd, src_fd, outbuf + 2, len); + + if (i == 0) { + while (1) { /* "Produce some output bytes" loop */ + i = read_bunzip(bd, outbuf, IOBUF_SIZE); + if (i <= 0) + break; + if (i != full_write(dst_fd, outbuf, i)) { + bb_error_msg("short write"); + goto release_mem; + } + IF_DESKTOP(total_written += i;) } - IF_DESKTOP(total_written += i;) } - } - /* Check CRC and release memory */ - - if (i == RETVAL_LAST_BLOCK) { + if (i != RETVAL_LAST_BLOCK) { + bb_error_msg("bunzip error %d", i); + break; + } if (bd->headerCRC != bd->totalCRC) { bb_error_msg("CRC error"); - } else { - i = RETVAL_OK; + break; } - } else if (i == RETVAL_SHORT_WRITE) { - bb_error_msg("short write"); - } else { - bb_error_msg("bunzip error %d", i); + + /* Successfully unpacked one BZ stream */ + i = RETVAL_OK; + + /* Do we have "BZ..." after last processed byte? + * pbzip2 (parallelized bzip2) produces such files. + */ + len = bd->inbufCount - bd->inbufPos; + memcpy(outbuf, &bd->inbuf[bd->inbufPos], len); + if (len < 2) { + if (safe_read(src_fd, outbuf + len, 2 - len) != 2 - len) + break; + len = 2; + } + if (*(uint16_t*)outbuf != BZIP2_MAGIC) /* "BZ"? */ + break; + dealloc_bunzip(bd); + len -= 2; } + + release_mem: dealloc_bunzip(bd); free(outbuf); diff --git a/include/unarchive.h b/include/unarchive.h index b55af6d9d..11d8c77a0 100644 --- a/include/unarchive.h +++ b/include/unarchive.h @@ -193,7 +193,7 @@ extern const llist_t *find_list_entry2(const llist_t *list, const char *filename /* A bit of bunzip2 internals are exposed for compressed help support: */ typedef struct bunzip_data bunzip_data; -int start_bunzip(bunzip_data **bdp, int in_fd, const unsigned char *inbuf, int len) FAST_FUNC; +int start_bunzip(bunzip_data **bdp, int in_fd, const void *inbuf, int len) FAST_FUNC; int read_bunzip(bunzip_data *bd, char *outbuf, int len) FAST_FUNC; void dealloc_bunzip(bunzip_data *bd) FAST_FUNC; diff --git a/libbb/appletlib.c b/libbb/appletlib.c index b32ff8808..fab996ca0 100644 --- a/libbb/appletlib.c +++ b/libbb/appletlib.c @@ -75,7 +75,7 @@ static const char *unpack_usage_messages(void) i = start_bunzip(&bd, /* src_fd: */ -1, - /* inbuf: */ (void *)packed_usage, + /* inbuf: */ packed_usage, /* len: */ sizeof(packed_usage)); /* read_bunzip can longjmp to start_bunzip, and ultimately * end up here with i != 0 on read data errors! Not trivial */ diff --git a/miscutils/bbconfig.c b/miscutils/bbconfig.c index 286077168..1cb42edeb 100644 --- a/miscutils/bbconfig.c +++ b/miscutils/bbconfig.c @@ -15,7 +15,7 @@ int bbconfig_main(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) bunzip_data *bd; int i = start_bunzip(&bd, /* src_fd: */ -1, - /* inbuf: */ (void *)bbconfig_config_bz2, + /* inbuf: */ bbconfig_config_bz2, /* len: */ sizeof(bbconfig_config_bz2)); /* read_bunzip can longjmp to start_bunzip, and ultimately * end up here with i != 0 on read data errors! Not trivial */ diff --git a/testsuite/bunzip2.tests b/testsuite/bunzip2.tests index 827aee867..fcfce1a31 100755 --- a/testsuite/bunzip2.tests +++ b/testsuite/bunzip2.tests @@ -463,6 +463,24 @@ $ECHO -ne "\x40\xa0\x00\x8b\x12\xe8\xfb\xb7\x27\xaa\xd3\x36\x0c\xfc\xe1\x40" $ECHO -ne "\x01\xff\x8b\xb9\x22\x9c\x28\x48\x5f\xa5\xca\xf3\x80" } +pbzip_4m_zeros() { +$ECHO -ne "\x42\x5a\x68\x31\x31\x41\x59\x26\x53\x59\x63\xe3\xec\xa2\x00\x06" +$ECHO -ne "\xe4\xc1\x00\xc0\x00\x02\x00\x00\x08\x20\x00\x30\xcc\x09\xaa\x69" +$ECHO -ne "\x94\xa1\x36\xa9\x28\x4f\x17\x72\x45\x38\x50\x90\x63\xe3\xec\xa2" +$ECHO -ne "\x42\x5a\x68\x31\x31\x41\x59\x26\x53\x59\x63\xe3\xec\xa2\x00\x06" +$ECHO -ne "\xe4\xc1\x00\xc0\x00\x02\x00\x00\x08\x20\x00\x30\xcc\x09\xaa\x69" +$ECHO -ne "\x94\xa1\x36\xa9\x28\x4f\x17\x72\x45\x38\x50\x90\x63\xe3\xec\xa2" +$ECHO -ne "\x42\x5a\x68\x31\x31\x41\x59\x26\x53\x59\x63\xe3\xec\xa2\x00\x06" +$ECHO -ne "\xe4\xc1\x00\xc0\x00\x02\x00\x00\x08\x20\x00\x30\xcc\x09\xaa\x69" +$ECHO -ne "\x94\xa1\x36\xa9\x28\x4f\x17\x72\x45\x38\x50\x90\x63\xe3\xec\xa2" +$ECHO -ne "\x42\x5a\x68\x31\x31\x41\x59\x26\x53\x59\x63\xe3\xec\xa2\x00\x06" +$ECHO -ne "\xe4\xc1\x00\xc0\x00\x02\x00\x00\x08\x20\x00\x30\xcc\x09\xaa\x69" +$ECHO -ne "\x94\xa1\x36\xa9\x28\x4f\x17\x72\x45\x38\x50\x90\x63\xe3\xec\xa2" +$ECHO -ne "\x42\x5a\x68\x31\x31\x41\x59\x26\x53\x59\xc9\xb5\x21\xef\x00\x04" +$ECHO -ne "\x8d\x40\x20\xc0\x00\x01\x00\x00\x08\x20\x00\x30\xcc\x05\x29\xa6" +$ECHO -ne "\x4a\x11\xb1\x4a\x11\xe2\xee\x48\xa7\x0a\x12\x19\x36\xa4\x3d\xe0" +} + prep() { rm -f t* hello_$ext >t1.$ext @@ -520,9 +538,18 @@ if test "${0##*/}" = "bunzip2.tests"; then if test1_bz2 | ${bb}bunzip2 >/dev/null \ && test "`test1_bz2 | ${bb}bunzip2 | md5sum`" = "61bbeee4be9c6f110a71447f584fda7b -" then - echo "PASS: $unpack: test bz2 file" + echo "PASS: $unpack: test_bz2 file" + else + echo "FAIL: $unpack: test_bz2 file" + FAILCOUNT=$((FAILCOUNT + 1)) + fi + + if pbzip_4m_zeros | ${bb}bunzip2 >/dev/null \ + && test "`pbzip_4m_zeros | ${bb}bunzip2 | md5sum`" = "b5cfa9d6c8febd618f91ac2843d50a1c -" + then + echo "PASS: $unpack: pbzip_4m_zeros file" else - echo "FAIL: $unpack: test bz2 file" + echo "FAIL: $unpack: pbzip_4m_zeros file" FAILCOUNT=$((FAILCOUNT + 1)) fi fi -- cgit v1.2.3-55-g6feb From dc8ef353fd8ae0641a53c2507138155dcd5f76e7 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Fri, 29 Oct 2010 00:37:56 +0200 Subject: dnsd: fix 64-bit bug 2539. Signed-off-by: Denys Vlasenko --- networking/dnsd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/networking/dnsd.c b/networking/dnsd.c index 92d4867aa..8ed31cea2 100644 --- a/networking/dnsd.c +++ b/networking/dnsd.c @@ -388,7 +388,7 @@ static int process_packet(struct dns_entry *conf_data, query_len = strlen(query_string) + 1; /* may be unaligned! */ unaligned_type_class = (void *)(query_string + query_len); - query_len += sizeof(unaligned_type_class); + query_len += sizeof(*unaligned_type_class); /* where to append answer block */ answb = (void *)(unaligned_type_class + 1); -- cgit v1.2.3-55-g6feb From 6b3f0b0dab46d910f7797dfc8d8554546dd33fa2 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Fri, 29 Oct 2010 00:50:09 +0200 Subject: unicode: update unicode_width on !unicode branch too. Closes bug 2593 Signed-off-by: Denys Vlasenko --- libbb/unicode.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/libbb/unicode.c b/libbb/unicode.c index 70c6abe00..cf0c6bed9 100644 --- a/libbb/unicode.c +++ b/libbb/unicode.c @@ -1005,8 +1005,11 @@ static char* FAST_FUNC unicode_conv_to_printable2(uni_stat_t *stats, const char d++; } } - if (stats) - stats->byte_count = stats->unicode_count = (d - dst); + if (stats) { + stats->byte_count = (d - dst); + stats->unicode_count = (d - dst); + stats->unicode_width = (d - dst); + } return dst; } -- cgit v1.2.3-55-g6feb From 036dbb9d9ab239bbd7eecad8580876c9c3e57dc5 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Fri, 29 Oct 2010 02:12:22 +0200 Subject: telnet: convert CR NUL -> CR on input. Closes bug 2569 function old new delta telnet_main 1558 1594 +36 Signed-off-by: Denys Vlasenko --- networking/telnet.c | 132 +++++++++++++++++++++++++--------------------------- 1 file changed, 63 insertions(+), 69 deletions(-) diff --git a/networking/telnet.c b/networking/telnet.c index 12d1970fa..0cf28f641 100644 --- a/networking/telnet.c +++ b/networking/telnet.c @@ -42,11 +42,13 @@ enum { UF_ECHO = 0x01, UF_SGA = 0x02, - TS_0 = 1, + TS_NORMAL = 0, + TS_COPY = 1, TS_IAC = 2, TS_OPT = 3, TS_SUB1 = 4, TS_SUB2 = 5, + TS_CR = 6, }; typedef unsigned char byte; @@ -83,13 +85,13 @@ struct globals { }; \ } while (0) -/* Function prototypes */ + static void rawmode(void); static void cookmode(void); static void do_linemode(void); static void will_charmode(void); static void telopt(byte c); -static int subneg(byte c); +static void subneg(byte c); static void iac_flush(void) { @@ -170,24 +172,24 @@ static void handle_net_output(int len) * So I implemented it. It's really useful for me. I hope that * other people will find it interesting too. */ - - int i, j; + byte outbuf[2 * DATABUFSIZE]; byte *p = (byte*)G.buf; - byte outbuf[4*DATABUFSIZE]; + int j = 0; - for (i = len, j = 0; i > 0; i--, p++) { - if (*p == 0x1d) { + for (; len > 0; len--, p++) { + byte c = *p; + if (c == 0x1d) { con_escape(); return; } - outbuf[j++] = *p; - if (*p == 0xff) - outbuf[j++] = 0xff; - else if (*p == 0x0d) - outbuf[j++] = 0x00; + outbuf[j++] = c; + if (c == IAC) + outbuf[j++] = c; /* IAC -> IAC IAC */ + else if (c == '\r') + outbuf[j++] = '\0'; /* CR -> CR NUL */ } if (j > 0) - write(netfd, outbuf, j); + full_write(netfd, outbuf, j); } static void handle_net_input(int len) @@ -198,25 +200,44 @@ static void handle_net_input(int len) for (i = 0; i < len; i++) { byte c = G.buf[i]; - if (G.telstate == 0) { /* most of the time state == 0 */ + if (G.telstate == TS_NORMAL) { /* most typical state */ if (c == IAC) { cstart = i; G.telstate = TS_IAC; } + else if (c == '\r') { + cstart = i + 1; + G.telstate = TS_CR; + } + /* No IACs were seen so far, no need to copy + * bytes within G.buf: */ continue; } + switch (G.telstate) { - case TS_0: + case TS_CR: + /* Prev char was CR. If cur one is NUL, ignore it. + * See RFC 1123 section 3.3.1 for discussion of telnet EOL handling. + */ + G.telstate = TS_COPY; + if (c == '\0') + break; + /* else: fall through - need to handle CR IAC ... properly */ + + case TS_COPY: /* Prev char was ordinary */ + /* Similar to NORMAL, but in TS_COPY we need to copy bytes */ if (c == IAC) G.telstate = TS_IAC; else G.buf[cstart++] = c; + if (c == '\r') + G.telstate = TS_CR; break; - case TS_IAC: - if (c == IAC) { /* IAC IAC -> 0xFF */ + case TS_IAC: /* Prev char was IAC */ + if (c == IAC) { /* IAC IAC -> one IAC */ G.buf[cstart++] = c; - G.telstate = TS_0; + G.telstate = TS_COPY; break; } /* else */ @@ -228,34 +249,38 @@ static void handle_net_input(int len) case DONT: case WILL: case WONT: - G.telwish = c; + G.telwish = c; G.telstate = TS_OPT; break; + /* DATA MARK must be added later */ default: - G.telstate = TS_0; /* DATA MARK must be added later */ + G.telstate = TS_COPY; } break; - case TS_OPT: /* WILL, WONT, DO, DONT */ + + case TS_OPT: /* Prev chars were IAC WILL/WONT/DO/DONT */ telopt(c); - G.telstate = TS_0; + G.telstate = TS_COPY; break; + case TS_SUB1: /* Subnegotiation */ case TS_SUB2: /* Subnegotiation */ - if (subneg(c)) - G.telstate = TS_0; + subneg(c); /* can change G.telstate */ break; } } - if (G.telstate) { + + if (G.telstate != TS_NORMAL) { + /* We had some IACs, or CR */ if (G.iaclen) iac_flush(); - if (G.telstate == TS_0) - G.telstate = 0; + if (G.telstate == TS_COPY) /* we aren't in the middle of IAC */ + G.telstate = TS_NORMAL; len = cstart; } if (len) - write(STDOUT_FILENO, G.buf, len); + full_write(STDOUT_FILENO, G.buf, len); } static void put_iac(int c) @@ -495,7 +520,7 @@ static void telopt(byte c) } /* subnegotiation -- ignore all (except TTYPE,NAWS) */ -static int subneg(byte c) +static void subneg(byte c) { switch (G.telstate) { case TS_SUB1: @@ -513,12 +538,13 @@ static int subneg(byte c) #endif break; case TS_SUB2: - if (c == SE) - return TRUE; + if (c == SE) { + G.telstate = TS_COPY; + return; + } G.telstate = TS_SUB1; - /* break; */ + break; } - return FALSE; } static void rawmode(void) @@ -533,21 +559,13 @@ static void cookmode(void) tcsetattr(0, TCSADRAIN, &G.termios_def); } -/* poll gives smaller (-70 bytes) code */ -#define USE_POLL 1 - int telnet_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int telnet_main(int argc UNUSED_PARAM, char **argv) { char *host; int port; int len; -#ifdef USE_POLL struct pollfd ufds[2]; -#else - fd_set readfds; - int maxfd; -#endif INIT_G(); @@ -585,25 +603,11 @@ int telnet_main(int argc UNUSED_PARAM, char **argv) signal(SIGINT, record_signo); -#ifdef USE_POLL ufds[0].fd = 0; ufds[1].fd = netfd; ufds[0].events = ufds[1].events = POLLIN; -#else - FD_ZERO(&readfds); - FD_SET(STDIN_FILENO, &readfds); - FD_SET(netfd, &readfds); - maxfd = netfd + 1; -#endif while (1) { -#ifndef USE_POLL - fd_set rfds = readfds; - - switch (select(maxfd, &rfds, NULL, NULL, NULL)) -#else - switch (poll(ufds, 2, -1)) -#endif - { + switch (poll(ufds, 2, -1)) { case 0: /* timeout */ case -1: @@ -615,12 +619,7 @@ int telnet_main(int argc UNUSED_PARAM, char **argv) break; default: -#ifdef USE_POLL - if (ufds[0].revents) -#else - if (FD_ISSET(STDIN_FILENO, &rfds)) -#endif - { + if (ufds[0].revents) { len = safe_read(STDIN_FILENO, G.buf, DATABUFSIZE); if (len <= 0) doexit(EXIT_SUCCESS); @@ -628,12 +627,7 @@ int telnet_main(int argc UNUSED_PARAM, char **argv) handle_net_output(len); } -#ifdef USE_POLL - if (ufds[1].revents) -#else - if (FD_ISSET(netfd, &rfds)) -#endif - { + if (ufds[1].revents) { len = safe_read(netfd, G.buf, DATABUFSIZE); if (len <= 0) { full_write1_str("Connection closed by foreign host\r\n"); -- cgit v1.2.3-55-g6feb From ec07420eb914f6ca62273c54790853ccf22636e8 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Fri, 29 Oct 2010 02:33:38 +0200 Subject: telnet: do not check for 0 return from poll (it's impossible) Signed-off-by: Denys Vlasenko --- networking/telnet.c | 48 ++++++++++++++++++++++++------------------------ 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/networking/telnet.c b/networking/telnet.c index 0cf28f641..f6fad684c 100644 --- a/networking/telnet.c +++ b/networking/telnet.c @@ -603,39 +603,39 @@ int telnet_main(int argc UNUSED_PARAM, char **argv) signal(SIGINT, record_signo); - ufds[0].fd = 0; ufds[1].fd = netfd; - ufds[0].events = ufds[1].events = POLLIN; + ufds[0].fd = STDIN_FILENO; + ufds[0].events = POLLIN; + ufds[1].fd = netfd; + ufds[1].events = POLLIN; while (1) { - switch (poll(ufds, 2, -1)) { - case 0: - /* timeout */ - case -1: + if (poll(ufds, 2, -1) < 0) { /* error, ignore and/or log something, bay go to loop */ if (bb_got_signal) con_escape(); else sleep(1); - break; - default: - - if (ufds[0].revents) { - len = safe_read(STDIN_FILENO, G.buf, DATABUFSIZE); - if (len <= 0) - doexit(EXIT_SUCCESS); - TRACE(0, ("Read con: %d\n", len)); - handle_net_output(len); - } + continue; + } + +// FIXME: reads can block. Need full bidirectional buffering. + + if (ufds[0].revents) { + len = safe_read(STDIN_FILENO, G.buf, DATABUFSIZE); + if (len <= 0) + doexit(EXIT_SUCCESS); + TRACE(0, ("Read con: %d\n", len)); + handle_net_output(len); + } - if (ufds[1].revents) { - len = safe_read(netfd, G.buf, DATABUFSIZE); - if (len <= 0) { - full_write1_str("Connection closed by foreign host\r\n"); - doexit(EXIT_FAILURE); - } - TRACE(0, ("Read netfd (%d): %d\n", netfd, len)); - handle_net_input(len); + if (ufds[1].revents) { + len = safe_read(netfd, G.buf, DATABUFSIZE); + if (len <= 0) { + full_write1_str("Connection closed by foreign host\r\n"); + doexit(EXIT_FAILURE); } + TRACE(0, ("Read netfd (%d): %d\n", netfd, len)); + handle_net_input(len); } } /* while (1) */ } -- cgit v1.2.3-55-g6feb From 66cb7bed33da605674c3d24734466b8e8a60e337 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Fri, 29 Oct 2010 02:42:20 +0200 Subject: ifupdown: add manual method for IPv6. Closes bug 2497. Signed-off-by: Denys Vlasenko --- networking/ifupdown.c | 123 ++++++++++++++++++++++++++++---------------------- 1 file changed, 68 insertions(+), 55 deletions(-) diff --git a/networking/ifupdown.c b/networking/ifupdown.c index 3cb1ec858..59df4e80f 100644 --- a/networking/ifupdown.c +++ b/networking/ifupdown.c @@ -164,7 +164,7 @@ static char *get_var(const char *id, size_t idlen, struct interface_defn_t *ifd) return NULL; } -#if ENABLE_FEATURE_IFUPDOWN_IP +# if ENABLE_FEATURE_IFUPDOWN_IP static int count_netmask_bits(const char *dotted_quad) { // int result; @@ -195,7 +195,7 @@ static int count_netmask_bits(const char *dotted_quad) } return result; } -#endif +# endif static char *parse(const char *command, struct interface_defn_t *ifd) { @@ -258,17 +258,17 @@ static char *parse(const char *command, struct interface_defn_t *ifd) varvalue = get_var(command, nextpercent - command, ifd); if (varvalue) { -#if ENABLE_FEATURE_IFUPDOWN_IP +# if ENABLE_FEATURE_IFUPDOWN_IP /* "hwaddress
": * unlike ifconfig, ip doesnt want * (usually "ether" keyword). Skip it. */ if (strncmp(command, "hwaddress", 9) == 0) { varvalue = skip_whitespace(skip_non_whitespace(varvalue)); } -#endif +# endif addstr(&result, varvalue, strlen(varvalue)); } else { -#if ENABLE_FEATURE_IFUPDOWN_IP +# if ENABLE_FEATURE_IFUPDOWN_IP /* Sigh... Add a special case for 'ip' to convert from * dotted quad to bit count style netmasks. */ if (strncmp(command, "bnmask", 6) == 0) { @@ -284,7 +284,7 @@ static char *parse(const char *command, struct interface_defn_t *ifd) } } } -#endif +# endif okay[opt_depth - 1] = 0; } @@ -329,56 +329,64 @@ static int execute(const char *command, struct interface_defn_t *ifd, execfn *ex } return 1; } -#endif + +#endif /* FEATURE_IFUPDOWN_IPV4 || FEATURE_IFUPDOWN_IPV6 */ + #if ENABLE_FEATURE_IFUPDOWN_IPV6 + static int FAST_FUNC loopback_up6(struct interface_defn_t *ifd, execfn *exec) { -#if ENABLE_FEATURE_IFUPDOWN_IP +# if ENABLE_FEATURE_IFUPDOWN_IP int result; result = execute("ip addr add ::1 dev %iface%", ifd, exec); result += execute("ip link set %iface% up", ifd, exec); return ((result == 2) ? 2 : 0); -#else +# else return execute("ifconfig %iface% add ::1", ifd, exec); -#endif +# endif } static int FAST_FUNC loopback_down6(struct interface_defn_t *ifd, execfn *exec) { -#if ENABLE_FEATURE_IFUPDOWN_IP +# if ENABLE_FEATURE_IFUPDOWN_IP return execute("ip link set %iface% down", ifd, exec); -#else +# else return execute("ifconfig %iface% del ::1", ifd, exec); -#endif +# endif +} + +static int FAST_FUNC manual_up_down6(struct interface_defn_t *ifd UNUSED_PARAM, execfn *exec UNUSED_PARAM) +{ + return 1; } static int FAST_FUNC static_up6(struct interface_defn_t *ifd, execfn *exec) { int result; -#if ENABLE_FEATURE_IFUPDOWN_IP +# if ENABLE_FEATURE_IFUPDOWN_IP result = execute("ip addr add %address%/%netmask% dev %iface%[[ label %label%]]", ifd, exec); result += execute("ip link set[[ mtu %mtu%]][[ addr %hwaddress%]] %iface% up", ifd, exec); /* Was: "[[ ip ....%gateway% ]]". Removed extra spaces w/o checking */ result += execute("[[ip route add ::/0 via %gateway%]]", ifd, exec); -#else +# else result = execute("ifconfig %iface%[[ media %media%]][[ hw %hwaddress%]][[ mtu %mtu%]] up", ifd, exec); result += execute("ifconfig %iface% add %address%/%netmask%", ifd, exec); result += execute("[[route -A inet6 add ::/0 gw %gateway%]]", ifd, exec); -#endif +# endif return ((result == 3) ? 3 : 0); } static int FAST_FUNC static_down6(struct interface_defn_t *ifd, execfn *exec) { -#if ENABLE_FEATURE_IFUPDOWN_IP +# if ENABLE_FEATURE_IFUPDOWN_IP return execute("ip link set %iface% down", ifd, exec); -#else +# else return execute("ifconfig %iface% down", ifd, exec); -#endif +# endif } -#if ENABLE_FEATURE_IFUPDOWN_IP +# if ENABLE_FEATURE_IFUPDOWN_IP static int FAST_FUNC v4tunnel_up(struct interface_defn_t *ifd, execfn *exec) { int result; @@ -394,14 +402,15 @@ static int FAST_FUNC v4tunnel_down(struct interface_defn_t * ifd, execfn * exec) { return execute("ip tunnel del %iface%", ifd, exec); } -#endif +# endif static const struct method_t methods6[] = { -#if ENABLE_FEATURE_IFUPDOWN_IP - { "v4tunnel", v4tunnel_up, v4tunnel_down, }, -#endif - { "static", static_up6, static_down6, }, - { "loopback", loopback_up6, loopback_down6, }, +# if ENABLE_FEATURE_IFUPDOWN_IP + { "v4tunnel" , v4tunnel_up , v4tunnel_down , }, +# endif + { "static" , static_up6 , static_down6 , }, + { "manual" , manual_up_down6 , manual_up_down6 , }, + { "loopback" , loopback_up6 , loopback_down6 , }, }; static const struct address_family_t addr_inet6 = { @@ -409,43 +418,46 @@ static const struct address_family_t addr_inet6 = { ARRAY_SIZE(methods6), methods6 }; + #endif /* FEATURE_IFUPDOWN_IPV6 */ + #if ENABLE_FEATURE_IFUPDOWN_IPV4 + static int FAST_FUNC loopback_up(struct interface_defn_t *ifd, execfn *exec) { -#if ENABLE_FEATURE_IFUPDOWN_IP +# if ENABLE_FEATURE_IFUPDOWN_IP int result; result = execute("ip addr add 127.0.0.1/8 dev %iface%", ifd, exec); result += execute("ip link set %iface% up", ifd, exec); return ((result == 2) ? 2 : 0); -#else +# else return execute("ifconfig %iface% 127.0.0.1 up", ifd, exec); -#endif +# endif } static int FAST_FUNC loopback_down(struct interface_defn_t *ifd, execfn *exec) { -#if ENABLE_FEATURE_IFUPDOWN_IP +# if ENABLE_FEATURE_IFUPDOWN_IP int result; result = execute("ip addr flush dev %iface%", ifd, exec); result += execute("ip link set %iface% down", ifd, exec); return ((result == 2) ? 2 : 0); -#else +# else return execute("ifconfig %iface% 127.0.0.1 down", ifd, exec); -#endif +# endif } static int FAST_FUNC static_up(struct interface_defn_t *ifd, execfn *exec) { int result; -#if ENABLE_FEATURE_IFUPDOWN_IP +# if ENABLE_FEATURE_IFUPDOWN_IP result = execute("ip addr add %address%/%bnmask%[[ broadcast %broadcast%]] " "dev %iface%[[ peer %pointopoint%]][[ label %label%]]", ifd, exec); result += execute("ip link set[[ mtu %mtu%]][[ addr %hwaddress%]] %iface% up", ifd, exec); result += execute("[[ip route add default via %gateway% dev %iface%]]", ifd, exec); return ((result == 3) ? 3 : 0); -#else +# else /* ifconfig said to set iface up before it processes hw %hwaddress%, * which then of course fails. Thus we run two separate ifconfig */ result = execute("ifconfig %iface%[[ hw %hwaddress%]][[ media %media%]][[ mtu %mtu%]] up", @@ -455,26 +467,26 @@ static int FAST_FUNC static_up(struct interface_defn_t *ifd, execfn *exec) ifd, exec); result += execute("[[route add default gw %gateway% %iface%]]", ifd, exec); return ((result == 3) ? 3 : 0); -#endif +# endif } static int FAST_FUNC static_down(struct interface_defn_t *ifd, execfn *exec) { int result; -#if ENABLE_FEATURE_IFUPDOWN_IP +# if ENABLE_FEATURE_IFUPDOWN_IP result = execute("ip addr flush dev %iface%", ifd, exec); result += execute("ip link set %iface% down", ifd, exec); -#else +# else /* result = execute("[[route del default gw %gateway% %iface%]]", ifd, exec); */ /* Bringing the interface down deletes the routes in itself. Otherwise this fails if we reference 'gateway' when using this from dhcp_down */ result = 1; result += execute("ifconfig %iface% down", ifd, exec); -#endif +# endif return ((result == 2) ? 2 : 0); } -#if ENABLE_FEATURE_IFUPDOWN_EXTERNAL_DHCP +# if ENABLE_FEATURE_IFUPDOWN_EXTERNAL_DHCP struct dhcp_client_t { const char *name; const char *startcmd; @@ -500,21 +512,21 @@ static const struct dhcp_client_t ext_dhcp_clients[] = { "kill `cat /var/run/udhcpc.%iface%.pid` 2>/dev/null", }, }; -#endif /* ENABLE_FEATURE_IFUPDOWN_EXTERNAL_DHCPC */ +# endif /* FEATURE_IFUPDOWN_EXTERNAL_DHCPC */ -#if ENABLE_FEATURE_IFUPDOWN_EXTERNAL_DHCP +# if ENABLE_FEATURE_IFUPDOWN_EXTERNAL_DHCP static int FAST_FUNC dhcp_up(struct interface_defn_t *ifd, execfn *exec) { unsigned i; -#if ENABLE_FEATURE_IFUPDOWN_IP +# if ENABLE_FEATURE_IFUPDOWN_IP /* ip doesn't up iface when it configures it (unlike ifconfig) */ if (!execute("ip link set[[ addr %hwaddress%]] %iface% up", ifd, exec)) return 0; -#else +# else /* needed if we have hwaddress on dhcp iface */ if (!execute("ifconfig %iface%[[ hw %hwaddress%]] up", ifd, exec)) return 0; -#endif +# endif for (i = 0; i < ARRAY_SIZE(ext_dhcp_clients); i++) { if (exists_execable(ext_dhcp_clients[i].name)) return execute(ext_dhcp_clients[i].startcmd, ifd, exec); @@ -522,31 +534,31 @@ static int FAST_FUNC dhcp_up(struct interface_defn_t *ifd, execfn *exec) bb_error_msg("no dhcp clients found"); return 0; } -#elif ENABLE_UDHCPC +# elif ENABLE_UDHCPC static int FAST_FUNC dhcp_up(struct interface_defn_t *ifd, execfn *exec) { -#if ENABLE_FEATURE_IFUPDOWN_IP +# if ENABLE_FEATURE_IFUPDOWN_IP /* ip doesn't up iface when it configures it (unlike ifconfig) */ if (!execute("ip link set[[ addr %hwaddress%]] %iface% up", ifd, exec)) return 0; -#else +# else /* needed if we have hwaddress on dhcp iface */ if (!execute("ifconfig %iface%[[ hw %hwaddress%]] up", ifd, exec)) return 0; -#endif +# endif return execute("udhcpc " UDHCPC_CMD_OPTIONS " -p /var/run/udhcpc.%iface%.pid " "-i %iface%[[ -H %hostname%]][[ -c %client%]][[ -s %script%]][[ %udhcpc_opts%]]", ifd, exec); } -#else +# else static int FAST_FUNC dhcp_up(struct interface_defn_t *ifd UNUSED_PARAM, execfn *exec UNUSED_PARAM) { return 0; /* no dhcp support */ } -#endif +# endif -#if ENABLE_FEATURE_IFUPDOWN_EXTERNAL_DHCP +# if ENABLE_FEATURE_IFUPDOWN_EXTERNAL_DHCP static int FAST_FUNC dhcp_down(struct interface_defn_t *ifd, execfn *exec) { int result = 0; @@ -569,7 +581,7 @@ static int FAST_FUNC dhcp_down(struct interface_defn_t *ifd, execfn *exec) result += static_down(ifd, exec); return ((result == 3) ? 3 : 0); } -#elif ENABLE_UDHCPC +# elif ENABLE_UDHCPC static int FAST_FUNC dhcp_down(struct interface_defn_t *ifd, execfn *exec) { int result; @@ -586,13 +598,13 @@ static int FAST_FUNC dhcp_down(struct interface_defn_t *ifd, execfn *exec) result += static_down(ifd, exec); return ((result == 3) ? 3 : 0); } -#else +# else static int FAST_FUNC dhcp_down(struct interface_defn_t *ifd UNUSED_PARAM, execfn *exec UNUSED_PARAM) { return 0; /* no dhcp support */ } -#endif +# endif static int FAST_FUNC manual_up_down(struct interface_defn_t *ifd UNUSED_PARAM, execfn *exec UNUSED_PARAM) { @@ -644,7 +656,8 @@ static const struct address_family_t addr_inet = { methods }; -#endif /* if ENABLE_FEATURE_IFUPDOWN_IPV4 */ +#endif /* FEATURE_IFUPDOWN_IPV4 */ + /* Returns pointer to the next word, or NULL. * In 1st case, advances *buf to the word after this one. -- cgit v1.2.3-55-g6feb From fb132e47370378474c68ad22c1c0cb2ccee178de Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Fri, 29 Oct 2010 11:46:52 +0200 Subject: whitespace cleanup Signed-off-by: Denys Vlasenko --- archival/ar.c | 16 ++++++++-------- archival/bz/bzlib.c | 2 +- archival/bz/compress.c | 9 ++++----- archival/dpkg.c | 11 ++++++----- archival/dpkg_deb.c | 10 +++++----- archival/libunarchive/decompress_bunzip2.c | 4 ++-- console-tools/kbd_mode.c | 4 ++-- console-tools/loadfont.c | 8 ++++---- console-tools/showkey.c | 12 ++++++------ coreutils/date.c | 2 +- coreutils/dd.c | 2 +- coreutils/mv.c | 2 +- coreutils/nice.c | 6 +++--- coreutils/od.c | 4 ++-- coreutils/sort.c | 4 ++-- coreutils/test.c | 6 +++--- coreutils/tr.c | 8 ++++---- coreutils/wc.c | 6 +++--- e2fsprogs/old_e2fsprogs/e2fsck.h | 2 +- editors/awk.c | 14 +++++++------- editors/diff.c | 2 +- editors/sed.c | 6 +++--- include/grp_.h | 2 +- include/platform.h | 2 +- include/pwd_.h | 2 +- include/rtc_.h | 4 ++-- libbb/hash_md5_sha.c | 8 ++++---- libbb/pw_encrypt_sha.c | 6 +++--- libbb/simplify_path.c | 10 +++++----- libpwdgrp/pwd_grp_internal.c | 4 ++-- miscutils/conspy.c | 8 ++++---- miscutils/ubi_attach_detach.c | 4 ++-- modutils/rmmod.c | 4 ++-- networking/httpd.c | 4 ++-- networking/inetd.c | 2 +- networking/ip.c | 4 +--- networking/ipcalc.c | 6 +++--- networking/libiproute/ip_parse_common_args.c | 15 ++++++--------- networking/libiproute/ipaddress.c | 10 ++++------ networking/libiproute/iplink.c | 6 +++--- networking/libiproute/iproute.c | 15 ++++++--------- networking/libiproute/iprule.c | 21 +++++++++------------ networking/libiproute/iptunnel.c | 10 ++++------ networking/libiproute/libnetlink.c | 12 ++++++------ networking/libiproute/libnetlink.h | 10 +++++----- networking/libiproute/ll_addr.c | 12 +++++------- networking/libiproute/ll_map.c | 15 ++++++--------- networking/libiproute/ll_proto.c | 12 +++++------- networking/libiproute/ll_types.c | 12 +++++------- networking/libiproute/rt_names.c | 12 +++++------- networking/libiproute/rtm_map.c | 13 +++++-------- networking/libiproute/utils.c | 4 ++-- networking/libiproute/utils.h | 6 +++--- networking/nameif.c | 4 ++-- networking/netstat.c | 2 +- networking/ntpd.c | 6 +++--- networking/ntpd_simple.c | 2 +- networking/slattach.c | 4 ++-- networking/telnetd.c | 6 +++--- networking/vconfig.c | 4 ++-- networking/wget.c | 6 +++--- procps/iostat.c | 10 +++++----- procps/mpstat.c | 14 +++++++------- procps/sysctl.c | 2 +- selinux/sestatus.c | 8 ++++---- shell/ash_test/recho.c | 13 ++++--------- shell/ash_test/zecho.c | 5 +---- util-linux/fbset.c | 6 +++--- util-linux/hexdump.c | 12 ++++++------ 69 files changed, 231 insertions(+), 268 deletions(-) diff --git a/archival/ar.c b/archival/ar.c index 05556c6cb..730d7c6c6 100644 --- a/archival/ar.c +++ b/archival/ar.c @@ -179,17 +179,17 @@ static void FAST_FUNC header_verbose_list_ar(const file_header_t *file_header) ); } -#define AR_OPT_VERBOSE (1 << 0) -#define AR_OPT_PRESERVE_DATE (1 << 1) +#define AR_OPT_VERBOSE (1 << 0) +#define AR_OPT_PRESERVE_DATE (1 << 1) /* "ar r" implies create, but warns about it. c suppresses warning. * bbox accepts but ignores it: */ -#define AR_OPT_CREATE (1 << 2) +#define AR_OPT_CREATE (1 << 2) -#define AR_CMD_PRINT (1 << 3) -#define FIRST_CMD AR_CMD_PRINT -#define AR_CMD_LIST (1 << 4) -#define AR_CMD_EXTRACT (1 << 5) -#define AR_CMD_INSERT (1 << 6) +#define AR_CMD_PRINT (1 << 3) +#define FIRST_CMD AR_CMD_PRINT +#define AR_CMD_LIST (1 << 4) +#define AR_CMD_EXTRACT (1 << 5) +#define AR_CMD_INSERT (1 << 6) int ar_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int ar_main(int argc UNUSED_PARAM, char **argv) diff --git a/archival/bz/bzlib.c b/archival/bz/bzlib.c index 834179403..b3beeabed 100644 --- a/archival/bz/bzlib.c +++ b/archival/bz/bzlib.c @@ -28,7 +28,7 @@ in the file LICENSE. * 0.9.0a/b -- no changes in this file. * 0.9.0c -- made zero-length BZ_FLUSH work correctly in bzCompress(). * fixed bzWrite/bzRead to ignore zero-length requests. - * fixed bzread to correctly handle read requests after EOF. + * fixed bzread to correctly handle read requests after EOF. * wrong parameter order in call to bzDecompressInit in * bzBuffToBuffDecompress. Fixed. */ diff --git a/archival/bz/compress.c b/archival/bz/compress.c index b9b0949a9..6f1c70a08 100644 --- a/archival/bz/compress.c +++ b/archival/bz/compress.c @@ -134,15 +134,14 @@ void generateMTFValues(EState* s) * holds the original block data. * * The first thing to do is generate the MTF values, - * and put them in - * ((uint16_t*)s->arr1)[0 .. s->nblock-1]. + * and put them in ((uint16_t*)s->arr1)[0 .. s->nblock-1]. + * * Because there are strictly fewer or equal MTF values * than block values, ptr values in this area are overwritten * with MTF values only when they are no longer needed. * * The final compressed bitstream is generated into the - * area starting at - * &((uint8_t*)s->arr2)[s->nblock] + * area starting at &((uint8_t*)s->arr2)[s->nblock] * * These storage aliases are set up in bzCompressInit(), * except for the last one, which is arranged in @@ -459,7 +458,7 @@ void sendMTFValues(EState* s) } AssertH(nGroups < 8, 3002); - AssertH(nSelectors < 32768 && nSelectors <= (2 + (900000 / BZ_G_SIZE)), 3003); + AssertH(nSelectors < 32768 && nSelectors <= (2 + (900000 / BZ_G_SIZE)), 3003); /*--- Compute MTF values for the selectors. ---*/ { diff --git a/archival/dpkg.c b/archival/dpkg.c index 508b4297b..53e30d541 100644 --- a/archival/dpkg.c +++ b/archival/dpkg.c @@ -939,8 +939,8 @@ static int package_satisfies_dependency(int package, int depend_type) return 0; switch (depend_type) { - case EDGE_PRE_DEPENDS: return get_status(status_num, 3) == search_name_hashtable("installed"); - case EDGE_DEPENDS: return get_status(status_num, 1) == search_name_hashtable("install"); + case EDGE_PRE_DEPENDS: return get_status(status_num, 3) == search_name_hashtable("installed"); + case EDGE_DEPENDS: return get_status(status_num, 1) == search_name_hashtable("install"); } return 0; } @@ -967,7 +967,7 @@ static int check_deps(deb_file_t **deb_file, int deb_start /*, int dep_max_count conflicts[conflicts_num] = package_num; conflicts_num++; /* add provides to conflicts list */ - for (j = 0; j < package_hashtable[package_num]->num_of_edges; j++) { + for (j = 0; j < package_hashtable[package_num]->num_of_edges; j++) { if (package_hashtable[package_num]->edge[j]->type == EDGE_PROVIDES) { const int conflicts_package_num = search_package_hashtable( package_hashtable[package_num]->edge[j]->name, @@ -1067,12 +1067,13 @@ static int check_deps(deb_file_t **deb_file, int deb_start /*, int dep_max_count if (package_edge->type == EDGE_OR_PRE_DEPENDS || package_edge->type == EDGE_OR_DEPENDS - ) { /* start an EDGE_OR_ list */ + ) { + /* start an EDGE_OR_ list */ number_of_alternatives = package_edge->version; root_of_alternatives = package_edge; continue; } - if (number_of_alternatives == 0) { /* not in the middle of an EDGE_OR_ list */ + if (number_of_alternatives == 0) { /* not in the middle of an EDGE_OR_ list */ number_of_alternatives = 1; root_of_alternatives = NULL; } diff --git a/archival/dpkg_deb.c b/archival/dpkg_deb.c index 4c627e890..0ce7c02d8 100644 --- a/archival/dpkg_deb.c +++ b/archival/dpkg_deb.c @@ -7,11 +7,11 @@ #include "libbb.h" #include "unarchive.h" -#define DPKG_DEB_OPT_CONTENTS 1 -#define DPKG_DEB_OPT_CONTROL 2 -#define DPKG_DEB_OPT_FIELD 4 -#define DPKG_DEB_OPT_EXTRACT 8 -#define DPKG_DEB_OPT_EXTRACT_VERBOSE 16 +#define DPKG_DEB_OPT_CONTENTS 1 +#define DPKG_DEB_OPT_CONTROL 2 +#define DPKG_DEB_OPT_FIELD 4 +#define DPKG_DEB_OPT_EXTRACT 8 +#define DPKG_DEB_OPT_EXTRACT_VERBOSE 16 int dpkg_deb_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int dpkg_deb_main(int argc, char **argv) diff --git a/archival/libunarchive/decompress_bunzip2.c b/archival/libunarchive/decompress_bunzip2.c index 549c8b19f..cf6e1988f 100644 --- a/archival/libunarchive/decompress_bunzip2.c +++ b/archival/libunarchive/decompress_bunzip2.c @@ -86,8 +86,8 @@ struct bunzip_data { /* Big things go last (register-relative addressing can be larger for big offsets) */ uint32_t crc32Table[256]; - unsigned char selectors[32768]; /* nSelectors=15 bits */ - struct group_data groups[MAX_GROUPS]; /* Huffman coding tables */ + unsigned char selectors[32768]; /* nSelectors=15 bits */ + struct group_data groups[MAX_GROUPS]; /* Huffman coding tables */ }; /* typedef struct bunzip_data bunzip_data; -- done in .h file */ diff --git a/console-tools/kbd_mode.c b/console-tools/kbd_mode.c index 14f2ae516..1481d0dbb 100644 --- a/console-tools/kbd_mode.c +++ b/console-tools/kbd_mode.c @@ -16,9 +16,9 @@ int kbd_mode_main(int argc UNUSED_PARAM, char **argv) { enum { SCANCODE = (1 << 0), - ASCII = (1 << 1), + ASCII = (1 << 1), MEDIUMRAW = (1 << 2), - UNICODE = (1 << 3), + UNICODE = (1 << 3), }; int fd; unsigned opt; diff --git a/console-tools/loadfont.c b/console-tools/loadfont.c index 3c77813b5..079626c20 100644 --- a/console-tools/loadfont.c +++ b/console-tools/loadfont.c @@ -136,7 +136,7 @@ static void do_loadfont(int fd, unsigned char *inbuf, int height, int width, int * Example: * At the font position for a capital A-ring glyph, we * may have: - * 00C5,212B,FFFE,0041,030A,FFFF + * 00C5,212B,FFFE,0041,030A,FFFF * Some font positions may be described by sequences only, * namely when there is no precomposed Unicode value for the glyph. */ @@ -159,7 +159,7 @@ static void do_loadtable(int fd, unsigned char *inbuf, int tailsz, int fontsize, int glyph; uint16_t unicode; - maxct = tailsz; /* more than enough */ + maxct = tailsz; /* more than enough */ up = xmalloc(maxct * sizeof(*up)); for (glyph = 0; glyph < fontsize; glyph++) { @@ -255,10 +255,10 @@ static void do_load(int fd, unsigned char *buffer, size_t len) } else #endif #if ENABLE_FEATURE_LOADFONT_RAW - if (len == 9780) { /* file with three code pages? */ + if (len == 9780) { /* file with three code pages? */ charsize = height = 16; font += 40; - } else if ((len & 0377) == 0) { /* bare font */ + } else if ((len & 0377) == 0) { /* bare font */ charsize = height = len / 256; } else #endif diff --git a/console-tools/showkey.c b/console-tools/showkey.c index b29c84d6a..e7834f702 100644 --- a/console-tools/showkey.c +++ b/console-tools/showkey.c @@ -16,9 +16,9 @@ struct globals { struct termios tio, tio0; }; #define G (*ptr_to_globals) -#define kbmode (G.kbmode) -#define tio (G.tio) -#define tio0 (G.tio0) +#define kbmode (G.kbmode) +#define tio (G.tio) +#define tio0 (G.tio0) #define INIT_G() do { \ SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \ } while (0) @@ -46,9 +46,9 @@ int showkey_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int showkey_main(int argc UNUSED_PARAM, char **argv) { enum { - OPT_a = (1<<0), // display the decimal/octal/hex values of the keys - OPT_k = (1<<1), // display only the interpreted keycodes (default) - OPT_s = (1<<2), // display only the raw scan-codes + OPT_a = (1<<0), // display the decimal/octal/hex values of the keys + OPT_k = (1<<1), // display only the interpreted keycodes (default) + OPT_s = (1<<2), // display only the raw scan-codes }; INIT_G(); diff --git a/coreutils/date.c b/coreutils/date.c index 87cc8f2ef..a8040757d 100644 --- a/coreutils/date.c +++ b/coreutils/date.c @@ -278,7 +278,7 @@ int date_main(int argc UNUSED_PARAM, char **argv) } /* Correct any day of week and day of year etc. fields */ - tm_time.tm_isdst = -1; /* Be sure to recheck dst */ + tm_time.tm_isdst = -1; /* Be sure to recheck dst */ ts.tv_sec = validate_tm_time(date_str, &tm_time); maybe_set_utc(opt); diff --git a/coreutils/dd.c b/coreutils/dd.c index aa6f765ce..347a19454 100644 --- a/coreutils/dd.c +++ b/coreutils/dd.c @@ -24,7 +24,7 @@ static const struct suffix_mult dd_suffixes[] = { { "b", 512 }, { "kD", 1000 }, { "k", 1024 }, - { "K", 1024 }, /* compat with coreutils dd */ + { "K", 1024 }, /* compat with coreutils dd */ { "MD", 1000000 }, { "M", 1048576 }, { "GD", 1000000000 }, diff --git a/coreutils/mv.c b/coreutils/mv.c index 245639bd0..399f391b2 100644 --- a/coreutils/mv.c +++ b/coreutils/mv.c @@ -92,7 +92,7 @@ int mv_main(int argc, char **argv) || (flags & OPT_FILEUTILS_INTERACTIVE)) ) { if (fprintf(stderr, "mv: overwrite '%s'? ", dest) < 0) { - goto RET_1; /* Ouch! fprintf failed! */ + goto RET_1; /* Ouch! fprintf failed! */ } if (!bb_ask_confirmation()) { goto RET_0; diff --git a/coreutils/nice.c b/coreutils/nice.c index 6b8fce24d..35d6bf3d9 100644 --- a/coreutils/nice.c +++ b/coreutils/nice.c @@ -17,12 +17,12 @@ int nice_main(int argc, char **argv) old_priority = getpriority(PRIO_PROCESS, 0); - if (!*++argv) { /* No args, so (GNU) output current nice value. */ + if (!*++argv) { /* No args, so (GNU) output current nice value. */ printf("%d\n", old_priority); fflush_stdout_and_exit(EXIT_SUCCESS); } - adjustment = 10; /* Set default adjustment. */ + adjustment = 10; /* Set default adjustment. */ if (argv[0][0] == '-') { if (argv[0][1] == 'n') { /* -n */ @@ -32,7 +32,7 @@ int nice_main(int argc, char **argv) } else { /* -NNN (NNN may be negative) == -n NNN */ argv[0] += 1; argv--; argc++; } - if (argc < 4) { /* Missing priority and/or utility! */ + if (argc < 4) { /* Missing priority and/or utility! */ bb_show_usage(); } adjustment = xatoi_range(argv[1], INT_MIN/2, INT_MAX/2); diff --git a/coreutils/od.c b/coreutils/od.c index dcd693446..e62711671 100644 --- a/coreutils/od.c +++ b/coreutils/od.c @@ -4,7 +4,7 @@ * Based on code from util-linux v 2.11l * * Copyright (c) 1990 - * The Regents of the University of California. All rights reserved. + * The Regents of the University of California. All rights reserved. * * Licensed under GPLv2 or later, see file LICENSE in this source tree. * @@ -174,7 +174,7 @@ int od_main(int argc, char **argv) bb_dump_add(dumper, "\" \""); } bb_dump_add(dumper, add_strings[(int)od_o2si[(p - od_opts)]]); - } else { /* P, p, s, w, or other unhandled */ + } else { /* P, p, s, w, or other unhandled */ bb_show_usage(); } } diff --git a/coreutils/sort.c b/coreutils/sort.c index eccc2d437..3562464d1 100644 --- a/coreutils/sort.c +++ b/coreutils/sort.c @@ -52,8 +52,8 @@ enum { static char key_separator; static struct sort_key { - struct sort_key *next_key; /* linked list */ - unsigned range[4]; /* start word, start char, end word, end char */ + struct sort_key *next_key; /* linked list */ + unsigned range[4]; /* start word, start char, end word, end char */ unsigned flags; } *key_list; diff --git a/coreutils/test.c b/coreutils/test.c index f18e3ae5a..6524c4f07 100644 --- a/coreutils/test.c +++ b/coreutils/test.c @@ -49,9 +49,9 @@ * state. */ /* test(1) accepts the following grammar: - oexpr ::= aexpr | aexpr "-o" oexpr ; - aexpr ::= nexpr | nexpr "-a" aexpr ; - nexpr ::= primary | "!" primary + oexpr ::= aexpr | aexpr "-o" oexpr ; + aexpr ::= nexpr | nexpr "-a" aexpr ; + nexpr ::= primary | "!" primary primary ::= unary-operator operand | operand binary-operator operand | operand diff --git a/coreutils/tr.c b/coreutils/tr.c index d6bc7d20a..21d77ef95 100644 --- a/coreutils/tr.c +++ b/coreutils/tr.c @@ -203,7 +203,7 @@ static unsigned expand(const char *arg, char **buffer_p) buffer[pos++] = *arg; /* copy CHAR */ if (!arg[0] || arg[1] != '=' || arg[2] != ']') bb_show_usage(); - arg += 3; /* skip CHAR=] */ + arg += 3; /* skip CHAR=] */ continue; } /* The rest of "[xyz..." cases is treated as normal @@ -258,9 +258,9 @@ int tr_main(int argc UNUSED_PARAM, char **argv) char *invec = vector + ASCII; char *outvec = vector + ASCII * 2; -#define TR_OPT_complement (3 << 0) -#define TR_OPT_delete (1 << 2) -#define TR_OPT_squeeze_reps (1 << 3) +#define TR_OPT_complement (3 << 0) +#define TR_OPT_delete (1 << 2) +#define TR_OPT_squeeze_reps (1 << 3) for (i = 0; i < ASCII; i++) { vector[i] = i; diff --git a/coreutils/wc.c b/coreutils/wc.c index ecadae59b..fe3f274f8 100644 --- a/coreutils/wc.c +++ b/coreutils/wc.c @@ -153,7 +153,7 @@ int wc_main(int argc UNUSED_PARAM, char **argv) bb_simple_perror_msg(arg); status = EXIT_FAILURE; } - goto DO_EOF; /* Treat an EOF as '\r'. */ + goto DO_EOF; /* Treat an EOF as '\r'. */ } /* Cater for -c and -m */ @@ -179,7 +179,7 @@ int wc_main(int argc UNUSED_PARAM, char **argv) */ if (c == '\t') { linepos = (linepos | 7) + 1; - } else { /* '\n', '\r', '\f', or '\v' */ + } else { /* '\n', '\r', '\f', or '\v' */ DO_EOF: if (linepos > counts[WC_LENGTH]) { counts[WC_LENGTH] = linepos; @@ -230,7 +230,7 @@ int wc_main(int argc UNUSED_PARAM, char **argv) * effect of trashing the totals array after outputting it, but that's * irrelavent since we no longer need it. */ if (num_files > 1) { - num_files = 0; /* Make sure we don't get here again. */ + num_files = 0; /* Make sure we don't get here again. */ arg = "total"; pcounts = totals; --argv; diff --git a/e2fsprogs/old_e2fsprogs/e2fsck.h b/e2fsprogs/old_e2fsprogs/e2fsck.h index fdfa2d84a..330209d69 100644 --- a/e2fsprogs/old_e2fsprogs/e2fsck.h +++ b/e2fsprogs/old_e2fsprogs/e2fsck.h @@ -629,7 +629,7 @@ struct e2fsck_struct { }; -#define tid_gt(x, y) ((x - y) > 0) +#define tid_gt(x, y) ((x - y) > 0) static inline int tid_geq(tid_t x, tid_t y) { diff --git a/editors/awk.c b/editors/awk.c index 8bc56756c..2eeb9d77a 100644 --- a/editors/awk.c +++ b/editors/awk.c @@ -277,10 +277,10 @@ enum { /* tokens and their corresponding info values */ -#define NTC "\377" /* switch to next token class (tc<<1) */ -#define NTCC '\377' +#define NTC "\377" /* switch to next token class (tc<<1) */ +#define NTCC '\377' -#define OC_B OC_BUILTIN +#define OC_B OC_BUILTIN static const char tokenlist[] ALIGN1 = "\1(" NTC @@ -368,7 +368,7 @@ static const uint32_t tokeninfo[] = { OC_B|B_ss|P(0x8f), OC_FBLTIN|F_ti, OC_B|B_ti|P(0x0b), OC_B|B_mt|P(0x0b), OC_B|B_lo|P(0x49), OC_B|B_up|P(0x49), OC_GETLINE|SV|P(0), - 0, 0, + 0, 0, 0, 0 /* END */ }; @@ -380,7 +380,7 @@ enum { ORS, RS, RT, FILENAME, SUBSEP, F0, ARGIND, ARGC, ARGV, ERRNO, FNR, NR, - NF, IGNORECASE, ENVIRON, NUM_INTERNAL_VARS + NF, IGNORECASE, ENVIRON, NUM_INTERNAL_VARS }; static const char vNames[] ALIGN1 = @@ -2335,7 +2335,7 @@ static var *evaluate(node *op, var *res) #define fnargs (G.evaluate__fnargs) /* seed is initialized to 1 */ #define seed (G.evaluate__seed) -#define sreg (G.evaluate__sreg) +#define sreg (G.evaluate__sreg) var *v1; @@ -2611,7 +2611,7 @@ static var *evaluate(node *op, var *res) rsm->F = popen(L.s, "r"); rsm->is_pipe = TRUE; } else { - rsm->F = fopen_for_read(L.s); /* not xfopen! */ + rsm->F = fopen_for_read(L.s); /* not xfopen! */ } } } else { diff --git a/editors/diff.c b/editors/diff.c index d9d709db6..cc7ba472e 100644 --- a/editors/diff.c +++ b/editors/diff.c @@ -230,7 +230,7 @@ static int search(const int *c, int k, int y, const struct cand *list) { int i, j; - if (list[c[k]].y < y) /* quick look for typical case */ + if (list[c[k]].y < y) /* quick look for typical case */ return k + 1; for (i = 0, j = k + 1;;) { diff --git a/editors/sed.c b/editors/sed.c index 964d0405e..b91acfb7f 100644 --- a/editors/sed.c +++ b/editors/sed.c @@ -117,9 +117,9 @@ struct globals { char *add_cmd_line; struct pipeline { - char *buf; /* Space to hold string */ - int idx; /* Space used */ - int len; /* Space allocated */ + char *buf; /* Space to hold string */ + int idx; /* Space used */ + int len; /* Space allocated */ } pipeline; } FIX_ALIASING; #define G (*(struct globals*)&bb_common_bufsiz1) diff --git a/include/grp_.h b/include/grp_.h index 7a95f88a6..5c24d558a 100644 --- a/include/grp_.h +++ b/include/grp_.h @@ -18,7 +18,7 @@ 02111-1307 USA. */ /* - * POSIX Standard: 9.2.1 Group Database Access + * POSIX Standard: 9.2.1 Group Database Access */ #ifndef BB_GRP_H #define BB_GRP_H 1 diff --git a/include/platform.h b/include/platform.h index 855cb289c..2666eebee 100644 --- a/include/platform.h +++ b/include/platform.h @@ -155,7 +155,7 @@ # include #elif defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) \ || defined(__APPLE__) -# include /* rlimit */ +# include /* rlimit */ # include # define bswap_64 __bswap64 # define bswap_32 __bswap32 diff --git a/include/pwd_.h b/include/pwd_.h index aa63ac940..e40b71dab 100644 --- a/include/pwd_.h +++ b/include/pwd_.h @@ -18,7 +18,7 @@ 02111-1307 USA. */ /* - * POSIX Standard: 9.2.2 User Database Access + * POSIX Standard: 9.2.2 User Database Access */ #ifndef BB_PWD_H diff --git a/include/rtc_.h b/include/rtc_.h index bd322c940..750fc20ec 100644 --- a/include/rtc_.h +++ b/include/rtc_.h @@ -35,9 +35,9 @@ struct linux_rtc_time { }; struct linux_rtc_wkalrm { - unsigned char enabled; /* 0 = alarm disabled, 1 = alarm enabled */ + unsigned char enabled; /* 0 = alarm disabled, 1 = alarm enabled */ unsigned char pending; /* 0 = alarm not pending, 1 = alarm pending */ - struct linux_rtc_time time; /* time the alarm is set to */ + struct linux_rtc_time time; /* time the alarm is set to */ }; /* diff --git a/libbb/hash_md5_sha.c b/libbb/hash_md5_sha.c index e427f6080..b87d1dde8 100644 --- a/libbb/hash_md5_sha.c +++ b/libbb/hash_md5_sha.c @@ -158,11 +158,11 @@ static void FAST_FUNC md5_process_block64(md5_ctx_t *ctx) }; static const char P_array[] ALIGN1 = { # if MD5_SIZE_VS_SPEED > 1 - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, /* 1 */ + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, /* 1 */ # endif - 1, 6, 11, 0, 5, 10, 15, 4, 9, 14, 3, 8, 13, 2, 7, 12, /* 2 */ - 5, 8, 11, 14, 1, 4, 7, 10, 13, 0, 3, 6, 9, 12, 15, 2, /* 3 */ - 0, 7, 14, 5, 12, 3, 10, 1, 8, 15, 6, 13, 4, 11, 2, 9 /* 4 */ + 1, 6, 11, 0, 5, 10, 15, 4, 9, 14, 3, 8, 13, 2, 7, 12, /* 2 */ + 5, 8, 11, 14, 1, 4, 7, 10, 13, 0, 3, 6, 9, 12, 15, 2, /* 3 */ + 0, 7, 14, 5, 12, 3, 10, 1, 8, 15, 6, 13, 4, 11, 2, 9 /* 4 */ }; #endif uint32_t *words = (void*) ctx->wbuffer; diff --git a/libbb/pw_encrypt_sha.c b/libbb/pw_encrypt_sha.c index 070e0d442..e46848b71 100644 --- a/libbb/pw_encrypt_sha.c +++ b/libbb/pw_encrypt_sha.c @@ -196,9 +196,9 @@ sha_crypt(/*const*/ char *key_data, /*const*/ char *salt_data) //TODO: replace with something like // bb_uuencode(cp, src, length, bb_uuenc_tbl_XXXbase64); #define b64_from_24bit(B2, B1, B0, N) \ -do { \ - unsigned w = ((B2) << 16) | ((B1) << 8) | (B0); \ - resptr = to64(resptr, w, N); \ +do { \ + unsigned w = ((B2) << 16) | ((B1) << 8) | (B0); \ + resptr = to64(resptr, w, N); \ } while (0) if (is_sha512 == '5') { unsigned i = 0; diff --git a/libbb/simplify_path.c b/libbb/simplify_path.c index 3818d32be..89dc5bdf2 100644 --- a/libbb/simplify_path.c +++ b/libbb/simplify_path.c @@ -15,17 +15,17 @@ char* FAST_FUNC bb_simplify_abs_path_inplace(char *start) p = s = start; do { if (*p == '/') { - if (*s == '/') { /* skip duplicate (or initial) slash */ + if (*s == '/') { /* skip duplicate (or initial) slash */ continue; } if (*s == '.') { - if (s[1] == '/' || !s[1]) { /* remove extra '.' */ + if (s[1] == '/' || !s[1]) { /* remove extra '.' */ continue; } if ((s[1] == '.') && (s[2] == '/' || !s[2])) { ++s; if (p > start) { - while (*--p != '/') /* omit previous dir */ + while (*--p != '/') /* omit previous dir */ continue; } continue; @@ -35,8 +35,8 @@ char* FAST_FUNC bb_simplify_abs_path_inplace(char *start) *++p = *s; } while (*++s); - if ((p == start) || (*p != '/')) { /* not a trailing slash */ - ++p; /* so keep last character */ + if ((p == start) || (*p != '/')) { /* not a trailing slash */ + ++p; /* so keep last character */ } *p = '\0'; return p; diff --git a/libpwdgrp/pwd_grp_internal.c b/libpwdgrp/pwd_grp_internal.c index 04e436fae..d6483be84 100644 --- a/libpwdgrp/pwd_grp_internal.c +++ b/libpwdgrp/pwd_grp_internal.c @@ -37,12 +37,12 @@ int GETXXKEY_R_FUNC(GETXXKEY_R_KEYTYPE key, while (1) { rv = bb__pgsreader(GETXXKEY_R_PARSER, resultbuf, buffer, buflen, stream); if (!rv) { - if (GETXXKEY_R_TEST(resultbuf)) { /* Found key? */ + if (GETXXKEY_R_TEST(resultbuf)) { /* found key? */ *result = resultbuf; break; } } else { - if (rv == ENOENT) { /* end-of-file encountered. */ + if (rv == ENOENT) { /* EOF encountered */ rv = 0; } break; diff --git a/miscutils/conspy.c b/miscutils/conspy.c index 040fa86f3..723b4208a 100644 --- a/miscutils/conspy.c +++ b/miscutils/conspy.c @@ -420,19 +420,19 @@ int conspy_main(int argc UNUSED_PARAM, char **argv) if (G.remote.cursor_x < G.x) { G.x = G.remote.cursor_x; - i = 0; // force refresh + i = 0; // force refresh } if (nx > G.x) { G.x = nx; - i = 0; // force refresh + i = 0; // force refresh } if (G.remote.cursor_y < G.y) { G.y = G.remote.cursor_y; - i = 0; // force refresh + i = 0; // force refresh } if (ny > G.y) { G.y = ny; - i = 0; // force refresh + i = 0; // force refresh } } diff --git a/miscutils/ubi_attach_detach.c b/miscutils/ubi_attach_detach.c index 18ffd4df2..b74d97b68 100644 --- a/miscutils/ubi_attach_detach.c +++ b/miscutils/ubi_attach_detach.c @@ -26,8 +26,8 @@ #include "libbb.h" #include -#define OPTION_M (1 << 0) -#define OPTION_D (1 << 1) +#define OPTION_M (1 << 0) +#define OPTION_D (1 << 1) #define do_attach (ENABLE_UBIATTACH && \ (!ENABLE_UBIDETACH || (applet_name[3] == 'a'))) diff --git a/modutils/rmmod.c b/modutils/rmmod.c index dde77731f..2486511d7 100644 --- a/modutils/rmmod.c +++ b/modutils/rmmod.c @@ -35,9 +35,9 @@ int rmmod_main(int argc UNUSED_PARAM, char **argv) /* Parse command line. */ n = getopt32(argv, "wfas"); // -s ignored argv += optind; - if (n & 1) // --wait + if (n & 1) // --wait flags &= ~O_NONBLOCK; - if (n & 2) // --force + if (n & 2) // --force flags |= O_TRUNC; if (n & 4) { /* Unload _all_ unused modules via NULL delete_module() call */ diff --git a/networking/httpd.c b/networking/httpd.c index c174958e2..fa42d9850 100644 --- a/networking/httpd.c +++ b/networking/httpd.c @@ -231,7 +231,7 @@ struct globals { int verbose; /* must be int (used by getopt32) */ smallint flg_deny_all; - unsigned rmt_ip; /* used for IP-based allow/deny rules */ + unsigned rmt_ip; /* used for IP-based allow/deny rules */ time_t last_mod; char *rmt_ip_str; /* for $REMOTE_ADDR and $REMOTE_PORT */ const char *bind_addr_or_port; @@ -267,7 +267,7 @@ struct globals { #if ENABLE_FEATURE_HTTPD_CONFIG_WITH_SCRIPT_INTERPR Htaccess *script_i; /* config script interpreters */ #endif - char *iobuf; /* [IOBUF_SIZE] */ + char *iobuf; /* [IOBUF_SIZE] */ #define hdr_buf bb_common_bufsiz1 char *hdr_ptr; int hdr_cnt; diff --git a/networking/inetd.c b/networking/inetd.c index 7030062b6..ac42c5272 100644 --- a/networking/inetd.c +++ b/networking/inetd.c @@ -295,7 +295,7 @@ struct globals { struct rlimit rlim_ofile; servtab_t *serv_list; int global_queuelen; - int maxsock; /* max fd# in allsock, -1: unknown */ + int maxsock; /* max fd# in allsock, -1: unknown */ /* whenever maxsock grows, prev_maxsock is set to new maxsock, * but if maxsock is set to -1, prev_maxsock is not changed */ int prev_maxsock; diff --git a/networking/ip.c b/networking/ip.c index 7b1e2eb6a..350656cef 100644 --- a/networking/ip.c +++ b/networking/ip.c @@ -1,13 +1,11 @@ /* vi: set sw=4 ts=4: */ /* - * "ip" utility frontend. - * * Licensed under GPLv2 or later, see file LICENSE in this source tree. * * Authors: Alexey Kuznetsov, * * Changes: - * Rani Assaf 980929: resolve addresses + * Rani Assaf 980929: resolve addresses * Bernhard Reutner-Fischer rewrote to use index_in_substr_array */ diff --git a/networking/ipcalc.c b/networking/ipcalc.c index d4aa885c6..acbaa4ac5 100644 --- a/networking/ipcalc.c +++ b/networking/ipcalc.c @@ -15,9 +15,9 @@ /* After libbb.h, because on some systems it needs other includes */ #include -#define CLASS_A_NETMASK ntohl(0xFF000000) -#define CLASS_B_NETMASK ntohl(0xFFFF0000) -#define CLASS_C_NETMASK ntohl(0xFFFFFF00) +#define CLASS_A_NETMASK ntohl(0xFF000000) +#define CLASS_B_NETMASK ntohl(0xFFFF0000) +#define CLASS_C_NETMASK ntohl(0xFFFFFF00) static unsigned long get_netmask(unsigned long ipaddr) { diff --git a/networking/libiproute/ip_parse_common_args.c b/networking/libiproute/ip_parse_common_args.c index bf01528c4..59c759b23 100644 --- a/networking/libiproute/ip_parse_common_args.c +++ b/networking/libiproute/ip_parse_common_args.c @@ -1,18 +1,15 @@ /* vi: set sw=4 ts=4: */ /* - * ip.c "ip" utility frontend. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - * - * Authors: Alexey Kuznetsov, + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. * + * Authors: Alexey Kuznetsov, * * Changes: * - * Rani Assaf 980929: resolve addresses + * Rani Assaf 980929: resolve addresses */ #include "ip_common.h" /* #include "libbb.h" is inside */ diff --git a/networking/libiproute/ipaddress.c b/networking/libiproute/ipaddress.c index 1be03a6c3..397a8ee34 100644 --- a/networking/libiproute/ipaddress.c +++ b/networking/libiproute/ipaddress.c @@ -1,13 +1,11 @@ /* vi: set sw=4 ts=4: */ /* - * ipaddress.c "ip address". - * * Licensed under GPLv2 or later, see file LICENSE in this source tree. * - * Authors: Alexey Kuznetsov, + * Authors: Alexey Kuznetsov, * * Changes: - * Laszlo Valko 990223: address label must be zero terminated + * Laszlo Valko 990223: address label must be zero terminated */ #include @@ -20,7 +18,7 @@ #ifndef IFF_LOWER_UP /* from linux/if.h */ -#define IFF_LOWER_UP 0x10000 /* driver signals L1 up*/ +#define IFF_LOWER_UP 0x10000 /* driver signals L1 up */ #endif struct filter_t { @@ -365,7 +363,7 @@ static int FAST_FUNC print_addrinfo(const struct sockaddr_nl *who UNUSED_PARAM, struct nlmsg_list { struct nlmsg_list *next; - struct nlmsghdr h; + struct nlmsghdr h; }; static int print_selected_addrinfo(int ifindex, struct nlmsg_list *ainfo) diff --git a/networking/libiproute/iplink.c b/networking/libiproute/iplink.c index c5ba294aa..5a86ce678 100644 --- a/networking/libiproute/iplink.c +++ b/networking/libiproute/iplink.c @@ -296,9 +296,9 @@ static int do_change(char **argv, const unsigned rtm) }; struct rtnl_handle rth; struct { - struct nlmsghdr n; - struct ifinfomsg i; - char buf[1024]; + struct nlmsghdr n; + struct ifinfomsg i; + char buf[1024]; } req; smalluint arg; char *name_str = NULL, *link_str = NULL, *type_str = NULL, *dev_str = NULL; diff --git a/networking/libiproute/iproute.c b/networking/libiproute/iproute.c index 1696e6a34..f66774afe 100644 --- a/networking/libiproute/iproute.c +++ b/networking/libiproute/iproute.c @@ -1,19 +1,16 @@ /* vi: set sw=4 ts=4: */ /* - * iproute.c "ip route". - * * Licensed under GPLv2 or later, see file LICENSE in this source tree. * - * Authors: Alexey Kuznetsov, - * + * Authors: Alexey Kuznetsov, * * Changes: * - * Rani Assaf 980929: resolve addresses + * Rani Assaf 980929: resolve addresses * Kunihiro Ishiguro 001102: rtnh_ifindex was not initialized */ -#include "ip_common.h" /* #include "libbb.h" is inside */ +#include "ip_common.h" /* #include "libbb.h" is inside */ #include "rt_names.h" #include "utils.h" @@ -327,9 +324,9 @@ IF_FEATURE_IP_RULE(ARG_table,) }; struct rtnl_handle rth; struct { - struct nlmsghdr n; - struct rtmsg r; - char buf[1024]; + struct nlmsghdr n; + struct rtmsg r; + char buf[1024]; } req; char mxbuf[256]; struct rtattr * mxrta = (void*)mxbuf; diff --git a/networking/libiproute/iprule.c b/networking/libiproute/iprule.c index 3af6a83a8..dd3265c7c 100644 --- a/networking/libiproute/iprule.c +++ b/networking/libiproute/iprule.c @@ -1,18 +1,15 @@ /* vi: set sw=4 ts=4: */ /* - * iprule.c "ip rule". - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - * - * Authors: Alexey Kuznetsov, + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. * + * Authors: Alexey Kuznetsov, * * Changes: * - * Rani Assaf 980929: resolve addresses + * Rani Assaf 980929: resolve addresses * initially integrated into busybox by Bernhard Reutner-Fischer */ @@ -191,9 +188,9 @@ static int iprule_modify(int cmd, char **argv) bool table_ok = 0; struct rtnl_handle rth; struct { - struct nlmsghdr n; - struct rtmsg r; - char buf[1024]; + struct nlmsghdr n; + struct rtmsg r; + char buf[1024]; } req; smalluint key; diff --git a/networking/libiproute/iptunnel.c b/networking/libiproute/iptunnel.c index bce373d05..5942feafc 100644 --- a/networking/libiproute/iptunnel.c +++ b/networking/libiproute/iptunnel.c @@ -1,16 +1,14 @@ /* vi: set sw=4 ts=4: */ /* - * iptunnel.c "ip tunnel" - * * Licensed under GPLv2 or later, see file LICENSE in this source tree. * - * Authors: Alexey Kuznetsov, + * Authors: Alexey Kuznetsov, * * Changes: * - * Rani Assaf 980929: resolve addresses - * Rani Assaf 980930: do not allow key for ipip/sit - * Phil Karn 990408: "pmtudisc" flag + * Rani Assaf 980929: resolve addresses + * Rani Assaf 980930: do not allow key for ipip/sit + * Phil Karn 990408: "pmtudisc" flag */ #include diff --git a/networking/libiproute/libnetlink.c b/networking/libiproute/libnetlink.c index 8da80b2fc..3a37d97f8 100644 --- a/networking/libiproute/libnetlink.c +++ b/networking/libiproute/libnetlink.c @@ -74,8 +74,8 @@ int FAST_FUNC rtnl_dump_request(struct rtnl_handle *rth, int type, void *req, in struct iovec iov[2] = { { &nlh, sizeof(nlh) }, { req, len } }; struct msghdr msg = { (void*)&nladdr, sizeof(nladdr), - iov, 2, - NULL, 0, + iov, 2, + NULL, 0, 0 }; @@ -108,8 +108,8 @@ static int rtnl_dump_filter(struct rtnl_handle *rth, struct msghdr msg = { (void*)&nladdr, sizeof(nladdr), - &iov, 1, - NULL, 0, + &iov, 1, + NULL, 0, 0 }; @@ -214,8 +214,8 @@ int FAST_FUNC rtnl_talk(struct rtnl_handle *rtnl, struct nlmsghdr *n, char *buf = xmalloc(8*1024); /* avoid big stack buffer */ struct msghdr msg = { (void*)&nladdr, sizeof(nladdr), - &iov, 1, - NULL, 0, + &iov, 1, + NULL, 0, 0 }; diff --git a/networking/libiproute/libnetlink.h b/networking/libiproute/libnetlink.h index 4e4d5b7b9..51bee2d67 100644 --- a/networking/libiproute/libnetlink.h +++ b/networking/libiproute/libnetlink.h @@ -11,11 +11,11 @@ PUSH_AND_SET_FUNCTION_VISIBILITY_TO_HIDDEN struct rtnl_handle { - int fd; - struct sockaddr_nl local; - struct sockaddr_nl peer; - uint32_t seq; - uint32_t dump; + int fd; + struct sockaddr_nl local; + struct sockaddr_nl peer; + uint32_t seq; + uint32_t dump; }; extern void xrtnl_open(struct rtnl_handle *rth) FAST_FUNC; diff --git a/networking/libiproute/ll_addr.c b/networking/libiproute/ll_addr.c index c2c01305d..33a54ea6c 100644 --- a/networking/libiproute/ll_addr.c +++ b/networking/libiproute/ll_addr.c @@ -1,13 +1,11 @@ /* vi: set sw=4 ts=4: */ /* - * ll_addr.c + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - * - * Authors: Alexey Kuznetsov, + * Authors: Alexey Kuznetsov, */ #include diff --git a/networking/libiproute/ll_map.c b/networking/libiproute/ll_map.c index 246b9e33a..27cd90f34 100644 --- a/networking/libiproute/ll_map.c +++ b/networking/libiproute/ll_map.c @@ -1,17 +1,14 @@ /* vi: set sw=4 ts=4: */ /* - * ll_map.c - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - * - * Authors: Alexey Kuznetsov, + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. * + * Authors: Alexey Kuznetsov, */ -#include /* struct ifreq and co. */ +#include /* struct ifreq and co. */ #include "libbb.h" #include "libnetlink.h" diff --git a/networking/libiproute/ll_proto.c b/networking/libiproute/ll_proto.c index 1cd576f1d..04925ecf6 100644 --- a/networking/libiproute/ll_proto.c +++ b/networking/libiproute/ll_proto.c @@ -1,13 +1,11 @@ /* vi: set sw=4 ts=4: */ /* - * ll_proto.c + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - * - * Authors: Alexey Kuznetsov, + * Authors: Alexey Kuznetsov, */ #include "libbb.h" diff --git a/networking/libiproute/ll_types.c b/networking/libiproute/ll_types.c index 3861c2870..38b6c0516 100644 --- a/networking/libiproute/ll_types.c +++ b/networking/libiproute/ll_types.c @@ -1,13 +1,11 @@ /* vi: set sw=4 ts=4: */ /* - * ll_types.c + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - * - * Authors: Alexey Kuznetsov, + * Authors: Alexey Kuznetsov, */ #include #include diff --git a/networking/libiproute/rt_names.c b/networking/libiproute/rt_names.c index 8dd16e3d3..c474ab903 100644 --- a/networking/libiproute/rt_names.c +++ b/networking/libiproute/rt_names.c @@ -1,13 +1,11 @@ /* vi: set sw=4 ts=4: */ /* - * rt_names.c rtnetlink names DB. + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - * - * Authors: Alexey Kuznetsov, + * Authors: Alexey Kuznetsov, */ #include "libbb.h" #include "rt_names.h" diff --git a/networking/libiproute/rtm_map.c b/networking/libiproute/rtm_map.c index 5e358e105..3bab53baf 100644 --- a/networking/libiproute/rtm_map.c +++ b/networking/libiproute/rtm_map.c @@ -1,14 +1,11 @@ /* vi: set sw=4 ts=4: */ /* - * rtm_map.c - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - * - * Authors: Alexey Kuznetsov, + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. * + * Authors: Alexey Kuznetsov, */ #include "libbb.h" diff --git a/networking/libiproute/utils.c b/networking/libiproute/utils.c index 2b646f0ea..24698864d 100644 --- a/networking/libiproute/utils.c +++ b/networking/libiproute/utils.c @@ -4,11 +4,11 @@ * * Licensed under GPLv2 or later, see file LICENSE in this source tree. * - * Authors: Alexey Kuznetsov, + * Authors: Alexey Kuznetsov, * * Changes: * - * Rani Assaf 980929: resolve addresses + * Rani Assaf 980929: resolve addresses */ #include "libbb.h" diff --git a/networking/libiproute/utils.h b/networking/libiproute/utils.h index ed03e785a..93c9d25d6 100644 --- a/networking/libiproute/utils.h +++ b/networking/libiproute/utils.h @@ -17,14 +17,14 @@ extern smallint oneline; extern char _SL_; #ifndef IPPROTO_ESP -#define IPPROTO_ESP 50 +#define IPPROTO_ESP 50 #endif #ifndef IPPROTO_AH -#define IPPROTO_AH 51 +#define IPPROTO_AH 51 #endif #define SPRINT_BSIZE 64 -#define SPRINT_BUF(x) char x[SPRINT_BSIZE] +#define SPRINT_BUF(x) char x[SPRINT_BSIZE] extern void incomplete_command(void) NORETURN; diff --git a/networking/nameif.c b/networking/nameif.c index 45a3229f4..d02c2c11b 100644 --- a/networking/nameif.c +++ b/networking/nameif.c @@ -21,10 +21,10 @@ #endif /* Taken from linux/sockios.h */ -#define SIOCSIFNAME 0x8923 /* set interface name */ +#define SIOCSIFNAME 0x8923 /* set interface name */ /* Octets in one Ethernet addr, from */ -#define ETH_ALEN 6 +#define ETH_ALEN 6 #ifndef ifr_newname #define ifr_newname ifr_ifru.ifru_slave diff --git a/networking/netstat.c b/networking/netstat.c index 2a83af3ac..356fb53cb 100644 --- a/networking/netstat.c +++ b/networking/netstat.c @@ -699,7 +699,7 @@ int netstat_main(int argc UNUSED_PARAM, char **argv) flags |= opt; } if (flags & (NETSTAT_TCP|NETSTAT_UDP|NETSTAT_RAW)) { - printf("Active Internet connections "); /* xxx */ + printf("Active Internet connections "); /* xxx */ if ((flags & (NETSTAT_LISTENING|NETSTAT_CONNECTED)) == (NETSTAT_LISTENING|NETSTAT_CONNECTED)) printf("(servers and established)"); diff --git a/networking/ntpd.c b/networking/ntpd.c index b7bd239b5..8fe529edb 100644 --- a/networking/ntpd.c +++ b/networking/ntpd.c @@ -89,7 +89,7 @@ //UNUSED: #define PANIC_THRESHOLD 1000 /* panic threshold (sec) */ #define FREQ_TOLERANCE 0.000015 /* frequency tolerance (15 PPM) */ -#define BURSTPOLL 0 /* initial poll */ +#define BURSTPOLL 0 /* initial poll */ #define MINPOLL 5 /* minimum poll interval. std ntpd uses 6 (6: 64 sec) */ #define BIGPOLL 10 /* drop to lower poll at any trouble (10: 17 min) */ #define MAXPOLL 12 /* maximum poll interval (12: 1.1h, 17: 36.4h). std ntpd uses 17 */ @@ -865,7 +865,7 @@ fit(peer_t *p, double rd) VERB3 bb_error_msg("peer %s unfit for selection: unreachable", p->p_dotted); return 0; } -#if 0 /* we filter out such packets earlier */ +#if 0 /* we filter out such packets earlier */ if ((p->lastpkt_status & LI_ALARM) == LI_ALARM || p->lastpkt_stratum >= MAXSTRAT ) { @@ -2110,7 +2110,7 @@ direct_freq(double fp_offset) } static void -set_freq(double freq) /* frequency update */ +set_freq(double freq) /* frequency update */ { char tbuf[80]; diff --git a/networking/ntpd_simple.c b/networking/ntpd_simple.c index 5905e54e9..4ad44e4f3 100644 --- a/networking/ntpd_simple.c +++ b/networking/ntpd_simple.c @@ -870,7 +870,7 @@ static NOINLINE void ntp_init(char **argv) int prec = 0; int b; # if 0 - struct timespec tp; + struct timespec tp; /* We can use sys_clock_getres but assuming 10ms tick should be fine */ clock_getres(CLOCK_REALTIME, &tp); tp.tv_sec = 0; diff --git a/networking/slattach.c b/networking/slattach.c index 921ec552d..71edd2f27 100644 --- a/networking/slattach.c +++ b/networking/slattach.c @@ -134,9 +134,9 @@ int slattach_main(int argc UNUSED_PARAM, char **argv) int i, encap, opt; struct termios state; const char *proto = "cslip"; - const char *extcmd; /* Command to execute after hangup */ + const char *extcmd; /* Command to execute after hangup */ const char *baud_str; - int baud_code = -1; /* Line baud rate (system code) */ + int baud_code = -1; /* Line baud rate (system code) */ enum { OPT_p_proto = 1 << 0, diff --git a/networking/telnetd.c b/networking/telnetd.c index 5c011e15d..671529d37 100644 --- a/networking/telnetd.c +++ b/networking/telnetd.c @@ -141,7 +141,7 @@ remove_iacs(struct tsession *ts, int *pnum_totty) if (ptr[1] == SB && ptr[2] == TELOPT_NAWS) { struct winsize ws; if ((ptr+8) >= end) - break; /* incomplete, can't process */ + break; /* incomplete, can't process */ ws.ws_col = (ptr[3] << 8) | ptr[4]; ws.ws_row = (ptr[5] << 8) | ptr[6]; ioctl(ts->ptyfd, TIOCSWINSZ, (char *)&ws); @@ -273,8 +273,8 @@ make_new_session( static const char iacs_to_send[] ALIGN1 = { IAC, DO, TELOPT_ECHO, IAC, DO, TELOPT_NAWS, - /* This requires telnetd.ctrlSQ.patch (incomplete) */ - /* IAC, DO, TELOPT_LFLOW, */ + /* This requires telnetd.ctrlSQ.patch (incomplete) */ + /*IAC, DO, TELOPT_LFLOW,*/ IAC, WILL, TELOPT_ECHO, IAC, WILL, TELOPT_SGA }; diff --git a/networking/vconfig.c b/networking/vconfig.c index 1f574d2ad..13c65ad78 100644 --- a/networking/vconfig.c +++ b/networking/vconfig.c @@ -47,8 +47,8 @@ struct vlan_ioctl_args { short vlan_qos; }; -#define VLAN_GROUP_ARRAY_LEN 4096 -#define SIOCSIFVLAN 0x8983 /* Set 802.1Q VLAN options */ +#define VLAN_GROUP_ARRAY_LEN 4096 +#define SIOCSIFVLAN 0x8983 /* Set 802.1Q VLAN options */ /* On entry, table points to the length of the current string * plus NUL terminator plus data length for the subsequent entry. diff --git a/networking/wget.c b/networking/wget.c index 4521abfcf..0db9b3365 100644 --- a/networking/wget.c +++ b/networking/wget.c @@ -6,7 +6,7 @@ * Licensed under GPLv2, see file LICENSE in this source tree. * * Copyright (C) 2010 Bradley M. Kuhn - * Kuhn's copyrights are licensed GPLv2-or-later. File as a whole remains GPLv2. + * Kuhn's copyrights are licensed GPLv2-or-later. File as a whole remains GPLv2. */ #include "libbb.h" @@ -48,7 +48,7 @@ struct BUG_G_too_big { /* Must match option string! */ enum { WGET_OPT_CONTINUE = (1 << 0), - WGET_OPT_SPIDER = (1 << 1), + WGET_OPT_SPIDER = (1 << 1), WGET_OPT_QUIET = (1 << 2), WGET_OPT_OUTNAME = (1 << 3), WGET_OPT_PREFIX = (1 << 4), @@ -785,7 +785,7 @@ However, in real world it was observed that some web servers */ case 204: break; - case 300: /* redirection */ + case 300: /* redirection */ case 301: case 302: case 303: diff --git a/procps/iostat.c b/procps/iostat.c index 5d829861e..a9ff13a05 100644 --- a/procps/iostat.c +++ b/procps/iostat.c @@ -18,14 +18,14 @@ //config: Report CPU and I/O statistics #include "libbb.h" -#include /* Need struct utsname */ +#include /* Need struct utsname */ //#define debug(fmt, ...) fprintf(stderr, fmt, ## __VA_ARGS__) #define debug(fmt, ...) ((void)0) -#define MAX_DEVICE_NAME 12 -#define CURRENT 0 -#define LAST 1 +#define MAX_DEVICE_NAME 12 +#define CURRENT 0 +#define LAST 1 #if 1 typedef unsigned long long cputime_t; @@ -327,7 +327,7 @@ static void do_disk_statistics(cputime_t itv) int i = 0; char buf[128]; unsigned major, minor; - unsigned long wr_ops, dummy; /* %*lu for suppres the conversion wouldn't work */ + unsigned long wr_ops, dummy; /* %*lu for suppress the conversion wouldn't work */ unsigned long long rd_sec_or_wr_ops; unsigned long long rd_sec_or_dummy, wr_sec_or_dummy, wr_sec; struct stats_dev sd; diff --git a/procps/mpstat.c b/procps/mpstat.c index f1a0b00b8..25efedf62 100644 --- a/procps/mpstat.c +++ b/procps/mpstat.c @@ -18,7 +18,7 @@ //config: Per-processor statistics #include "libbb.h" -#include /* struct utsname */ +#include /* struct utsname */ //#define debug(fmt, ...) fprintf(stderr, fmt, ## __VA_ARGS__) #define debug(fmt, ...) ((void)0) @@ -634,7 +634,7 @@ static void get_irqs_from_interrupts(const char *fname, while (irq < irqs_per_cpu) { /* Number of interrupts per CPU has changed */ ic = &per_cpu_stats[current][irq]; - ic->irq_name[0] = '\0'; /* False interrupt */ + ic->irq_name[0] = '\0'; /* False interrupt */ irq++; } } @@ -820,7 +820,7 @@ static int get_irqcpu_nr(const char *f, int max_irqs) unsigned irq; fp = fopen_for_read(f); - if (!fp) /* No interrupts file */ + if (!fp) /* No interrupts file */ return 0; linelen = INTERRUPTS_LINE + 16 * G.cpu_nr; @@ -858,10 +858,10 @@ int mpstat_main(int UNUSED_PARAM argc, char **argv) char *opt_set_cpu; int i, opt; enum { - OPT_ALL = 1 << 0, /* -A */ - OPT_INTS = 1 << 1, /* -I */ - OPT_SETCPU = 1 << 2, /* -P */ - OPT_UTIL = 1 << 3, /* -u */ + OPT_ALL = 1 << 0, /* -A */ + OPT_INTS = 1 << 1, /* -I */ + OPT_SETCPU = 1 << 2, /* -P */ + OPT_UTIL = 1 << 3, /* -u */ }; /* Dont buffer data if redirected to a pipe */ diff --git a/procps/sysctl.c b/procps/sysctl.c index 20b372c54..aba966e7f 100644 --- a/procps/sysctl.c +++ b/procps/sysctl.c @@ -91,7 +91,7 @@ static int sysctl_act_on_setting(char *setting) retval = EXIT_FAILURE; goto end; } - value = cptr + 1; /* point to the value in name=value */ + value = cptr + 1; /* point to the value in name=value */ if (setting == cptr || !*value) { bb_error_msg("error: malformed setting '%s'", outname); retval = EXIT_FAILURE; diff --git a/selinux/sestatus.c b/selinux/sestatus.c index 7fb2b470b..aa12e806c 100644 --- a/selinux/sestatus.c +++ b/selinux/sestatus.c @@ -12,10 +12,10 @@ extern char *selinux_mnt; -#define OPT_VERBOSE (1 << 0) -#define OPT_BOOLEAN (1 << 1) +#define OPT_VERBOSE (1 << 0) +#define OPT_BOOLEAN (1 << 1) -#define COL_FMT "%-31s " +#define COL_FMT "%-31s " static void display_boolean(void) { @@ -151,7 +151,7 @@ int sestatus_main(int argc UNUSED_PARAM, char **argv) const char *pol_path; int rc; - opt_complementary = "?0"; /* no arguments are required. */ + opt_complementary = "?0"; /* no arguments are required. */ opts = getopt32(argv, "vb"); /* SELinux status: line */ diff --git a/shell/ash_test/recho.c b/shell/ash_test/recho.c index fb48d9c48..42a5feafd 100644 --- a/shell/ash_test/recho.c +++ b/shell/ash_test/recho.c @@ -29,12 +29,9 @@ void strprint(); -int -main(argc, argv) -int argc; -char **argv; +int main(int argc, char **argv) { - register int i; + int i; for (i = 1; i < argc; i++) { printf("argv[%d] = <", i); @@ -44,11 +41,9 @@ char **argv; exit(EXIT_SUCCESS); } -void -strprint(str) -char *str; +void strprint(char *str) { - register unsigned char *s; + unsigned char *s; for (s = (unsigned char *)str; s && *s; s++) { if (*s < ' ') { diff --git a/shell/ash_test/zecho.c b/shell/ash_test/zecho.c index bf876f641..cbaa59b81 100644 --- a/shell/ash_test/zecho.c +++ b/shell/ash_test/zecho.c @@ -21,10 +21,7 @@ #include #include -int -main(argc, argv) -int argc; -char **argv; +int main(int argc, char **argv) { argv++; diff --git a/util-linux/fbset.c b/util-linux/fbset.c index 07c8f55d1..77cc1fc12 100644 --- a/util-linux/fbset.c +++ b/util-linux/fbset.c @@ -26,7 +26,7 @@ enum { struct fb_bitfield { uint32_t offset; /* beginning of bitfield */ - uint32_t length; /* length of bitfield */ + uint32_t length; /* length of bitfield */ uint32_t msb_right; /* !=0: Most significant bit is right */ }; struct fb_var_screeninfo { @@ -52,7 +52,7 @@ struct fb_var_screeninfo { uint32_t height; /* height of picture in mm */ uint32_t width; /* width of picture in mm */ - uint32_t accel_flags; /* acceleration flags (hints) */ + uint32_t accel_flags; /* acceleration flags (hints) */ /* Timing: All values in pixclocks, except pixclock (of course) */ uint32_t pixclock; /* pixel clock in ps (pico seconds) */ @@ -317,7 +317,7 @@ static int read_mode_db(struct fb_var_screeninfo *base, const char *fn, } case 4: case 5: - case 6: { + case 6: { static const uint32_t syncs[] = {FB_SYNC_VERT_HIGH_ACT, FB_SYNC_HOR_HIGH_ACT, FB_SYNC_COMP_HIGH_ACT}; ss(&base->sync, syncs[i-4], p, "low"); //bb_info_msg("SYNC[%s]", p); diff --git a/util-linux/hexdump.c b/util-linux/hexdump.c index 8c4d521ab..a38fe05e7 100644 --- a/util-linux/hexdump.c +++ b/util-linux/hexdump.c @@ -4,7 +4,7 @@ * Based on code from util-linux v 2.11l * * Copyright (c) 1989 - * The Regents of the University of California. All rights reserved. + * The Regents of the University of California. All rights reserved. * * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ @@ -32,11 +32,11 @@ static void bb_dump_addfile(dumper_t *dumper, char *name) } static const char *const add_strings[] = { - "\"%07.7_ax \" 16/1 \"%03o \" \"\\n\"", /* b */ - "\"%07.7_ax \" 16/1 \"%3_c \" \"\\n\"", /* c */ - "\"%07.7_ax \" 8/2 \" %05u \" \"\\n\"", /* d */ - "\"%07.7_ax \" 8/2 \" %06o \" \"\\n\"", /* o */ - "\"%07.7_ax \" 8/2 \" %04x \" \"\\n\"", /* x */ + "\"%07.7_ax \" 16/1 \"%03o \" \"\\n\"", /* b */ + "\"%07.7_ax \" 16/1 \"%3_c \" \"\\n\"", /* c */ + "\"%07.7_ax \" 8/2 \" %05u \" \"\\n\"", /* d */ + "\"%07.7_ax \" 8/2 \" %06o \" \"\\n\"", /* o */ + "\"%07.7_ax \" 8/2 \" %04x \" \"\\n\"", /* x */ }; static const char add_first[] ALIGN1 = "\"%07.7_Ax\n\""; -- cgit v1.2.3-55-g6feb From 36ef0a677ee26ea007e0620227d361e14d3940ef Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Fri, 29 Oct 2010 16:05:05 +0200 Subject: decompress_bunzip2: code shrink function old new delta get_next_block 1828 1827 -1 get_bits 164 156 -8 read_bunzip 304 261 -43 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 0/3 up/down: 0/-52) Total: -52 bytes Signed-off-by: Denys Vlasenko --- archival/libunarchive/decompress_bunzip2.c | 111 +++++++++++++++++------------ 1 file changed, 67 insertions(+), 44 deletions(-) diff --git a/archival/libunarchive/decompress_bunzip2.c b/archival/libunarchive/decompress_bunzip2.c index cf6e1988f..3a5d23345 100644 --- a/archival/libunarchive/decompress_bunzip2.c +++ b/archival/libunarchive/decompress_bunzip2.c @@ -16,7 +16,7 @@ function, and various other tweaks. In (limited) tests, approximately 20% faster than bzcat on x86 and about 10% faster on arm. - Note that about 2/3 of the time is spent in read_unzip() reversing + Note that about 2/3 of the time is spent in read_bunzip() reversing the Burrows-Wheeler transformation. Much of that time is delay resulting from cache misses. @@ -70,23 +70,25 @@ struct bunzip_data { /* I/O tracking data (file handles, buffers, positions, etc.) */ unsigned inbufBitCount, inbufBits; int in_fd, out_fd, inbufCount, inbufPos /*, outbufPos*/; - unsigned char *inbuf /*,*outbuf*/; + uint8_t *inbuf /*,*outbuf*/; /* State for interrupting output loop */ - int writeCopies, writePos, writeRunCountdown, writeCount, writeCurrent; + int writeCopies, writePos, writeRunCountdown, writeCount; + int writeCurrent; /* actually a uint8_t */ /* The CRC values stored in the block header and calculated from the data */ uint32_t headerCRC, totalCRC, writeCRC; /* Intermediate buffer and its size (in bytes) */ - unsigned *dbuf, dbufSize; + uint32_t *dbuf; + unsigned dbufSize; /* For I/O error handling */ jmp_buf jmpbuf; /* Big things go last (register-relative addressing can be larger for big offsets) */ uint32_t crc32Table[256]; - unsigned char selectors[32768]; /* nSelectors=15 bits */ + 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 */ @@ -94,14 +96,15 @@ struct bunzip_data { /* Return the next nnn bits of input. All reads from the compressed input are done through this function. All reads are big endian */ - static unsigned get_bits(bunzip_data *bd, int bits_wanted) { unsigned bits = 0; + /* Cache bd->inbufBitCount in a CPU register (hopefully): */ + int bit_count = bd->inbufBitCount; /* If we need to get more data from the byte buffer, do so. (Loop getting one byte at a time to enforce endianness and avoid unaligned access.) */ - while ((int)(bd->inbufBitCount) < bits_wanted) { + while (bit_count < bits_wanted) { /* If we need to read more data from file into byte buffer, do so */ if (bd->inbufPos == bd->inbufCount) { @@ -113,33 +116,35 @@ static unsigned get_bits(bunzip_data *bd, int bits_wanted) } /* Avoid 32-bit overflow (dump bit buffer to top of output) */ - if (bd->inbufBitCount >= 24) { - bits = bd->inbufBits & ((1 << bd->inbufBitCount) - 1); - bits_wanted -= bd->inbufBitCount; + if (bit_count >= 24) { + bits = bd->inbufBits & ((1 << bit_count) - 1); + bits_wanted -= bit_count; bits <<= bits_wanted; - bd->inbufBitCount = 0; + bit_count = 0; } /* Grab next 8 bits of input from buffer. */ bd->inbufBits = (bd->inbufBits << 8) | bd->inbuf[bd->inbufPos++]; - bd->inbufBitCount += 8; + bit_count += 8; } /* Calculate result */ - bd->inbufBitCount -= bits_wanted; - bits |= (bd->inbufBits >> bd->inbufBitCount) & ((1 << bits_wanted) - 1); + bit_count -= bits_wanted; + bd->inbufBitCount = bit_count; + bits |= (bd->inbufBits >> bit_count) & ((1 << bits_wanted) - 1); return bits; } -/* Unpacks the next block and sets up for the inverse burrows-wheeler step. */ +/* Unpacks the next block and sets up for the inverse Burrows-Wheeler step. */ static int get_next_block(bunzip_data *bd) { struct group_data *hufGroup; int dbufCount, nextSym, dbufSize, groupCount, *base, *limit, selector, i, j, k, t, runPos, symCount, symTotal, nSelectors, byteCount[256]; - unsigned char uc, symToByte[256], mtfSymbol[256], *selectors; - unsigned *dbuf, origPtr; + uint8_t uc, symToByte[256], mtfSymbol[256], *selectors; + uint32_t *dbuf; + unsigned origPtr; dbuf = bd->dbuf; dbufSize = bd->dbufSize; @@ -200,7 +205,8 @@ static int get_next_block(bunzip_data *bd) /* Decode MTF to get the next selector */ uc = mtfSymbol[j]; - for (;j;j--) mtfSymbol[j] = mtfSymbol[j-1]; + for (; j; j--) + mtfSymbol[j] = mtfSymbol[j-1]; mtfSymbol[0] = selectors[i] = uc; } @@ -208,7 +214,7 @@ static int get_next_block(bunzip_data *bd) literal symbols, plus two run symbols (RUNA, RUNB) */ symCount = symTotal + 2; for (j = 0; j < groupCount; j++) { - unsigned char length[MAX_SYMBOLS]; + uint8_t length[MAX_SYMBOLS]; /* 8 bits is ALMOST enough for temp[], see below */ unsigned temp[MAX_HUFCODE_BITS+1]; int minLen, maxLen, pp; @@ -315,7 +321,7 @@ static int get_next_block(bunzip_data *bd) memset(byteCount, 0, sizeof(byteCount)); /* smaller, maybe slower? */ for (i = 0; i < 256; i++) { //byteCount[i] = 0; - mtfSymbol[i] = (unsigned char)i; + mtfSymbol[i] = (uint8_t)i; } /* Loop through compressed symbols. */ @@ -456,7 +462,7 @@ static int get_next_block(bunzip_data *bd) /* Figure out what order dbuf would be in if we sorted it. */ for (i = 0; i < dbufCount; i++) { - uc = (unsigned char)(dbuf[i] & 0xff); + uc = (uint8_t)dbuf[i]; dbuf[byteCount[uc]] |= (i << 8); byteCount[uc]++; } @@ -465,10 +471,11 @@ static int get_next_block(bunzip_data *bd) doesn't get output, and if the first three characters are identical it doesn't qualify as a run (hence writeRunCountdown=5). */ if (dbufCount) { + uint32_t tmp; if ((int)origPtr >= dbufCount) return RETVAL_DATA_ERROR; - bd->writePos = dbuf[origPtr]; - bd->writeCurrent = (unsigned char)(bd->writePos & 0xff); - bd->writePos >>= 8; + tmp = dbuf[origPtr]; + bd->writeCurrent = (uint8_t)tmp; + bd->writePos = (tmp >> 8); bd->writeRunCountdown = 5; } bd->writeCount = dbufCount; @@ -476,7 +483,7 @@ static int get_next_block(bunzip_data *bd) return RETVAL_OK; } -/* Undo burrows-wheeler transform on intermediate buffer to produce output. +/* Undo Burrows-Wheeler transform on intermediate buffer to produce output. If start_bunzip was initialized with out_fd=-1, then up to len bytes of data are written to outbuf. Return value is number of bytes written or error (all errors are negative numbers). If out_fd!=-1, outbuf and len @@ -484,7 +491,7 @@ static int get_next_block(bunzip_data *bd) */ int FAST_FUNC read_bunzip(bunzip_data *bd, char *outbuf, int len) { - const unsigned *dbuf; + const uint32_t *dbuf; int pos, current, previous, gotcount; /* If last read was short due to end of file, return last block now */ @@ -500,6 +507,7 @@ int FAST_FUNC read_bunzip(bunzip_data *bd, char *outbuf, int len) Huffman-decoded a block into the intermediate buffer yet). */ if (bd->writeCopies) { + dec_writeCopies: /* Inside the loop, writeCopies means extra copies (beyond 1) */ --bd->writeCopies; @@ -508,10 +516,10 @@ int FAST_FUNC read_bunzip(bunzip_data *bd, char *outbuf, int len) /* If the output buffer is full, snapshot state and return */ if (gotcount >= len) { - bd->writePos = pos; - bd->writeCurrent = current; - bd->writeCopies++; - return len; + /* Unlikely branch. + * Use of "goto" instead of keeping code here + * helps compiler to realize this. */ + goto outbuf_full; } /* Write next byte into output buffer, updating CRC */ @@ -521,15 +529,21 @@ int FAST_FUNC read_bunzip(bunzip_data *bd, char *outbuf, int len) /* Loop now if we're outputting multiple copies of this byte */ if (bd->writeCopies) { - --bd->writeCopies; - continue; + /* Unlikely branch */ + /*--bd->writeCopies;*/ + /*continue;*/ + /* Same, but (ab)using other existing --writeCopies operation. + * Luckily, this also compiles into just one branch insn: */ + goto dec_writeCopies; } decode_next_byte: - if (!bd->writeCount--) break; + if (--bd->writeCount < 0) + break; /* input block is fully consumed, need next one */ + /* Follow sequence vector to undo Burrows-Wheeler transform */ previous = current; pos = dbuf[pos]; - current = pos & 0xff; + current = (uint8_t)pos; pos >>= 8; /* After 3 consecutive copies of the same byte, the 4th @@ -539,7 +553,7 @@ int FAST_FUNC read_bunzip(bunzip_data *bd, char *outbuf, int len) if (current != previous) bd->writeRunCountdown = 4; } else { - + /* Unlikely branch */ /* We have a repeated run, this byte indicates the count */ bd->writeCopies = current; current = previous; @@ -551,9 +565,9 @@ int FAST_FUNC read_bunzip(bunzip_data *bd, char *outbuf, int len) /* Subtract the 1 copy we'd output anyway to get extras */ --bd->writeCopies; } - } + } /* for(;;) */ - /* Decompression of this block completed successfully */ + /* Decompression of this input block completed successfully */ bd->writeCRC = ~bd->writeCRC; bd->totalCRC = ((bd->totalCRC << 1) | (bd->totalCRC >> 31)) ^ bd->writeCRC; @@ -565,16 +579,25 @@ int FAST_FUNC read_bunzip(bunzip_data *bd, char *outbuf, int len) } /* Refill the intermediate buffer by Huffman-decoding next block of input */ - /* (previous is just a convenient unused temp variable here) */ - previous = get_next_block(bd); - if (previous) { - bd->writeCount = previous; - return (previous != RETVAL_LAST_BLOCK) ? previous : gotcount; + { + int r = get_next_block(bd); + if (r) { + bd->writeCount = r; + return (r != RETVAL_LAST_BLOCK) ? r : gotcount; + } } + bd->writeCRC = ~0; pos = bd->writePos; current = bd->writeCurrent; goto decode_next_byte; + + outbuf_full: + /* Output buffer is full, snapshot state and return */ + bd->writePos = pos; + bd->writeCurrent = current; + bd->writeCopies++; + return gotcount; } /* Allocate the structure, read file header. If in_fd==-1, inbuf must contain @@ -607,7 +630,7 @@ int FAST_FUNC start_bunzip(bunzip_data **bdp, int in_fd, /* in this case, bd->inbuf is read-only */ bd->inbuf = (void*)inbuf; /* cast away const-ness */ } else { - bd->inbuf = (unsigned char *)(bd + 1); + bd->inbuf = (uint8_t*)(bd + 1); memcpy(bd->inbuf, inbuf, len); } bd->inbufCount = len; @@ -634,7 +657,7 @@ int FAST_FUNC start_bunzip(bunzip_data **bdp, int in_fd, bd->dbufSize = 100000 * (i - h0); /* Cannot use xmalloc - may leak bd in NOFORK case! */ - bd->dbuf = malloc_or_warn(bd->dbufSize * sizeof(int)); + bd->dbuf = malloc_or_warn(bd->dbufSize * sizeof(bd->dbuf[0])); if (!bd->dbuf) { free(bd); xfunc_die(); -- cgit v1.2.3-55-g6feb From f29a1c56568e2cb572ea8bc47b29f70947abca7a Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Fri, 29 Oct 2010 16:25:18 +0200 Subject: powertop: build fix for !386 compiles Signed-off-by: Denys Vlasenko --- procps/powertop.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/procps/powertop.c b/procps/powertop.c index 250da817b..77b071ffb 100644 --- a/procps/powertop.c +++ b/procps/powertop.c @@ -635,7 +635,7 @@ static NOINLINE void print_intel_cstates(void) bb_putchar('\n'); } #else -# define print_intel_cstates(void) ((void)0) +# define print_intel_cstates() ((void)0) #endif static void show_timerstats(void) -- cgit v1.2.3-55-g6feb From bf3bec51fced9dbc800954885191e5671cb485ef Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Fri, 29 Oct 2010 18:16:29 +0200 Subject: decompress_bunzip2: keep bd->writeCRC in CPU reg in the hot loop -5 bytes on 64-bit, +7 bytes on 32-bit. Signed-off-by: Denys Vlasenko --- archival/libunarchive/decompress_bunzip2.c | 49 +++++++++++++++++------------- 1 file changed, 28 insertions(+), 21 deletions(-) diff --git a/archival/libunarchive/decompress_bunzip2.c b/archival/libunarchive/decompress_bunzip2.c index 3a5d23345..8d7746a79 100644 --- a/archival/libunarchive/decompress_bunzip2.c +++ b/archival/libunarchive/decompress_bunzip2.c @@ -492,15 +492,20 @@ static int get_next_block(bunzip_data *bd) int FAST_FUNC read_bunzip(bunzip_data *bd, char *outbuf, int len) { const uint32_t *dbuf; - int pos, current, previous, gotcount; + int pos, current, previous, out_count; + uint32_t CRC; - /* If last read was short due to end of file, return last block now */ - if (bd->writeCount < 0) return bd->writeCount; + /* If we already have error/end indicator, return it */ + if (bd->writeCount < 0) + return bd->writeCount; - gotcount = 0; + out_count = 0; dbuf = bd->dbuf; + + /* Register-cached state (hopefully): */ pos = bd->writePos; current = bd->writeCurrent; + CRC = bd->writeCRC; /* small loss on x86-32 (not enough regs), win on x86-64 */ /* We will always have pending decoded data to write into the output buffer unless this is the very first call (in which case we haven't @@ -514,8 +519,8 @@ int FAST_FUNC read_bunzip(bunzip_data *bd, char *outbuf, int len) /* Loop outputting bytes */ for (;;) { - /* If the output buffer is full, snapshot state and return */ - if (gotcount >= len) { + /* If the output buffer is full, save cached state and return */ + if (out_count >= len) { /* Unlikely branch. * Use of "goto" instead of keeping code here * helps compiler to realize this. */ @@ -523,17 +528,16 @@ int FAST_FUNC read_bunzip(bunzip_data *bd, char *outbuf, int len) } /* Write next byte into output buffer, updating CRC */ - outbuf[gotcount++] = current; - bd->writeCRC = (bd->writeCRC << 8) - ^ bd->crc32Table[(bd->writeCRC >> 24) ^ current]; + outbuf[out_count++] = current; + CRC = (CRC << 8) ^ bd->crc32Table[(CRC >> 24) ^ current]; /* Loop now if we're outputting multiple copies of this byte */ if (bd->writeCopies) { /* Unlikely branch */ /*--bd->writeCopies;*/ /*continue;*/ - /* Same, but (ab)using other existing --writeCopies operation. - * Luckily, this also compiles into just one branch insn: */ + /* Same, but (ab)using other existing --writeCopies operation + * (and this if() compiles into just test+branch pair): */ goto dec_writeCopies; } decode_next_byte: @@ -549,7 +553,7 @@ int FAST_FUNC read_bunzip(bunzip_data *bd, char *outbuf, int len) /* After 3 consecutive copies of the same byte, the 4th * is a repeat count. We count down from 4 instead * of counting up because testing for non-zero is faster */ - if (--bd->writeRunCountdown) { + if (--bd->writeRunCountdown != 0) { if (current != previous) bd->writeRunCountdown = 4; } else { @@ -568,11 +572,11 @@ int FAST_FUNC read_bunzip(bunzip_data *bd, char *outbuf, int len) } /* for(;;) */ /* Decompression of this input block completed successfully */ - bd->writeCRC = ~bd->writeCRC; - bd->totalCRC = ((bd->totalCRC << 1) | (bd->totalCRC >> 31)) ^ bd->writeCRC; + bd->writeCRC = CRC = ~CRC; + bd->totalCRC = ((bd->totalCRC << 1) | (bd->totalCRC >> 31)) ^ CRC; - /* If this block had a CRC error, force file level CRC error. */ - if (bd->writeCRC != bd->headerCRC) { + /* If this block had a CRC error, force file level CRC error */ + if (CRC != bd->headerCRC) { bd->totalCRC = bd->headerCRC + 1; return RETVAL_LAST_BLOCK; } @@ -581,23 +585,26 @@ int FAST_FUNC read_bunzip(bunzip_data *bd, char *outbuf, int len) /* Refill the intermediate buffer by Huffman-decoding next block of input */ { int r = get_next_block(bd); - if (r) { + if (r) { /* error/end */ bd->writeCount = r; - return (r != RETVAL_LAST_BLOCK) ? r : gotcount; + return (r != RETVAL_LAST_BLOCK) ? r : out_count; } } - bd->writeCRC = ~0; + CRC = ~0; pos = bd->writePos; current = bd->writeCurrent; goto decode_next_byte; outbuf_full: - /* Output buffer is full, snapshot state and return */ + /* Output buffer is full, save cached state and return */ bd->writePos = pos; bd->writeCurrent = current; + bd->writeCRC = CRC; + bd->writeCopies++; - return gotcount; + + return out_count; } /* Allocate the structure, read file header. If in_fd==-1, inbuf must contain -- cgit v1.2.3-55-g6feb From 1014a9adbf2f32684865b052bab803581d416875 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Fri, 29 Oct 2010 19:01:58 +0200 Subject: decompress_bunzip2: relieve register pressure in hot function read_bunzip function old new delta unpack_bz2_stream 318 329 +11 read_bunzip 268 262 -6 Signed-off-by: Denys Vlasenko --- archival/libunarchive/decompress_bunzip2.c | 20 +++++++++++++------- include/unarchive.h | 2 ++ 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/archival/libunarchive/decompress_bunzip2.c b/archival/libunarchive/decompress_bunzip2.c index 8d7746a79..00ec47c75 100644 --- a/archival/libunarchive/decompress_bunzip2.c +++ b/archival/libunarchive/decompress_bunzip2.c @@ -488,18 +488,21 @@ static int get_next_block(bunzip_data *bd) data are written to outbuf. Return value is number of bytes written or error (all errors are negative numbers). If out_fd!=-1, outbuf and len are ignored, data is written to out_fd and return is RETVAL_OK or error. + + 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. + (Why? This allows to get rid of one local variable) */ int FAST_FUNC read_bunzip(bunzip_data *bd, char *outbuf, int len) { const uint32_t *dbuf; - int pos, current, previous, out_count; + int pos, current, previous; uint32_t CRC; /* If we already have error/end indicator, return it */ if (bd->writeCount < 0) return bd->writeCount; - out_count = 0; dbuf = bd->dbuf; /* Register-cached state (hopefully): */ @@ -520,7 +523,7 @@ int FAST_FUNC read_bunzip(bunzip_data *bd, char *outbuf, int len) for (;;) { /* If the output buffer is full, save cached state and return */ - if (out_count >= len) { + if (--len < 0) { /* Unlikely branch. * Use of "goto" instead of keeping code here * helps compiler to realize this. */ @@ -528,7 +531,7 @@ int FAST_FUNC read_bunzip(bunzip_data *bd, char *outbuf, int len) } /* Write next byte into output buffer, updating CRC */ - outbuf[out_count++] = current; + *outbuf++ = current; CRC = (CRC << 8) ^ bd->crc32Table[(CRC >> 24) ^ current]; /* Loop now if we're outputting multiple copies of this byte */ @@ -587,7 +590,7 @@ int FAST_FUNC read_bunzip(bunzip_data *bd, char *outbuf, int len) int r = get_next_block(bd); if (r) { /* error/end */ bd->writeCount = r; - return (r != RETVAL_LAST_BLOCK) ? r : out_count; + return (r != RETVAL_LAST_BLOCK) ? r : len; } } @@ -604,7 +607,7 @@ int FAST_FUNC read_bunzip(bunzip_data *bd, char *outbuf, int len) bd->writeCopies++; - return out_count; + return 0; } /* Allocate the structure, read file header. If in_fd==-1, inbuf must contain @@ -698,7 +701,10 @@ unpack_bz2_stream(int src_fd, int dst_fd) if (i == 0) { while (1) { /* "Produce some output bytes" loop */ i = read_bunzip(bd, outbuf, IOBUF_SIZE); - if (i <= 0) + if (i < 0) /* error? */ + break; + i = IOBUF_SIZE - i; /* number of bytes produced */ + if (i == 0) /* EOF? */ break; if (i != full_write(dst_fd, outbuf, i)) { bb_error_msg("short write"); diff --git a/include/unarchive.h b/include/unarchive.h index 11d8c77a0..ba6d323e0 100644 --- a/include/unarchive.h +++ b/include/unarchive.h @@ -194,6 +194,8 @@ extern const llist_t *find_list_entry2(const llist_t *list, const char *filename /* A bit of bunzip2 internals are exposed for compressed help support: */ typedef struct bunzip_data bunzip_data; int start_bunzip(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; -- cgit v1.2.3-55-g6feb From 1642d0271027a7021a0a69fda3ac7082f5b01314 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Fri, 29 Oct 2010 19:06:20 +0200 Subject: scripts/mkdiff_obj: show "size OBJFILE" too Signed-off-by: Denys Vlasenko --- scripts/mkdiff_obj | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/mkdiff_obj b/scripts/mkdiff_obj index f783491af..307474874 100755 --- a/scripts/mkdiff_obj +++ b/scripts/mkdiff_obj @@ -39,8 +39,8 @@ while IFS='' read -r oname; do continue fi diff -q -- "$1/$oname" "$2/$oname" >/dev/null && continue - (cd "$1"; objdump -dr "$oname" | filter >"$oname.disasm") - (cd "$2"; objdump -dr "$oname" | filter >"$oname.disasm") + (cd "$1" && { size "$oname"; objdump -dr "$oname" | filter; } >"$oname.disasm") + (cd "$2" && { size "$oname"; objdump -dr "$oname" | filter; } >"$oname.disasm") diff -u -- "$1/$oname.disasm" "$2/$oname.disasm" done ) -- cgit v1.2.3-55-g6feb From 5d49b72f1a3a362957171610b722ca8ec3f49734 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Fri, 29 Oct 2010 19:26:38 +0200 Subject: decompress_bunzip2: add profiling data to comment. no code changes Signed-off-by: Denys Vlasenko --- archival/libunarchive/decompress_bunzip2.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/archival/libunarchive/decompress_bunzip2.c b/archival/libunarchive/decompress_bunzip2.c index 00ec47c75..2fa0f898a 100644 --- a/archival/libunarchive/decompress_bunzip2.c +++ b/archival/libunarchive/decompress_bunzip2.c @@ -20,6 +20,17 @@ the Burrows-Wheeler transformation. Much of that time is delay resulting from cache misses. + (2010 update by vda: profiled "bzcat <84mbyte.bz2 >/dev/null" + on x86-64 CPU with L2 > 1M: get_next_block is hotter than read_bunzip: + %time seconds calls function + 71.01 12.69 444 get_next_block + 28.65 5.12 93065 read_bunzip + 00.22 0.04 7736490 get_bits + 00.11 0.02 47 dealloc_bunzip + 00.00 0.00 93018 full_write + ...) + + I would ask that anyone benefiting from this work, especially those using it in commercial products, consider making a donation to my local non-profit hospice organization (www.hospiceacadiana.com) in the name of -- cgit v1.2.3-55-g6feb From 0c576975c87c543522ab31566139c078429dff38 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sat, 30 Oct 2010 00:54:10 +0200 Subject: decompress_bunzip2: code shrink ~10 bytes Signed-off-by: Denys Vlasenko --- archival/libunarchive/decompress_bunzip2.c | 173 +++++++++++++++++------------ 1 file changed, 99 insertions(+), 74 deletions(-) diff --git a/archival/libunarchive/decompress_bunzip2.c b/archival/libunarchive/decompress_bunzip2.c index 2fa0f898a..2d4867220 100644 --- a/archival/libunarchive/decompress_bunzip2.c +++ b/archival/libunarchive/decompress_bunzip2.c @@ -151,8 +151,8 @@ static unsigned get_bits(bunzip_data *bd, int bits_wanted) static int get_next_block(bunzip_data *bd) { struct group_data *hufGroup; - int dbufCount, nextSym, dbufSize, groupCount, *base, *limit, selector, - i, j, k, t, runPos, symCount, symTotal, nSelectors, byteCount[256]; + int dbufCount, dbufSize, groupCount, *base, *limit, selector, + i, j, t, runPos, symCount, symTotal, nSelectors, byteCount[256]; uint8_t uc, symToByte[256], mtfSymbol[256], *selectors; uint32_t *dbuf; unsigned origPtr; @@ -161,9 +161,12 @@ static int get_next_block(bunzip_data *bd) dbufSize = bd->dbufSize; selectors = bd->selectors; +/* In bbox, we are ok with aborting through setjmp which is set up in start_bunzip */ +#if 0 /* Reset longjmp I/O error handling */ i = setjmp(bd->jmpbuf); if (i) return i; +#endif /* Read in header signature and CRC, then validate signature. (last block signature means CRC is for whole file, return now) */ @@ -185,16 +188,23 @@ static int get_next_block(bunzip_data *bd) symbols to deal with, and writes a sparse bitfield indicating which values were present. We make a translation table to convert the symbols back to the corresponding bytes. */ - t = get_bits(bd, 16); symTotal = 0; - for (i = 0; i < 16; i++) { - if (t & (1 << (15-i))) { - k = get_bits(bd, 16); - for (j = 0; j < 16; j++) - if (k & (1 << (15-j))) - symToByte[symTotal++] = (16*i) + j; + i = 0; + t = get_bits(bd, 16); + do { + if (t & (1 << 15)) { + unsigned inner_map = get_bits(bd, 16); + do { + if (inner_map & (1 << 15)) + symToByte[symTotal++] = i; + inner_map <<= 1; + i++; + } while (i & 15); + i -= 16; } - } + t <<= 1; + i += 16; + } while (i < 256); /* How many different Huffman coding groups does this block use? */ groupCount = get_bits(bd, 3); @@ -205,20 +215,24 @@ static int get_next_block(bunzip_data *bd) group. Read in the group selector list, which is stored as MTF encoded bit runs. (MTF=Move To Front, as each value is used it's moved to the start of the list.) */ + for (i = 0; i < groupCount; i++) + mtfSymbol[i] = i; nSelectors = get_bits(bd, 15); - if (!nSelectors) return RETVAL_DATA_ERROR; - for (i = 0; i < groupCount; i++) mtfSymbol[i] = i; + if (!nSelectors) + return RETVAL_DATA_ERROR; for (i = 0; i < nSelectors; i++) { - + uint8_t tmp_byte; /* Get next value */ - for (j = 0; get_bits(bd, 1); j++) - if (j >= groupCount) return RETVAL_DATA_ERROR; - + int n = 0; + while (get_bits(bd, 1)) { + if (n >= groupCount) return RETVAL_DATA_ERROR; + n++; + } /* Decode MTF to get the next selector */ - uc = mtfSymbol[j]; - for (; j; j--) - mtfSymbol[j] = mtfSymbol[j-1]; - mtfSymbol[0] = selectors[i] = uc; + tmp_byte = mtfSymbol[n]; + while (--n >= 0) + mtfSymbol[n + 1] = mtfSymbol[n]; + mtfSymbol[0] = selectors[i] = tmp_byte; } /* Read the Huffman coding tables for each group, which code for symTotal @@ -239,20 +253,21 @@ static int get_next_block(bunzip_data *bd) t = get_bits(bd, 5) - 1; for (i = 0; i < symCount; i++) { for (;;) { + int two_bits; if ((unsigned)t > (MAX_HUFCODE_BITS-1)) return RETVAL_DATA_ERROR; /* If first bit is 0, stop. Else second bit indicates whether to increment or decrement the value. Optimization: grab 2 bits and unget the second if the first was 0. */ - k = get_bits(bd, 2); - if (k < 2) { + two_bits = get_bits(bd, 2); + if (two_bits < 2) { bd->inbufBitCount++; break; } /* Add one if second bit 1, else subtract 1. Avoids if/else */ - t += (((k+1) & 2) - 1); + t += (((two_bits+1) & 2) - 1); } /* Correct for the initial -1, to get the final symbol length */ @@ -282,17 +297,18 @@ static int get_next_block(bunzip_data *bd) /* Note that minLen can't be smaller than 1, so we adjust the base and limit array pointers so we're not always wasting the first - entry. We do this again when using them (during symbol decoding).*/ + entry. We do this again when using them (during symbol decoding). */ base = hufGroup->base - 1; limit = hufGroup->limit - 1; /* Calculate permute[]. Concurently, initialize temp[] and limit[]. */ pp = 0; for (i = minLen; i <= maxLen; i++) { + int k; temp[i] = limit[i] = 0; - for (t = 0; t < symCount; t++) - if (length[t] == i) - hufGroup->permute[pp++] = t; + for (k = 0; k < symCount; k++) + if (length[k] == i) + hufGroup->permute[pp++] = k; } /* Count symbols coded for at each bit length */ @@ -305,8 +321,10 @@ static int get_next_block(bunzip_data *bd) * base[] (number of symbols to ignore at each bit length, which is * limit minus the cumulative count of symbols coded for already). */ pp = t = 0; - for (i = minLen; i < maxLen; i++) { - pp += temp[i]; + for (i = minLen; i < maxLen;) { + unsigned temp_i = temp[i]; + + pp += temp_i; /* We read the largest possible symbol size and then unget bits after determining how many we need, and those extra bits could @@ -316,8 +334,8 @@ static int get_next_block(bunzip_data *bd) don't affect the value>limit[length] comparison. */ limit[i] = (pp << (maxLen - i)) - 1; pp <<= 1; - t += temp[i]; - base[i+1] = pp - t; + t += temp_i; + base[++i] = pp - t; } limit[maxLen+1] = INT_MAX; /* Sentinel value for reading next sym. */ limit[maxLen] = pp + temp[maxLen] - 1; @@ -329,9 +347,9 @@ static int get_next_block(bunzip_data *bd) and run length encoding, saving the result into dbuf[dbufCount++] = uc */ /* Initialize symbol occurrence counters and symbol Move To Front table */ - memset(byteCount, 0, sizeof(byteCount)); /* smaller, maybe slower? */ + /*memset(byteCount, 0, sizeof(byteCount)); - smaller, but slower */ for (i = 0; i < 256; i++) { - //byteCount[i] = 0; + byteCount[i] = 0; mtfSymbol[i] = (uint8_t)i; } @@ -339,6 +357,7 @@ static int get_next_block(bunzip_data *bd) runPos = dbufCount = selector = 0; for (;;) { + int nextSym; /* Fetch next Huffman coding group from list. */ symCount = GROUP_SIZE - 1; @@ -346,44 +365,49 @@ static int get_next_block(bunzip_data *bd) hufGroup = bd->groups + selectors[selector++]; base = hufGroup->base - 1; limit = hufGroup->limit - 1; - continue_this_group: + continue_this_group: /* Read next Huffman-coded symbol. */ /* Note: It is far cheaper to read maxLen bits and back up than it is - to read minLen bits and then an additional bit at a time, testing + to read minLen bits and then add additional bit at a time, testing as we go. Because there is a trailing last block (with file CRC), there is no danger of the overread causing an unexpected EOF for a - valid compressed file. As a further optimization, we do the read - inline (falling back to a call to get_bits if the buffer runs - dry). The following (up to got_huff_bits:) is equivalent to - j = get_bits(bd, hufGroup->maxLen); + valid compressed file. */ - while ((int)(bd->inbufBitCount) < hufGroup->maxLen) { - if (bd->inbufPos == bd->inbufCount) { - j = get_bits(bd, hufGroup->maxLen); - goto got_huff_bits; - } - bd->inbufBits = (bd->inbufBits << 8) | bd->inbuf[bd->inbufPos++]; - bd->inbufBitCount += 8; - }; - bd->inbufBitCount -= hufGroup->maxLen; - j = (bd->inbufBits >> bd->inbufBitCount) & ((1 << hufGroup->maxLen) - 1); - - got_huff_bits: - - /* Figure how how many bits are in next symbol and unget extras */ + if (1) { + /* As a further optimization, we do the read inline + (falling back to a call to get_bits if the buffer runs dry). + */ + int new_cnt; + while ((new_cnt = bd->inbufBitCount - hufGroup->maxLen) < 0) { + /* bd->inbufBitCount < hufGroup->maxLen */ + if (bd->inbufPos == bd->inbufCount) { + nextSym = get_bits(bd, hufGroup->maxLen); + goto got_huff_bits; + } + bd->inbufBits = (bd->inbufBits << 8) | bd->inbuf[bd->inbufPos++]; + bd->inbufBitCount += 8; + }; + bd->inbufBitCount = new_cnt; /* "bd->inbufBitCount -= hufGroup->maxLen;" */ + nextSym = (bd->inbufBits >> new_cnt) & ((1 << hufGroup->maxLen) - 1); + got_huff_bits: ; + } else { /* unoptimized equivalent */ + nextSym = get_bits(bd, hufGroup->maxLen); + } + /* Figure how many bits are in next symbol and unget extras */ i = hufGroup->minLen; - while (j > limit[i]) ++i; - bd->inbufBitCount += (hufGroup->maxLen - i); + while (nextSym > limit[i]) ++i; + j = hufGroup->maxLen - i; + if (j < 0) + return RETVAL_DATA_ERROR; + bd->inbufBitCount += j; /* Huffman decode value to get nextSym (with bounds checking) */ - if (i > hufGroup->maxLen) + nextSym = (nextSym >> j) - base[i]; + if ((unsigned)nextSym >= MAX_SYMBOLS) return RETVAL_DATA_ERROR; - j = (j >> (hufGroup->maxLen - i)) - base[i]; - if ((unsigned)j >= MAX_SYMBOLS) - return RETVAL_DATA_ERROR; - nextSym = hufGroup->permute[j]; + nextSym = hufGroup->permute[nextSym]; /* We have now decoded the symbol, which indicates either a new literal byte, or a repeated run of the most recent literal byte. First, @@ -392,7 +416,7 @@ static int get_next_block(bunzip_data *bd) if ((unsigned)nextSym <= SYMBOL_RUNB) { /* RUNA or RUNB */ /* If this is the start of a new run, zero out counter */ - if (!runPos) { + if (runPos == 0) { runPos = 1; t = 0; } @@ -413,13 +437,13 @@ static int get_next_block(bunzip_data *bd) how many times to repeat the last literal, so append that many copies to our buffer of decoded symbols (dbuf) now. (The last literal used is the one at the head of the mtfSymbol array.) */ - if (runPos) { - runPos = 0; + if (runPos != 0) { + uint8_t tmp_byte; if (dbufCount + t >= dbufSize) return RETVAL_DATA_ERROR; - - uc = symToByte[mtfSymbol[0]]; - byteCount[uc] += t; - while (t--) dbuf[dbufCount++] = uc; + tmp_byte = symToByte[mtfSymbol[0]]; + byteCount[tmp_byte] += t; + while (--t >= 0) dbuf[dbufCount++] = tmp_byte; + runPos = 0; } /* Is this the terminating symbol? */ @@ -448,12 +472,12 @@ static int get_next_block(bunzip_data *bd) /* We have our literal byte. Save it into dbuf. */ byteCount[uc]++; - dbuf[dbufCount++] = (unsigned)uc; + dbuf[dbufCount++] = (uint32_t)uc; /* Skip group initialization if we're not done with this group. Done * this way to avoid compiler warning. */ end_of_huffman_loop: - if (symCount--) goto continue_this_group; + if (--symCount >= 0) goto continue_this_group; } /* At this point, we've read all the Huffman-coded symbols (and repeated @@ -466,16 +490,17 @@ static int get_next_block(bunzip_data *bd) /* Turn byteCount into cumulative occurrence counts of 0 to n-1. */ j = 0; for (i = 0; i < 256; i++) { - k = j + byteCount[i]; + int tmp_count = j + byteCount[i]; byteCount[i] = j; - j = k; + j = tmp_count; } /* Figure out what order dbuf would be in if we sorted it. */ for (i = 0; i < dbufCount; i++) { - uc = (uint8_t)dbuf[i]; - dbuf[byteCount[uc]] |= (i << 8); - byteCount[uc]++; + uint8_t tmp_byte = (uint8_t)dbuf[i]; + int tmp_count = byteCount[tmp_byte]; + dbuf[tmp_count] |= (i << 8); + byteCount[tmp_byte] = tmp_count + 1; } /* Decode first byte by hand to initialize "previous" byte. Note that it -- cgit v1.2.3-55-g6feb From f16727ebbbb385b1bf4d03608a04f8310469cf1f Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sat, 30 Oct 2010 00:55:02 +0200 Subject: decompress_bunzip2: code shrink ~5 bytes Signed-off-by: Denys Vlasenko --- archival/libunarchive/decompress_bunzip2.c | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/archival/libunarchive/decompress_bunzip2.c b/archival/libunarchive/decompress_bunzip2.c index 2d4867220..d30166fa4 100644 --- a/archival/libunarchive/decompress_bunzip2.c +++ b/archival/libunarchive/decompress_bunzip2.c @@ -153,6 +153,7 @@ static int get_next_block(bunzip_data *bd) struct group_data *hufGroup; int dbufCount, dbufSize, groupCount, *base, *limit, selector, i, j, t, runPos, symCount, symTotal, nSelectors, byteCount[256]; + int runCnt = runCnt; /* for compiler */ uint8_t uc, symToByte[256], mtfSymbol[256], *selectors; uint32_t *dbuf; unsigned origPtr; @@ -242,19 +243,19 @@ static int get_next_block(bunzip_data *bd) uint8_t length[MAX_SYMBOLS]; /* 8 bits is ALMOST enough for temp[], see below */ unsigned temp[MAX_HUFCODE_BITS+1]; - int minLen, maxLen, pp; + int minLen, maxLen, pp, len_m1; /* Read Huffman code lengths for each symbol. They're stored in a way similar to mtf; record a starting value for the first symbol, - and an offset from the previous value for everys symbol after that. + and an offset from the previous value for every symbol after that. (Subtracting 1 before the loop and then adding it back at the end is an optimization that makes the test inside the loop simpler: symbol length 0 becomes negative, so an unsigned inequality catches it.) */ - t = get_bits(bd, 5) - 1; + len_m1 = get_bits(bd, 5) - 1; for (i = 0; i < symCount; i++) { for (;;) { int two_bits; - if ((unsigned)t > (MAX_HUFCODE_BITS-1)) + if ((unsigned)len_m1 > (MAX_HUFCODE_BITS-1)) return RETVAL_DATA_ERROR; /* If first bit is 0, stop. Else second bit indicates whether @@ -267,11 +268,11 @@ static int get_next_block(bunzip_data *bd) } /* Add one if second bit 1, else subtract 1. Avoids if/else */ - t += (((two_bits+1) & 2) - 1); + len_m1 += (((two_bits+1) & 2) - 1); } /* Correct for the initial -1, to get the final symbol length */ - length[i] = t + 1; + length[i] = len_m1 + 1; } /* Find largest and smallest lengths in this group */ @@ -337,8 +338,8 @@ static int get_next_block(bunzip_data *bd) t += temp_i; base[++i] = pp - t; } - limit[maxLen+1] = INT_MAX; /* Sentinel value for reading next sym. */ limit[maxLen] = pp + temp[maxLen] - 1; + limit[maxLen+1] = INT_MAX; /* Sentinel value for reading next sym. */ base[minLen] = 0; } @@ -418,7 +419,7 @@ static int get_next_block(bunzip_data *bd) /* If this is the start of a new run, zero out counter */ if (runPos == 0) { runPos = 1; - t = 0; + runCnt = 0; } /* Neat trick that saves 1 symbol: instead of or-ing 0 or 1 at @@ -428,7 +429,7 @@ static int get_next_block(bunzip_data *bd) the basic or 0/1 method (except all bits 0, which would use no symbols, but a run of length 0 doesn't mean anything in this context). Thus space is saved. */ - t += (runPos << nextSym); /* +runPos if RUNA; +2*runPos if RUNB */ + runCnt += (runPos << nextSym); /* +runPos if RUNA; +2*runPos if RUNB */ if (runPos < dbufSize) runPos <<= 1; goto end_of_huffman_loop; } @@ -439,10 +440,10 @@ static int get_next_block(bunzip_data *bd) literal used is the one at the head of the mtfSymbol array.) */ if (runPos != 0) { uint8_t tmp_byte; - if (dbufCount + t >= dbufSize) return RETVAL_DATA_ERROR; + if (dbufCount + runCnt >= dbufSize) return RETVAL_DATA_ERROR; tmp_byte = symToByte[mtfSymbol[0]]; - byteCount[tmp_byte] += t; - while (--t >= 0) dbuf[dbufCount++] = tmp_byte; + byteCount[tmp_byte] += runCnt; + while (--runCnt >= 0) dbuf[dbufCount++] = (uint32_t)tmp_byte; runPos = 0; } -- cgit v1.2.3-55-g6feb From 11872cab325f99b3719bc0416401a656556d6230 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sat, 30 Oct 2010 02:24:48 +0200 Subject: networking/*: remove superfluous comments Signed-off-by: Denys Vlasenko --- networking/arping.c | 4 +--- networking/libiproute/iplink.c | 2 -- networking/libiproute/libnetlink.c | 2 -- networking/libiproute/utils.c | 2 -- networking/tc.c | 2 -- 5 files changed, 1 insertion(+), 11 deletions(-) diff --git a/networking/arping.c b/networking/arping.c index f2b12ed04..6f6b59cfb 100644 --- a/networking/arping.c +++ b/networking/arping.c @@ -1,10 +1,8 @@ /* vi: set sw=4 ts=4: */ /* - * arping.c - Ping hosts by ARP requests/replies - * * Licensed under GPLv2 or later, see file LICENSE in this source tree. * - * Author: Alexey Kuznetsov + * Author: Alexey Kuznetsov * Busybox port: Nick Fedchik */ diff --git a/networking/libiproute/iplink.c b/networking/libiproute/iplink.c index 5a86ce678..82ab979a5 100644 --- a/networking/libiproute/iplink.c +++ b/networking/libiproute/iplink.c @@ -1,7 +1,5 @@ /* vi: set sw=4 ts=4: */ /* - * iplink.c "ip link". - * * Authors: Alexey Kuznetsov, * * Licensed under GPLv2 or later, see file LICENSE in this source tree. diff --git a/networking/libiproute/libnetlink.c b/networking/libiproute/libnetlink.c index 3a37d97f8..7291ee2f1 100644 --- a/networking/libiproute/libnetlink.c +++ b/networking/libiproute/libnetlink.c @@ -1,7 +1,5 @@ /* vi: set sw=4 ts=4: */ /* - * RTnetlink service routines. - * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version diff --git a/networking/libiproute/utils.c b/networking/libiproute/utils.c index 24698864d..d32db8de5 100644 --- a/networking/libiproute/utils.c +++ b/networking/libiproute/utils.c @@ -1,7 +1,5 @@ /* vi: set sw=4 ts=4: */ /* - * utils.c - * * Licensed under GPLv2 or later, see file LICENSE in this source tree. * * Authors: Alexey Kuznetsov, diff --git a/networking/tc.c b/networking/tc.c index 9242741e4..2e2473a70 100644 --- a/networking/tc.c +++ b/networking/tc.c @@ -1,7 +1,5 @@ /* vi: set sw=4 ts=4: */ /* - * "tc" utility frontend. - * * Licensed under GPLv2 or later, see file LICENSE in this source tree. * * Authors: Alexey Kuznetsov, -- cgit v1.2.3-55-g6feb From d7559c274139c91af5ce77bd4b9f863f78a69f69 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sat, 30 Oct 2010 02:40:08 +0200 Subject: fdisk: fix trivial build failure Signed-off-by: Denys Vlasenko --- util-linux/fdisk.c | 1 + 1 file changed, 1 insertion(+) diff --git a/util-linux/fdisk.c b/util-linux/fdisk.c index 3f2e0d3ae..02785ab85 100644 --- a/util-linux/fdisk.c +++ b/util-linux/fdisk.c @@ -662,6 +662,7 @@ STATIC_OSF void bsd_select(void); STATIC_OSF void xbsd_print_disklabel(int); #include "fdisk_osf.c" +STATIC_GPT void gpt_list_table(int xtra); #include "fdisk_gpt.c" #if ENABLE_FEATURE_SGI_LABEL || ENABLE_FEATURE_SUN_LABEL -- cgit v1.2.3-55-g6feb From 66be9197a5111d0293732f4823d1711ccab51675 Mon Sep 17 00:00:00 2001 From: Eric Lammerts Date: Sat, 30 Oct 2010 02:48:20 +0200 Subject: stat: fix mtime/ctime/atime If you set CONFIG_FEATURE_STAT_FORMAT=n, two of the three printed times are wrong, because a global buffer is reused. Fix below. Signed-off-by: Eric Lammerts Signed-off-by: Denys Vlasenko --- coreutils/stat.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/coreutils/stat.c b/coreutils/stat.c index b4e6f10fd..7351f5956 100644 --- a/coreutils/stat.c +++ b/coreutils/stat.c @@ -630,10 +630,9 @@ static bool do_stat(const char *filename, const char *format) # if ENABLE_SELINUX printf(" S_Context: %lc\n", *scontext); # endif - printf("Access: %s\n" "Modify: %s\n" "Change: %s\n", - human_time(statbuf.st_atime), - human_time(statbuf.st_mtime), - human_time(statbuf.st_ctime)); + printf("Access: %s\n", human_time(statbuf.st_atime)); + printf("Modify: %s\n", human_time(statbuf.st_mtime)); + printf("Change: %s\n", human_time(statbuf.st_ctime)); } #endif /* FEATURE_STAT_FORMAT */ return 1; -- cgit v1.2.3-55-g6feb From 2658888c78b572f349f326dce499930fa4418b4e Mon Sep 17 00:00:00 2001 From: Rob Landley Date: Mon, 1 Nov 2010 00:43:34 +0100 Subject: umount: cleanup and code shrink Signed-off-by: Rob Landley Signed-off-by: Denys Vlasenko --- util-linux/umount.c | 47 +++++++---------------------------------------- 1 file changed, 7 insertions(+), 40 deletions(-) diff --git a/util-linux/umount.c b/util-linux/umount.c index 78c603856..5597d9eba 100644 --- a/util-linux/umount.c +++ b/util-linux/umount.c @@ -9,39 +9,10 @@ */ #include #include -/* Make sure we have all the new mount flags we actually try to use. */ -#ifndef MS_BIND -# define MS_BIND (1 << 12) -#endif -#ifndef MS_MOVE -# define MS_MOVE (1 << 13) -#endif -#ifndef MS_RECURSIVE -# define MS_RECURSIVE (1 << 14) -#endif -#ifndef MS_SILENT -# define MS_SILENT (1 << 15) -#endif -/* The shared subtree stuff, which went in around 2.6.15. */ -#ifndef MS_UNBINDABLE -# define MS_UNBINDABLE (1 << 17) -#endif -#ifndef MS_PRIVATE -# define MS_PRIVATE (1 << 18) -#endif -#ifndef MS_SLAVE -# define MS_SLAVE (1 << 19) -#endif -#ifndef MS_SHARED -# define MS_SHARED (1 << 20) -#endif -#ifndef MS_RELATIME -# define MS_RELATIME (1 << 21) -#endif #include "libbb.h" - #if defined(__dietlibc__) +// TODO: This does not belong here. /* 16.12.2006, Sampo Kellomaki (sampo@iki.fi) * dietlibc-0.30 does not have implementation of getmntent_r() */ static struct mntent *getmntent_r(FILE* stream, struct mntent* result, @@ -54,23 +25,17 @@ static struct mntent *getmntent_r(FILE* stream, struct mntent* result, /* ignored: -v -d -t -i */ #define OPTION_STRING "fldnra" "vdt:i" -#define OPT_FORCE (1 << 0) -#define OPT_LAZY (1 << 1) +#define OPT_FORCE (1 << 0) // Same as MNT_FORCE +#define OPT_LAZY (1 << 1) // Same as MNT_DETACH #define OPT_FREELOOP (1 << 2) #define OPT_NO_MTAB (1 << 3) #define OPT_REMOUNT (1 << 4) #define OPT_ALL (ENABLE_FEATURE_UMOUNT_ALL ? (1 << 5) : 0) -// These constants from linux/fs.h must match OPT_FORCE and OPT_LAZY, -// otherwise "doForce" trick below won't work! -//#define MNT_FORCE 0x00000001 /* Attempt to forcibly umount */ -//#define MNT_DETACH 0x00000002 /* Just detach from the tree */ - int umount_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int umount_main(int argc UNUSED_PARAM, char **argv) { int doForce; - char *const buf = xmalloc(4096); /* reducing stack usage */ struct mntent me; FILE *fp; char *fstype = NULL; @@ -85,6 +50,9 @@ int umount_main(int argc UNUSED_PARAM, char **argv) opt = getopt32(argv, OPTION_STRING, &fstype); //argc -= optind; argv += optind; + + // MNT_FORCE and MNT_DETACH (from linux/fs.h) must match + // OPT_FORCE and OPT_LAZY, otherwise this trick won't work: doForce = MAX((opt & OPT_FORCE), (opt & OPT_LAZY)); /* Get a list of mount points from mtab. We read them all in now mostly @@ -101,7 +69,7 @@ int umount_main(int argc UNUSED_PARAM, char **argv) if (opt & OPT_ALL) bb_error_msg_and_die("can't open '%s'", bb_path_mtab_file); } else { - while (getmntent_r(fp, &me, buf, 4096)) { + while (getmntent_r(fp, &me, bb_common_bufsiz1, sizeof(bb_common_bufsiz1))) { /* Match fstype if passed */ if (!match_fstype(&me, fstype)) continue; @@ -203,7 +171,6 @@ int umount_main(int argc UNUSED_PARAM, char **argv) free(mtl); mtl = m; } - free(buf); } return status; -- cgit v1.2.3-55-g6feb From 8531c43b505916067d5162469307828a4eab0ab8 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Mon, 1 Nov 2010 01:38:54 +0100 Subject: decompress_bunzip2: reinstate erroneously deleted RETVAL_SHORT_WRITE Signed-off-by: Denys Vlasenko --- archival/libunarchive/decompress_bunzip2.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/archival/libunarchive/decompress_bunzip2.c b/archival/libunarchive/decompress_bunzip2.c index d30166fa4..0fa4fb886 100644 --- a/archival/libunarchive/decompress_bunzip2.c +++ b/archival/libunarchive/decompress_bunzip2.c @@ -55,7 +55,7 @@ #define RETVAL_LAST_BLOCK (-1) #define RETVAL_NOT_BZIP_DATA (-2) #define RETVAL_UNEXPECTED_INPUT_EOF (-3) -//#define RETVAL_SHORT_WRITE (-4) +#define RETVAL_SHORT_WRITE (-4) #define RETVAL_DATA_ERROR (-5) #define RETVAL_OUT_OF_MEMORY (-6) #define RETVAL_OBSOLETE_INPUT (-7) @@ -745,6 +745,7 @@ unpack_bz2_stream(int src_fd, int dst_fd) break; if (i != full_write(dst_fd, outbuf, i)) { bb_error_msg("short write"); + i = RETVAL_SHORT_WRITE; goto release_mem; } IF_DESKTOP(total_written += i;) -- cgit v1.2.3-55-g6feb From 4d4d1a015f351816982e61a7f7dc861bfe06ca78 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Mon, 1 Nov 2010 02:19:47 +0100 Subject: whitespace fix Signed-off-by: Denys Vlasenko --- archival/libunarchive/decompress_bunzip2.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/archival/libunarchive/decompress_bunzip2.c b/archival/libunarchive/decompress_bunzip2.c index 0fa4fb886..15f08a60e 100644 --- a/archival/libunarchive/decompress_bunzip2.c +++ b/archival/libunarchive/decompress_bunzip2.c @@ -724,7 +724,7 @@ IF_DESKTOP(long long) int FAST_FUNC unpack_bz2_stream(int src_fd, int dst_fd) { IF_DESKTOP(long long total_written = 0;) - bunzip_data *bd; + bunzip_data *bd; char *outbuf; int i; unsigned len; -- cgit v1.2.3-55-g6feb From db5fe62b6d9977304b864f961dae71232091b26c Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Tue, 2 Nov 2010 20:13:03 +0100 Subject: init: if PID!=1, show clearer error message. move usage text closer to main() Signed-off-by: Denys Vlasenko --- include/usage.src.h | 3 - init/init.c | 271 ++++++++++++++++++++++++++-------------------------- 2 files changed, 137 insertions(+), 137 deletions(-) diff --git a/include/usage.src.h b/include/usage.src.h index 6973c93ef..37b9d0747 100644 --- a/include/usage.src.h +++ b/include/usage.src.h @@ -2044,9 +2044,6 @@ INSERT #define linux64_trivial_usage NOUSAGE_STR #define linux64_full_usage "" -#define linuxrc_trivial_usage NOUSAGE_STR -#define linuxrc_full_usage "" - #define setarch_trivial_usage \ "personality PROG ARGS" #define setarch_full_usage "\n\n" \ diff --git a/init/init.c b/init/init.c index a7bbd5e64..0a0d503b5 100644 --- a/init/init.c +++ b/init/init.c @@ -108,138 +108,6 @@ //config: Note that on Linux, init attempts to detect serial terminal and //config: sets TERM to "vt102" if one is found. -//usage:#define init_trivial_usage -//usage: "" -//usage:#define init_full_usage "\n\n" -//usage: "Init is the parent of all processes" -//usage: -//usage:#define init_notes_usage -//usage: "This version of init is designed to be run only by the kernel.\n" -//usage: "\n" -//usage: "BusyBox init doesn't support multiple runlevels. The runlevels field of\n" -//usage: "the /etc/inittab file is completely ignored by BusyBox init. If you want\n" -//usage: "runlevels, use sysvinit.\n" -//usage: "\n" -//usage: "BusyBox init works just fine without an inittab. If no inittab is found,\n" -//usage: "it has the following default behavior:\n" -//usage: "\n" -//usage: " ::sysinit:/etc/init.d/rcS\n" -//usage: " ::askfirst:/bin/sh\n" -//usage: " ::ctrlaltdel:/sbin/reboot\n" -//usage: " ::shutdown:/sbin/swapoff -a\n" -//usage: " ::shutdown:/bin/umount -a -r\n" -//usage: " ::restart:/sbin/init\n" -//usage: "\n" -//usage: "if it detects that /dev/console is _not_ a serial console, it will also run:\n" -//usage: "\n" -//usage: " tty2::askfirst:/bin/sh\n" -//usage: " tty3::askfirst:/bin/sh\n" -//usage: " tty4::askfirst:/bin/sh\n" -//usage: "\n" -//usage: "If you choose to use an /etc/inittab file, the inittab entry format is as follows:\n" -//usage: "\n" -//usage: " :::\n" -//usage: "\n" -//usage: " :\n" -//usage: "\n" -//usage: " WARNING: This field has a non-traditional meaning for BusyBox init!\n" -//usage: " The id field is used by BusyBox init to specify the controlling tty for\n" -//usage: " the specified process to run on. The contents of this field are\n" -//usage: " appended to \"/dev/\" and used as-is. There is no need for this field to\n" -//usage: " be unique, although if it isn't you may have strange results. If this\n" -//usage: " field is left blank, the controlling tty is set to the console. Also\n" -//usage: " note that if BusyBox detects that a serial console is in use, then only\n" -//usage: " entries whose controlling tty is either the serial console or /dev/null\n" -//usage: " will be run. BusyBox init does nothing with utmp. We don't need no\n" -//usage: " stinkin' utmp.\n" -//usage: "\n" -//usage: " :\n" -//usage: "\n" -//usage: " The runlevels field is completely ignored.\n" -//usage: "\n" -//usage: " :\n" -//usage: "\n" -//usage: " Valid actions include: sysinit, respawn, askfirst, wait,\n" -//usage: " once, restart, ctrlaltdel, and shutdown.\n" -//usage: "\n" -//usage: " The available actions can be classified into two groups: actions\n" -//usage: " that are run only once, and actions that are re-run when the specified\n" -//usage: " process exits.\n" -//usage: "\n" -//usage: " Run only-once actions:\n" -//usage: "\n" -//usage: " 'sysinit' is the first item run on boot. init waits until all\n" -//usage: " sysinit actions are completed before continuing. Following the\n" -//usage: " completion of all sysinit actions, all 'wait' actions are run.\n" -//usage: " 'wait' actions, like 'sysinit' actions, cause init to wait until\n" -//usage: " the specified task completes. 'once' actions are asynchronous,\n" -//usage: " therefore, init does not wait for them to complete. 'restart' is\n" -//usage: " the action taken to restart the init process. By default this should\n" -//usage: " simply run /sbin/init, but can be a script which runs pivot_root or it\n" -//usage: " can do all sorts of other interesting things. The 'ctrlaltdel' init\n" -//usage: " actions are run when the system detects that someone on the system\n" -//usage: " console has pressed the CTRL-ALT-DEL key combination. Typically one\n" -//usage: " wants to run 'reboot' at this point to cause the system to reboot.\n" -//usage: " Finally the 'shutdown' action specifies the actions to taken when\n" -//usage: " init is told to reboot. Unmounting filesystems and disabling swap\n" -//usage: " is a very good here.\n" -//usage: "\n" -//usage: " Run repeatedly actions:\n" -//usage: "\n" -//usage: " 'respawn' actions are run after the 'once' actions. When a process\n" -//usage: " started with a 'respawn' action exits, init automatically restarts\n" -//usage: " it. Unlike sysvinit, BusyBox init does not stop processes from\n" -//usage: " respawning out of control. The 'askfirst' actions acts just like\n" -//usage: " respawn, except that before running the specified process it\n" -//usage: " displays the line \"Please press Enter to activate this console.\"\n" -//usage: " and then waits for the user to press enter before starting the\n" -//usage: " specified process.\n" -//usage: "\n" -//usage: " Unrecognized actions (like initdefault) will cause init to emit an\n" -//usage: " error message, and then go along with its business. All actions are\n" -//usage: " run in the order they appear in /etc/inittab.\n" -//usage: "\n" -//usage: " :\n" -//usage: "\n" -//usage: " Specifies the process to be executed and its command line.\n" -//usage: "\n" -//usage: "Example /etc/inittab file:\n" -//usage: "\n" -//usage: " # This is run first except when booting in single-user mode\n" -//usage: " #\n" -//usage: " ::sysinit:/etc/init.d/rcS\n" -//usage: " \n" -//usage: " # /bin/sh invocations on selected ttys\n" -//usage: " #\n" -//usage: " # Start an \"askfirst\" shell on the console (whatever that may be)\n" -//usage: " ::askfirst:-/bin/sh\n" -//usage: " # Start an \"askfirst\" shell on /dev/tty2-4\n" -//usage: " tty2::askfirst:-/bin/sh\n" -//usage: " tty3::askfirst:-/bin/sh\n" -//usage: " tty4::askfirst:-/bin/sh\n" -//usage: " \n" -//usage: " # /sbin/getty invocations for selected ttys\n" -//usage: " #\n" -//usage: " tty4::respawn:/sbin/getty 38400 tty4\n" -//usage: " tty5::respawn:/sbin/getty 38400 tty5\n" -//usage: " \n" -//usage: " \n" -//usage: " # Example of how to put a getty on a serial line (for a terminal)\n" -//usage: " #\n" -//usage: " #::respawn:/sbin/getty -L ttyS0 9600 vt100\n" -//usage: " #::respawn:/sbin/getty -L ttyS1 9600 vt100\n" -//usage: " #\n" -//usage: " # Example how to put a getty on a modem line\n" -//usage: " #::respawn:/sbin/getty 57600 ttyS2\n" -//usage: " \n" -//usage: " # Stuff to do when restarting the init process\n" -//usage: " ::restart:/sbin/init\n" -//usage: " \n" -//usage: " # Stuff to do before rebooting\n" -//usage: " ::ctrlaltdel:/sbin/reboot\n" -//usage: " ::shutdown:/bin/umount -a -r\n" -//usage: " ::shutdown:/sbin/swapoff -a\n" - #include "libbb.h" #include #include @@ -1095,9 +963,9 @@ int init_main(int argc UNUSED_PARAM, char **argv) if (!DEBUG_INIT) { /* Expect to be invoked as init with PID=1 or be invoked as linuxrc */ if (getpid() != 1 - && (!ENABLE_FEATURE_INITRD || !strstr(applet_name, "linuxrc")) + && (!ENABLE_FEATURE_INITRD || applet_name[0] != 'l') /* not linuxrc? */ ) { - bb_show_usage(); + bb_error_msg_and_die("must be run as PID 1"); } #ifdef RB_DISABLE_CAD /* Turn off rebooting via CTL-ALT-DEL - we get a @@ -1286,3 +1154,138 @@ int init_main(int argc UNUSED_PARAM, char **argv) } } /* while (1) */ } + +//usage:#define linuxrc_trivial_usage NOUSAGE_STR +//usage:#define linuxrc_full_usage "" + +//usage:#define init_trivial_usage +//usage: "" +//usage:#define init_full_usage "\n\n" +//usage: "Init is the parent of all processes" +//usage: +//usage:#define init_notes_usage +//usage: "This version of init is designed to be run only by the kernel.\n" +//usage: "\n" +//usage: "BusyBox init doesn't support multiple runlevels. The runlevels field of\n" +//usage: "the /etc/inittab file is completely ignored by BusyBox init. If you want\n" +//usage: "runlevels, use sysvinit.\n" +//usage: "\n" +//usage: "BusyBox init works just fine without an inittab. If no inittab is found,\n" +//usage: "it has the following default behavior:\n" +//usage: "\n" +//usage: " ::sysinit:/etc/init.d/rcS\n" +//usage: " ::askfirst:/bin/sh\n" +//usage: " ::ctrlaltdel:/sbin/reboot\n" +//usage: " ::shutdown:/sbin/swapoff -a\n" +//usage: " ::shutdown:/bin/umount -a -r\n" +//usage: " ::restart:/sbin/init\n" +//usage: "\n" +//usage: "if it detects that /dev/console is _not_ a serial console, it will also run:\n" +//usage: "\n" +//usage: " tty2::askfirst:/bin/sh\n" +//usage: " tty3::askfirst:/bin/sh\n" +//usage: " tty4::askfirst:/bin/sh\n" +//usage: "\n" +//usage: "If you choose to use an /etc/inittab file, the inittab entry format is as follows:\n" +//usage: "\n" +//usage: " :::\n" +//usage: "\n" +//usage: " :\n" +//usage: "\n" +//usage: " WARNING: This field has a non-traditional meaning for BusyBox init!\n" +//usage: " The id field is used by BusyBox init to specify the controlling tty for\n" +//usage: " the specified process to run on. The contents of this field are\n" +//usage: " appended to \"/dev/\" and used as-is. There is no need for this field to\n" +//usage: " be unique, although if it isn't you may have strange results. If this\n" +//usage: " field is left blank, the controlling tty is set to the console. Also\n" +//usage: " note that if BusyBox detects that a serial console is in use, then only\n" +//usage: " entries whose controlling tty is either the serial console or /dev/null\n" +//usage: " will be run. BusyBox init does nothing with utmp. We don't need no\n" +//usage: " stinkin' utmp.\n" +//usage: "\n" +//usage: " :\n" +//usage: "\n" +//usage: " The runlevels field is completely ignored.\n" +//usage: "\n" +//usage: " :\n" +//usage: "\n" +//usage: " Valid actions include: sysinit, respawn, askfirst, wait,\n" +//usage: " once, restart, ctrlaltdel, and shutdown.\n" +//usage: "\n" +//usage: " The available actions can be classified into two groups: actions\n" +//usage: " that are run only once, and actions that are re-run when the specified\n" +//usage: " process exits.\n" +//usage: "\n" +//usage: " Run only-once actions:\n" +//usage: "\n" +//usage: " 'sysinit' is the first item run on boot. init waits until all\n" +//usage: " sysinit actions are completed before continuing. Following the\n" +//usage: " completion of all sysinit actions, all 'wait' actions are run.\n" +//usage: " 'wait' actions, like 'sysinit' actions, cause init to wait until\n" +//usage: " the specified task completes. 'once' actions are asynchronous,\n" +//usage: " therefore, init does not wait for them to complete. 'restart' is\n" +//usage: " the action taken to restart the init process. By default this should\n" +//usage: " simply run /sbin/init, but can be a script which runs pivot_root or it\n" +//usage: " can do all sorts of other interesting things. The 'ctrlaltdel' init\n" +//usage: " actions are run when the system detects that someone on the system\n" +//usage: " console has pressed the CTRL-ALT-DEL key combination. Typically one\n" +//usage: " wants to run 'reboot' at this point to cause the system to reboot.\n" +//usage: " Finally the 'shutdown' action specifies the actions to taken when\n" +//usage: " init is told to reboot. Unmounting filesystems and disabling swap\n" +//usage: " is a very good here.\n" +//usage: "\n" +//usage: " Run repeatedly actions:\n" +//usage: "\n" +//usage: " 'respawn' actions are run after the 'once' actions. When a process\n" +//usage: " started with a 'respawn' action exits, init automatically restarts\n" +//usage: " it. Unlike sysvinit, BusyBox init does not stop processes from\n" +//usage: " respawning out of control. The 'askfirst' actions acts just like\n" +//usage: " respawn, except that before running the specified process it\n" +//usage: " displays the line \"Please press Enter to activate this console.\"\n" +//usage: " and then waits for the user to press enter before starting the\n" +//usage: " specified process.\n" +//usage: "\n" +//usage: " Unrecognized actions (like initdefault) will cause init to emit an\n" +//usage: " error message, and then go along with its business. All actions are\n" +//usage: " run in the order they appear in /etc/inittab.\n" +//usage: "\n" +//usage: " :\n" +//usage: "\n" +//usage: " Specifies the process to be executed and its command line.\n" +//usage: "\n" +//usage: "Example /etc/inittab file:\n" +//usage: "\n" +//usage: " # This is run first except when booting in single-user mode\n" +//usage: " #\n" +//usage: " ::sysinit:/etc/init.d/rcS\n" +//usage: " \n" +//usage: " # /bin/sh invocations on selected ttys\n" +//usage: " #\n" +//usage: " # Start an \"askfirst\" shell on the console (whatever that may be)\n" +//usage: " ::askfirst:-/bin/sh\n" +//usage: " # Start an \"askfirst\" shell on /dev/tty2-4\n" +//usage: " tty2::askfirst:-/bin/sh\n" +//usage: " tty3::askfirst:-/bin/sh\n" +//usage: " tty4::askfirst:-/bin/sh\n" +//usage: " \n" +//usage: " # /sbin/getty invocations for selected ttys\n" +//usage: " #\n" +//usage: " tty4::respawn:/sbin/getty 38400 tty4\n" +//usage: " tty5::respawn:/sbin/getty 38400 tty5\n" +//usage: " \n" +//usage: " \n" +//usage: " # Example of how to put a getty on a serial line (for a terminal)\n" +//usage: " #\n" +//usage: " #::respawn:/sbin/getty -L ttyS0 9600 vt100\n" +//usage: " #::respawn:/sbin/getty -L ttyS1 9600 vt100\n" +//usage: " #\n" +//usage: " # Example how to put a getty on a modem line\n" +//usage: " #::respawn:/sbin/getty 57600 ttyS2\n" +//usage: " \n" +//usage: " # Stuff to do when restarting the init process\n" +//usage: " ::restart:/sbin/init\n" +//usage: " \n" +//usage: " # Stuff to do before rebooting\n" +//usage: " ::ctrlaltdel:/sbin/reboot\n" +//usage: " ::shutdown:/bin/umount -a -r\n" +//usage: " ::shutdown:/sbin/swapoff -a\n" -- cgit v1.2.3-55-g6feb From 5e9934028aa030312a1a2e2e32d5ceade8672beb Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Wed, 3 Nov 2010 02:27:49 +0100 Subject: *: move lzo compressor code to archival/libunarchive/. No code changes Signed-off-by: Denys Vlasenko --- archival/Kbuild.src | 3 +- archival/liblzo.h | 93 ---- archival/liblzo_interface.h | 71 --- archival/libunarchive/Kbuild.src | 2 + archival/libunarchive/liblzo.h | 93 ++++ archival/libunarchive/lzo1x_1.c | 35 ++ archival/libunarchive/lzo1x_1o.c | 35 ++ archival/libunarchive/lzo1x_9x.c | 921 +++++++++++++++++++++++++++++++++++++++ archival/libunarchive/lzo1x_c.c | 296 +++++++++++++ archival/libunarchive/lzo1x_d.c | 420 ++++++++++++++++++ archival/lzo1x_1.c | 35 -- archival/lzo1x_1o.c | 35 -- archival/lzo1x_9x.c | 921 --------------------------------------- archival/lzo1x_c.c | 296 ------------- archival/lzo1x_d.c | 420 ------------------ include/liblzo_interface.h | 71 +++ 16 files changed, 1874 insertions(+), 1873 deletions(-) delete mode 100644 archival/liblzo.h delete mode 100644 archival/liblzo_interface.h create mode 100644 archival/libunarchive/liblzo.h create mode 100644 archival/libunarchive/lzo1x_1.c create mode 100644 archival/libunarchive/lzo1x_1o.c create mode 100644 archival/libunarchive/lzo1x_9x.c create mode 100644 archival/libunarchive/lzo1x_c.c create mode 100644 archival/libunarchive/lzo1x_d.c delete mode 100644 archival/lzo1x_1.c delete mode 100644 archival/lzo1x_1o.c delete mode 100644 archival/lzo1x_9x.c delete mode 100644 archival/lzo1x_c.c delete mode 100644 archival/lzo1x_d.c create mode 100644 include/liblzo_interface.h diff --git a/archival/Kbuild.src b/archival/Kbuild.src index a0edb123d..e49d38538 100644 --- a/archival/Kbuild.src +++ b/archival/Kbuild.src @@ -19,8 +19,7 @@ lib-$(CONFIG_RPM) += rpm.o lib-$(CONFIG_TAR) += tar.o lib-$(CONFIG_UNZIP) += unzip.o -lib-$(CONFIG_LZOP) += lzop.o lzo1x_1.o lzo1x_1o.o lzo1x_d.o bbunzip.o -lib-$(CONFIG_LZOP_COMPR_HIGH) += lzo1x_9x.o +lib-$(CONFIG_LZOP) += lzop.o bbunzip.o lib-$(CONFIG_GZIP) += gzip.o bbunzip.o lib-$(CONFIG_BZIP2) += bzip2.o bbunzip.o diff --git a/archival/liblzo.h b/archival/liblzo.h deleted file mode 100644 index 843997cb9..000000000 --- a/archival/liblzo.h +++ /dev/null @@ -1,93 +0,0 @@ -/* - This file is part of the LZO real-time data compression library. - - Copyright (C) 1996..2008 Markus Franz Xaver Johannes Oberhumer - All Rights Reserved. - - Markus F.X.J. Oberhumer - http://www.oberhumer.com/opensource/lzo/ - - The LZO library is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License as - published by the Free Software Foundation; either version 2 of - the License, or (at your option) any later version. - - The LZO library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with the LZO library; see the file COPYING. - If not, write to the Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -#include "liblzo_interface.h" - -/* lzo-2.03/src/config1x.h */ -#define M2_MIN_LEN 3 -#define M2_MAX_LEN 8 -#define M3_MAX_LEN 33 -#define M4_MAX_LEN 9 -#define M1_MAX_OFFSET 0x0400 -#define M2_MAX_OFFSET 0x0800 -#define M3_MAX_OFFSET 0x4000 -#define M4_MAX_OFFSET 0xbfff -#define M1_MARKER 0 -#define M3_MARKER 32 -#define M4_MARKER 16 - -#define MX_MAX_OFFSET (M1_MAX_OFFSET + M2_MAX_OFFSET) -#define MIN_LOOKAHEAD (M2_MAX_LEN + 1) - -#define LZO_EOF_CODE - -/* lzo-2.03/src/lzo_dict.h */ -#define GINDEX(m_pos,m_off,dict,dindex,in) m_pos = dict[dindex] -#define DX2(p,s1,s2) \ - (((((unsigned)((p)[2]) << (s2)) ^ (p)[1]) << (s1)) ^ (p)[0]) -//#define DA3(p,s1,s2,s3) ((DA2((p)+1,s2,s3) << (s1)) + (p)[0]) -//#define DS3(p,s1,s2,s3) ((DS2((p)+1,s2,s3) << (s1)) - (p)[0]) -#define DX3(p,s1,s2,s3) ((DX2((p)+1,s2,s3) << (s1)) ^ (p)[0]) - -#define D_SIZE (1U << D_BITS) -#define D_MASK ((1U << D_BITS) - 1) -#define D_HIGH ((D_MASK >> 1) + 1) - -#define LZO_CHECK_MPOS_NON_DET(m_pos,m_off,in,ip,max_offset) \ - ( \ - m_pos = ip - (unsigned)(ip - m_pos), \ - ((uintptr_t)m_pos < (uintptr_t)in \ - || (m_off = (unsigned)(ip - m_pos)) <= 0 \ - || m_off > max_offset) \ - ) - -#define DENTRY(p,in) (p) -#define UPDATE_I(dict,drun,index,p,in) dict[index] = DENTRY(p,in) - -#define DMS(v,s) ((unsigned) (((v) & (D_MASK >> (s))) << (s))) -#define DM(v) ((unsigned) ((v) & D_MASK)) -#define DMUL(a,b) ((unsigned) ((a) * (b))) - -/* lzo-2.03/src/lzo_ptr.h */ -#define pd(a,b) ((unsigned)((a)-(b))) - -# define TEST_IP (ip < ip_end) -# define NEED_IP(x) \ - if ((unsigned)(ip_end - ip) < (unsigned)(x)) goto input_overrun - -# undef TEST_OP /* don't need both of the tests here */ -# define TEST_OP 1 -# define NEED_OP(x) \ - if ((unsigned)(op_end - op) < (unsigned)(x)) goto output_overrun - -#define HAVE_ANY_OP 1 - -//#if defined(LZO_TEST_OVERRUN_LOOKBEHIND) -# define TEST_LB(m_pos) if (m_pos < out || m_pos >= op) goto lookbehind_overrun -//# define TEST_LBO(m_pos,o) if (m_pos < out || m_pos >= op - (o)) goto lookbehind_overrun -//#else -//# define TEST_LB(m_pos) ((void) 0) -//# define TEST_LBO(m_pos,o) ((void) 0) -//#endif diff --git a/archival/liblzo_interface.h b/archival/liblzo_interface.h deleted file mode 100644 index 9a84c0b6b..000000000 --- a/archival/liblzo_interface.h +++ /dev/null @@ -1,71 +0,0 @@ -/* - This file is part of the LZO real-time data compression library. - - Copyright (C) 1996..2008 Markus Franz Xaver Johannes Oberhumer - All Rights Reserved. - - Markus F.X.J. Oberhumer - http://www.oberhumer.com/opensource/lzo/ - - The LZO library is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License as - published by the Free Software Foundation; either version 2 of - the License, or (at your option) any later version. - - The LZO library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with the LZO library; see the file COPYING. - If not, write to the Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -#define LZO1X -#undef LZO1Y - -#undef assert -/* -static void die_at(int line) -{ - bb_error_msg_and_die("internal error at %d", line); -} -#define assert(v) if (!(v)) die_at(__LINE__) -*/ -#define assert(v) ((void)0) - -int lzo1x_1_compress(const uint8_t* src, unsigned src_len, - uint8_t* dst, unsigned* dst_len, - void* wrkmem); -int lzo1x_1_15_compress(const uint8_t* src, unsigned src_len, - uint8_t* dst, unsigned* dst_len, - void* wrkmem); -int lzo1x_999_compress_level(const uint8_t* in, unsigned in_len, - uint8_t* out, unsigned* out_len, - void* wrkmem, - int compression_level); - -/* decompression */ -//int lzo1x_decompress(const uint8_t* src, unsigned src_len, -// uint8_t* dst, unsigned* dst_len, -// void* wrkmem /* NOT USED */); -/* safe decompression with overrun testing */ -int lzo1x_decompress_safe(const uint8_t* src, unsigned src_len, - uint8_t* dst, unsigned* dst_len, - void* wrkmem /* NOT USED */); - -#define LZO_E_OK 0 -#define LZO_E_ERROR (-1) -#define LZO_E_OUT_OF_MEMORY (-2) /* [not used right now] */ -#define LZO_E_NOT_COMPRESSIBLE (-3) /* [not used right now] */ -#define LZO_E_INPUT_OVERRUN (-4) -#define LZO_E_OUTPUT_OVERRUN (-5) -#define LZO_E_LOOKBEHIND_OVERRUN (-6) -#define LZO_E_EOF_NOT_FOUND (-7) -#define LZO_E_INPUT_NOT_CONSUMED (-8) -#define LZO_E_NOT_YET_IMPLEMENTED (-9) /* [not used right now] */ - -/* lzo-2.03/include/lzo/lzoconf.h */ -#define LZO_VERSION 0x2030 diff --git a/archival/libunarchive/Kbuild.src b/archival/libunarchive/Kbuild.src index e92b4aad2..b0bc4e5aa 100644 --- a/archival/libunarchive/Kbuild.src +++ b/archival/libunarchive/Kbuild.src @@ -48,6 +48,8 @@ lib-$(CONFIG_RPM) += open_transformer.o decompress_unzip.o lib-$(CONFIG_TAR) += get_header_tar.o lib-$(CONFIG_UNCOMPRESS) += decompress_uncompress.o lib-$(CONFIG_UNZIP) += decompress_unzip.o +lib-$(CONFIG_LZOP) += lzo1x_1.o lzo1x_1o.o lzo1x_d.o +lib-$(CONFIG_LZOP_COMPR_HIGH) += lzo1x_9x.o lib-$(CONFIG_FEATURE_SEAMLESS_Z) += open_transformer.o decompress_uncompress.o lib-$(CONFIG_FEATURE_SEAMLESS_GZ) += open_transformer.o decompress_unzip.o get_header_tar_gz.o lib-$(CONFIG_FEATURE_SEAMLESS_BZ2) += open_transformer.o decompress_bunzip2.o get_header_tar_bz2.o diff --git a/archival/libunarchive/liblzo.h b/archival/libunarchive/liblzo.h new file mode 100644 index 000000000..843997cb9 --- /dev/null +++ b/archival/libunarchive/liblzo.h @@ -0,0 +1,93 @@ +/* + This file is part of the LZO real-time data compression library. + + Copyright (C) 1996..2008 Markus Franz Xaver Johannes Oberhumer + All Rights Reserved. + + Markus F.X.J. Oberhumer + http://www.oberhumer.com/opensource/lzo/ + + The LZO library is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of + the License, or (at your option) any later version. + + The LZO library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with the LZO library; see the file COPYING. + If not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "liblzo_interface.h" + +/* lzo-2.03/src/config1x.h */ +#define M2_MIN_LEN 3 +#define M2_MAX_LEN 8 +#define M3_MAX_LEN 33 +#define M4_MAX_LEN 9 +#define M1_MAX_OFFSET 0x0400 +#define M2_MAX_OFFSET 0x0800 +#define M3_MAX_OFFSET 0x4000 +#define M4_MAX_OFFSET 0xbfff +#define M1_MARKER 0 +#define M3_MARKER 32 +#define M4_MARKER 16 + +#define MX_MAX_OFFSET (M1_MAX_OFFSET + M2_MAX_OFFSET) +#define MIN_LOOKAHEAD (M2_MAX_LEN + 1) + +#define LZO_EOF_CODE + +/* lzo-2.03/src/lzo_dict.h */ +#define GINDEX(m_pos,m_off,dict,dindex,in) m_pos = dict[dindex] +#define DX2(p,s1,s2) \ + (((((unsigned)((p)[2]) << (s2)) ^ (p)[1]) << (s1)) ^ (p)[0]) +//#define DA3(p,s1,s2,s3) ((DA2((p)+1,s2,s3) << (s1)) + (p)[0]) +//#define DS3(p,s1,s2,s3) ((DS2((p)+1,s2,s3) << (s1)) - (p)[0]) +#define DX3(p,s1,s2,s3) ((DX2((p)+1,s2,s3) << (s1)) ^ (p)[0]) + +#define D_SIZE (1U << D_BITS) +#define D_MASK ((1U << D_BITS) - 1) +#define D_HIGH ((D_MASK >> 1) + 1) + +#define LZO_CHECK_MPOS_NON_DET(m_pos,m_off,in,ip,max_offset) \ + ( \ + m_pos = ip - (unsigned)(ip - m_pos), \ + ((uintptr_t)m_pos < (uintptr_t)in \ + || (m_off = (unsigned)(ip - m_pos)) <= 0 \ + || m_off > max_offset) \ + ) + +#define DENTRY(p,in) (p) +#define UPDATE_I(dict,drun,index,p,in) dict[index] = DENTRY(p,in) + +#define DMS(v,s) ((unsigned) (((v) & (D_MASK >> (s))) << (s))) +#define DM(v) ((unsigned) ((v) & D_MASK)) +#define DMUL(a,b) ((unsigned) ((a) * (b))) + +/* lzo-2.03/src/lzo_ptr.h */ +#define pd(a,b) ((unsigned)((a)-(b))) + +# define TEST_IP (ip < ip_end) +# define NEED_IP(x) \ + if ((unsigned)(ip_end - ip) < (unsigned)(x)) goto input_overrun + +# undef TEST_OP /* don't need both of the tests here */ +# define TEST_OP 1 +# define NEED_OP(x) \ + if ((unsigned)(op_end - op) < (unsigned)(x)) goto output_overrun + +#define HAVE_ANY_OP 1 + +//#if defined(LZO_TEST_OVERRUN_LOOKBEHIND) +# define TEST_LB(m_pos) if (m_pos < out || m_pos >= op) goto lookbehind_overrun +//# define TEST_LBO(m_pos,o) if (m_pos < out || m_pos >= op - (o)) goto lookbehind_overrun +//#else +//# define TEST_LB(m_pos) ((void) 0) +//# define TEST_LBO(m_pos,o) ((void) 0) +//#endif diff --git a/archival/libunarchive/lzo1x_1.c b/archival/libunarchive/lzo1x_1.c new file mode 100644 index 000000000..a88839846 --- /dev/null +++ b/archival/libunarchive/lzo1x_1.c @@ -0,0 +1,35 @@ +/* LZO1X-1 compression + + This file is part of the LZO real-time data compression library. + + Copyright (C) 1996..2008 Markus Franz Xaver Johannes Oberhumer + All Rights Reserved. + + Markus F.X.J. Oberhumer + http://www.oberhumer.com/opensource/lzo/ + + The LZO library is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of + the License, or (at your option) any later version. + + The LZO library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with the LZO library; see the file COPYING. + If not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#include "libbb.h" +#include "liblzo.h" + +#define D_BITS 14 +#define D_INDEX1(d,p) d = DM(DMUL(0x21,DX3(p,5,5,6)) >> 5) +#define D_INDEX2(d,p) d = (d & (D_MASK & 0x7ff)) ^ (D_HIGH | 0x1f) + +#define DO_COMPRESS lzo1x_1_compress + +#include "lzo1x_c.c" diff --git a/archival/libunarchive/lzo1x_1o.c b/archival/libunarchive/lzo1x_1o.c new file mode 100644 index 000000000..3c61253e0 --- /dev/null +++ b/archival/libunarchive/lzo1x_1o.c @@ -0,0 +1,35 @@ +/* LZO1X-1(15) compression + + This file is part of the LZO real-time data compression library. + + Copyright (C) 1996..2008 Markus Franz Xaver Johannes Oberhumer + All Rights Reserved. + + Markus F.X.J. Oberhumer + http://www.oberhumer.com/opensource/lzo/ + + The LZO library is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of + the License, or (at your option) any later version. + + The LZO library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with the LZO library; see the file COPYING. + If not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#include "libbb.h" +#include "liblzo.h" + +#define D_BITS 15 +#define D_INDEX1(d,p) d = DM(DMUL(0x21,DX3(p,5,5,6)) >> 5) +#define D_INDEX2(d,p) d = (d & (D_MASK & 0x7ff)) ^ (D_HIGH | 0x1f) + +#define DO_COMPRESS lzo1x_1_15_compress + +#include "lzo1x_c.c" diff --git a/archival/libunarchive/lzo1x_9x.c b/archival/libunarchive/lzo1x_9x.c new file mode 100644 index 000000000..483205155 --- /dev/null +++ b/archival/libunarchive/lzo1x_9x.c @@ -0,0 +1,921 @@ +/* lzo1x_9x.c -- implementation of the LZO1X-999 compression algorithm + + This file is part of the LZO real-time data compression library. + + Copyright (C) 2008 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 2007 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 2006 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 2005 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 2004 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 2003 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 2002 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 2001 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 2000 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 1999 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 1998 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 1997 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 1996 Markus Franz Xaver Johannes Oberhumer + All Rights Reserved. + + The LZO library is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of + the License, or (at your option) any later version. + + The LZO library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with the LZO library; see the file COPYING. + If not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + Markus F.X.J. Oberhumer + + http://www.oberhumer.com/opensource/lzo/ +*/ +#include "libbb.h" + +/* The following is probably only safe on Intel-compatible processors ... */ +#define LZO_UNALIGNED_OK_2 +#define LZO_UNALIGNED_OK_4 + +#include "liblzo.h" + +#define LZO_MAX(a,b) ((a) >= (b) ? (a) : (b)) +#define LZO_MIN(a,b) ((a) <= (b) ? (a) : (b)) +#define LZO_MAX3(a,b,c) ((a) >= (b) ? LZO_MAX(a,c) : LZO_MAX(b,c)) + +/*********************************************************************** +// +************************************************************************/ +#define SWD_N M4_MAX_OFFSET /* size of ring buffer */ +#define SWD_F 2048 /* upper limit for match length */ + +#define SWD_BEST_OFF (LZO_MAX3(M2_MAX_LEN, M3_MAX_LEN, M4_MAX_LEN) + 1) + +typedef struct { + int init; + + unsigned look; /* bytes in lookahead buffer */ + + unsigned m_len; + unsigned m_off; + + const uint8_t *bp; + const uint8_t *ip; + const uint8_t *in; + const uint8_t *in_end; + uint8_t *out; + + unsigned r1_lit; + +} lzo1x_999_t; + +#define getbyte(c) ((c).ip < (c).in_end ? *((c).ip)++ : (-1)) + +/* lzo_swd.c -- sliding window dictionary */ + +/*********************************************************************** +// +************************************************************************/ +#define SWD_UINT_MAX USHRT_MAX + +#ifndef SWD_HSIZE +# define SWD_HSIZE 16384 +#endif +#ifndef SWD_MAX_CHAIN +# define SWD_MAX_CHAIN 2048 +#endif + +#define HEAD3(b, p) \ + ( ((0x9f5f * ((((b[p]<<5)^b[p+1])<<5) ^ b[p+2])) >> 5) & (SWD_HSIZE-1) ) + +#if defined(LZO_UNALIGNED_OK_2) +# define HEAD2(b,p) (* (uint16_t *) &(b[p])) +#else +# define HEAD2(b,p) (b[p] ^ ((unsigned)b[p+1]<<8)) +#endif +#define NIL2 SWD_UINT_MAX + +typedef struct lzo_swd { + /* public - "built-in" */ + + /* public - configuration */ + unsigned max_chain; + int use_best_off; + + /* public - output */ + unsigned m_len; + unsigned m_off; + unsigned look; + int b_char; +#if defined(SWD_BEST_OFF) + unsigned best_off[SWD_BEST_OFF]; +#endif + + /* semi public */ + lzo1x_999_t *c; + unsigned m_pos; +#if defined(SWD_BEST_OFF) + unsigned best_pos[SWD_BEST_OFF]; +#endif + + /* private */ + unsigned ip; /* input pointer (lookahead) */ + unsigned bp; /* buffer pointer */ + unsigned rp; /* remove pointer */ + + unsigned node_count; + unsigned first_rp; + + uint8_t b[SWD_N + SWD_F]; + uint8_t b_wrap[SWD_F]; /* must follow b */ + uint16_t head3[SWD_HSIZE]; + uint16_t succ3[SWD_N + SWD_F]; + uint16_t best3[SWD_N + SWD_F]; + uint16_t llen3[SWD_HSIZE]; +#ifdef HEAD2 + uint16_t head2[65536L]; +#endif +} lzo_swd_t, *lzo_swd_p; + +#define SIZEOF_LZO_SWD_T (sizeof(lzo_swd_t)) + + +/* Access macro for head3. + * head3[key] may be uninitialized, but then its value will never be used. + */ +#define s_get_head3(s,key) s->head3[key] + + +/*********************************************************************** +// +************************************************************************/ +#define B_SIZE (SWD_N + SWD_F) + +static int swd_init(lzo_swd_p s) +{ + /* defaults */ + s->node_count = SWD_N; + + memset(s->llen3, 0, sizeof(s->llen3[0]) * (unsigned)SWD_HSIZE); +#ifdef HEAD2 + memset(s->head2, 0xff, sizeof(s->head2[0]) * 65536L); + assert(s->head2[0] == NIL2); +#endif + + s->ip = 0; + s->bp = s->ip; + s->first_rp = s->ip; + + assert(s->ip + SWD_F <= B_SIZE); + s->look = (unsigned) (s->c->in_end - s->c->ip); + if (s->look > 0) { + if (s->look > SWD_F) + s->look = SWD_F; + memcpy(&s->b[s->ip], s->c->ip, s->look); + s->c->ip += s->look; + s->ip += s->look; + } + if (s->ip == B_SIZE) + s->ip = 0; + + s->rp = s->first_rp; + if (s->rp >= s->node_count) + s->rp -= s->node_count; + else + s->rp += B_SIZE - s->node_count; + + return LZO_E_OK; +} + +#define swd_pos2off(s,pos) \ + (s->bp > (pos) ? s->bp - (pos) : B_SIZE - ((pos) - s->bp)) + + +/*********************************************************************** +// +************************************************************************/ +static void swd_getbyte(lzo_swd_p s) +{ + int c; + + if ((c = getbyte(*(s->c))) < 0) { + if (s->look > 0) + --s->look; + } else { + s->b[s->ip] = c; + if (s->ip < SWD_F) + s->b_wrap[s->ip] = c; + } + if (++s->ip == B_SIZE) + s->ip = 0; + if (++s->bp == B_SIZE) + s->bp = 0; + if (++s->rp == B_SIZE) + s->rp = 0; +} + + +/*********************************************************************** +// remove node from lists +************************************************************************/ +static void swd_remove_node(lzo_swd_p s, unsigned node) +{ + if (s->node_count == 0) { + unsigned key; + + key = HEAD3(s->b,node); + assert(s->llen3[key] > 0); + --s->llen3[key]; + +#ifdef HEAD2 + key = HEAD2(s->b,node); + assert(s->head2[key] != NIL2); + if ((unsigned) s->head2[key] == node) + s->head2[key] = NIL2; +#endif + } else + --s->node_count; +} + + +/*********************************************************************** +// +************************************************************************/ +static void swd_accept(lzo_swd_p s, unsigned n) +{ + assert(n <= s->look); + + while (n--) { + unsigned key; + + swd_remove_node(s,s->rp); + + /* add bp into HEAD3 */ + key = HEAD3(s->b, s->bp); + s->succ3[s->bp] = s_get_head3(s, key); + s->head3[key] = s->bp; + s->best3[s->bp] = SWD_F + 1; + s->llen3[key]++; + assert(s->llen3[key] <= SWD_N); + +#ifdef HEAD2 + /* add bp into HEAD2 */ + key = HEAD2(s->b, s->bp); + s->head2[key] = s->bp; +#endif + + swd_getbyte(s); + } +} + + +/*********************************************************************** +// +************************************************************************/ +static void swd_search(lzo_swd_p s, unsigned node, unsigned cnt) +{ + const uint8_t *p1; + const uint8_t *p2; + const uint8_t *px; + unsigned m_len = s->m_len; + const uint8_t *b = s->b; + const uint8_t *bp = s->b + s->bp; + const uint8_t *bx = s->b + s->bp + s->look; + unsigned char scan_end1; + + assert(s->m_len > 0); + + scan_end1 = bp[m_len - 1]; + for ( ; cnt-- > 0; node = s->succ3[node]) { + p1 = bp; + p2 = b + node; + px = bx; + + assert(m_len < s->look); + + if (p2[m_len - 1] == scan_end1 + && p2[m_len] == p1[m_len] + && p2[0] == p1[0] + && p2[1] == p1[1] + ) { + unsigned i; + assert(lzo_memcmp(bp, &b[node], 3) == 0); + + p1 += 2; p2 += 2; + do {} while (++p1 < px && *p1 == *++p2); + i = p1-bp; + + assert(lzo_memcmp(bp, &b[node], i) == 0); + +#if defined(SWD_BEST_OFF) + if (i < SWD_BEST_OFF) { + if (s->best_pos[i] == 0) + s->best_pos[i] = node + 1; + } +#endif + if (i > m_len) { + s->m_len = m_len = i; + s->m_pos = node; + if (m_len == s->look) + return; + if (m_len >= SWD_F) + return; + if (m_len > (unsigned) s->best3[node]) + return; + scan_end1 = bp[m_len - 1]; + } + } + } +} + + +/*********************************************************************** +// +************************************************************************/ +#ifdef HEAD2 + +static int swd_search2(lzo_swd_p s) +{ + unsigned key; + + assert(s->look >= 2); + assert(s->m_len > 0); + + key = s->head2[HEAD2(s->b, s->bp)]; + if (key == NIL2) + return 0; + assert(lzo_memcmp(&s->b[s->bp], &s->b[key], 2) == 0); +#if defined(SWD_BEST_OFF) + if (s->best_pos[2] == 0) + s->best_pos[2] = key + 1; +#endif + + if (s->m_len < 2) { + s->m_len = 2; + s->m_pos = key; + } + return 1; +} + +#endif + + +/*********************************************************************** +// +************************************************************************/ +static void swd_findbest(lzo_swd_p s) +{ + unsigned key; + unsigned cnt, node; + unsigned len; + + assert(s->m_len > 0); + + /* get current head, add bp into HEAD3 */ + key = HEAD3(s->b,s->bp); + node = s->succ3[s->bp] = s_get_head3(s, key); + cnt = s->llen3[key]++; + assert(s->llen3[key] <= SWD_N + SWD_F); + if (cnt > s->max_chain) + cnt = s->max_chain; + s->head3[key] = s->bp; + + s->b_char = s->b[s->bp]; + len = s->m_len; + if (s->m_len >= s->look) { + if (s->look == 0) + s->b_char = -1; + s->m_off = 0; + s->best3[s->bp] = SWD_F + 1; + } else { +#ifdef HEAD2 + if (swd_search2(s)) +#endif + if (s->look >= 3) + swd_search(s, node, cnt); + if (s->m_len > len) + s->m_off = swd_pos2off(s,s->m_pos); + s->best3[s->bp] = s->m_len; + +#if defined(SWD_BEST_OFF) + if (s->use_best_off) { + int i; + for (i = 2; i < SWD_BEST_OFF; i++) { + if (s->best_pos[i] > 0) + s->best_off[i] = swd_pos2off(s, s->best_pos[i]-1); + else + s->best_off[i] = 0; + } + } +#endif + } + + swd_remove_node(s,s->rp); + +#ifdef HEAD2 + /* add bp into HEAD2 */ + key = HEAD2(s->b, s->bp); + s->head2[key] = s->bp; +#endif +} + +#undef HEAD3 +#undef HEAD2 +#undef s_get_head3 + + +/*********************************************************************** +// +************************************************************************/ +static int init_match(lzo1x_999_t *c, lzo_swd_p s, uint32_t use_best_off) +{ + int r; + + assert(!c->init); + c->init = 1; + + s->c = c; + + r = swd_init(s); + if (r != 0) + return r; + + s->use_best_off = use_best_off; + return r; +} + + +/*********************************************************************** +// +************************************************************************/ +static int find_match(lzo1x_999_t *c, lzo_swd_p s, + unsigned this_len, unsigned skip) +{ + assert(c->init); + + if (skip > 0) { + assert(this_len >= skip); + swd_accept(s, this_len - skip); + } else { + assert(this_len <= 1); + } + + s->m_len = 1; + s->m_len = 1; +#ifdef SWD_BEST_OFF + if (s->use_best_off) + memset(s->best_pos, 0, sizeof(s->best_pos)); +#endif + swd_findbest(s); + c->m_len = s->m_len; + c->m_off = s->m_off; + + swd_getbyte(s); + + if (s->b_char < 0) { + c->look = 0; + c->m_len = 0; + } else { + c->look = s->look + 1; + } + c->bp = c->ip - c->look; + + return LZO_E_OK; +} + +/* this is a public functions, but there is no prototype in a header file */ +static int lzo1x_999_compress_internal(const uint8_t *in , unsigned in_len, + uint8_t *out, unsigned *out_len, + void *wrkmem, + unsigned good_length, + unsigned max_lazy, + unsigned max_chain, + uint32_t use_best_off); + + +/*********************************************************************** +// +************************************************************************/ +static uint8_t *code_match(lzo1x_999_t *c, + uint8_t *op, unsigned m_len, unsigned m_off) +{ + assert(op > c->out); + if (m_len == 2) { + assert(m_off <= M1_MAX_OFFSET); + assert(c->r1_lit > 0); + assert(c->r1_lit < 4); + m_off -= 1; + *op++ = M1_MARKER | ((m_off & 3) << 2); + *op++ = m_off >> 2; + } else if (m_len <= M2_MAX_LEN && m_off <= M2_MAX_OFFSET) { + assert(m_len >= 3); + m_off -= 1; + *op++ = ((m_len - 1) << 5) | ((m_off & 7) << 2); + *op++ = m_off >> 3; + assert(op[-2] >= M2_MARKER); + } else if (m_len == M2_MIN_LEN && m_off <= MX_MAX_OFFSET && c->r1_lit >= 4) { + assert(m_len == 3); + assert(m_off > M2_MAX_OFFSET); + m_off -= 1 + M2_MAX_OFFSET; + *op++ = M1_MARKER | ((m_off & 3) << 2); + *op++ = m_off >> 2; + } else if (m_off <= M3_MAX_OFFSET) { + assert(m_len >= 3); + m_off -= 1; + if (m_len <= M3_MAX_LEN) + *op++ = M3_MARKER | (m_len - 2); + else { + m_len -= M3_MAX_LEN; + *op++ = M3_MARKER | 0; + while (m_len > 255) { + m_len -= 255; + *op++ = 0; + } + assert(m_len > 0); + *op++ = m_len; + } + *op++ = m_off << 2; + *op++ = m_off >> 6; + } else { + unsigned k; + + assert(m_len >= 3); + assert(m_off > 0x4000); + assert(m_off <= 0xbfff); + m_off -= 0x4000; + k = (m_off & 0x4000) >> 11; + if (m_len <= M4_MAX_LEN) + *op++ = M4_MARKER | k | (m_len - 2); + else { + m_len -= M4_MAX_LEN; + *op++ = M4_MARKER | k | 0; + while (m_len > 255) { + m_len -= 255; + *op++ = 0; + } + assert(m_len > 0); + *op++ = m_len; + } + *op++ = m_off << 2; + *op++ = m_off >> 6; + } + + return op; +} + + +static uint8_t *STORE_RUN(lzo1x_999_t *c, uint8_t *op, + const uint8_t *ii, unsigned t) +{ + if (op == c->out && t <= 238) { + *op++ = 17 + t; + } else if (t <= 3) { + op[-2] |= t; + } else if (t <= 18) { + *op++ = t - 3; + } else { + unsigned tt = t - 18; + + *op++ = 0; + while (tt > 255) { + tt -= 255; + *op++ = 0; + } + assert(tt > 0); + *op++ = tt; + } + do *op++ = *ii++; while (--t > 0); + + return op; +} + + +static uint8_t *code_run(lzo1x_999_t *c, uint8_t *op, const uint8_t *ii, + unsigned lit) +{ + if (lit > 0) { + assert(m_len >= 2); + op = STORE_RUN(c, op, ii, lit); + } else { + assert(m_len >= 3); + } + c->r1_lit = lit; + + return op; +} + + +/*********************************************************************** +// +************************************************************************/ +static int len_of_coded_match(unsigned m_len, unsigned m_off, unsigned lit) +{ + int n = 4; + + if (m_len < 2) + return -1; + if (m_len == 2) + return (m_off <= M1_MAX_OFFSET && lit > 0 && lit < 4) ? 2 : -1; + if (m_len <= M2_MAX_LEN && m_off <= M2_MAX_OFFSET) + return 2; + if (m_len == M2_MIN_LEN && m_off <= MX_MAX_OFFSET && lit >= 4) + return 2; + if (m_off <= M3_MAX_OFFSET) { + if (m_len <= M3_MAX_LEN) + return 3; + m_len -= M3_MAX_LEN; + } else if (m_off <= M4_MAX_OFFSET) { + if (m_len <= M4_MAX_LEN) + return 3; + m_len -= M4_MAX_LEN; + } else + return -1; + while (m_len > 255) { + m_len -= 255; + n++; + } + return n; +} + + +static int min_gain(unsigned ahead, unsigned lit1, + unsigned lit2, int l1, int l2, int l3) +{ + int lazy_match_min_gain = 0; + + assert (ahead >= 1); + lazy_match_min_gain += ahead; + + if (lit1 <= 3) + lazy_match_min_gain += (lit2 <= 3) ? 0 : 2; + else if (lit1 <= 18) + lazy_match_min_gain += (lit2 <= 18) ? 0 : 1; + + lazy_match_min_gain += (l2 - l1) * 2; + if (l3 > 0) + lazy_match_min_gain -= (ahead - l3) * 2; + + if (lazy_match_min_gain < 0) + lazy_match_min_gain = 0; + + return lazy_match_min_gain; +} + + +/*********************************************************************** +// +************************************************************************/ +#if defined(SWD_BEST_OFF) + +static void better_match(const lzo_swd_p swd, + unsigned *m_len, unsigned *m_off) +{ + if (*m_len <= M2_MIN_LEN) + return; + + if (*m_off <= M2_MAX_OFFSET) + return; + + /* M3/M4 -> M2 */ + if (*m_off > M2_MAX_OFFSET + && *m_len >= M2_MIN_LEN + 1 && *m_len <= M2_MAX_LEN + 1 + && swd->best_off[*m_len-1] && swd->best_off[*m_len-1] <= M2_MAX_OFFSET + ) { + *m_len = *m_len - 1; + *m_off = swd->best_off[*m_len]; + return; + } + + /* M4 -> M2 */ + if (*m_off > M3_MAX_OFFSET + && *m_len >= M4_MAX_LEN + 1 && *m_len <= M2_MAX_LEN + 2 + && swd->best_off[*m_len-2] && swd->best_off[*m_len-2] <= M2_MAX_OFFSET + ) { + *m_len = *m_len - 2; + *m_off = swd->best_off[*m_len]; + return; + } + /* M4 -> M3 */ + if (*m_off > M3_MAX_OFFSET + && *m_len >= M4_MAX_LEN + 1 && *m_len <= M3_MAX_LEN + 1 + && swd->best_off[*m_len-1] && swd->best_off[*m_len-1] <= M3_MAX_OFFSET + ) { + *m_len = *m_len - 1; + *m_off = swd->best_off[*m_len]; + } +} + +#endif + + +/*********************************************************************** +// +************************************************************************/ +static int lzo1x_999_compress_internal(const uint8_t *in, unsigned in_len, + uint8_t *out, unsigned *out_len, + void *wrkmem, + unsigned good_length, + unsigned max_lazy, + unsigned max_chain, + uint32_t use_best_off) +{ + uint8_t *op; + const uint8_t *ii; + unsigned lit; + unsigned m_len, m_off; + lzo1x_999_t cc; + lzo1x_999_t *const c = &cc; + const lzo_swd_p swd = (lzo_swd_p) wrkmem; + int r; + + c->init = 0; + c->ip = c->in = in; + c->in_end = in + in_len; + c->out = out; + + op = out; + ii = c->ip; /* point to start of literal run */ + lit = 0; + c->r1_lit = 0; + + r = init_match(c, swd, use_best_off); + if (r != 0) + return r; + swd->max_chain = max_chain; + + r = find_match(c, swd, 0, 0); + if (r != 0) + return r; + + while (c->look > 0) { + unsigned ahead; + unsigned max_ahead; + int l1, l2, l3; + + m_len = c->m_len; + m_off = c->m_off; + + assert(c->bp == c->ip - c->look); + assert(c->bp >= in); + if (lit == 0) + ii = c->bp; + assert(ii + lit == c->bp); + assert(swd->b_char == *(c->bp)); + + if (m_len < 2 + || (m_len == 2 && (m_off > M1_MAX_OFFSET || lit == 0 || lit >= 4)) + /* Do not accept this match for compressed-data compatibility + * with LZO v1.01 and before + * [ might be a problem for decompress() and optimize() ] + */ + || (m_len == 2 && op == out) + || (op == out && lit == 0) + ) { + /* a literal */ + m_len = 0; + } + else if (m_len == M2_MIN_LEN) { + /* compression ratio improves if we code a literal in some cases */ + if (m_off > MX_MAX_OFFSET && lit >= 4) + m_len = 0; + } + + if (m_len == 0) { + /* a literal */ + lit++; + swd->max_chain = max_chain; + r = find_match(c, swd, 1, 0); + assert(r == 0); + continue; + } + + /* a match */ +#if defined(SWD_BEST_OFF) + if (swd->use_best_off) + better_match(swd, &m_len, &m_off); +#endif + + /* shall we try a lazy match ? */ + ahead = 0; + if (m_len >= max_lazy) { + /* no */ + l1 = 0; + max_ahead = 0; + } else { + /* yes, try a lazy match */ + l1 = len_of_coded_match(m_len, m_off, lit); + assert(l1 > 0); + max_ahead = LZO_MIN(2, (unsigned)l1 - 1); + } + + + while (ahead < max_ahead && c->look > m_len) { + int lazy_match_min_gain; + + if (m_len >= good_length) + swd->max_chain = max_chain >> 2; + else + swd->max_chain = max_chain; + r = find_match(c, swd, 1, 0); + ahead++; + + assert(r == 0); + assert(c->look > 0); + assert(ii + lit + ahead == c->bp); + + if (c->m_len < m_len) + continue; + if (c->m_len == m_len && c->m_off >= m_off) + continue; +#if defined(SWD_BEST_OFF) + if (swd->use_best_off) + better_match(swd, &c->m_len, &c->m_off); +#endif + l2 = len_of_coded_match(c->m_len, c->m_off, lit+ahead); + if (l2 < 0) + continue; + + /* compressed-data compatibility [see above] */ + l3 = (op == out) ? -1 : len_of_coded_match(ahead, m_off, lit); + + lazy_match_min_gain = min_gain(ahead, lit, lit+ahead, l1, l2, l3); + if (c->m_len >= m_len + lazy_match_min_gain) { + if (l3 > 0) { + /* code previous run */ + op = code_run(c, op, ii, lit); + lit = 0; + /* code shortened match */ + op = code_match(c, op, ahead, m_off); + } else { + lit += ahead; + assert(ii + lit == c->bp); + } + goto lazy_match_done; + } + } + + assert(ii + lit + ahead == c->bp); + + /* 1 - code run */ + op = code_run(c, op, ii, lit); + lit = 0; + + /* 2 - code match */ + op = code_match(c, op, m_len, m_off); + swd->max_chain = max_chain; + r = find_match(c, swd, m_len, 1+ahead); + assert(r == 0); + + lazy_match_done: ; + } + + /* store final run */ + if (lit > 0) + op = STORE_RUN(c, op, ii, lit); + +#if defined(LZO_EOF_CODE) + *op++ = M4_MARKER | 1; + *op++ = 0; + *op++ = 0; +#endif + + *out_len = op - out; + + return LZO_E_OK; +} + + +/*********************************************************************** +// +************************************************************************/ +int lzo1x_999_compress_level(const uint8_t *in, unsigned in_len, + uint8_t *out, unsigned *out_len, + void *wrkmem, + int compression_level) +{ + static const struct { + uint16_t good_length; + uint16_t max_lazy; + uint16_t max_chain; + uint16_t use_best_off; + } c[3] = { + { 8, 32, 256, 0 }, + { 32, 128, 2048, 1 }, + { SWD_F, SWD_F, 4096, 1 } /* max. compression */ + }; + + if (compression_level < 7 || compression_level > 9) + return LZO_E_ERROR; + + compression_level -= 7; + return lzo1x_999_compress_internal(in, in_len, out, out_len, wrkmem, + c[compression_level].good_length, + c[compression_level].max_lazy, + c[compression_level].max_chain, + c[compression_level].use_best_off); +} diff --git a/archival/libunarchive/lzo1x_c.c b/archival/libunarchive/lzo1x_c.c new file mode 100644 index 000000000..cc86f74b1 --- /dev/null +++ b/archival/libunarchive/lzo1x_c.c @@ -0,0 +1,296 @@ +/* implementation of the LZO1[XY]-1 compression algorithm + + This file is part of the LZO real-time data compression library. + + Copyright (C) 1996..2008 Markus Franz Xaver Johannes Oberhumer + All Rights Reserved. + + Markus F.X.J. Oberhumer + http://www.oberhumer.com/opensource/lzo/ + + The LZO library is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of + the License, or (at your option) any later version. + + The LZO library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with the LZO library; see the file COPYING. + If not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +/*********************************************************************** +// compress a block of data. +************************************************************************/ +static NOINLINE unsigned +do_compress(const uint8_t* in, unsigned in_len, + uint8_t* out, unsigned* out_len, + void* wrkmem) +{ + register const uint8_t* ip; + uint8_t* op; + const uint8_t* const in_end = in + in_len; + const uint8_t* const ip_end = in + in_len - M2_MAX_LEN - 5; + const uint8_t* ii; + const void* *const dict = (const void**) wrkmem; + + op = out; + ip = in; + ii = ip; + + ip += 4; + for (;;) { + register const uint8_t* m_pos; + unsigned m_off; + unsigned m_len; + unsigned dindex; + + D_INDEX1(dindex,ip); + GINDEX(m_pos,m_off,dict,dindex,in); + if (LZO_CHECK_MPOS_NON_DET(m_pos,m_off,in,ip,M4_MAX_OFFSET)) + goto literal; +#if 1 + if (m_off <= M2_MAX_OFFSET || m_pos[3] == ip[3]) + goto try_match; + D_INDEX2(dindex,ip); +#endif + GINDEX(m_pos,m_off,dict,dindex,in); + if (LZO_CHECK_MPOS_NON_DET(m_pos,m_off,in,ip,M4_MAX_OFFSET)) + goto literal; + if (m_off <= M2_MAX_OFFSET || m_pos[3] == ip[3]) + goto try_match; + goto literal; + + try_match: +#if 1 && defined(LZO_UNALIGNED_OK_2) + if (* (const lzo_ushortp) m_pos != * (const lzo_ushortp) ip) +#else + if (m_pos[0] != ip[0] || m_pos[1] != ip[1]) +#endif + { + } else { + if (m_pos[2] == ip[2]) { +#if 0 + if (m_off <= M2_MAX_OFFSET) + goto match; + if (lit <= 3) + goto match; + if (lit == 3) { /* better compression, but slower */ + assert(op - 2 > out); op[-2] |= (uint8_t)(3); + *op++ = *ii++; *op++ = *ii++; *op++ = *ii++; + goto code_match; + } + if (m_pos[3] == ip[3]) +#endif + goto match; + } + else { + /* still need a better way for finding M1 matches */ +#if 0 + /* a M1 match */ +#if 0 + if (m_off <= M1_MAX_OFFSET && lit > 0 && lit <= 3) +#else + if (m_off <= M1_MAX_OFFSET && lit == 3) +#endif + { + register unsigned t; + + t = lit; + assert(op - 2 > out); op[-2] |= (uint8_t)(t); + do *op++ = *ii++; while (--t > 0); + assert(ii == ip); + m_off -= 1; + *op++ = (uint8_t)(M1_MARKER | ((m_off & 3) << 2)); + *op++ = (uint8_t)(m_off >> 2); + ip += 2; + goto match_done; + } +#endif + } + } + + /* a literal */ + literal: + UPDATE_I(dict, 0, dindex, ip, in); + ++ip; + if (ip >= ip_end) + break; + continue; + + /* a match */ +match: + UPDATE_I(dict, 0, dindex, ip, in); + /* store current literal run */ + if (pd(ip, ii) > 0) { + register unsigned t = pd(ip, ii); + + if (t <= 3) { + assert(op - 2 > out); + op[-2] |= (uint8_t)(t); + } + else if (t <= 18) + *op++ = (uint8_t)(t - 3); + else { + register unsigned tt = t - 18; + + *op++ = 0; + while (tt > 255) { + tt -= 255; + *op++ = 0; + } + assert(tt > 0); + *op++ = (uint8_t)(tt); + } + do *op++ = *ii++; while (--t > 0); + } + + /* code the match */ + assert(ii == ip); + ip += 3; + if (m_pos[3] != *ip++ || m_pos[4] != *ip++ || m_pos[5] != *ip++ + || m_pos[6] != *ip++ || m_pos[7] != *ip++ || m_pos[8] != *ip++ +#ifdef LZO1Y + || m_pos[ 9] != *ip++ || m_pos[10] != *ip++ || m_pos[11] != *ip++ + || m_pos[12] != *ip++ || m_pos[13] != *ip++ || m_pos[14] != *ip++ +#endif + ) { + --ip; + m_len = pd(ip, ii); + assert(m_len >= 3); + assert(m_len <= M2_MAX_LEN); + + if (m_off <= M2_MAX_OFFSET) { + m_off -= 1; +#if defined(LZO1X) + *op++ = (uint8_t)(((m_len - 1) << 5) | ((m_off & 7) << 2)); + *op++ = (uint8_t)(m_off >> 3); +#elif defined(LZO1Y) + *op++ = (uint8_t)(((m_len + 1) << 4) | ((m_off & 3) << 2)); + *op++ = (uint8_t)(m_off >> 2); +#endif + } + else if (m_off <= M3_MAX_OFFSET) { + m_off -= 1; + *op++ = (uint8_t)(M3_MARKER | (m_len - 2)); + goto m3_m4_offset; + } else { +#if defined(LZO1X) + m_off -= 0x4000; + assert(m_off > 0); + assert(m_off <= 0x7fff); + *op++ = (uint8_t)(M4_MARKER | ((m_off & 0x4000) >> 11) | (m_len - 2)); + goto m3_m4_offset; +#elif defined(LZO1Y) + goto m4_match; +#endif + } + } + else { + { + const uint8_t* end = in_end; + const uint8_t* m = m_pos + M2_MAX_LEN + 1; + while (ip < end && *m == *ip) + m++, ip++; + m_len = pd(ip, ii); + } + assert(m_len > M2_MAX_LEN); + + if (m_off <= M3_MAX_OFFSET) { + m_off -= 1; + if (m_len <= 33) + *op++ = (uint8_t)(M3_MARKER | (m_len - 2)); + else { + m_len -= 33; + *op++ = M3_MARKER | 0; + goto m3_m4_len; + } + } else { +#if defined(LZO1Y) + m4_match: +#endif + m_off -= 0x4000; + assert(m_off > 0); + assert(m_off <= 0x7fff); + if (m_len <= M4_MAX_LEN) + *op++ = (uint8_t)(M4_MARKER | ((m_off & 0x4000) >> 11) | (m_len - 2)); + else { + m_len -= M4_MAX_LEN; + *op++ = (uint8_t)(M4_MARKER | ((m_off & 0x4000) >> 11)); + m3_m4_len: + while (m_len > 255) { + m_len -= 255; + *op++ = 0; + } + assert(m_len > 0); + *op++ = (uint8_t)(m_len); + } + } + m3_m4_offset: + *op++ = (uint8_t)((m_off & 63) << 2); + *op++ = (uint8_t)(m_off >> 6); + } +#if 0 + match_done: +#endif + ii = ip; + if (ip >= ip_end) + break; + } + + *out_len = pd(op, out); + return pd(in_end, ii); +} + +/*********************************************************************** +// public entry point +************************************************************************/ +int DO_COMPRESS(const uint8_t* in, unsigned in_len, + uint8_t* out, unsigned* out_len, + void* wrkmem) +{ + uint8_t* op = out; + unsigned t; + + if (in_len <= M2_MAX_LEN + 5) + t = in_len; + else { + t = do_compress(in,in_len,op,out_len,wrkmem); + op += *out_len; + } + + if (t > 0) { + const uint8_t* ii = in + in_len - t; + + if (op == out && t <= 238) + *op++ = (uint8_t)(17 + t); + else if (t <= 3) + op[-2] |= (uint8_t)(t); + else if (t <= 18) + *op++ = (uint8_t)(t - 3); + else { + unsigned tt = t - 18; + + *op++ = 0; + while (tt > 255) { + tt -= 255; + *op++ = 0; + } + assert(tt > 0); + *op++ = (uint8_t)(tt); + } + do *op++ = *ii++; while (--t > 0); + } + + *op++ = M4_MARKER | 1; + *op++ = 0; + *op++ = 0; + + *out_len = pd(op, out); + return 0; /*LZO_E_OK*/ +} diff --git a/archival/libunarchive/lzo1x_d.c b/archival/libunarchive/lzo1x_d.c new file mode 100644 index 000000000..348a85510 --- /dev/null +++ b/archival/libunarchive/lzo1x_d.c @@ -0,0 +1,420 @@ +/* implementation of the LZO1X decompression algorithm + + This file is part of the LZO real-time data compression library. + + Copyright (C) 1996..2008 Markus Franz Xaver Johannes Oberhumer + All Rights Reserved. + + Markus F.X.J. Oberhumer + http://www.oberhumer.com/opensource/lzo/ + + The LZO library is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of + the License, or (at your option) any later version. + + The LZO library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with the LZO library; see the file COPYING. + If not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#include "libbb.h" +#include "liblzo.h" + +/*********************************************************************** +// decompress a block of data. +************************************************************************/ +/* safe decompression with overrun testing */ +int lzo1x_decompress_safe(const uint8_t* in, unsigned in_len, + uint8_t* out, unsigned* out_len, + void* wrkmem UNUSED_PARAM) +{ + register uint8_t* op; + register const uint8_t* ip; + register unsigned t; +#if defined(COPY_DICT) + unsigned m_off; + const uint8_t* dict_end; +#else + register const uint8_t* m_pos = NULL; /* possibly not needed */ +#endif + const uint8_t* const ip_end = in + in_len; +#if defined(HAVE_ANY_OP) + uint8_t* const op_end = out + *out_len; +#endif +#if defined(LZO1Z) + unsigned last_m_off = 0; +#endif + +// LZO_UNUSED(wrkmem); + +#if defined(COPY_DICT) + if (dict) { + if (dict_len > M4_MAX_OFFSET) { + dict += dict_len - M4_MAX_OFFSET; + dict_len = M4_MAX_OFFSET; + } + dict_end = dict + dict_len; + } else { + dict_len = 0; + dict_end = NULL; + } +#endif /* COPY_DICT */ + + *out_len = 0; + + op = out; + ip = in; + + if (*ip > 17) { + t = *ip++ - 17; + if (t < 4) + goto match_next; + assert(t > 0); NEED_OP(t); NEED_IP(t+1); + do *op++ = *ip++; while (--t > 0); + goto first_literal_run; + } + + while (TEST_IP && TEST_OP) { + t = *ip++; + if (t >= 16) + goto match; + /* a literal run */ + if (t == 0) { + NEED_IP(1); + while (*ip == 0) { + t += 255; + ip++; + NEED_IP(1); + } + t += 15 + *ip++; + } + /* copy literals */ + assert(t > 0); + NEED_OP(t+3); + NEED_IP(t+4); +#if defined(LZO_UNALIGNED_OK_4) || defined(LZO_ALIGNED_OK_4) +# if !defined(LZO_UNALIGNED_OK_4) + if (PTR_ALIGNED2_4(op, ip)) +# endif + { + COPY4(op, ip); + op += 4; + ip += 4; + if (--t > 0) { + if (t >= 4) { + do { + COPY4(op, ip); + op += 4; + ip += 4; + t -= 4; + } while (t >= 4); + if (t > 0) + do *op++ = *ip++; while (--t > 0); + } else { + do *op++ = *ip++; while (--t > 0); + } + } + } +# if !defined(LZO_UNALIGNED_OK_4) + else +# endif +#endif +#if !defined(LZO_UNALIGNED_OK_4) + { + *op++ = *ip++; + *op++ = *ip++; + *op++ = *ip++; + do *op++ = *ip++; while (--t > 0); + } +#endif + + first_literal_run: + t = *ip++; + if (t >= 16) + goto match; +#if defined(COPY_DICT) +#if defined(LZO1Z) + m_off = (1 + M2_MAX_OFFSET) + (t << 6) + (*ip++ >> 2); + last_m_off = m_off; +#else + m_off = (1 + M2_MAX_OFFSET) + (t >> 2) + (*ip++ << 2); +#endif + NEED_OP(3); + t = 3; COPY_DICT(t,m_off) +#else /* !COPY_DICT */ +#if defined(LZO1Z) + t = (1 + M2_MAX_OFFSET) + (t << 6) + (*ip++ >> 2); + m_pos = op - t; + last_m_off = t; +#else + m_pos = op - (1 + M2_MAX_OFFSET); + m_pos -= t >> 2; + m_pos -= *ip++ << 2; +#endif + TEST_LB(m_pos); NEED_OP(3); + *op++ = *m_pos++; + *op++ = *m_pos++; + *op++ = *m_pos; +#endif /* COPY_DICT */ + goto match_done; + + /* handle matches */ + do { + match: + if (t >= 64) { /* a M2 match */ +#if defined(COPY_DICT) +#if defined(LZO1X) + m_off = 1 + ((t >> 2) & 7) + (*ip++ << 3); + t = (t >> 5) - 1; +#elif defined(LZO1Y) + m_off = 1 + ((t >> 2) & 3) + (*ip++ << 2); + t = (t >> 4) - 3; +#elif defined(LZO1Z) + m_off = t & 0x1f; + if (m_off >= 0x1c) + m_off = last_m_off; + else { + m_off = 1 + (m_off << 6) + (*ip++ >> 2); + last_m_off = m_off; + } + t = (t >> 5) - 1; +#endif +#else /* !COPY_DICT */ +#if defined(LZO1X) + m_pos = op - 1; + m_pos -= (t >> 2) & 7; + m_pos -= *ip++ << 3; + t = (t >> 5) - 1; +#elif defined(LZO1Y) + m_pos = op - 1; + m_pos -= (t >> 2) & 3; + m_pos -= *ip++ << 2; + t = (t >> 4) - 3; +#elif defined(LZO1Z) + { + unsigned off = t & 0x1f; + m_pos = op; + if (off >= 0x1c) { + assert(last_m_off > 0); + m_pos -= last_m_off; + } else { + off = 1 + (off << 6) + (*ip++ >> 2); + m_pos -= off; + last_m_off = off; + } + } + t = (t >> 5) - 1; +#endif + TEST_LB(m_pos); assert(t > 0); NEED_OP(t+3-1); + goto copy_match; +#endif /* COPY_DICT */ + } + else if (t >= 32) { /* a M3 match */ + t &= 31; + if (t == 0) { + NEED_IP(1); + while (*ip == 0) { + t += 255; + ip++; + NEED_IP(1); + } + t += 31 + *ip++; + } +#if defined(COPY_DICT) +#if defined(LZO1Z) + m_off = 1 + (ip[0] << 6) + (ip[1] >> 2); + last_m_off = m_off; +#else + m_off = 1 + (ip[0] >> 2) + (ip[1] << 6); +#endif +#else /* !COPY_DICT */ +#if defined(LZO1Z) + { + unsigned off = 1 + (ip[0] << 6) + (ip[1] >> 2); + m_pos = op - off; + last_m_off = off; + } +#elif defined(LZO_UNALIGNED_OK_2) && defined(LZO_ABI_LITTLE_ENDIAN) + m_pos = op - 1; + m_pos -= (* (const lzo_ushortp) ip) >> 2; +#else + m_pos = op - 1; + m_pos -= (ip[0] >> 2) + (ip[1] << 6); +#endif +#endif /* COPY_DICT */ + ip += 2; + } + else if (t >= 16) { /* a M4 match */ +#if defined(COPY_DICT) + m_off = (t & 8) << 11; +#else /* !COPY_DICT */ + m_pos = op; + m_pos -= (t & 8) << 11; +#endif /* COPY_DICT */ + t &= 7; + if (t == 0) { + NEED_IP(1); + while (*ip == 0) { + t += 255; + ip++; + NEED_IP(1); + } + t += 7 + *ip++; + } +#if defined(COPY_DICT) +#if defined(LZO1Z) + m_off += (ip[0] << 6) + (ip[1] >> 2); +#else + m_off += (ip[0] >> 2) + (ip[1] << 6); +#endif + ip += 2; + if (m_off == 0) + goto eof_found; + m_off += 0x4000; +#if defined(LZO1Z) + last_m_off = m_off; +#endif +#else /* !COPY_DICT */ +#if defined(LZO1Z) + m_pos -= (ip[0] << 6) + (ip[1] >> 2); +#elif defined(LZO_UNALIGNED_OK_2) && defined(LZO_ABI_LITTLE_ENDIAN) + m_pos -= (* (const lzo_ushortp) ip) >> 2; +#else + m_pos -= (ip[0] >> 2) + (ip[1] << 6); +#endif + ip += 2; + if (m_pos == op) + goto eof_found; + m_pos -= 0x4000; +#if defined(LZO1Z) + last_m_off = pd((const uint8_t*)op, m_pos); +#endif +#endif /* COPY_DICT */ + } + else { /* a M1 match */ +#if defined(COPY_DICT) +#if defined(LZO1Z) + m_off = 1 + (t << 6) + (*ip++ >> 2); + last_m_off = m_off; +#else + m_off = 1 + (t >> 2) + (*ip++ << 2); +#endif + NEED_OP(2); + t = 2; COPY_DICT(t,m_off) +#else /* !COPY_DICT */ +#if defined(LZO1Z) + t = 1 + (t << 6) + (*ip++ >> 2); + m_pos = op - t; + last_m_off = t; +#else + m_pos = op - 1; + m_pos -= t >> 2; + m_pos -= *ip++ << 2; +#endif + TEST_LB(m_pos); NEED_OP(2); + *op++ = *m_pos++; + *op++ = *m_pos; +#endif /* COPY_DICT */ + goto match_done; + } + + /* copy match */ +#if defined(COPY_DICT) + + NEED_OP(t+3-1); + t += 3-1; COPY_DICT(t,m_off) + +#else /* !COPY_DICT */ + + TEST_LB(m_pos); assert(t > 0); NEED_OP(t+3-1); +#if defined(LZO_UNALIGNED_OK_4) || defined(LZO_ALIGNED_OK_4) +# if !defined(LZO_UNALIGNED_OK_4) + if (t >= 2 * 4 - (3 - 1) && PTR_ALIGNED2_4(op,m_pos)) { + assert((op - m_pos) >= 4); /* both pointers are aligned */ +# else + if (t >= 2 * 4 - (3 - 1) && (op - m_pos) >= 4) { +# endif + COPY4(op,m_pos); + op += 4; m_pos += 4; t -= 4 - (3 - 1); + do { + COPY4(op,m_pos); + op += 4; m_pos += 4; t -= 4; + } while (t >= 4); + if (t > 0) + do *op++ = *m_pos++; while (--t > 0); + } + else +#endif + { + copy_match: + *op++ = *m_pos++; *op++ = *m_pos++; + do *op++ = *m_pos++; while (--t > 0); + } + +#endif /* COPY_DICT */ + + match_done: +#if defined(LZO1Z) + t = ip[-1] & 3; +#else + t = ip[-2] & 3; +#endif + if (t == 0) + break; + + /* copy literals */ + match_next: + assert(t > 0); + assert(t < 4); + NEED_OP(t); + NEED_IP(t+1); +#if 0 + do *op++ = *ip++; while (--t > 0); +#else + *op++ = *ip++; + if (t > 1) { + *op++ = *ip++; + if (t > 2) + *op++ = *ip++; + } +#endif + t = *ip++; + } while (TEST_IP && TEST_OP); + } + +//#if defined(HAVE_TEST_IP) || defined(HAVE_TEST_OP) + /* no EOF code was found */ + *out_len = pd(op, out); + return LZO_E_EOF_NOT_FOUND; +//#endif + + eof_found: + assert(t == 1); + *out_len = pd(op, out); + return (ip == ip_end ? LZO_E_OK : + (ip < ip_end ? LZO_E_INPUT_NOT_CONSUMED : LZO_E_INPUT_OVERRUN)); + +//#if defined(HAVE_NEED_IP) + input_overrun: + *out_len = pd(op, out); + return LZO_E_INPUT_OVERRUN; +//#endif + +//#if defined(HAVE_NEED_OP) + output_overrun: + *out_len = pd(op, out); + return LZO_E_OUTPUT_OVERRUN; +//#endif + +//#if defined(LZO_TEST_OVERRUN_LOOKBEHIND) + lookbehind_overrun: + *out_len = pd(op, out); + return LZO_E_LOOKBEHIND_OVERRUN; +//#endif +} diff --git a/archival/lzo1x_1.c b/archival/lzo1x_1.c deleted file mode 100644 index a88839846..000000000 --- a/archival/lzo1x_1.c +++ /dev/null @@ -1,35 +0,0 @@ -/* LZO1X-1 compression - - This file is part of the LZO real-time data compression library. - - Copyright (C) 1996..2008 Markus Franz Xaver Johannes Oberhumer - All Rights Reserved. - - Markus F.X.J. Oberhumer - http://www.oberhumer.com/opensource/lzo/ - - The LZO library is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License as - published by the Free Software Foundation; either version 2 of - the License, or (at your option) any later version. - - The LZO library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with the LZO library; see the file COPYING. - If not, write to the Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -#include "libbb.h" -#include "liblzo.h" - -#define D_BITS 14 -#define D_INDEX1(d,p) d = DM(DMUL(0x21,DX3(p,5,5,6)) >> 5) -#define D_INDEX2(d,p) d = (d & (D_MASK & 0x7ff)) ^ (D_HIGH | 0x1f) - -#define DO_COMPRESS lzo1x_1_compress - -#include "lzo1x_c.c" diff --git a/archival/lzo1x_1o.c b/archival/lzo1x_1o.c deleted file mode 100644 index 3c61253e0..000000000 --- a/archival/lzo1x_1o.c +++ /dev/null @@ -1,35 +0,0 @@ -/* LZO1X-1(15) compression - - This file is part of the LZO real-time data compression library. - - Copyright (C) 1996..2008 Markus Franz Xaver Johannes Oberhumer - All Rights Reserved. - - Markus F.X.J. Oberhumer - http://www.oberhumer.com/opensource/lzo/ - - The LZO library is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License as - published by the Free Software Foundation; either version 2 of - the License, or (at your option) any later version. - - The LZO library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with the LZO library; see the file COPYING. - If not, write to the Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -#include "libbb.h" -#include "liblzo.h" - -#define D_BITS 15 -#define D_INDEX1(d,p) d = DM(DMUL(0x21,DX3(p,5,5,6)) >> 5) -#define D_INDEX2(d,p) d = (d & (D_MASK & 0x7ff)) ^ (D_HIGH | 0x1f) - -#define DO_COMPRESS lzo1x_1_15_compress - -#include "lzo1x_c.c" diff --git a/archival/lzo1x_9x.c b/archival/lzo1x_9x.c deleted file mode 100644 index 483205155..000000000 --- a/archival/lzo1x_9x.c +++ /dev/null @@ -1,921 +0,0 @@ -/* lzo1x_9x.c -- implementation of the LZO1X-999 compression algorithm - - This file is part of the LZO real-time data compression library. - - Copyright (C) 2008 Markus Franz Xaver Johannes Oberhumer - Copyright (C) 2007 Markus Franz Xaver Johannes Oberhumer - Copyright (C) 2006 Markus Franz Xaver Johannes Oberhumer - Copyright (C) 2005 Markus Franz Xaver Johannes Oberhumer - Copyright (C) 2004 Markus Franz Xaver Johannes Oberhumer - Copyright (C) 2003 Markus Franz Xaver Johannes Oberhumer - Copyright (C) 2002 Markus Franz Xaver Johannes Oberhumer - Copyright (C) 2001 Markus Franz Xaver Johannes Oberhumer - Copyright (C) 2000 Markus Franz Xaver Johannes Oberhumer - Copyright (C) 1999 Markus Franz Xaver Johannes Oberhumer - Copyright (C) 1998 Markus Franz Xaver Johannes Oberhumer - Copyright (C) 1997 Markus Franz Xaver Johannes Oberhumer - Copyright (C) 1996 Markus Franz Xaver Johannes Oberhumer - All Rights Reserved. - - The LZO library is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License as - published by the Free Software Foundation; either version 2 of - the License, or (at your option) any later version. - - The LZO library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with the LZO library; see the file COPYING. - If not, write to the Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - - Markus F.X.J. Oberhumer - - http://www.oberhumer.com/opensource/lzo/ -*/ -#include "libbb.h" - -/* The following is probably only safe on Intel-compatible processors ... */ -#define LZO_UNALIGNED_OK_2 -#define LZO_UNALIGNED_OK_4 - -#include "liblzo.h" - -#define LZO_MAX(a,b) ((a) >= (b) ? (a) : (b)) -#define LZO_MIN(a,b) ((a) <= (b) ? (a) : (b)) -#define LZO_MAX3(a,b,c) ((a) >= (b) ? LZO_MAX(a,c) : LZO_MAX(b,c)) - -/*********************************************************************** -// -************************************************************************/ -#define SWD_N M4_MAX_OFFSET /* size of ring buffer */ -#define SWD_F 2048 /* upper limit for match length */ - -#define SWD_BEST_OFF (LZO_MAX3(M2_MAX_LEN, M3_MAX_LEN, M4_MAX_LEN) + 1) - -typedef struct { - int init; - - unsigned look; /* bytes in lookahead buffer */ - - unsigned m_len; - unsigned m_off; - - const uint8_t *bp; - const uint8_t *ip; - const uint8_t *in; - const uint8_t *in_end; - uint8_t *out; - - unsigned r1_lit; - -} lzo1x_999_t; - -#define getbyte(c) ((c).ip < (c).in_end ? *((c).ip)++ : (-1)) - -/* lzo_swd.c -- sliding window dictionary */ - -/*********************************************************************** -// -************************************************************************/ -#define SWD_UINT_MAX USHRT_MAX - -#ifndef SWD_HSIZE -# define SWD_HSIZE 16384 -#endif -#ifndef SWD_MAX_CHAIN -# define SWD_MAX_CHAIN 2048 -#endif - -#define HEAD3(b, p) \ - ( ((0x9f5f * ((((b[p]<<5)^b[p+1])<<5) ^ b[p+2])) >> 5) & (SWD_HSIZE-1) ) - -#if defined(LZO_UNALIGNED_OK_2) -# define HEAD2(b,p) (* (uint16_t *) &(b[p])) -#else -# define HEAD2(b,p) (b[p] ^ ((unsigned)b[p+1]<<8)) -#endif -#define NIL2 SWD_UINT_MAX - -typedef struct lzo_swd { - /* public - "built-in" */ - - /* public - configuration */ - unsigned max_chain; - int use_best_off; - - /* public - output */ - unsigned m_len; - unsigned m_off; - unsigned look; - int b_char; -#if defined(SWD_BEST_OFF) - unsigned best_off[SWD_BEST_OFF]; -#endif - - /* semi public */ - lzo1x_999_t *c; - unsigned m_pos; -#if defined(SWD_BEST_OFF) - unsigned best_pos[SWD_BEST_OFF]; -#endif - - /* private */ - unsigned ip; /* input pointer (lookahead) */ - unsigned bp; /* buffer pointer */ - unsigned rp; /* remove pointer */ - - unsigned node_count; - unsigned first_rp; - - uint8_t b[SWD_N + SWD_F]; - uint8_t b_wrap[SWD_F]; /* must follow b */ - uint16_t head3[SWD_HSIZE]; - uint16_t succ3[SWD_N + SWD_F]; - uint16_t best3[SWD_N + SWD_F]; - uint16_t llen3[SWD_HSIZE]; -#ifdef HEAD2 - uint16_t head2[65536L]; -#endif -} lzo_swd_t, *lzo_swd_p; - -#define SIZEOF_LZO_SWD_T (sizeof(lzo_swd_t)) - - -/* Access macro for head3. - * head3[key] may be uninitialized, but then its value will never be used. - */ -#define s_get_head3(s,key) s->head3[key] - - -/*********************************************************************** -// -************************************************************************/ -#define B_SIZE (SWD_N + SWD_F) - -static int swd_init(lzo_swd_p s) -{ - /* defaults */ - s->node_count = SWD_N; - - memset(s->llen3, 0, sizeof(s->llen3[0]) * (unsigned)SWD_HSIZE); -#ifdef HEAD2 - memset(s->head2, 0xff, sizeof(s->head2[0]) * 65536L); - assert(s->head2[0] == NIL2); -#endif - - s->ip = 0; - s->bp = s->ip; - s->first_rp = s->ip; - - assert(s->ip + SWD_F <= B_SIZE); - s->look = (unsigned) (s->c->in_end - s->c->ip); - if (s->look > 0) { - if (s->look > SWD_F) - s->look = SWD_F; - memcpy(&s->b[s->ip], s->c->ip, s->look); - s->c->ip += s->look; - s->ip += s->look; - } - if (s->ip == B_SIZE) - s->ip = 0; - - s->rp = s->first_rp; - if (s->rp >= s->node_count) - s->rp -= s->node_count; - else - s->rp += B_SIZE - s->node_count; - - return LZO_E_OK; -} - -#define swd_pos2off(s,pos) \ - (s->bp > (pos) ? s->bp - (pos) : B_SIZE - ((pos) - s->bp)) - - -/*********************************************************************** -// -************************************************************************/ -static void swd_getbyte(lzo_swd_p s) -{ - int c; - - if ((c = getbyte(*(s->c))) < 0) { - if (s->look > 0) - --s->look; - } else { - s->b[s->ip] = c; - if (s->ip < SWD_F) - s->b_wrap[s->ip] = c; - } - if (++s->ip == B_SIZE) - s->ip = 0; - if (++s->bp == B_SIZE) - s->bp = 0; - if (++s->rp == B_SIZE) - s->rp = 0; -} - - -/*********************************************************************** -// remove node from lists -************************************************************************/ -static void swd_remove_node(lzo_swd_p s, unsigned node) -{ - if (s->node_count == 0) { - unsigned key; - - key = HEAD3(s->b,node); - assert(s->llen3[key] > 0); - --s->llen3[key]; - -#ifdef HEAD2 - key = HEAD2(s->b,node); - assert(s->head2[key] != NIL2); - if ((unsigned) s->head2[key] == node) - s->head2[key] = NIL2; -#endif - } else - --s->node_count; -} - - -/*********************************************************************** -// -************************************************************************/ -static void swd_accept(lzo_swd_p s, unsigned n) -{ - assert(n <= s->look); - - while (n--) { - unsigned key; - - swd_remove_node(s,s->rp); - - /* add bp into HEAD3 */ - key = HEAD3(s->b, s->bp); - s->succ3[s->bp] = s_get_head3(s, key); - s->head3[key] = s->bp; - s->best3[s->bp] = SWD_F + 1; - s->llen3[key]++; - assert(s->llen3[key] <= SWD_N); - -#ifdef HEAD2 - /* add bp into HEAD2 */ - key = HEAD2(s->b, s->bp); - s->head2[key] = s->bp; -#endif - - swd_getbyte(s); - } -} - - -/*********************************************************************** -// -************************************************************************/ -static void swd_search(lzo_swd_p s, unsigned node, unsigned cnt) -{ - const uint8_t *p1; - const uint8_t *p2; - const uint8_t *px; - unsigned m_len = s->m_len; - const uint8_t *b = s->b; - const uint8_t *bp = s->b + s->bp; - const uint8_t *bx = s->b + s->bp + s->look; - unsigned char scan_end1; - - assert(s->m_len > 0); - - scan_end1 = bp[m_len - 1]; - for ( ; cnt-- > 0; node = s->succ3[node]) { - p1 = bp; - p2 = b + node; - px = bx; - - assert(m_len < s->look); - - if (p2[m_len - 1] == scan_end1 - && p2[m_len] == p1[m_len] - && p2[0] == p1[0] - && p2[1] == p1[1] - ) { - unsigned i; - assert(lzo_memcmp(bp, &b[node], 3) == 0); - - p1 += 2; p2 += 2; - do {} while (++p1 < px && *p1 == *++p2); - i = p1-bp; - - assert(lzo_memcmp(bp, &b[node], i) == 0); - -#if defined(SWD_BEST_OFF) - if (i < SWD_BEST_OFF) { - if (s->best_pos[i] == 0) - s->best_pos[i] = node + 1; - } -#endif - if (i > m_len) { - s->m_len = m_len = i; - s->m_pos = node; - if (m_len == s->look) - return; - if (m_len >= SWD_F) - return; - if (m_len > (unsigned) s->best3[node]) - return; - scan_end1 = bp[m_len - 1]; - } - } - } -} - - -/*********************************************************************** -// -************************************************************************/ -#ifdef HEAD2 - -static int swd_search2(lzo_swd_p s) -{ - unsigned key; - - assert(s->look >= 2); - assert(s->m_len > 0); - - key = s->head2[HEAD2(s->b, s->bp)]; - if (key == NIL2) - return 0; - assert(lzo_memcmp(&s->b[s->bp], &s->b[key], 2) == 0); -#if defined(SWD_BEST_OFF) - if (s->best_pos[2] == 0) - s->best_pos[2] = key + 1; -#endif - - if (s->m_len < 2) { - s->m_len = 2; - s->m_pos = key; - } - return 1; -} - -#endif - - -/*********************************************************************** -// -************************************************************************/ -static void swd_findbest(lzo_swd_p s) -{ - unsigned key; - unsigned cnt, node; - unsigned len; - - assert(s->m_len > 0); - - /* get current head, add bp into HEAD3 */ - key = HEAD3(s->b,s->bp); - node = s->succ3[s->bp] = s_get_head3(s, key); - cnt = s->llen3[key]++; - assert(s->llen3[key] <= SWD_N + SWD_F); - if (cnt > s->max_chain) - cnt = s->max_chain; - s->head3[key] = s->bp; - - s->b_char = s->b[s->bp]; - len = s->m_len; - if (s->m_len >= s->look) { - if (s->look == 0) - s->b_char = -1; - s->m_off = 0; - s->best3[s->bp] = SWD_F + 1; - } else { -#ifdef HEAD2 - if (swd_search2(s)) -#endif - if (s->look >= 3) - swd_search(s, node, cnt); - if (s->m_len > len) - s->m_off = swd_pos2off(s,s->m_pos); - s->best3[s->bp] = s->m_len; - -#if defined(SWD_BEST_OFF) - if (s->use_best_off) { - int i; - for (i = 2; i < SWD_BEST_OFF; i++) { - if (s->best_pos[i] > 0) - s->best_off[i] = swd_pos2off(s, s->best_pos[i]-1); - else - s->best_off[i] = 0; - } - } -#endif - } - - swd_remove_node(s,s->rp); - -#ifdef HEAD2 - /* add bp into HEAD2 */ - key = HEAD2(s->b, s->bp); - s->head2[key] = s->bp; -#endif -} - -#undef HEAD3 -#undef HEAD2 -#undef s_get_head3 - - -/*********************************************************************** -// -************************************************************************/ -static int init_match(lzo1x_999_t *c, lzo_swd_p s, uint32_t use_best_off) -{ - int r; - - assert(!c->init); - c->init = 1; - - s->c = c; - - r = swd_init(s); - if (r != 0) - return r; - - s->use_best_off = use_best_off; - return r; -} - - -/*********************************************************************** -// -************************************************************************/ -static int find_match(lzo1x_999_t *c, lzo_swd_p s, - unsigned this_len, unsigned skip) -{ - assert(c->init); - - if (skip > 0) { - assert(this_len >= skip); - swd_accept(s, this_len - skip); - } else { - assert(this_len <= 1); - } - - s->m_len = 1; - s->m_len = 1; -#ifdef SWD_BEST_OFF - if (s->use_best_off) - memset(s->best_pos, 0, sizeof(s->best_pos)); -#endif - swd_findbest(s); - c->m_len = s->m_len; - c->m_off = s->m_off; - - swd_getbyte(s); - - if (s->b_char < 0) { - c->look = 0; - c->m_len = 0; - } else { - c->look = s->look + 1; - } - c->bp = c->ip - c->look; - - return LZO_E_OK; -} - -/* this is a public functions, but there is no prototype in a header file */ -static int lzo1x_999_compress_internal(const uint8_t *in , unsigned in_len, - uint8_t *out, unsigned *out_len, - void *wrkmem, - unsigned good_length, - unsigned max_lazy, - unsigned max_chain, - uint32_t use_best_off); - - -/*********************************************************************** -// -************************************************************************/ -static uint8_t *code_match(lzo1x_999_t *c, - uint8_t *op, unsigned m_len, unsigned m_off) -{ - assert(op > c->out); - if (m_len == 2) { - assert(m_off <= M1_MAX_OFFSET); - assert(c->r1_lit > 0); - assert(c->r1_lit < 4); - m_off -= 1; - *op++ = M1_MARKER | ((m_off & 3) << 2); - *op++ = m_off >> 2; - } else if (m_len <= M2_MAX_LEN && m_off <= M2_MAX_OFFSET) { - assert(m_len >= 3); - m_off -= 1; - *op++ = ((m_len - 1) << 5) | ((m_off & 7) << 2); - *op++ = m_off >> 3; - assert(op[-2] >= M2_MARKER); - } else if (m_len == M2_MIN_LEN && m_off <= MX_MAX_OFFSET && c->r1_lit >= 4) { - assert(m_len == 3); - assert(m_off > M2_MAX_OFFSET); - m_off -= 1 + M2_MAX_OFFSET; - *op++ = M1_MARKER | ((m_off & 3) << 2); - *op++ = m_off >> 2; - } else if (m_off <= M3_MAX_OFFSET) { - assert(m_len >= 3); - m_off -= 1; - if (m_len <= M3_MAX_LEN) - *op++ = M3_MARKER | (m_len - 2); - else { - m_len -= M3_MAX_LEN; - *op++ = M3_MARKER | 0; - while (m_len > 255) { - m_len -= 255; - *op++ = 0; - } - assert(m_len > 0); - *op++ = m_len; - } - *op++ = m_off << 2; - *op++ = m_off >> 6; - } else { - unsigned k; - - assert(m_len >= 3); - assert(m_off > 0x4000); - assert(m_off <= 0xbfff); - m_off -= 0x4000; - k = (m_off & 0x4000) >> 11; - if (m_len <= M4_MAX_LEN) - *op++ = M4_MARKER | k | (m_len - 2); - else { - m_len -= M4_MAX_LEN; - *op++ = M4_MARKER | k | 0; - while (m_len > 255) { - m_len -= 255; - *op++ = 0; - } - assert(m_len > 0); - *op++ = m_len; - } - *op++ = m_off << 2; - *op++ = m_off >> 6; - } - - return op; -} - - -static uint8_t *STORE_RUN(lzo1x_999_t *c, uint8_t *op, - const uint8_t *ii, unsigned t) -{ - if (op == c->out && t <= 238) { - *op++ = 17 + t; - } else if (t <= 3) { - op[-2] |= t; - } else if (t <= 18) { - *op++ = t - 3; - } else { - unsigned tt = t - 18; - - *op++ = 0; - while (tt > 255) { - tt -= 255; - *op++ = 0; - } - assert(tt > 0); - *op++ = tt; - } - do *op++ = *ii++; while (--t > 0); - - return op; -} - - -static uint8_t *code_run(lzo1x_999_t *c, uint8_t *op, const uint8_t *ii, - unsigned lit) -{ - if (lit > 0) { - assert(m_len >= 2); - op = STORE_RUN(c, op, ii, lit); - } else { - assert(m_len >= 3); - } - c->r1_lit = lit; - - return op; -} - - -/*********************************************************************** -// -************************************************************************/ -static int len_of_coded_match(unsigned m_len, unsigned m_off, unsigned lit) -{ - int n = 4; - - if (m_len < 2) - return -1; - if (m_len == 2) - return (m_off <= M1_MAX_OFFSET && lit > 0 && lit < 4) ? 2 : -1; - if (m_len <= M2_MAX_LEN && m_off <= M2_MAX_OFFSET) - return 2; - if (m_len == M2_MIN_LEN && m_off <= MX_MAX_OFFSET && lit >= 4) - return 2; - if (m_off <= M3_MAX_OFFSET) { - if (m_len <= M3_MAX_LEN) - return 3; - m_len -= M3_MAX_LEN; - } else if (m_off <= M4_MAX_OFFSET) { - if (m_len <= M4_MAX_LEN) - return 3; - m_len -= M4_MAX_LEN; - } else - return -1; - while (m_len > 255) { - m_len -= 255; - n++; - } - return n; -} - - -static int min_gain(unsigned ahead, unsigned lit1, - unsigned lit2, int l1, int l2, int l3) -{ - int lazy_match_min_gain = 0; - - assert (ahead >= 1); - lazy_match_min_gain += ahead; - - if (lit1 <= 3) - lazy_match_min_gain += (lit2 <= 3) ? 0 : 2; - else if (lit1 <= 18) - lazy_match_min_gain += (lit2 <= 18) ? 0 : 1; - - lazy_match_min_gain += (l2 - l1) * 2; - if (l3 > 0) - lazy_match_min_gain -= (ahead - l3) * 2; - - if (lazy_match_min_gain < 0) - lazy_match_min_gain = 0; - - return lazy_match_min_gain; -} - - -/*********************************************************************** -// -************************************************************************/ -#if defined(SWD_BEST_OFF) - -static void better_match(const lzo_swd_p swd, - unsigned *m_len, unsigned *m_off) -{ - if (*m_len <= M2_MIN_LEN) - return; - - if (*m_off <= M2_MAX_OFFSET) - return; - - /* M3/M4 -> M2 */ - if (*m_off > M2_MAX_OFFSET - && *m_len >= M2_MIN_LEN + 1 && *m_len <= M2_MAX_LEN + 1 - && swd->best_off[*m_len-1] && swd->best_off[*m_len-1] <= M2_MAX_OFFSET - ) { - *m_len = *m_len - 1; - *m_off = swd->best_off[*m_len]; - return; - } - - /* M4 -> M2 */ - if (*m_off > M3_MAX_OFFSET - && *m_len >= M4_MAX_LEN + 1 && *m_len <= M2_MAX_LEN + 2 - && swd->best_off[*m_len-2] && swd->best_off[*m_len-2] <= M2_MAX_OFFSET - ) { - *m_len = *m_len - 2; - *m_off = swd->best_off[*m_len]; - return; - } - /* M4 -> M3 */ - if (*m_off > M3_MAX_OFFSET - && *m_len >= M4_MAX_LEN + 1 && *m_len <= M3_MAX_LEN + 1 - && swd->best_off[*m_len-1] && swd->best_off[*m_len-1] <= M3_MAX_OFFSET - ) { - *m_len = *m_len - 1; - *m_off = swd->best_off[*m_len]; - } -} - -#endif - - -/*********************************************************************** -// -************************************************************************/ -static int lzo1x_999_compress_internal(const uint8_t *in, unsigned in_len, - uint8_t *out, unsigned *out_len, - void *wrkmem, - unsigned good_length, - unsigned max_lazy, - unsigned max_chain, - uint32_t use_best_off) -{ - uint8_t *op; - const uint8_t *ii; - unsigned lit; - unsigned m_len, m_off; - lzo1x_999_t cc; - lzo1x_999_t *const c = &cc; - const lzo_swd_p swd = (lzo_swd_p) wrkmem; - int r; - - c->init = 0; - c->ip = c->in = in; - c->in_end = in + in_len; - c->out = out; - - op = out; - ii = c->ip; /* point to start of literal run */ - lit = 0; - c->r1_lit = 0; - - r = init_match(c, swd, use_best_off); - if (r != 0) - return r; - swd->max_chain = max_chain; - - r = find_match(c, swd, 0, 0); - if (r != 0) - return r; - - while (c->look > 0) { - unsigned ahead; - unsigned max_ahead; - int l1, l2, l3; - - m_len = c->m_len; - m_off = c->m_off; - - assert(c->bp == c->ip - c->look); - assert(c->bp >= in); - if (lit == 0) - ii = c->bp; - assert(ii + lit == c->bp); - assert(swd->b_char == *(c->bp)); - - if (m_len < 2 - || (m_len == 2 && (m_off > M1_MAX_OFFSET || lit == 0 || lit >= 4)) - /* Do not accept this match for compressed-data compatibility - * with LZO v1.01 and before - * [ might be a problem for decompress() and optimize() ] - */ - || (m_len == 2 && op == out) - || (op == out && lit == 0) - ) { - /* a literal */ - m_len = 0; - } - else if (m_len == M2_MIN_LEN) { - /* compression ratio improves if we code a literal in some cases */ - if (m_off > MX_MAX_OFFSET && lit >= 4) - m_len = 0; - } - - if (m_len == 0) { - /* a literal */ - lit++; - swd->max_chain = max_chain; - r = find_match(c, swd, 1, 0); - assert(r == 0); - continue; - } - - /* a match */ -#if defined(SWD_BEST_OFF) - if (swd->use_best_off) - better_match(swd, &m_len, &m_off); -#endif - - /* shall we try a lazy match ? */ - ahead = 0; - if (m_len >= max_lazy) { - /* no */ - l1 = 0; - max_ahead = 0; - } else { - /* yes, try a lazy match */ - l1 = len_of_coded_match(m_len, m_off, lit); - assert(l1 > 0); - max_ahead = LZO_MIN(2, (unsigned)l1 - 1); - } - - - while (ahead < max_ahead && c->look > m_len) { - int lazy_match_min_gain; - - if (m_len >= good_length) - swd->max_chain = max_chain >> 2; - else - swd->max_chain = max_chain; - r = find_match(c, swd, 1, 0); - ahead++; - - assert(r == 0); - assert(c->look > 0); - assert(ii + lit + ahead == c->bp); - - if (c->m_len < m_len) - continue; - if (c->m_len == m_len && c->m_off >= m_off) - continue; -#if defined(SWD_BEST_OFF) - if (swd->use_best_off) - better_match(swd, &c->m_len, &c->m_off); -#endif - l2 = len_of_coded_match(c->m_len, c->m_off, lit+ahead); - if (l2 < 0) - continue; - - /* compressed-data compatibility [see above] */ - l3 = (op == out) ? -1 : len_of_coded_match(ahead, m_off, lit); - - lazy_match_min_gain = min_gain(ahead, lit, lit+ahead, l1, l2, l3); - if (c->m_len >= m_len + lazy_match_min_gain) { - if (l3 > 0) { - /* code previous run */ - op = code_run(c, op, ii, lit); - lit = 0; - /* code shortened match */ - op = code_match(c, op, ahead, m_off); - } else { - lit += ahead; - assert(ii + lit == c->bp); - } - goto lazy_match_done; - } - } - - assert(ii + lit + ahead == c->bp); - - /* 1 - code run */ - op = code_run(c, op, ii, lit); - lit = 0; - - /* 2 - code match */ - op = code_match(c, op, m_len, m_off); - swd->max_chain = max_chain; - r = find_match(c, swd, m_len, 1+ahead); - assert(r == 0); - - lazy_match_done: ; - } - - /* store final run */ - if (lit > 0) - op = STORE_RUN(c, op, ii, lit); - -#if defined(LZO_EOF_CODE) - *op++ = M4_MARKER | 1; - *op++ = 0; - *op++ = 0; -#endif - - *out_len = op - out; - - return LZO_E_OK; -} - - -/*********************************************************************** -// -************************************************************************/ -int lzo1x_999_compress_level(const uint8_t *in, unsigned in_len, - uint8_t *out, unsigned *out_len, - void *wrkmem, - int compression_level) -{ - static const struct { - uint16_t good_length; - uint16_t max_lazy; - uint16_t max_chain; - uint16_t use_best_off; - } c[3] = { - { 8, 32, 256, 0 }, - { 32, 128, 2048, 1 }, - { SWD_F, SWD_F, 4096, 1 } /* max. compression */ - }; - - if (compression_level < 7 || compression_level > 9) - return LZO_E_ERROR; - - compression_level -= 7; - return lzo1x_999_compress_internal(in, in_len, out, out_len, wrkmem, - c[compression_level].good_length, - c[compression_level].max_lazy, - c[compression_level].max_chain, - c[compression_level].use_best_off); -} diff --git a/archival/lzo1x_c.c b/archival/lzo1x_c.c deleted file mode 100644 index cc86f74b1..000000000 --- a/archival/lzo1x_c.c +++ /dev/null @@ -1,296 +0,0 @@ -/* implementation of the LZO1[XY]-1 compression algorithm - - This file is part of the LZO real-time data compression library. - - Copyright (C) 1996..2008 Markus Franz Xaver Johannes Oberhumer - All Rights Reserved. - - Markus F.X.J. Oberhumer - http://www.oberhumer.com/opensource/lzo/ - - The LZO library is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License as - published by the Free Software Foundation; either version 2 of - the License, or (at your option) any later version. - - The LZO library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with the LZO library; see the file COPYING. - If not, write to the Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -/*********************************************************************** -// compress a block of data. -************************************************************************/ -static NOINLINE unsigned -do_compress(const uint8_t* in, unsigned in_len, - uint8_t* out, unsigned* out_len, - void* wrkmem) -{ - register const uint8_t* ip; - uint8_t* op; - const uint8_t* const in_end = in + in_len; - const uint8_t* const ip_end = in + in_len - M2_MAX_LEN - 5; - const uint8_t* ii; - const void* *const dict = (const void**) wrkmem; - - op = out; - ip = in; - ii = ip; - - ip += 4; - for (;;) { - register const uint8_t* m_pos; - unsigned m_off; - unsigned m_len; - unsigned dindex; - - D_INDEX1(dindex,ip); - GINDEX(m_pos,m_off,dict,dindex,in); - if (LZO_CHECK_MPOS_NON_DET(m_pos,m_off,in,ip,M4_MAX_OFFSET)) - goto literal; -#if 1 - if (m_off <= M2_MAX_OFFSET || m_pos[3] == ip[3]) - goto try_match; - D_INDEX2(dindex,ip); -#endif - GINDEX(m_pos,m_off,dict,dindex,in); - if (LZO_CHECK_MPOS_NON_DET(m_pos,m_off,in,ip,M4_MAX_OFFSET)) - goto literal; - if (m_off <= M2_MAX_OFFSET || m_pos[3] == ip[3]) - goto try_match; - goto literal; - - try_match: -#if 1 && defined(LZO_UNALIGNED_OK_2) - if (* (const lzo_ushortp) m_pos != * (const lzo_ushortp) ip) -#else - if (m_pos[0] != ip[0] || m_pos[1] != ip[1]) -#endif - { - } else { - if (m_pos[2] == ip[2]) { -#if 0 - if (m_off <= M2_MAX_OFFSET) - goto match; - if (lit <= 3) - goto match; - if (lit == 3) { /* better compression, but slower */ - assert(op - 2 > out); op[-2] |= (uint8_t)(3); - *op++ = *ii++; *op++ = *ii++; *op++ = *ii++; - goto code_match; - } - if (m_pos[3] == ip[3]) -#endif - goto match; - } - else { - /* still need a better way for finding M1 matches */ -#if 0 - /* a M1 match */ -#if 0 - if (m_off <= M1_MAX_OFFSET && lit > 0 && lit <= 3) -#else - if (m_off <= M1_MAX_OFFSET && lit == 3) -#endif - { - register unsigned t; - - t = lit; - assert(op - 2 > out); op[-2] |= (uint8_t)(t); - do *op++ = *ii++; while (--t > 0); - assert(ii == ip); - m_off -= 1; - *op++ = (uint8_t)(M1_MARKER | ((m_off & 3) << 2)); - *op++ = (uint8_t)(m_off >> 2); - ip += 2; - goto match_done; - } -#endif - } - } - - /* a literal */ - literal: - UPDATE_I(dict, 0, dindex, ip, in); - ++ip; - if (ip >= ip_end) - break; - continue; - - /* a match */ -match: - UPDATE_I(dict, 0, dindex, ip, in); - /* store current literal run */ - if (pd(ip, ii) > 0) { - register unsigned t = pd(ip, ii); - - if (t <= 3) { - assert(op - 2 > out); - op[-2] |= (uint8_t)(t); - } - else if (t <= 18) - *op++ = (uint8_t)(t - 3); - else { - register unsigned tt = t - 18; - - *op++ = 0; - while (tt > 255) { - tt -= 255; - *op++ = 0; - } - assert(tt > 0); - *op++ = (uint8_t)(tt); - } - do *op++ = *ii++; while (--t > 0); - } - - /* code the match */ - assert(ii == ip); - ip += 3; - if (m_pos[3] != *ip++ || m_pos[4] != *ip++ || m_pos[5] != *ip++ - || m_pos[6] != *ip++ || m_pos[7] != *ip++ || m_pos[8] != *ip++ -#ifdef LZO1Y - || m_pos[ 9] != *ip++ || m_pos[10] != *ip++ || m_pos[11] != *ip++ - || m_pos[12] != *ip++ || m_pos[13] != *ip++ || m_pos[14] != *ip++ -#endif - ) { - --ip; - m_len = pd(ip, ii); - assert(m_len >= 3); - assert(m_len <= M2_MAX_LEN); - - if (m_off <= M2_MAX_OFFSET) { - m_off -= 1; -#if defined(LZO1X) - *op++ = (uint8_t)(((m_len - 1) << 5) | ((m_off & 7) << 2)); - *op++ = (uint8_t)(m_off >> 3); -#elif defined(LZO1Y) - *op++ = (uint8_t)(((m_len + 1) << 4) | ((m_off & 3) << 2)); - *op++ = (uint8_t)(m_off >> 2); -#endif - } - else if (m_off <= M3_MAX_OFFSET) { - m_off -= 1; - *op++ = (uint8_t)(M3_MARKER | (m_len - 2)); - goto m3_m4_offset; - } else { -#if defined(LZO1X) - m_off -= 0x4000; - assert(m_off > 0); - assert(m_off <= 0x7fff); - *op++ = (uint8_t)(M4_MARKER | ((m_off & 0x4000) >> 11) | (m_len - 2)); - goto m3_m4_offset; -#elif defined(LZO1Y) - goto m4_match; -#endif - } - } - else { - { - const uint8_t* end = in_end; - const uint8_t* m = m_pos + M2_MAX_LEN + 1; - while (ip < end && *m == *ip) - m++, ip++; - m_len = pd(ip, ii); - } - assert(m_len > M2_MAX_LEN); - - if (m_off <= M3_MAX_OFFSET) { - m_off -= 1; - if (m_len <= 33) - *op++ = (uint8_t)(M3_MARKER | (m_len - 2)); - else { - m_len -= 33; - *op++ = M3_MARKER | 0; - goto m3_m4_len; - } - } else { -#if defined(LZO1Y) - m4_match: -#endif - m_off -= 0x4000; - assert(m_off > 0); - assert(m_off <= 0x7fff); - if (m_len <= M4_MAX_LEN) - *op++ = (uint8_t)(M4_MARKER | ((m_off & 0x4000) >> 11) | (m_len - 2)); - else { - m_len -= M4_MAX_LEN; - *op++ = (uint8_t)(M4_MARKER | ((m_off & 0x4000) >> 11)); - m3_m4_len: - while (m_len > 255) { - m_len -= 255; - *op++ = 0; - } - assert(m_len > 0); - *op++ = (uint8_t)(m_len); - } - } - m3_m4_offset: - *op++ = (uint8_t)((m_off & 63) << 2); - *op++ = (uint8_t)(m_off >> 6); - } -#if 0 - match_done: -#endif - ii = ip; - if (ip >= ip_end) - break; - } - - *out_len = pd(op, out); - return pd(in_end, ii); -} - -/*********************************************************************** -// public entry point -************************************************************************/ -int DO_COMPRESS(const uint8_t* in, unsigned in_len, - uint8_t* out, unsigned* out_len, - void* wrkmem) -{ - uint8_t* op = out; - unsigned t; - - if (in_len <= M2_MAX_LEN + 5) - t = in_len; - else { - t = do_compress(in,in_len,op,out_len,wrkmem); - op += *out_len; - } - - if (t > 0) { - const uint8_t* ii = in + in_len - t; - - if (op == out && t <= 238) - *op++ = (uint8_t)(17 + t); - else if (t <= 3) - op[-2] |= (uint8_t)(t); - else if (t <= 18) - *op++ = (uint8_t)(t - 3); - else { - unsigned tt = t - 18; - - *op++ = 0; - while (tt > 255) { - tt -= 255; - *op++ = 0; - } - assert(tt > 0); - *op++ = (uint8_t)(tt); - } - do *op++ = *ii++; while (--t > 0); - } - - *op++ = M4_MARKER | 1; - *op++ = 0; - *op++ = 0; - - *out_len = pd(op, out); - return 0; /*LZO_E_OK*/ -} diff --git a/archival/lzo1x_d.c b/archival/lzo1x_d.c deleted file mode 100644 index 348a85510..000000000 --- a/archival/lzo1x_d.c +++ /dev/null @@ -1,420 +0,0 @@ -/* implementation of the LZO1X decompression algorithm - - This file is part of the LZO real-time data compression library. - - Copyright (C) 1996..2008 Markus Franz Xaver Johannes Oberhumer - All Rights Reserved. - - Markus F.X.J. Oberhumer - http://www.oberhumer.com/opensource/lzo/ - - The LZO library is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License as - published by the Free Software Foundation; either version 2 of - the License, or (at your option) any later version. - - The LZO library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with the LZO library; see the file COPYING. - If not, write to the Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -#include "libbb.h" -#include "liblzo.h" - -/*********************************************************************** -// decompress a block of data. -************************************************************************/ -/* safe decompression with overrun testing */ -int lzo1x_decompress_safe(const uint8_t* in, unsigned in_len, - uint8_t* out, unsigned* out_len, - void* wrkmem UNUSED_PARAM) -{ - register uint8_t* op; - register const uint8_t* ip; - register unsigned t; -#if defined(COPY_DICT) - unsigned m_off; - const uint8_t* dict_end; -#else - register const uint8_t* m_pos = NULL; /* possibly not needed */ -#endif - const uint8_t* const ip_end = in + in_len; -#if defined(HAVE_ANY_OP) - uint8_t* const op_end = out + *out_len; -#endif -#if defined(LZO1Z) - unsigned last_m_off = 0; -#endif - -// LZO_UNUSED(wrkmem); - -#if defined(COPY_DICT) - if (dict) { - if (dict_len > M4_MAX_OFFSET) { - dict += dict_len - M4_MAX_OFFSET; - dict_len = M4_MAX_OFFSET; - } - dict_end = dict + dict_len; - } else { - dict_len = 0; - dict_end = NULL; - } -#endif /* COPY_DICT */ - - *out_len = 0; - - op = out; - ip = in; - - if (*ip > 17) { - t = *ip++ - 17; - if (t < 4) - goto match_next; - assert(t > 0); NEED_OP(t); NEED_IP(t+1); - do *op++ = *ip++; while (--t > 0); - goto first_literal_run; - } - - while (TEST_IP && TEST_OP) { - t = *ip++; - if (t >= 16) - goto match; - /* a literal run */ - if (t == 0) { - NEED_IP(1); - while (*ip == 0) { - t += 255; - ip++; - NEED_IP(1); - } - t += 15 + *ip++; - } - /* copy literals */ - assert(t > 0); - NEED_OP(t+3); - NEED_IP(t+4); -#if defined(LZO_UNALIGNED_OK_4) || defined(LZO_ALIGNED_OK_4) -# if !defined(LZO_UNALIGNED_OK_4) - if (PTR_ALIGNED2_4(op, ip)) -# endif - { - COPY4(op, ip); - op += 4; - ip += 4; - if (--t > 0) { - if (t >= 4) { - do { - COPY4(op, ip); - op += 4; - ip += 4; - t -= 4; - } while (t >= 4); - if (t > 0) - do *op++ = *ip++; while (--t > 0); - } else { - do *op++ = *ip++; while (--t > 0); - } - } - } -# if !defined(LZO_UNALIGNED_OK_4) - else -# endif -#endif -#if !defined(LZO_UNALIGNED_OK_4) - { - *op++ = *ip++; - *op++ = *ip++; - *op++ = *ip++; - do *op++ = *ip++; while (--t > 0); - } -#endif - - first_literal_run: - t = *ip++; - if (t >= 16) - goto match; -#if defined(COPY_DICT) -#if defined(LZO1Z) - m_off = (1 + M2_MAX_OFFSET) + (t << 6) + (*ip++ >> 2); - last_m_off = m_off; -#else - m_off = (1 + M2_MAX_OFFSET) + (t >> 2) + (*ip++ << 2); -#endif - NEED_OP(3); - t = 3; COPY_DICT(t,m_off) -#else /* !COPY_DICT */ -#if defined(LZO1Z) - t = (1 + M2_MAX_OFFSET) + (t << 6) + (*ip++ >> 2); - m_pos = op - t; - last_m_off = t; -#else - m_pos = op - (1 + M2_MAX_OFFSET); - m_pos -= t >> 2; - m_pos -= *ip++ << 2; -#endif - TEST_LB(m_pos); NEED_OP(3); - *op++ = *m_pos++; - *op++ = *m_pos++; - *op++ = *m_pos; -#endif /* COPY_DICT */ - goto match_done; - - /* handle matches */ - do { - match: - if (t >= 64) { /* a M2 match */ -#if defined(COPY_DICT) -#if defined(LZO1X) - m_off = 1 + ((t >> 2) & 7) + (*ip++ << 3); - t = (t >> 5) - 1; -#elif defined(LZO1Y) - m_off = 1 + ((t >> 2) & 3) + (*ip++ << 2); - t = (t >> 4) - 3; -#elif defined(LZO1Z) - m_off = t & 0x1f; - if (m_off >= 0x1c) - m_off = last_m_off; - else { - m_off = 1 + (m_off << 6) + (*ip++ >> 2); - last_m_off = m_off; - } - t = (t >> 5) - 1; -#endif -#else /* !COPY_DICT */ -#if defined(LZO1X) - m_pos = op - 1; - m_pos -= (t >> 2) & 7; - m_pos -= *ip++ << 3; - t = (t >> 5) - 1; -#elif defined(LZO1Y) - m_pos = op - 1; - m_pos -= (t >> 2) & 3; - m_pos -= *ip++ << 2; - t = (t >> 4) - 3; -#elif defined(LZO1Z) - { - unsigned off = t & 0x1f; - m_pos = op; - if (off >= 0x1c) { - assert(last_m_off > 0); - m_pos -= last_m_off; - } else { - off = 1 + (off << 6) + (*ip++ >> 2); - m_pos -= off; - last_m_off = off; - } - } - t = (t >> 5) - 1; -#endif - TEST_LB(m_pos); assert(t > 0); NEED_OP(t+3-1); - goto copy_match; -#endif /* COPY_DICT */ - } - else if (t >= 32) { /* a M3 match */ - t &= 31; - if (t == 0) { - NEED_IP(1); - while (*ip == 0) { - t += 255; - ip++; - NEED_IP(1); - } - t += 31 + *ip++; - } -#if defined(COPY_DICT) -#if defined(LZO1Z) - m_off = 1 + (ip[0] << 6) + (ip[1] >> 2); - last_m_off = m_off; -#else - m_off = 1 + (ip[0] >> 2) + (ip[1] << 6); -#endif -#else /* !COPY_DICT */ -#if defined(LZO1Z) - { - unsigned off = 1 + (ip[0] << 6) + (ip[1] >> 2); - m_pos = op - off; - last_m_off = off; - } -#elif defined(LZO_UNALIGNED_OK_2) && defined(LZO_ABI_LITTLE_ENDIAN) - m_pos = op - 1; - m_pos -= (* (const lzo_ushortp) ip) >> 2; -#else - m_pos = op - 1; - m_pos -= (ip[0] >> 2) + (ip[1] << 6); -#endif -#endif /* COPY_DICT */ - ip += 2; - } - else if (t >= 16) { /* a M4 match */ -#if defined(COPY_DICT) - m_off = (t & 8) << 11; -#else /* !COPY_DICT */ - m_pos = op; - m_pos -= (t & 8) << 11; -#endif /* COPY_DICT */ - t &= 7; - if (t == 0) { - NEED_IP(1); - while (*ip == 0) { - t += 255; - ip++; - NEED_IP(1); - } - t += 7 + *ip++; - } -#if defined(COPY_DICT) -#if defined(LZO1Z) - m_off += (ip[0] << 6) + (ip[1] >> 2); -#else - m_off += (ip[0] >> 2) + (ip[1] << 6); -#endif - ip += 2; - if (m_off == 0) - goto eof_found; - m_off += 0x4000; -#if defined(LZO1Z) - last_m_off = m_off; -#endif -#else /* !COPY_DICT */ -#if defined(LZO1Z) - m_pos -= (ip[0] << 6) + (ip[1] >> 2); -#elif defined(LZO_UNALIGNED_OK_2) && defined(LZO_ABI_LITTLE_ENDIAN) - m_pos -= (* (const lzo_ushortp) ip) >> 2; -#else - m_pos -= (ip[0] >> 2) + (ip[1] << 6); -#endif - ip += 2; - if (m_pos == op) - goto eof_found; - m_pos -= 0x4000; -#if defined(LZO1Z) - last_m_off = pd((const uint8_t*)op, m_pos); -#endif -#endif /* COPY_DICT */ - } - else { /* a M1 match */ -#if defined(COPY_DICT) -#if defined(LZO1Z) - m_off = 1 + (t << 6) + (*ip++ >> 2); - last_m_off = m_off; -#else - m_off = 1 + (t >> 2) + (*ip++ << 2); -#endif - NEED_OP(2); - t = 2; COPY_DICT(t,m_off) -#else /* !COPY_DICT */ -#if defined(LZO1Z) - t = 1 + (t << 6) + (*ip++ >> 2); - m_pos = op - t; - last_m_off = t; -#else - m_pos = op - 1; - m_pos -= t >> 2; - m_pos -= *ip++ << 2; -#endif - TEST_LB(m_pos); NEED_OP(2); - *op++ = *m_pos++; - *op++ = *m_pos; -#endif /* COPY_DICT */ - goto match_done; - } - - /* copy match */ -#if defined(COPY_DICT) - - NEED_OP(t+3-1); - t += 3-1; COPY_DICT(t,m_off) - -#else /* !COPY_DICT */ - - TEST_LB(m_pos); assert(t > 0); NEED_OP(t+3-1); -#if defined(LZO_UNALIGNED_OK_4) || defined(LZO_ALIGNED_OK_4) -# if !defined(LZO_UNALIGNED_OK_4) - if (t >= 2 * 4 - (3 - 1) && PTR_ALIGNED2_4(op,m_pos)) { - assert((op - m_pos) >= 4); /* both pointers are aligned */ -# else - if (t >= 2 * 4 - (3 - 1) && (op - m_pos) >= 4) { -# endif - COPY4(op,m_pos); - op += 4; m_pos += 4; t -= 4 - (3 - 1); - do { - COPY4(op,m_pos); - op += 4; m_pos += 4; t -= 4; - } while (t >= 4); - if (t > 0) - do *op++ = *m_pos++; while (--t > 0); - } - else -#endif - { - copy_match: - *op++ = *m_pos++; *op++ = *m_pos++; - do *op++ = *m_pos++; while (--t > 0); - } - -#endif /* COPY_DICT */ - - match_done: -#if defined(LZO1Z) - t = ip[-1] & 3; -#else - t = ip[-2] & 3; -#endif - if (t == 0) - break; - - /* copy literals */ - match_next: - assert(t > 0); - assert(t < 4); - NEED_OP(t); - NEED_IP(t+1); -#if 0 - do *op++ = *ip++; while (--t > 0); -#else - *op++ = *ip++; - if (t > 1) { - *op++ = *ip++; - if (t > 2) - *op++ = *ip++; - } -#endif - t = *ip++; - } while (TEST_IP && TEST_OP); - } - -//#if defined(HAVE_TEST_IP) || defined(HAVE_TEST_OP) - /* no EOF code was found */ - *out_len = pd(op, out); - return LZO_E_EOF_NOT_FOUND; -//#endif - - eof_found: - assert(t == 1); - *out_len = pd(op, out); - return (ip == ip_end ? LZO_E_OK : - (ip < ip_end ? LZO_E_INPUT_NOT_CONSUMED : LZO_E_INPUT_OVERRUN)); - -//#if defined(HAVE_NEED_IP) - input_overrun: - *out_len = pd(op, out); - return LZO_E_INPUT_OVERRUN; -//#endif - -//#if defined(HAVE_NEED_OP) - output_overrun: - *out_len = pd(op, out); - return LZO_E_OUTPUT_OVERRUN; -//#endif - -//#if defined(LZO_TEST_OVERRUN_LOOKBEHIND) - lookbehind_overrun: - *out_len = pd(op, out); - return LZO_E_LOOKBEHIND_OVERRUN; -//#endif -} diff --git a/include/liblzo_interface.h b/include/liblzo_interface.h new file mode 100644 index 000000000..9a84c0b6b --- /dev/null +++ b/include/liblzo_interface.h @@ -0,0 +1,71 @@ +/* + This file is part of the LZO real-time data compression library. + + Copyright (C) 1996..2008 Markus Franz Xaver Johannes Oberhumer + All Rights Reserved. + + Markus F.X.J. Oberhumer + http://www.oberhumer.com/opensource/lzo/ + + The LZO library is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of + the License, or (at your option) any later version. + + The LZO library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with the LZO library; see the file COPYING. + If not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#define LZO1X +#undef LZO1Y + +#undef assert +/* +static void die_at(int line) +{ + bb_error_msg_and_die("internal error at %d", line); +} +#define assert(v) if (!(v)) die_at(__LINE__) +*/ +#define assert(v) ((void)0) + +int lzo1x_1_compress(const uint8_t* src, unsigned src_len, + uint8_t* dst, unsigned* dst_len, + void* wrkmem); +int lzo1x_1_15_compress(const uint8_t* src, unsigned src_len, + uint8_t* dst, unsigned* dst_len, + void* wrkmem); +int lzo1x_999_compress_level(const uint8_t* in, unsigned in_len, + uint8_t* out, unsigned* out_len, + void* wrkmem, + int compression_level); + +/* decompression */ +//int lzo1x_decompress(const uint8_t* src, unsigned src_len, +// uint8_t* dst, unsigned* dst_len, +// void* wrkmem /* NOT USED */); +/* safe decompression with overrun testing */ +int lzo1x_decompress_safe(const uint8_t* src, unsigned src_len, + uint8_t* dst, unsigned* dst_len, + void* wrkmem /* NOT USED */); + +#define LZO_E_OK 0 +#define LZO_E_ERROR (-1) +#define LZO_E_OUT_OF_MEMORY (-2) /* [not used right now] */ +#define LZO_E_NOT_COMPRESSIBLE (-3) /* [not used right now] */ +#define LZO_E_INPUT_OVERRUN (-4) +#define LZO_E_OUTPUT_OVERRUN (-5) +#define LZO_E_LOOKBEHIND_OVERRUN (-6) +#define LZO_E_EOF_NOT_FOUND (-7) +#define LZO_E_INPUT_NOT_CONSUMED (-8) +#define LZO_E_NOT_YET_IMPLEMENTED (-9) /* [not used right now] */ + +/* lzo-2.03/include/lzo/lzoconf.h */ +#define LZO_VERSION 0x2030 -- cgit v1.2.3-55-g6feb From 833d4e7f84f59099ee66eabfa3457ebb7d37eaa8 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Wed, 3 Nov 2010 02:38:31 +0100 Subject: rename archival/libunarchive -> archival/libarchive; move bz/ into it Signed-off-by: Denys Vlasenko --- Makefile | 2 +- archival/Kbuild.src | 2 +- archival/ar.c | 2 +- archival/bbunzip.c | 2 +- archival/bz/LICENSE | 44 - archival/bz/README | 90 -- archival/bz/blocksort.c | 1072 ----------------- archival/bz/bzlib.c | 431 ------- archival/bz/bzlib.h | 65 - archival/bz/bzlib_private.h | 219 ---- archival/bz/compress.c | 685 ----------- archival/bz/huffman.c | 229 ---- archival/bzip2.c | 14 +- archival/cpio.c | 2 +- archival/dpkg.c | 2 +- archival/dpkg_deb.c | 2 +- archival/gzip.c | 2 +- archival/libarchive/Kbuild.src | 64 + archival/libarchive/bz/LICENSE | 44 + archival/libarchive/bz/README | 90 ++ archival/libarchive/bz/blocksort.c | 1072 +++++++++++++++++ archival/libarchive/bz/bzlib.c | 431 +++++++ archival/libarchive/bz/bzlib.h | 65 + archival/libarchive/bz/bzlib_private.h | 219 ++++ archival/libarchive/bz/compress.c | 685 +++++++++++ archival/libarchive/bz/huffman.c | 229 ++++ archival/libarchive/data_align.c | 15 + archival/libarchive/data_extract_all.c | 200 ++++ archival/libarchive/data_extract_to_command.c | 134 +++ archival/libarchive/data_extract_to_stdout.c | 14 + archival/libarchive/data_skip.c | 12 + archival/libarchive/decompress_bunzip2.c | 822 +++++++++++++ archival/libarchive/decompress_uncompress.c | 307 +++++ archival/libarchive/decompress_unlzma.c | 465 ++++++++ archival/libarchive/decompress_unxz.c | 98 ++ archival/libarchive/decompress_unzip.c | 1252 ++++++++++++++++++++ archival/libarchive/filter_accept_all.c | 17 + archival/libarchive/filter_accept_list.c | 19 + archival/libarchive/filter_accept_list_reassign.c | 51 + archival/libarchive/filter_accept_reject_list.c | 36 + archival/libarchive/find_list_entry.c | 54 + archival/libarchive/get_header_ar.c | 133 +++ archival/libarchive/get_header_cpio.c | 186 +++ archival/libarchive/get_header_tar.c | 461 +++++++ archival/libarchive/get_header_tar_bz2.c | 21 + archival/libarchive/get_header_tar_gz.c | 36 + archival/libarchive/get_header_tar_lzma.c | 24 + archival/libarchive/header_list.c | 12 + archival/libarchive/header_skip.c | 10 + archival/libarchive/header_verbose_list.c | 69 ++ archival/libarchive/init_handle.c | 22 + archival/libarchive/liblzo.h | 93 ++ archival/libarchive/lzo1x_1.c | 35 + archival/libarchive/lzo1x_1o.c | 35 + archival/libarchive/lzo1x_9x.c | 921 ++++++++++++++ archival/libarchive/lzo1x_c.c | 296 +++++ archival/libarchive/lzo1x_d.c | 420 +++++++ archival/libarchive/open_transformer.c | 54 + archival/libarchive/seek_by_jump.c | 19 + archival/libarchive/seek_by_read.c | 16 + archival/libarchive/unpack_ar_archive.c | 22 + archival/libarchive/unxz/README | 135 +++ archival/libarchive/unxz/xz.h | 271 +++++ archival/libarchive/unxz/xz_config.h | 123 ++ archival/libarchive/unxz/xz_dec_bcj.c | 564 +++++++++ archival/libarchive/unxz/xz_dec_lzma2.c | 1175 ++++++++++++++++++ archival/libarchive/unxz/xz_dec_stream.c | 822 +++++++++++++ archival/libarchive/unxz/xz_lzma2.h | 204 ++++ archival/libarchive/unxz/xz_private.h | 159 +++ archival/libarchive/unxz/xz_stream.h | 57 + archival/libunarchive/Kbuild.src | 64 - archival/libunarchive/data_align.c | 15 - archival/libunarchive/data_extract_all.c | 200 ---- archival/libunarchive/data_extract_to_command.c | 134 --- archival/libunarchive/data_extract_to_stdout.c | 14 - archival/libunarchive/data_skip.c | 12 - archival/libunarchive/decompress_bunzip2.c | 822 ------------- archival/libunarchive/decompress_uncompress.c | 307 ----- archival/libunarchive/decompress_unlzma.c | 465 -------- archival/libunarchive/decompress_unxz.c | 98 -- archival/libunarchive/decompress_unzip.c | 1252 -------------------- archival/libunarchive/filter_accept_all.c | 17 - archival/libunarchive/filter_accept_list.c | 19 - .../libunarchive/filter_accept_list_reassign.c | 51 - archival/libunarchive/filter_accept_reject_list.c | 36 - archival/libunarchive/find_list_entry.c | 54 - archival/libunarchive/get_header_ar.c | 133 --- archival/libunarchive/get_header_cpio.c | 186 --- archival/libunarchive/get_header_tar.c | 461 ------- archival/libunarchive/get_header_tar_bz2.c | 21 - archival/libunarchive/get_header_tar_gz.c | 36 - archival/libunarchive/get_header_tar_lzma.c | 24 - archival/libunarchive/header_list.c | 12 - archival/libunarchive/header_skip.c | 10 - archival/libunarchive/header_verbose_list.c | 69 -- archival/libunarchive/init_handle.c | 22 - archival/libunarchive/liblzo.h | 93 -- archival/libunarchive/lzo1x_1.c | 35 - archival/libunarchive/lzo1x_1o.c | 35 - archival/libunarchive/lzo1x_9x.c | 921 -------------- archival/libunarchive/lzo1x_c.c | 296 ----- archival/libunarchive/lzo1x_d.c | 420 ------- archival/libunarchive/open_transformer.c | 54 - archival/libunarchive/seek_by_jump.c | 19 - archival/libunarchive/seek_by_read.c | 16 - archival/libunarchive/unpack_ar_archive.c | 22 - archival/libunarchive/unxz/README | 135 --- archival/libunarchive/unxz/xz.h | 271 ----- archival/libunarchive/unxz/xz_config.h | 123 -- archival/libunarchive/unxz/xz_dec_bcj.c | 564 --------- archival/libunarchive/unxz/xz_dec_lzma2.c | 1175 ------------------ archival/libunarchive/unxz/xz_dec_stream.c | 822 ------------- archival/libunarchive/unxz/xz_lzma2.h | 204 ---- archival/libunarchive/unxz/xz_private.h | 159 --- archival/libunarchive/unxz/xz_stream.h | 57 - archival/lzop.c | 2 +- archival/rpm.c | 2 +- archival/rpm2cpio.c | 2 +- archival/tar.c | 2 +- archival/unzip.c | 2 +- docs/keep_data_small.txt | 2 +- include/archive.h | 238 ++++ include/unarchive.h | 238 ---- libbb/appletlib.c | 2 +- libbb/read_printf.c | 2 +- miscutils/bbconfig.c | 2 +- procps/smemcap.c | 2 +- scripts/Makefile.IMA | 4 +- 128 files changed, 13055 insertions(+), 13055 deletions(-) delete mode 100644 archival/bz/LICENSE delete mode 100644 archival/bz/README delete mode 100644 archival/bz/blocksort.c delete mode 100644 archival/bz/bzlib.c delete mode 100644 archival/bz/bzlib.h delete mode 100644 archival/bz/bzlib_private.h delete mode 100644 archival/bz/compress.c delete mode 100644 archival/bz/huffman.c create mode 100644 archival/libarchive/Kbuild.src create mode 100644 archival/libarchive/bz/LICENSE create mode 100644 archival/libarchive/bz/README create mode 100644 archival/libarchive/bz/blocksort.c create mode 100644 archival/libarchive/bz/bzlib.c create mode 100644 archival/libarchive/bz/bzlib.h create mode 100644 archival/libarchive/bz/bzlib_private.h create mode 100644 archival/libarchive/bz/compress.c create mode 100644 archival/libarchive/bz/huffman.c create mode 100644 archival/libarchive/data_align.c create mode 100644 archival/libarchive/data_extract_all.c create mode 100644 archival/libarchive/data_extract_to_command.c create mode 100644 archival/libarchive/data_extract_to_stdout.c create mode 100644 archival/libarchive/data_skip.c create mode 100644 archival/libarchive/decompress_bunzip2.c create mode 100644 archival/libarchive/decompress_uncompress.c create mode 100644 archival/libarchive/decompress_unlzma.c create mode 100644 archival/libarchive/decompress_unxz.c create mode 100644 archival/libarchive/decompress_unzip.c create mode 100644 archival/libarchive/filter_accept_all.c create mode 100644 archival/libarchive/filter_accept_list.c create mode 100644 archival/libarchive/filter_accept_list_reassign.c create mode 100644 archival/libarchive/filter_accept_reject_list.c create mode 100644 archival/libarchive/find_list_entry.c create mode 100644 archival/libarchive/get_header_ar.c create mode 100644 archival/libarchive/get_header_cpio.c create mode 100644 archival/libarchive/get_header_tar.c create mode 100644 archival/libarchive/get_header_tar_bz2.c create mode 100644 archival/libarchive/get_header_tar_gz.c create mode 100644 archival/libarchive/get_header_tar_lzma.c create mode 100644 archival/libarchive/header_list.c create mode 100644 archival/libarchive/header_skip.c create mode 100644 archival/libarchive/header_verbose_list.c create mode 100644 archival/libarchive/init_handle.c create mode 100644 archival/libarchive/liblzo.h create mode 100644 archival/libarchive/lzo1x_1.c create mode 100644 archival/libarchive/lzo1x_1o.c create mode 100644 archival/libarchive/lzo1x_9x.c create mode 100644 archival/libarchive/lzo1x_c.c create mode 100644 archival/libarchive/lzo1x_d.c create mode 100644 archival/libarchive/open_transformer.c create mode 100644 archival/libarchive/seek_by_jump.c create mode 100644 archival/libarchive/seek_by_read.c create mode 100644 archival/libarchive/unpack_ar_archive.c create mode 100644 archival/libarchive/unxz/README create mode 100644 archival/libarchive/unxz/xz.h create mode 100644 archival/libarchive/unxz/xz_config.h create mode 100644 archival/libarchive/unxz/xz_dec_bcj.c create mode 100644 archival/libarchive/unxz/xz_dec_lzma2.c create mode 100644 archival/libarchive/unxz/xz_dec_stream.c create mode 100644 archival/libarchive/unxz/xz_lzma2.h create mode 100644 archival/libarchive/unxz/xz_private.h create mode 100644 archival/libarchive/unxz/xz_stream.h delete mode 100644 archival/libunarchive/Kbuild.src delete mode 100644 archival/libunarchive/data_align.c delete mode 100644 archival/libunarchive/data_extract_all.c delete mode 100644 archival/libunarchive/data_extract_to_command.c delete mode 100644 archival/libunarchive/data_extract_to_stdout.c delete mode 100644 archival/libunarchive/data_skip.c delete mode 100644 archival/libunarchive/decompress_bunzip2.c delete mode 100644 archival/libunarchive/decompress_uncompress.c delete mode 100644 archival/libunarchive/decompress_unlzma.c delete mode 100644 archival/libunarchive/decompress_unxz.c delete mode 100644 archival/libunarchive/decompress_unzip.c delete mode 100644 archival/libunarchive/filter_accept_all.c delete mode 100644 archival/libunarchive/filter_accept_list.c delete mode 100644 archival/libunarchive/filter_accept_list_reassign.c delete mode 100644 archival/libunarchive/filter_accept_reject_list.c delete mode 100644 archival/libunarchive/find_list_entry.c delete mode 100644 archival/libunarchive/get_header_ar.c delete mode 100644 archival/libunarchive/get_header_cpio.c delete mode 100644 archival/libunarchive/get_header_tar.c delete mode 100644 archival/libunarchive/get_header_tar_bz2.c delete mode 100644 archival/libunarchive/get_header_tar_gz.c delete mode 100644 archival/libunarchive/get_header_tar_lzma.c delete mode 100644 archival/libunarchive/header_list.c delete mode 100644 archival/libunarchive/header_skip.c delete mode 100644 archival/libunarchive/header_verbose_list.c delete mode 100644 archival/libunarchive/init_handle.c delete mode 100644 archival/libunarchive/liblzo.h delete mode 100644 archival/libunarchive/lzo1x_1.c delete mode 100644 archival/libunarchive/lzo1x_1o.c delete mode 100644 archival/libunarchive/lzo1x_9x.c delete mode 100644 archival/libunarchive/lzo1x_c.c delete mode 100644 archival/libunarchive/lzo1x_d.c delete mode 100644 archival/libunarchive/open_transformer.c delete mode 100644 archival/libunarchive/seek_by_jump.c delete mode 100644 archival/libunarchive/seek_by_read.c delete mode 100644 archival/libunarchive/unpack_ar_archive.c delete mode 100644 archival/libunarchive/unxz/README delete mode 100644 archival/libunarchive/unxz/xz.h delete mode 100644 archival/libunarchive/unxz/xz_config.h delete mode 100644 archival/libunarchive/unxz/xz_dec_bcj.c delete mode 100644 archival/libunarchive/unxz/xz_dec_lzma2.c delete mode 100644 archival/libunarchive/unxz/xz_dec_stream.c delete mode 100644 archival/libunarchive/unxz/xz_lzma2.h delete mode 100644 archival/libunarchive/unxz/xz_private.h delete mode 100644 archival/libunarchive/unxz/xz_stream.h create mode 100644 include/archive.h delete mode 100644 include/unarchive.h diff --git a/Makefile b/Makefile index c41643d8b..8fac9e9f9 100644 --- a/Makefile +++ b/Makefile @@ -464,7 +464,7 @@ core-y := \ libs-y := \ archival/ \ - archival/libunarchive/ \ + archival/libarchive/ \ console-tools/ \ coreutils/ \ coreutils/libcoreutils/ \ diff --git a/archival/Kbuild.src b/archival/Kbuild.src index e49d38538..3466452f7 100644 --- a/archival/Kbuild.src +++ b/archival/Kbuild.src @@ -4,7 +4,7 @@ # # Licensed under GPLv2, see file LICENSE in this source tree. -libs-y += libunarchive/ +libs-y += libarchive/ lib-y:= diff --git a/archival/ar.c b/archival/ar.c index 730d7c6c6..a2e3306ac 100644 --- a/archival/ar.c +++ b/archival/ar.c @@ -18,7 +18,7 @@ */ #include "libbb.h" -#include "unarchive.h" +#include "archive.h" #include "ar.h" #if ENABLE_FEATURE_AR_CREATE diff --git a/archival/bbunzip.c b/archival/bbunzip.c index 6b6457673..a69e1b3ca 100644 --- a/archival/bbunzip.c +++ b/archival/bbunzip.c @@ -5,7 +5,7 @@ * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ #include "libbb.h" -#include "unarchive.h" +#include "archive.h" enum { OPT_STDOUT = 1 << 0, diff --git a/archival/bz/LICENSE b/archival/bz/LICENSE deleted file mode 100644 index da4346520..000000000 --- a/archival/bz/LICENSE +++ /dev/null @@ -1,44 +0,0 @@ -bzip2 applet in busybox is based on lightly-modified source -of bzip2 version 1.0.4. bzip2 source is distributed -under the following conditions (copied verbatim from LICENSE file) -=========================================================== - - -This program, "bzip2", the associated library "libbzip2", and all -documentation, are copyright (C) 1996-2006 Julian R Seward. All -rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions -are met: - -1. Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - -2. The origin of this software must not be misrepresented; you must - not claim that you wrote the original software. If you use this - software in a product, an acknowledgment in the product - documentation would be appreciated but is not required. - -3. Altered source versions must be plainly marked as such, and must - not be misrepresented as being the original software. - -4. The name of the author may not be used to endorse or promote - products derived from this software without specific prior written - permission. - -THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS -OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE -GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, -WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -Julian Seward, Cambridge, UK. -jseward@bzip.org -bzip2/libbzip2 version 1.0.4 of 20 December 2006 diff --git a/archival/bz/README b/archival/bz/README deleted file mode 100644 index fffd47b8a..000000000 --- a/archival/bz/README +++ /dev/null @@ -1,90 +0,0 @@ -This file is an abridged version of README from bzip2 1.0.4 -Build instructions (which are not relevant to busyboxed bzip2) -are removed. -=========================================================== - - -This is the README for bzip2/libzip2. -This version is fully compatible with the previous public releases. - ------------------------------------------------------------------- -This file is part of bzip2/libbzip2, a program and library for -lossless, block-sorting data compression. - -bzip2/libbzip2 version 1.0.4 of 20 December 2006 -Copyright (C) 1996-2006 Julian Seward - -Please read the WARNING, DISCLAIMER and PATENTS sections in this file. - -This program is released under the terms of the license contained -in the file LICENSE. ------------------------------------------------------------------- - -Please read and be aware of the following: - - -WARNING: - - This program and library (attempts to) compress data by - performing several non-trivial transformations on it. - Unless you are 100% familiar with *all* the algorithms - contained herein, and with the consequences of modifying them, - you should NOT meddle with the compression or decompression - machinery. Incorrect changes can and very likely *will* - lead to disastrous loss of data. - - -DISCLAIMER: - - I TAKE NO RESPONSIBILITY FOR ANY LOSS OF DATA ARISING FROM THE - USE OF THIS PROGRAM/LIBRARY, HOWSOEVER CAUSED. - - Every compression of a file implies an assumption that the - compressed file can be decompressed to reproduce the original. - Great efforts in design, coding and testing have been made to - ensure that this program works correctly. However, the complexity - of the algorithms, and, in particular, the presence of various - special cases in the code which occur with very low but non-zero - probability make it impossible to rule out the possibility of bugs - remaining in the program. DO NOT COMPRESS ANY DATA WITH THIS - PROGRAM UNLESS YOU ARE PREPARED TO ACCEPT THE POSSIBILITY, HOWEVER - SMALL, THAT THE DATA WILL NOT BE RECOVERABLE. - - That is not to say this program is inherently unreliable. - Indeed, I very much hope the opposite is true. bzip2/libbzip2 - has been carefully constructed and extensively tested. - - -PATENTS: - - To the best of my knowledge, bzip2/libbzip2 does not use any - patented algorithms. However, I do not have the resources - to carry out a patent search. Therefore I cannot give any - guarantee of the above statement. - - -I hope you find bzip2 useful. Feel free to contact me at - jseward@bzip.org -if you have any suggestions or queries. Many people mailed me with -comments, suggestions and patches after the releases of bzip-0.15, -bzip-0.21, and bzip2 versions 0.1pl2, 0.9.0, 0.9.5, 1.0.0, 1.0.1, -1.0.2 and 1.0.3, and the changes in bzip2 are largely a result of this -feedback. I thank you for your comments. - -bzip2's "home" is http://www.bzip.org/ - -Julian Seward -jseward@bzip.org -Cambridge, UK. - -18 July 1996 (version 0.15) -25 August 1996 (version 0.21) - 7 August 1997 (bzip2, version 0.1) -29 August 1997 (bzip2, version 0.1pl2) -23 August 1998 (bzip2, version 0.9.0) - 8 June 1999 (bzip2, version 0.9.5) - 4 Sept 1999 (bzip2, version 0.9.5d) - 5 May 2000 (bzip2, version 1.0pre8) -30 December 2001 (bzip2, version 1.0.2pre1) -15 February 2005 (bzip2, version 1.0.3) -20 December 2006 (bzip2, version 1.0.4) diff --git a/archival/bz/blocksort.c b/archival/bz/blocksort.c deleted file mode 100644 index f70c3701d..000000000 --- a/archival/bz/blocksort.c +++ /dev/null @@ -1,1072 +0,0 @@ -/* - * bzip2 is written by Julian Seward . - * Adapted for busybox by Denys Vlasenko . - * See README and LICENSE files in this directory for more information. - */ - -/*-------------------------------------------------------------*/ -/*--- Block sorting machinery ---*/ -/*--- blocksort.c ---*/ -/*-------------------------------------------------------------*/ - -/* ------------------------------------------------------------------ -This file is part of bzip2/libbzip2, a program and library for -lossless, block-sorting data compression. - -bzip2/libbzip2 version 1.0.4 of 20 December 2006 -Copyright (C) 1996-2006 Julian Seward - -Please read the WARNING, DISCLAIMER and PATENTS sections in the -README file. - -This program is released under the terms of the license contained -in the file LICENSE. ------------------------------------------------------------------- */ - -/* #include "bzlib_private.h" */ - -#define mswap(zz1, zz2) \ -{ \ - int32_t zztmp = zz1; \ - zz1 = zz2; \ - zz2 = zztmp; \ -} - -static -/* No measurable speed gain with inlining */ -/* ALWAYS_INLINE */ -void mvswap(uint32_t* ptr, int32_t zzp1, int32_t zzp2, int32_t zzn) -{ - while (zzn > 0) { - mswap(ptr[zzp1], ptr[zzp2]); - zzp1++; - zzp2++; - zzn--; - } -} - -static -ALWAYS_INLINE -int32_t mmin(int32_t a, int32_t b) -{ - return (a < b) ? a : b; -} - - -/*---------------------------------------------*/ -/*--- Fallback O(N log(N)^2) sorting ---*/ -/*--- algorithm, for repetitive blocks ---*/ -/*---------------------------------------------*/ - -/*---------------------------------------------*/ -static -inline -void fallbackSimpleSort(uint32_t* fmap, - uint32_t* eclass, - int32_t lo, - int32_t hi) -{ - int32_t i, j, tmp; - uint32_t ec_tmp; - - if (lo == hi) return; - - if (hi - lo > 3) { - for (i = hi-4; i >= lo; i--) { - tmp = fmap[i]; - ec_tmp = eclass[tmp]; - for (j = i+4; j <= hi && ec_tmp > eclass[fmap[j]]; j += 4) - fmap[j-4] = fmap[j]; - fmap[j-4] = tmp; - } - } - - for (i = hi-1; i >= lo; i--) { - tmp = fmap[i]; - ec_tmp = eclass[tmp]; - for (j = i+1; j <= hi && ec_tmp > eclass[fmap[j]]; j++) - fmap[j-1] = fmap[j]; - fmap[j-1] = tmp; - } -} - - -/*---------------------------------------------*/ -#define fpush(lz,hz) { \ - stackLo[sp] = lz; \ - stackHi[sp] = hz; \ - sp++; \ -} - -#define fpop(lz,hz) { \ - sp--; \ - lz = stackLo[sp]; \ - hz = stackHi[sp]; \ -} - -#define FALLBACK_QSORT_SMALL_THRESH 10 -#define FALLBACK_QSORT_STACK_SIZE 100 - -static -void fallbackQSort3(uint32_t* fmap, - uint32_t* eclass, - int32_t loSt, - int32_t hiSt) -{ - int32_t unLo, unHi, ltLo, gtHi, n, m; - int32_t sp, lo, hi; - uint32_t med, r, r3; - int32_t stackLo[FALLBACK_QSORT_STACK_SIZE]; - int32_t stackHi[FALLBACK_QSORT_STACK_SIZE]; - - r = 0; - - sp = 0; - fpush(loSt, hiSt); - - while (sp > 0) { - AssertH(sp < FALLBACK_QSORT_STACK_SIZE - 1, 1004); - - fpop(lo, hi); - if (hi - lo < FALLBACK_QSORT_SMALL_THRESH) { - fallbackSimpleSort(fmap, eclass, lo, hi); - continue; - } - - /* Random partitioning. Median of 3 sometimes fails to - * avoid bad cases. Median of 9 seems to help but - * looks rather expensive. This too seems to work but - * is cheaper. Guidance for the magic constants - * 7621 and 32768 is taken from Sedgewick's algorithms - * book, chapter 35. - */ - r = ((r * 7621) + 1) % 32768; - r3 = r % 3; - if (r3 == 0) - med = eclass[fmap[lo]]; - else if (r3 == 1) - med = eclass[fmap[(lo+hi)>>1]]; - else - med = eclass[fmap[hi]]; - - unLo = ltLo = lo; - unHi = gtHi = hi; - - while (1) { - while (1) { - if (unLo > unHi) break; - n = (int32_t)eclass[fmap[unLo]] - (int32_t)med; - if (n == 0) { - mswap(fmap[unLo], fmap[ltLo]); - ltLo++; - unLo++; - continue; - }; - if (n > 0) break; - unLo++; - } - while (1) { - if (unLo > unHi) break; - n = (int32_t)eclass[fmap[unHi]] - (int32_t)med; - if (n == 0) { - mswap(fmap[unHi], fmap[gtHi]); - gtHi--; unHi--; - continue; - }; - if (n < 0) break; - unHi--; - } - if (unLo > unHi) break; - mswap(fmap[unLo], fmap[unHi]); unLo++; unHi--; - } - - AssertD(unHi == unLo-1, "fallbackQSort3(2)"); - - if (gtHi < ltLo) continue; - - n = mmin(ltLo-lo, unLo-ltLo); mvswap(fmap, lo, unLo-n, n); - m = mmin(hi-gtHi, gtHi-unHi); mvswap(fmap, unLo, hi-m+1, m); - - n = lo + unLo - ltLo - 1; - m = hi - (gtHi - unHi) + 1; - - if (n - lo > hi - m) { - fpush(lo, n); - fpush(m, hi); - } else { - fpush(m, hi); - fpush(lo, n); - } - } -} - -#undef fpush -#undef fpop -#undef FALLBACK_QSORT_SMALL_THRESH -#undef FALLBACK_QSORT_STACK_SIZE - - -/*---------------------------------------------*/ -/* Pre: - * nblock > 0 - * eclass exists for [0 .. nblock-1] - * ((uint8_t*)eclass) [0 .. nblock-1] holds block - * ptr exists for [0 .. nblock-1] - * - * Post: - * ((uint8_t*)eclass) [0 .. nblock-1] holds block - * All other areas of eclass destroyed - * fmap [0 .. nblock-1] holds sorted order - * bhtab[0 .. 2+(nblock/32)] destroyed -*/ - -#define SET_BH(zz) bhtab[(zz) >> 5] |= (1 << ((zz) & 31)) -#define CLEAR_BH(zz) bhtab[(zz) >> 5] &= ~(1 << ((zz) & 31)) -#define ISSET_BH(zz) (bhtab[(zz) >> 5] & (1 << ((zz) & 31))) -#define WORD_BH(zz) bhtab[(zz) >> 5] -#define UNALIGNED_BH(zz) ((zz) & 0x01f) - -static -void fallbackSort(uint32_t* fmap, - uint32_t* eclass, - uint32_t* bhtab, - int32_t nblock) -{ - int32_t ftab[257]; - int32_t ftabCopy[256]; - int32_t H, i, j, k, l, r, cc, cc1; - int32_t nNotDone; - int32_t nBhtab; - uint8_t* eclass8 = (uint8_t*)eclass; - - /* - * Initial 1-char radix sort to generate - * initial fmap and initial BH bits. - */ - for (i = 0; i < 257; i++) ftab[i] = 0; - for (i = 0; i < nblock; i++) ftab[eclass8[i]]++; - for (i = 0; i < 256; i++) ftabCopy[i] = ftab[i]; - - j = ftab[0]; /* bbox: optimized */ - for (i = 1; i < 257; i++) { - j += ftab[i]; - ftab[i] = j; - } - - for (i = 0; i < nblock; i++) { - j = eclass8[i]; - k = ftab[j] - 1; - ftab[j] = k; - fmap[k] = i; - } - - nBhtab = 2 + ((uint32_t)nblock / 32); /* bbox: unsigned div is easier */ - for (i = 0; i < nBhtab; i++) bhtab[i] = 0; - for (i = 0; i < 256; i++) SET_BH(ftab[i]); - - /* - * Inductively refine the buckets. Kind-of an - * "exponential radix sort" (!), inspired by the - * Manber-Myers suffix array construction algorithm. - */ - - /*-- set sentinel bits for block-end detection --*/ - for (i = 0; i < 32; i++) { - SET_BH(nblock + 2*i); - CLEAR_BH(nblock + 2*i + 1); - } - - /*-- the log(N) loop --*/ - H = 1; - while (1) { - j = 0; - for (i = 0; i < nblock; i++) { - if (ISSET_BH(i)) - j = i; - k = fmap[i] - H; - if (k < 0) - k += nblock; - eclass[k] = j; - } - - nNotDone = 0; - r = -1; - while (1) { - - /*-- find the next non-singleton bucket --*/ - k = r + 1; - while (ISSET_BH(k) && UNALIGNED_BH(k)) - k++; - if (ISSET_BH(k)) { - while (WORD_BH(k) == 0xffffffff) k += 32; - while (ISSET_BH(k)) k++; - } - l = k - 1; - if (l >= nblock) - break; - while (!ISSET_BH(k) && UNALIGNED_BH(k)) - k++; - if (!ISSET_BH(k)) { - while (WORD_BH(k) == 0x00000000) k += 32; - while (!ISSET_BH(k)) k++; - } - r = k - 1; - if (r >= nblock) - break; - - /*-- now [l, r] bracket current bucket --*/ - if (r > l) { - nNotDone += (r - l + 1); - fallbackQSort3(fmap, eclass, l, r); - - /*-- scan bucket and generate header bits-- */ - cc = -1; - for (i = l; i <= r; i++) { - cc1 = eclass[fmap[i]]; - if (cc != cc1) { - SET_BH(i); - cc = cc1; - }; - } - } - } - - H *= 2; - if (H > nblock || nNotDone == 0) - break; - } - - /* - * Reconstruct the original block in - * eclass8 [0 .. nblock-1], since the - * previous phase destroyed it. - */ - j = 0; - for (i = 0; i < nblock; i++) { - while (ftabCopy[j] == 0) - j++; - ftabCopy[j]--; - eclass8[fmap[i]] = (uint8_t)j; - } - AssertH(j < 256, 1005); -} - -#undef SET_BH -#undef CLEAR_BH -#undef ISSET_BH -#undef WORD_BH -#undef UNALIGNED_BH - - -/*---------------------------------------------*/ -/*--- The main, O(N^2 log(N)) sorting ---*/ -/*--- algorithm. Faster for "normal" ---*/ -/*--- non-repetitive blocks. ---*/ -/*---------------------------------------------*/ - -/*---------------------------------------------*/ -static -NOINLINE -int mainGtU( - uint32_t i1, - uint32_t i2, - uint8_t* block, - uint16_t* quadrant, - uint32_t nblock, - int32_t* budget) -{ - int32_t k; - uint8_t c1, c2; - uint16_t s1, s2; - -/* Loop unrolling here is actually very useful - * (generated code is much simpler), - * code size increase is only 270 bytes (i386) - * but speeds up compression 10% overall - */ - -#if CONFIG_BZIP2_FEATURE_SPEED >= 1 - -#define TIMES_8(code) \ - code; code; code; code; \ - code; code; code; code; -#define TIMES_12(code) \ - code; code; code; code; \ - code; code; code; code; \ - code; code; code; code; - -#else - -#define TIMES_8(code) \ -{ \ - int nn = 8; \ - do { \ - code; \ - } while (--nn); \ -} -#define TIMES_12(code) \ -{ \ - int nn = 12; \ - do { \ - code; \ - } while (--nn); \ -} - -#endif - - AssertD(i1 != i2, "mainGtU"); - TIMES_12( - c1 = block[i1]; c2 = block[i2]; - if (c1 != c2) return (c1 > c2); - i1++; i2++; - ) - - k = nblock + 8; - - do { - TIMES_8( - c1 = block[i1]; c2 = block[i2]; - if (c1 != c2) return (c1 > c2); - s1 = quadrant[i1]; s2 = quadrant[i2]; - if (s1 != s2) return (s1 > s2); - i1++; i2++; - ) - - if (i1 >= nblock) i1 -= nblock; - if (i2 >= nblock) i2 -= nblock; - - (*budget)--; - k -= 8; - } while (k >= 0); - - return False; -} -#undef TIMES_8 -#undef TIMES_12 - -/*---------------------------------------------*/ -/* - * Knuth's increments seem to work better - * than Incerpi-Sedgewick here. Possibly - * because the number of elems to sort is - * usually small, typically <= 20. - */ -static -const int32_t incs[14] = { - 1, 4, 13, 40, 121, 364, 1093, 3280, - 9841, 29524, 88573, 265720, - 797161, 2391484 -}; - -static -void mainSimpleSort(uint32_t* ptr, - uint8_t* block, - uint16_t* quadrant, - int32_t nblock, - int32_t lo, - int32_t hi, - int32_t d, - int32_t* budget) -{ - int32_t i, j, h, bigN, hp; - uint32_t v; - - bigN = hi - lo + 1; - if (bigN < 2) return; - - hp = 0; - while (incs[hp] < bigN) hp++; - hp--; - - for (; hp >= 0; hp--) { - h = incs[hp]; - - i = lo + h; - while (1) { - /*-- copy 1 --*/ - if (i > hi) break; - v = ptr[i]; - j = i; - while (mainGtU(ptr[j-h]+d, v+d, block, quadrant, nblock, budget)) { - ptr[j] = ptr[j-h]; - j = j - h; - if (j <= (lo + h - 1)) break; - } - ptr[j] = v; - i++; - -/* 1.5% overall speedup, +290 bytes */ -#if CONFIG_BZIP2_FEATURE_SPEED >= 3 - /*-- copy 2 --*/ - if (i > hi) break; - v = ptr[i]; - j = i; - while (mainGtU(ptr[j-h]+d, v+d, block, quadrant, nblock, budget)) { - ptr[j] = ptr[j-h]; - j = j - h; - if (j <= (lo + h - 1)) break; - } - ptr[j] = v; - i++; - - /*-- copy 3 --*/ - if (i > hi) break; - v = ptr[i]; - j = i; - while (mainGtU(ptr[j-h]+d, v+d, block, quadrant, nblock, budget)) { - ptr[j] = ptr[j-h]; - j = j - h; - if (j <= (lo + h - 1)) break; - } - ptr[j] = v; - i++; -#endif - if (*budget < 0) return; - } - } -} - - -/*---------------------------------------------*/ -/* - * The following is an implementation of - * an elegant 3-way quicksort for strings, - * described in a paper "Fast Algorithms for - * Sorting and Searching Strings", by Robert - * Sedgewick and Jon L. Bentley. - */ - -static -ALWAYS_INLINE -uint8_t mmed3(uint8_t a, uint8_t b, uint8_t c) -{ - uint8_t t; - if (a > b) { - t = a; - a = b; - b = t; - }; - /* here b >= a */ - if (b > c) { - b = c; - if (a > b) - b = a; - } - return b; -} - -#define mpush(lz,hz,dz) \ -{ \ - stackLo[sp] = lz; \ - stackHi[sp] = hz; \ - stackD [sp] = dz; \ - sp++; \ -} - -#define mpop(lz,hz,dz) \ -{ \ - sp--; \ - lz = stackLo[sp]; \ - hz = stackHi[sp]; \ - dz = stackD [sp]; \ -} - -#define mnextsize(az) (nextHi[az] - nextLo[az]) - -#define mnextswap(az,bz) \ -{ \ - int32_t tz; \ - tz = nextLo[az]; nextLo[az] = nextLo[bz]; nextLo[bz] = tz; \ - tz = nextHi[az]; nextHi[az] = nextHi[bz]; nextHi[bz] = tz; \ - tz = nextD [az]; nextD [az] = nextD [bz]; nextD [bz] = tz; \ -} - -#define MAIN_QSORT_SMALL_THRESH 20 -#define MAIN_QSORT_DEPTH_THRESH (BZ_N_RADIX + BZ_N_QSORT) -#define MAIN_QSORT_STACK_SIZE 100 - -static NOINLINE -void mainQSort3(uint32_t* ptr, - uint8_t* block, - uint16_t* quadrant, - int32_t nblock, - int32_t loSt, - int32_t hiSt, - int32_t dSt, - int32_t* budget) -{ - int32_t unLo, unHi, ltLo, gtHi, n, m, med; - int32_t sp, lo, hi, d; - - int32_t stackLo[MAIN_QSORT_STACK_SIZE]; - int32_t stackHi[MAIN_QSORT_STACK_SIZE]; - int32_t stackD [MAIN_QSORT_STACK_SIZE]; - - int32_t nextLo[3]; - int32_t nextHi[3]; - int32_t nextD [3]; - - sp = 0; - mpush(loSt, hiSt, dSt); - - while (sp > 0) { - AssertH(sp < MAIN_QSORT_STACK_SIZE - 2, 1001); - - mpop(lo, hi, d); - if (hi - lo < MAIN_QSORT_SMALL_THRESH - || d > MAIN_QSORT_DEPTH_THRESH - ) { - mainSimpleSort(ptr, block, quadrant, nblock, lo, hi, d, budget); - if (*budget < 0) - return; - continue; - } - med = (int32_t) mmed3(block[ptr[lo ] + d], - block[ptr[hi ] + d], - block[ptr[(lo+hi) >> 1] + d]); - - unLo = ltLo = lo; - unHi = gtHi = hi; - - while (1) { - while (1) { - if (unLo > unHi) - break; - n = ((int32_t)block[ptr[unLo]+d]) - med; - if (n == 0) { - mswap(ptr[unLo], ptr[ltLo]); - ltLo++; - unLo++; - continue; - }; - if (n > 0) break; - unLo++; - } - while (1) { - if (unLo > unHi) - break; - n = ((int32_t)block[ptr[unHi]+d]) - med; - if (n == 0) { - mswap(ptr[unHi], ptr[gtHi]); - gtHi--; - unHi--; - continue; - }; - if (n < 0) break; - unHi--; - } - if (unLo > unHi) - break; - mswap(ptr[unLo], ptr[unHi]); - unLo++; - unHi--; - } - - AssertD(unHi == unLo-1, "mainQSort3(2)"); - - if (gtHi < ltLo) { - mpush(lo, hi, d + 1); - continue; - } - - n = mmin(ltLo-lo, unLo-ltLo); mvswap(ptr, lo, unLo-n, n); - m = mmin(hi-gtHi, gtHi-unHi); mvswap(ptr, unLo, hi-m+1, m); - - n = lo + unLo - ltLo - 1; - m = hi - (gtHi - unHi) + 1; - - nextLo[0] = lo; nextHi[0] = n; nextD[0] = d; - nextLo[1] = m; nextHi[1] = hi; nextD[1] = d; - nextLo[2] = n+1; nextHi[2] = m-1; nextD[2] = d+1; - - if (mnextsize(0) < mnextsize(1)) mnextswap(0, 1); - if (mnextsize(1) < mnextsize(2)) mnextswap(1, 2); - if (mnextsize(0) < mnextsize(1)) mnextswap(0, 1); - - AssertD (mnextsize(0) >= mnextsize(1), "mainQSort3(8)"); - AssertD (mnextsize(1) >= mnextsize(2), "mainQSort3(9)"); - - mpush(nextLo[0], nextHi[0], nextD[0]); - mpush(nextLo[1], nextHi[1], nextD[1]); - mpush(nextLo[2], nextHi[2], nextD[2]); - } -} - -#undef mpush -#undef mpop -#undef mnextsize -#undef mnextswap -#undef MAIN_QSORT_SMALL_THRESH -#undef MAIN_QSORT_DEPTH_THRESH -#undef MAIN_QSORT_STACK_SIZE - - -/*---------------------------------------------*/ -/* Pre: - * nblock > N_OVERSHOOT - * block32 exists for [0 .. nblock-1 +N_OVERSHOOT] - * ((uint8_t*)block32) [0 .. nblock-1] holds block - * ptr exists for [0 .. nblock-1] - * - * Post: - * ((uint8_t*)block32) [0 .. nblock-1] holds block - * All other areas of block32 destroyed - * ftab[0 .. 65536] destroyed - * ptr [0 .. nblock-1] holds sorted order - * if (*budget < 0), sorting was abandoned - */ - -#define BIGFREQ(b) (ftab[((b)+1) << 8] - ftab[(b) << 8]) -#define SETMASK (1 << 21) -#define CLEARMASK (~(SETMASK)) - -static NOINLINE -void mainSort(EState* state, - uint32_t* ptr, - uint8_t* block, - uint16_t* quadrant, - uint32_t* ftab, - int32_t nblock, - int32_t* budget) -{ - int32_t i, j, k, ss, sb; - uint8_t c1; - int32_t numQSorted; - uint16_t s; - Bool bigDone[256]; - /* bbox: moved to EState to save stack - int32_t runningOrder[256]; - int32_t copyStart[256]; - int32_t copyEnd [256]; - */ -#define runningOrder (state->mainSort__runningOrder) -#define copyStart (state->mainSort__copyStart) -#define copyEnd (state->mainSort__copyEnd) - - /*-- set up the 2-byte frequency table --*/ - /* was: for (i = 65536; i >= 0; i--) ftab[i] = 0; */ - memset(ftab, 0, 65537 * sizeof(ftab[0])); - - j = block[0] << 8; - i = nblock - 1; -/* 3%, +300 bytes */ -#if CONFIG_BZIP2_FEATURE_SPEED >= 2 - for (; i >= 3; i -= 4) { - quadrant[i] = 0; - j = (j >> 8) | (((uint16_t)block[i]) << 8); - ftab[j]++; - quadrant[i-1] = 0; - j = (j >> 8) | (((uint16_t)block[i-1]) << 8); - ftab[j]++; - quadrant[i-2] = 0; - j = (j >> 8) | (((uint16_t)block[i-2]) << 8); - ftab[j]++; - quadrant[i-3] = 0; - j = (j >> 8) | (((uint16_t)block[i-3]) << 8); - ftab[j]++; - } -#endif - for (; i >= 0; i--) { - quadrant[i] = 0; - j = (j >> 8) | (((uint16_t)block[i]) << 8); - ftab[j]++; - } - - /*-- (emphasises close relationship of block & quadrant) --*/ - for (i = 0; i < BZ_N_OVERSHOOT; i++) { - block [nblock+i] = block[i]; - quadrant[nblock+i] = 0; - } - - /*-- Complete the initial radix sort --*/ - j = ftab[0]; /* bbox: optimized */ - for (i = 1; i <= 65536; i++) { - j += ftab[i]; - ftab[i] = j; - } - - s = block[0] << 8; - i = nblock - 1; -#if CONFIG_BZIP2_FEATURE_SPEED >= 2 - for (; i >= 3; i -= 4) { - s = (s >> 8) | (block[i] << 8); - j = ftab[s] - 1; - ftab[s] = j; - ptr[j] = i; - s = (s >> 8) | (block[i-1] << 8); - j = ftab[s] - 1; - ftab[s] = j; - ptr[j] = i-1; - s = (s >> 8) | (block[i-2] << 8); - j = ftab[s] - 1; - ftab[s] = j; - ptr[j] = i-2; - s = (s >> 8) | (block[i-3] << 8); - j = ftab[s] - 1; - ftab[s] = j; - ptr[j] = i-3; - } -#endif - for (; i >= 0; i--) { - s = (s >> 8) | (block[i] << 8); - j = ftab[s] - 1; - ftab[s] = j; - ptr[j] = i; - } - - /* - * Now ftab contains the first loc of every small bucket. - * Calculate the running order, from smallest to largest - * big bucket. - */ - for (i = 0; i <= 255; i++) { - bigDone [i] = False; - runningOrder[i] = i; - } - - { - int32_t vv; - /* bbox: was: int32_t h = 1; */ - /* do h = 3 * h + 1; while (h <= 256); */ - uint32_t h = 364; - - do { - /*h = h / 3;*/ - h = (h * 171) >> 9; /* bbox: fast h/3 */ - for (i = h; i <= 255; i++) { - vv = runningOrder[i]; - j = i; - while (BIGFREQ(runningOrder[j-h]) > BIGFREQ(vv)) { - runningOrder[j] = runningOrder[j-h]; - j = j - h; - if (j <= (h - 1)) - goto zero; - } - zero: - runningOrder[j] = vv; - } - } while (h != 1); - } - - /* - * The main sorting loop. - */ - - numQSorted = 0; - - for (i = 0; i <= 255; i++) { - - /* - * Process big buckets, starting with the least full. - * Basically this is a 3-step process in which we call - * mainQSort3 to sort the small buckets [ss, j], but - * also make a big effort to avoid the calls if we can. - */ - ss = runningOrder[i]; - - /* - * Step 1: - * Complete the big bucket [ss] by quicksorting - * any unsorted small buckets [ss, j], for j != ss. - * Hopefully previous pointer-scanning phases have already - * completed many of the small buckets [ss, j], so - * we don't have to sort them at all. - */ - for (j = 0; j <= 255; j++) { - if (j != ss) { - sb = (ss << 8) + j; - if (!(ftab[sb] & SETMASK)) { - int32_t lo = ftab[sb] & CLEARMASK; - int32_t hi = (ftab[sb+1] & CLEARMASK) - 1; - if (hi > lo) { - mainQSort3( - ptr, block, quadrant, nblock, - lo, hi, BZ_N_RADIX, budget - ); - if (*budget < 0) return; - numQSorted += (hi - lo + 1); - } - } - ftab[sb] |= SETMASK; - } - } - - AssertH(!bigDone[ss], 1006); - - /* - * Step 2: - * Now scan this big bucket [ss] so as to synthesise the - * sorted order for small buckets [t, ss] for all t, - * including, magically, the bucket [ss,ss] too. - * This will avoid doing Real Work in subsequent Step 1's. - */ - { - for (j = 0; j <= 255; j++) { - copyStart[j] = ftab[(j << 8) + ss] & CLEARMASK; - copyEnd [j] = (ftab[(j << 8) + ss + 1] & CLEARMASK) - 1; - } - for (j = ftab[ss << 8] & CLEARMASK; j < copyStart[ss]; j++) { - k = ptr[j] - 1; - if (k < 0) - k += nblock; - c1 = block[k]; - if (!bigDone[c1]) - ptr[copyStart[c1]++] = k; - } - for (j = (ftab[(ss+1) << 8] & CLEARMASK) - 1; j > copyEnd[ss]; j--) { - k = ptr[j]-1; - if (k < 0) - k += nblock; - c1 = block[k]; - if (!bigDone[c1]) - ptr[copyEnd[c1]--] = k; - } - } - - /* Extremely rare case missing in bzip2-1.0.0 and 1.0.1. - * Necessity for this case is demonstrated by compressing - * a sequence of approximately 48.5 million of character - * 251; 1.0.0/1.0.1 will then die here. */ - AssertH((copyStart[ss]-1 == copyEnd[ss]) \ - || (copyStart[ss] == 0 && copyEnd[ss] == nblock-1), 1007); - - for (j = 0; j <= 255; j++) - ftab[(j << 8) + ss] |= SETMASK; - - /* - * Step 3: - * The [ss] big bucket is now done. Record this fact, - * and update the quadrant descriptors. Remember to - * update quadrants in the overshoot area too, if - * necessary. The "if (i < 255)" test merely skips - * this updating for the last bucket processed, since - * updating for the last bucket is pointless. - * - * The quadrant array provides a way to incrementally - * cache sort orderings, as they appear, so as to - * make subsequent comparisons in fullGtU() complete - * faster. For repetitive blocks this makes a big - * difference (but not big enough to be able to avoid - * the fallback sorting mechanism, exponential radix sort). - * - * The precise meaning is: at all times: - * - * for 0 <= i < nblock and 0 <= j <= nblock - * - * if block[i] != block[j], - * - * then the relative values of quadrant[i] and - * quadrant[j] are meaningless. - * - * else { - * if quadrant[i] < quadrant[j] - * then the string starting at i lexicographically - * precedes the string starting at j - * - * else if quadrant[i] > quadrant[j] - * then the string starting at j lexicographically - * precedes the string starting at i - * - * else - * the relative ordering of the strings starting - * at i and j has not yet been determined. - * } - */ - bigDone[ss] = True; - - if (i < 255) { - int32_t bbStart = ftab[ss << 8] & CLEARMASK; - int32_t bbSize = (ftab[(ss+1) << 8] & CLEARMASK) - bbStart; - int32_t shifts = 0; - - while ((bbSize >> shifts) > 65534) shifts++; - - for (j = bbSize-1; j >= 0; j--) { - int32_t a2update = ptr[bbStart + j]; - uint16_t qVal = (uint16_t)(j >> shifts); - quadrant[a2update] = qVal; - if (a2update < BZ_N_OVERSHOOT) - quadrant[a2update + nblock] = qVal; - } - AssertH(((bbSize-1) >> shifts) <= 65535, 1002); - } - } -#undef runningOrder -#undef copyStart -#undef copyEnd -} - -#undef BIGFREQ -#undef SETMASK -#undef CLEARMASK - - -/*---------------------------------------------*/ -/* Pre: - * nblock > 0 - * arr2 exists for [0 .. nblock-1 +N_OVERSHOOT] - * ((uint8_t*)arr2)[0 .. nblock-1] holds block - * arr1 exists for [0 .. nblock-1] - * - * Post: - * ((uint8_t*)arr2) [0 .. nblock-1] holds block - * All other areas of block destroyed - * ftab[0 .. 65536] destroyed - * arr1[0 .. nblock-1] holds sorted order - */ -static NOINLINE -void BZ2_blockSort(EState* s) -{ - /* In original bzip2 1.0.4, it's a parameter, but 30 - * (which was the default) should work ok. */ - enum { wfact = 30 }; - - uint32_t* ptr = s->ptr; - uint8_t* block = s->block; - uint32_t* ftab = s->ftab; - int32_t nblock = s->nblock; - uint16_t* quadrant; - int32_t budget; - int32_t i; - - if (nblock < 10000) { - fallbackSort(s->arr1, s->arr2, ftab, nblock); - } else { - /* Calculate the location for quadrant, remembering to get - * the alignment right. Assumes that &(block[0]) is at least - * 2-byte aligned -- this should be ok since block is really - * the first section of arr2. - */ - i = nblock + BZ_N_OVERSHOOT; - if (i & 1) i++; - quadrant = (uint16_t*)(&(block[i])); - - /* (wfact-1) / 3 puts the default-factor-30 - * transition point at very roughly the same place as - * with v0.1 and v0.9.0. - * Not that it particularly matters any more, since the - * resulting compressed stream is now the same regardless - * of whether or not we use the main sort or fallback sort. - */ - budget = nblock * ((wfact-1) / 3); - - mainSort(s, ptr, block, quadrant, ftab, nblock, &budget); - if (budget < 0) { - fallbackSort(s->arr1, s->arr2, ftab, nblock); - } - } - - s->origPtr = -1; - for (i = 0; i < s->nblock; i++) - if (ptr[i] == 0) { - s->origPtr = i; - break; - }; - - AssertH(s->origPtr != -1, 1003); -} - - -/*-------------------------------------------------------------*/ -/*--- end blocksort.c ---*/ -/*-------------------------------------------------------------*/ diff --git a/archival/bz/bzlib.c b/archival/bz/bzlib.c deleted file mode 100644 index b3beeabed..000000000 --- a/archival/bz/bzlib.c +++ /dev/null @@ -1,431 +0,0 @@ -/* - * bzip2 is written by Julian Seward . - * Adapted for busybox by Denys Vlasenko . - * See README and LICENSE files in this directory for more information. - */ - -/*-------------------------------------------------------------*/ -/*--- Library top-level functions. ---*/ -/*--- bzlib.c ---*/ -/*-------------------------------------------------------------*/ - -/* ------------------------------------------------------------------ -This file is part of bzip2/libbzip2, a program and library for -lossless, block-sorting data compression. - -bzip2/libbzip2 version 1.0.4 of 20 December 2006 -Copyright (C) 1996-2006 Julian Seward - -Please read the WARNING, DISCLAIMER and PATENTS sections in the -README file. - -This program is released under the terms of the license contained -in the file LICENSE. ------------------------------------------------------------------- */ - -/* CHANGES - * 0.9.0 -- original version. - * 0.9.0a/b -- no changes in this file. - * 0.9.0c -- made zero-length BZ_FLUSH work correctly in bzCompress(). - * fixed bzWrite/bzRead to ignore zero-length requests. - * fixed bzread to correctly handle read requests after EOF. - * wrong parameter order in call to bzDecompressInit in - * bzBuffToBuffDecompress. Fixed. - */ - -/* #include "bzlib_private.h" */ - -/*---------------------------------------------------*/ -/*--- Compression stuff ---*/ -/*---------------------------------------------------*/ - -/*---------------------------------------------------*/ -#if BZ_LIGHT_DEBUG -static -void bz_assert_fail(int errcode) -{ - /* if (errcode == 1007) bb_error_msg_and_die("probably bad RAM"); */ - bb_error_msg_and_die("internal error %d", errcode); -} -#endif - -/*---------------------------------------------------*/ -static -void prepare_new_block(EState* s) -{ - int i; - s->nblock = 0; - s->numZ = 0; - s->state_out_pos = 0; - BZ_INITIALISE_CRC(s->blockCRC); - /* inlined memset would be nice to have here */ - for (i = 0; i < 256; i++) - s->inUse[i] = 0; - s->blockNo++; -} - - -/*---------------------------------------------------*/ -static -ALWAYS_INLINE -void init_RL(EState* s) -{ - s->state_in_ch = 256; - s->state_in_len = 0; -} - - -static -int isempty_RL(EState* s) -{ - return (s->state_in_ch >= 256 || s->state_in_len <= 0); -} - - -/*---------------------------------------------------*/ -static -void BZ2_bzCompressInit(bz_stream *strm, int blockSize100k) -{ - int32_t n; - EState* s; - - s = xzalloc(sizeof(EState)); - s->strm = strm; - - n = 100000 * blockSize100k; - s->arr1 = xmalloc(n * sizeof(uint32_t)); - s->mtfv = (uint16_t*)s->arr1; - s->ptr = (uint32_t*)s->arr1; - s->arr2 = xmalloc((n + BZ_N_OVERSHOOT) * sizeof(uint32_t)); - s->block = (uint8_t*)s->arr2; - s->ftab = xmalloc(65537 * sizeof(uint32_t)); - - s->crc32table = crc32_filltable(NULL, 1); - - s->state = BZ_S_INPUT; - s->mode = BZ_M_RUNNING; - s->blockSize100k = blockSize100k; - s->nblockMAX = n - 19; - - strm->state = s; - /*strm->total_in = 0;*/ - strm->total_out = 0; - init_RL(s); - prepare_new_block(s); -} - - -/*---------------------------------------------------*/ -static -void add_pair_to_block(EState* s) -{ - int32_t i; - uint8_t ch = (uint8_t)(s->state_in_ch); - for (i = 0; i < s->state_in_len; i++) { - BZ_UPDATE_CRC(s, s->blockCRC, ch); - } - s->inUse[s->state_in_ch] = 1; - switch (s->state_in_len) { - case 3: - s->block[s->nblock] = (uint8_t)ch; s->nblock++; - /* fall through */ - case 2: - s->block[s->nblock] = (uint8_t)ch; s->nblock++; - /* fall through */ - case 1: - s->block[s->nblock] = (uint8_t)ch; s->nblock++; - break; - default: - s->inUse[s->state_in_len - 4] = 1; - s->block[s->nblock] = (uint8_t)ch; s->nblock++; - s->block[s->nblock] = (uint8_t)ch; s->nblock++; - s->block[s->nblock] = (uint8_t)ch; s->nblock++; - s->block[s->nblock] = (uint8_t)ch; s->nblock++; - s->block[s->nblock] = (uint8_t)(s->state_in_len - 4); - s->nblock++; - break; - } -} - - -/*---------------------------------------------------*/ -static -void flush_RL(EState* s) -{ - if (s->state_in_ch < 256) add_pair_to_block(s); - init_RL(s); -} - - -/*---------------------------------------------------*/ -#define ADD_CHAR_TO_BLOCK(zs, zchh0) \ -{ \ - uint32_t zchh = (uint32_t)(zchh0); \ - /*-- fast track the common case --*/ \ - if (zchh != zs->state_in_ch && zs->state_in_len == 1) { \ - uint8_t ch = (uint8_t)(zs->state_in_ch); \ - BZ_UPDATE_CRC(zs, zs->blockCRC, ch); \ - zs->inUse[zs->state_in_ch] = 1; \ - zs->block[zs->nblock] = (uint8_t)ch; \ - zs->nblock++; \ - zs->state_in_ch = zchh; \ - } \ - else \ - /*-- general, uncommon cases --*/ \ - if (zchh != zs->state_in_ch || zs->state_in_len == 255) { \ - if (zs->state_in_ch < 256) \ - add_pair_to_block(zs); \ - zs->state_in_ch = zchh; \ - zs->state_in_len = 1; \ - } else { \ - zs->state_in_len++; \ - } \ -} - - -/*---------------------------------------------------*/ -static -void /*Bool*/ copy_input_until_stop(EState* s) -{ - /*Bool progress_in = False;*/ - -#ifdef SAME_CODE_AS_BELOW - if (s->mode == BZ_M_RUNNING) { - /*-- fast track the common case --*/ - while (1) { - /*-- no input? --*/ - if (s->strm->avail_in == 0) break; - /*-- block full? --*/ - if (s->nblock >= s->nblockMAX) break; - /*progress_in = True;*/ - ADD_CHAR_TO_BLOCK(s, (uint32_t)(*(uint8_t*)(s->strm->next_in))); - s->strm->next_in++; - s->strm->avail_in--; - /*s->strm->total_in++;*/ - } - } else -#endif - { - /*-- general, uncommon case --*/ - while (1) { - /*-- no input? --*/ - if (s->strm->avail_in == 0) break; - /*-- block full? --*/ - if (s->nblock >= s->nblockMAX) break; - //# /*-- flush/finish end? --*/ - //# if (s->avail_in_expect == 0) break; - /*progress_in = True;*/ - ADD_CHAR_TO_BLOCK(s, *(uint8_t*)(s->strm->next_in)); - s->strm->next_in++; - s->strm->avail_in--; - /*s->strm->total_in++;*/ - //# s->avail_in_expect--; - } - } - /*return progress_in;*/ -} - - -/*---------------------------------------------------*/ -static -void /*Bool*/ copy_output_until_stop(EState* s) -{ - /*Bool progress_out = False;*/ - - while (1) { - /*-- no output space? --*/ - if (s->strm->avail_out == 0) break; - - /*-- block done? --*/ - if (s->state_out_pos >= s->numZ) break; - - /*progress_out = True;*/ - *(s->strm->next_out) = s->zbits[s->state_out_pos]; - s->state_out_pos++; - s->strm->avail_out--; - s->strm->next_out++; - s->strm->total_out++; - } - /*return progress_out;*/ -} - - -/*---------------------------------------------------*/ -static -void /*Bool*/ handle_compress(bz_stream *strm) -{ - /*Bool progress_in = False;*/ - /*Bool progress_out = False;*/ - EState* s = strm->state; - - while (1) { - if (s->state == BZ_S_OUTPUT) { - /*progress_out |=*/ copy_output_until_stop(s); - if (s->state_out_pos < s->numZ) break; - if (s->mode == BZ_M_FINISHING - //# && s->avail_in_expect == 0 - && s->strm->avail_in == 0 - && isempty_RL(s)) - break; - prepare_new_block(s); - s->state = BZ_S_INPUT; -#ifdef FLUSH_IS_UNUSED - if (s->mode == BZ_M_FLUSHING - && s->avail_in_expect == 0 - && isempty_RL(s)) - break; -#endif - } - - if (s->state == BZ_S_INPUT) { - /*progress_in |=*/ copy_input_until_stop(s); - //#if (s->mode != BZ_M_RUNNING && s->avail_in_expect == 0) { - if (s->mode != BZ_M_RUNNING && s->strm->avail_in == 0) { - flush_RL(s); - BZ2_compressBlock(s, (s->mode == BZ_M_FINISHING)); - s->state = BZ_S_OUTPUT; - } else - if (s->nblock >= s->nblockMAX) { - BZ2_compressBlock(s, 0); - s->state = BZ_S_OUTPUT; - } else - if (s->strm->avail_in == 0) { - break; - } - } - } - - /*return progress_in || progress_out;*/ -} - - -/*---------------------------------------------------*/ -static -int BZ2_bzCompress(bz_stream *strm, int action) -{ - /*Bool progress;*/ - EState* s; - - s = strm->state; - - switch (s->mode) { - case BZ_M_RUNNING: - if (action == BZ_RUN) { - /*progress =*/ handle_compress(strm); - /*return progress ? BZ_RUN_OK : BZ_PARAM_ERROR;*/ - return BZ_RUN_OK; - } -#ifdef FLUSH_IS_UNUSED - else - if (action == BZ_FLUSH) { - //#s->avail_in_expect = strm->avail_in; - s->mode = BZ_M_FLUSHING; - goto case_BZ_M_FLUSHING; - } -#endif - else - /*if (action == BZ_FINISH)*/ { - //#s->avail_in_expect = strm->avail_in; - s->mode = BZ_M_FINISHING; - goto case_BZ_M_FINISHING; - } - -#ifdef FLUSH_IS_UNUSED - case_BZ_M_FLUSHING: - case BZ_M_FLUSHING: - /*if (s->avail_in_expect != s->strm->avail_in) - return BZ_SEQUENCE_ERROR;*/ - /*progress =*/ handle_compress(strm); - if (s->avail_in_expect > 0 || !isempty_RL(s) || s->state_out_pos < s->numZ) - return BZ_FLUSH_OK; - s->mode = BZ_M_RUNNING; - return BZ_RUN_OK; -#endif - - case_BZ_M_FINISHING: - /*case BZ_M_FINISHING:*/ - default: - /*if (s->avail_in_expect != s->strm->avail_in) - return BZ_SEQUENCE_ERROR;*/ - /*progress =*/ handle_compress(strm); - /*if (!progress) return BZ_SEQUENCE_ERROR;*/ - //#if (s->avail_in_expect > 0 || !isempty_RL(s) || s->state_out_pos < s->numZ) - //# return BZ_FINISH_OK; - if (s->strm->avail_in > 0 || !isempty_RL(s) || s->state_out_pos < s->numZ) - return BZ_FINISH_OK; - /*s->mode = BZ_M_IDLE;*/ - return BZ_STREAM_END; - } - /* return BZ_OK; --not reached--*/ -} - - -/*---------------------------------------------------*/ -#if ENABLE_FEATURE_CLEAN_UP -static -void BZ2_bzCompressEnd(bz_stream *strm) -{ - EState* s; - - s = strm->state; - free(s->arr1); - free(s->arr2); - free(s->ftab); - free(s->crc32table); - free(strm->state); -} -#endif - - -/*---------------------------------------------------*/ -/*--- Misc convenience stuff ---*/ -/*---------------------------------------------------*/ - -/*---------------------------------------------------*/ -#ifdef EXAMPLE_CODE_FOR_MEM_TO_MEM_COMPRESSION -static -int BZ2_bzBuffToBuffCompress(char* dest, - unsigned int* destLen, - char* source, - unsigned int sourceLen, - int blockSize100k) -{ - bz_stream strm; - int ret; - - if (dest == NULL || destLen == NULL - || source == NULL - || blockSize100k < 1 || blockSize100k > 9 - ) { - return BZ_PARAM_ERROR; - } - - BZ2_bzCompressInit(&strm, blockSize100k); - - strm.next_in = source; - strm.next_out = dest; - strm.avail_in = sourceLen; - strm.avail_out = *destLen; - - ret = BZ2_bzCompress(&strm, BZ_FINISH); - if (ret == BZ_FINISH_OK) goto output_overflow; - if (ret != BZ_STREAM_END) goto errhandler; - - /* normal termination */ - *destLen -= strm.avail_out; - BZ2_bzCompressEnd(&strm); - return BZ_OK; - - output_overflow: - BZ2_bzCompressEnd(&strm); - return BZ_OUTBUFF_FULL; - - errhandler: - BZ2_bzCompressEnd(&strm); - return ret; -} -#endif - -/*-------------------------------------------------------------*/ -/*--- end bzlib.c ---*/ -/*-------------------------------------------------------------*/ diff --git a/archival/bz/bzlib.h b/archival/bz/bzlib.h deleted file mode 100644 index 1bb811c4a..000000000 --- a/archival/bz/bzlib.h +++ /dev/null @@ -1,65 +0,0 @@ -/* - * bzip2 is written by Julian Seward . - * Adapted for busybox by Denys Vlasenko . - * See README and LICENSE files in this directory for more information. - */ - -/*-------------------------------------------------------------*/ -/*--- Public header file for the library. ---*/ -/*--- bzlib.h ---*/ -/*-------------------------------------------------------------*/ - -/* ------------------------------------------------------------------ -This file is part of bzip2/libbzip2, a program and library for -lossless, block-sorting data compression. - -bzip2/libbzip2 version 1.0.4 of 20 December 2006 -Copyright (C) 1996-2006 Julian Seward - -Please read the WARNING, DISCLAIMER and PATENTS sections in the -README file. - -This program is released under the terms of the license contained -in the file LICENSE. ------------------------------------------------------------------- */ - -#define BZ_RUN 0 -#define BZ_FLUSH 1 -#define BZ_FINISH 2 - -#define BZ_OK 0 -#define BZ_RUN_OK 1 -#define BZ_FLUSH_OK 2 -#define BZ_FINISH_OK 3 -#define BZ_STREAM_END 4 -#define BZ_SEQUENCE_ERROR (-1) -#define BZ_PARAM_ERROR (-2) -#define BZ_MEM_ERROR (-3) -#define BZ_DATA_ERROR (-4) -#define BZ_DATA_ERROR_MAGIC (-5) -#define BZ_IO_ERROR (-6) -#define BZ_UNEXPECTED_EOF (-7) -#define BZ_OUTBUFF_FULL (-8) -#define BZ_CONFIG_ERROR (-9) - -typedef struct bz_stream { - void *state; - char *next_in; - char *next_out; - unsigned avail_in; - unsigned avail_out; - /*unsigned long long total_in;*/ - unsigned long long total_out; -} bz_stream; - -/*-- Core (low-level) library functions --*/ - -static void BZ2_bzCompressInit(bz_stream *strm, int blockSize100k); -static int BZ2_bzCompress(bz_stream *strm, int action); -#if ENABLE_FEATURE_CLEAN_UP -static void BZ2_bzCompressEnd(bz_stream *strm); -#endif - -/*-------------------------------------------------------------*/ -/*--- end bzlib.h ---*/ -/*-------------------------------------------------------------*/ diff --git a/archival/bz/bzlib_private.h b/archival/bz/bzlib_private.h deleted file mode 100644 index 6430ce407..000000000 --- a/archival/bz/bzlib_private.h +++ /dev/null @@ -1,219 +0,0 @@ -/* - * bzip2 is written by Julian Seward . - * Adapted for busybox by Denys Vlasenko . - * See README and LICENSE files in this directory for more information. - */ - -/*-------------------------------------------------------------*/ -/*--- Private header file for the library. ---*/ -/*--- bzlib_private.h ---*/ -/*-------------------------------------------------------------*/ - -/* ------------------------------------------------------------------ -This file is part of bzip2/libbzip2, a program and library for -lossless, block-sorting data compression. - -bzip2/libbzip2 version 1.0.4 of 20 December 2006 -Copyright (C) 1996-2006 Julian Seward - -Please read the WARNING, DISCLAIMER and PATENTS sections in the -README file. - -This program is released under the terms of the license contained -in the file LICENSE. ------------------------------------------------------------------- */ - -/* #include "bzlib.h" */ - -/*-- General stuff. --*/ - -typedef unsigned char Bool; - -#define True ((Bool)1) -#define False ((Bool)0) - -#if BZ_LIGHT_DEBUG -static void bz_assert_fail(int errcode) NORETURN; -#define AssertH(cond, errcode) \ -do { \ - if (!(cond)) \ - bz_assert_fail(errcode); \ -} while (0) -#else -#define AssertH(cond, msg) do { } while (0) -#endif - -#if BZ_DEBUG -#define AssertD(cond, msg) \ -do { \ - if (!(cond)) \ - bb_error_msg_and_die("(debug build): internal error %s", msg); \ -} while (0) -#else -#define AssertD(cond, msg) do { } while (0) -#endif - - -/*-- Header bytes. --*/ - -#define BZ_HDR_B 0x42 /* 'B' */ -#define BZ_HDR_Z 0x5a /* 'Z' */ -#define BZ_HDR_h 0x68 /* 'h' */ -#define BZ_HDR_0 0x30 /* '0' */ - -#define BZ_HDR_BZh0 0x425a6830 - -/*-- Constants for the back end. --*/ - -#define BZ_MAX_ALPHA_SIZE 258 -#define BZ_MAX_CODE_LEN 23 - -#define BZ_RUNA 0 -#define BZ_RUNB 1 - -#define BZ_N_GROUPS 6 -#define BZ_G_SIZE 50 -#define BZ_N_ITERS 4 - -#define BZ_MAX_SELECTORS (2 + (900000 / BZ_G_SIZE)) - - -/*-- Stuff for doing CRCs. --*/ - -#define BZ_INITIALISE_CRC(crcVar) \ -{ \ - crcVar = 0xffffffffL; \ -} - -#define BZ_FINALISE_CRC(crcVar) \ -{ \ - crcVar = ~(crcVar); \ -} - -#define BZ_UPDATE_CRC(s, crcVar, cha) \ -{ \ - crcVar = (crcVar << 8) ^ s->crc32table[(crcVar >> 24) ^ ((uint8_t)cha)]; \ -} - - -/*-- States and modes for compression. --*/ - -#define BZ_M_IDLE 1 -#define BZ_M_RUNNING 2 -#define BZ_M_FLUSHING 3 -#define BZ_M_FINISHING 4 - -#define BZ_S_OUTPUT 1 -#define BZ_S_INPUT 2 - -#define BZ_N_RADIX 2 -#define BZ_N_QSORT 12 -#define BZ_N_SHELL 18 -#define BZ_N_OVERSHOOT (BZ_N_RADIX + BZ_N_QSORT + BZ_N_SHELL + 2) - - -/*-- Structure holding all the compression-side stuff. --*/ - -typedef struct EState { - /* pointer back to the struct bz_stream */ - bz_stream *strm; - - /* mode this stream is in, and whether inputting */ - /* or outputting data */ - int32_t mode; - int32_t state; - - /* remembers avail_in when flush/finish requested */ -/* bbox: not needed, strm->avail_in always has the same value */ -/* commented out with '//#' throughout the code */ - /* uint32_t avail_in_expect; */ - - /* for doing the block sorting */ - int32_t origPtr; - uint32_t *arr1; - uint32_t *arr2; - uint32_t *ftab; - - /* aliases for arr1 and arr2 */ - uint32_t *ptr; - uint8_t *block; - uint16_t *mtfv; - uint8_t *zbits; - - /* guess what */ - uint32_t *crc32table; - - /* run-length-encoding of the input */ - uint32_t state_in_ch; - int32_t state_in_len; - - /* input and output limits and current posns */ - int32_t nblock; - int32_t nblockMAX; - int32_t numZ; - int32_t state_out_pos; - - /* the buffer for bit stream creation */ - uint32_t bsBuff; - int32_t bsLive; - - /* block and combined CRCs */ - uint32_t blockCRC; - uint32_t combinedCRC; - - /* misc administratium */ - int32_t blockNo; - int32_t blockSize100k; - - /* stuff for coding the MTF values */ - int32_t nMTF; - - /* map of bytes used in block */ - int32_t nInUse; - Bool inUse[256] ALIGNED(sizeof(long)); - uint8_t unseqToSeq[256]; - - /* stuff for coding the MTF values */ - int32_t mtfFreq [BZ_MAX_ALPHA_SIZE]; - uint8_t selector [BZ_MAX_SELECTORS]; - uint8_t selectorMtf[BZ_MAX_SELECTORS]; - - uint8_t len[BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE]; - - /* stack-saving measures: these can be local, but they are too big */ - int32_t sendMTFValues__code [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE]; - int32_t sendMTFValues__rfreq[BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE]; -#if CONFIG_BZIP2_FEATURE_SPEED >= 5 - /* second dimension: only 3 needed; 4 makes index calculations faster */ - uint32_t sendMTFValues__len_pack[BZ_MAX_ALPHA_SIZE][4]; -#endif - int32_t BZ2_hbMakeCodeLengths__heap [BZ_MAX_ALPHA_SIZE + 2]; - int32_t BZ2_hbMakeCodeLengths__weight[BZ_MAX_ALPHA_SIZE * 2]; - int32_t BZ2_hbMakeCodeLengths__parent[BZ_MAX_ALPHA_SIZE * 2]; - - int32_t mainSort__runningOrder[256]; - int32_t mainSort__copyStart[256]; - int32_t mainSort__copyEnd[256]; -} EState; - - -/*-- compression. --*/ - -static void -BZ2_blockSort(EState*); - -static void -BZ2_compressBlock(EState*, int); - -static void -BZ2_bsInitWrite(EState*); - -static void -BZ2_hbAssignCodes(int32_t*, uint8_t*, int32_t, int32_t, int32_t); - -static void -BZ2_hbMakeCodeLengths(EState*, uint8_t*, int32_t*, int32_t, int32_t); - -/*-------------------------------------------------------------*/ -/*--- end bzlib_private.h ---*/ -/*-------------------------------------------------------------*/ diff --git a/archival/bz/compress.c b/archival/bz/compress.c deleted file mode 100644 index 6f1c70a08..000000000 --- a/archival/bz/compress.c +++ /dev/null @@ -1,685 +0,0 @@ -/* - * bzip2 is written by Julian Seward . - * Adapted for busybox by Denys Vlasenko . - * See README and LICENSE files in this directory for more information. - */ - -/*-------------------------------------------------------------*/ -/*--- Compression machinery (not incl block sorting) ---*/ -/*--- compress.c ---*/ -/*-------------------------------------------------------------*/ - -/* ------------------------------------------------------------------ -This file is part of bzip2/libbzip2, a program and library for -lossless, block-sorting data compression. - -bzip2/libbzip2 version 1.0.4 of 20 December 2006 -Copyright (C) 1996-2006 Julian Seward - -Please read the WARNING, DISCLAIMER and PATENTS sections in the -README file. - -This program is released under the terms of the license contained -in the file LICENSE. ------------------------------------------------------------------- */ - -/* CHANGES - * 0.9.0 -- original version. - * 0.9.0a/b -- no changes in this file. - * 0.9.0c -- changed setting of nGroups in sendMTFValues() - * so as to do a bit better on small files -*/ - -/* #include "bzlib_private.h" */ - -/*---------------------------------------------------*/ -/*--- Bit stream I/O ---*/ -/*---------------------------------------------------*/ - -/*---------------------------------------------------*/ -static -void BZ2_bsInitWrite(EState* s) -{ - s->bsLive = 0; - s->bsBuff = 0; -} - - -/*---------------------------------------------------*/ -static NOINLINE -void bsFinishWrite(EState* s) -{ - while (s->bsLive > 0) { - s->zbits[s->numZ] = (uint8_t)(s->bsBuff >> 24); - s->numZ++; - s->bsBuff <<= 8; - s->bsLive -= 8; - } -} - - -/*---------------------------------------------------*/ -static -/* Helps only on level 5, on other levels hurts. ? */ -#if CONFIG_BZIP2_FEATURE_SPEED >= 5 -ALWAYS_INLINE -#endif -void bsW(EState* s, int32_t n, uint32_t v) -{ - while (s->bsLive >= 8) { - s->zbits[s->numZ] = (uint8_t)(s->bsBuff >> 24); - s->numZ++; - s->bsBuff <<= 8; - s->bsLive -= 8; - } - s->bsBuff |= (v << (32 - s->bsLive - n)); - s->bsLive += n; -} - - -/*---------------------------------------------------*/ -static -void bsPutU32(EState* s, unsigned u) -{ - bsW(s, 8, (u >> 24) & 0xff); - bsW(s, 8, (u >> 16) & 0xff); - bsW(s, 8, (u >> 8) & 0xff); - bsW(s, 8, u & 0xff); -} - - -/*---------------------------------------------------*/ -static -void bsPutU16(EState* s, unsigned u) -{ - bsW(s, 8, (u >> 8) & 0xff); - bsW(s, 8, u & 0xff); -} - - -/*---------------------------------------------------*/ -/*--- The back end proper ---*/ -/*---------------------------------------------------*/ - -/*---------------------------------------------------*/ -static -void makeMaps_e(EState* s) -{ - int i; - s->nInUse = 0; - for (i = 0; i < 256; i++) { - if (s->inUse[i]) { - s->unseqToSeq[i] = s->nInUse; - s->nInUse++; - } - } -} - - -/*---------------------------------------------------*/ -static NOINLINE -void generateMTFValues(EState* s) -{ - uint8_t yy[256]; - int32_t i, j; - int32_t zPend; - int32_t wr; - int32_t EOB; - - /* - * After sorting (eg, here), - * s->arr1[0 .. s->nblock-1] holds sorted order, - * and - * ((uint8_t*)s->arr2)[0 .. s->nblock-1] - * holds the original block data. - * - * The first thing to do is generate the MTF values, - * and put them in ((uint16_t*)s->arr1)[0 .. s->nblock-1]. - * - * Because there are strictly fewer or equal MTF values - * than block values, ptr values in this area are overwritten - * with MTF values only when they are no longer needed. - * - * The final compressed bitstream is generated into the - * area starting at &((uint8_t*)s->arr2)[s->nblock] - * - * These storage aliases are set up in bzCompressInit(), - * except for the last one, which is arranged in - * compressBlock(). - */ - uint32_t* ptr = s->ptr; - uint8_t* block = s->block; - uint16_t* mtfv = s->mtfv; - - makeMaps_e(s); - EOB = s->nInUse+1; - - for (i = 0; i <= EOB; i++) - s->mtfFreq[i] = 0; - - wr = 0; - zPend = 0; - for (i = 0; i < s->nInUse; i++) - yy[i] = (uint8_t) i; - - for (i = 0; i < s->nblock; i++) { - uint8_t ll_i; - AssertD(wr <= i, "generateMTFValues(1)"); - j = ptr[i] - 1; - if (j < 0) - j += s->nblock; - ll_i = s->unseqToSeq[block[j]]; - AssertD(ll_i < s->nInUse, "generateMTFValues(2a)"); - - if (yy[0] == ll_i) { - zPend++; - } else { - if (zPend > 0) { - zPend--; - while (1) { - if (zPend & 1) { - mtfv[wr] = BZ_RUNB; wr++; - s->mtfFreq[BZ_RUNB]++; - } else { - mtfv[wr] = BZ_RUNA; wr++; - s->mtfFreq[BZ_RUNA]++; - } - if (zPend < 2) break; - zPend = (uint32_t)(zPend - 2) / 2; - /* bbox: unsigned div is easier */ - }; - zPend = 0; - } - { - register uint8_t rtmp; - register uint8_t* ryy_j; - register uint8_t rll_i; - rtmp = yy[1]; - yy[1] = yy[0]; - ryy_j = &(yy[1]); - rll_i = ll_i; - while (rll_i != rtmp) { - register uint8_t rtmp2; - ryy_j++; - rtmp2 = rtmp; - rtmp = *ryy_j; - *ryy_j = rtmp2; - }; - yy[0] = rtmp; - j = ryy_j - &(yy[0]); - mtfv[wr] = j+1; - wr++; - s->mtfFreq[j+1]++; - } - } - } - - if (zPend > 0) { - zPend--; - while (1) { - if (zPend & 1) { - mtfv[wr] = BZ_RUNB; - wr++; - s->mtfFreq[BZ_RUNB]++; - } else { - mtfv[wr] = BZ_RUNA; - wr++; - s->mtfFreq[BZ_RUNA]++; - } - if (zPend < 2) - break; - zPend = (uint32_t)(zPend - 2) / 2; - /* bbox: unsigned div is easier */ - }; - zPend = 0; - } - - mtfv[wr] = EOB; - wr++; - s->mtfFreq[EOB]++; - - s->nMTF = wr; -} - - -/*---------------------------------------------------*/ -#define BZ_LESSER_ICOST 0 -#define BZ_GREATER_ICOST 15 - -static NOINLINE -void sendMTFValues(EState* s) -{ - int32_t v, t, i, j, gs, ge, totc, bt, bc, iter; - int32_t nSelectors, alphaSize, minLen, maxLen, selCtr; - int32_t nGroups, nBytes; - - /* - * uint8_t len[BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE]; - * is a global since the decoder also needs it. - * - * int32_t code[BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE]; - * int32_t rfreq[BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE]; - * are also globals only used in this proc. - * Made global to keep stack frame size small. - */ -#define code sendMTFValues__code -#define rfreq sendMTFValues__rfreq -#define len_pack sendMTFValues__len_pack - - uint16_t cost[BZ_N_GROUPS]; - int32_t fave[BZ_N_GROUPS]; - - uint16_t* mtfv = s->mtfv; - - alphaSize = s->nInUse + 2; - for (t = 0; t < BZ_N_GROUPS; t++) - for (v = 0; v < alphaSize; v++) - s->len[t][v] = BZ_GREATER_ICOST; - - /*--- Decide how many coding tables to use ---*/ - AssertH(s->nMTF > 0, 3001); - if (s->nMTF < 200) nGroups = 2; else - if (s->nMTF < 600) nGroups = 3; else - if (s->nMTF < 1200) nGroups = 4; else - if (s->nMTF < 2400) nGroups = 5; else - nGroups = 6; - - /*--- Generate an initial set of coding tables ---*/ - { - int32_t nPart, remF, tFreq, aFreq; - - nPart = nGroups; - remF = s->nMTF; - gs = 0; - while (nPart > 0) { - tFreq = remF / nPart; - ge = gs - 1; - aFreq = 0; - while (aFreq < tFreq && ge < alphaSize-1) { - ge++; - aFreq += s->mtfFreq[ge]; - } - - if (ge > gs - && nPart != nGroups && nPart != 1 - && ((nGroups - nPart) % 2 == 1) /* bbox: can this be replaced by x & 1? */ - ) { - aFreq -= s->mtfFreq[ge]; - ge--; - } - - for (v = 0; v < alphaSize; v++) - if (v >= gs && v <= ge) - s->len[nPart-1][v] = BZ_LESSER_ICOST; - else - s->len[nPart-1][v] = BZ_GREATER_ICOST; - - nPart--; - gs = ge + 1; - remF -= aFreq; - } - } - - /* - * Iterate up to BZ_N_ITERS times to improve the tables. - */ - for (iter = 0; iter < BZ_N_ITERS; iter++) { - for (t = 0; t < nGroups; t++) - fave[t] = 0; - - for (t = 0; t < nGroups; t++) - for (v = 0; v < alphaSize; v++) - s->rfreq[t][v] = 0; - -#if CONFIG_BZIP2_FEATURE_SPEED >= 5 - /* - * Set up an auxiliary length table which is used to fast-track - * the common case (nGroups == 6). - */ - if (nGroups == 6) { - for (v = 0; v < alphaSize; v++) { - s->len_pack[v][0] = (s->len[1][v] << 16) | s->len[0][v]; - s->len_pack[v][1] = (s->len[3][v] << 16) | s->len[2][v]; - s->len_pack[v][2] = (s->len[5][v] << 16) | s->len[4][v]; - } - } -#endif - nSelectors = 0; - totc = 0; - gs = 0; - while (1) { - /*--- Set group start & end marks. --*/ - if (gs >= s->nMTF) - break; - ge = gs + BZ_G_SIZE - 1; - if (ge >= s->nMTF) - ge = s->nMTF-1; - - /* - * Calculate the cost of this group as coded - * by each of the coding tables. - */ - for (t = 0; t < nGroups; t++) - cost[t] = 0; -#if CONFIG_BZIP2_FEATURE_SPEED >= 5 - if (nGroups == 6 && 50 == ge-gs+1) { - /*--- fast track the common case ---*/ - register uint32_t cost01, cost23, cost45; - register uint16_t icv; - cost01 = cost23 = cost45 = 0; -#define BZ_ITER(nn) \ - icv = mtfv[gs+(nn)]; \ - cost01 += s->len_pack[icv][0]; \ - cost23 += s->len_pack[icv][1]; \ - cost45 += s->len_pack[icv][2]; - BZ_ITER(0); BZ_ITER(1); BZ_ITER(2); BZ_ITER(3); BZ_ITER(4); - BZ_ITER(5); BZ_ITER(6); BZ_ITER(7); BZ_ITER(8); BZ_ITER(9); - BZ_ITER(10); BZ_ITER(11); BZ_ITER(12); BZ_ITER(13); BZ_ITER(14); - BZ_ITER(15); BZ_ITER(16); BZ_ITER(17); BZ_ITER(18); BZ_ITER(19); - BZ_ITER(20); BZ_ITER(21); BZ_ITER(22); BZ_ITER(23); BZ_ITER(24); - BZ_ITER(25); BZ_ITER(26); BZ_ITER(27); BZ_ITER(28); BZ_ITER(29); - BZ_ITER(30); BZ_ITER(31); BZ_ITER(32); BZ_ITER(33); BZ_ITER(34); - BZ_ITER(35); BZ_ITER(36); BZ_ITER(37); BZ_ITER(38); BZ_ITER(39); - BZ_ITER(40); BZ_ITER(41); BZ_ITER(42); BZ_ITER(43); BZ_ITER(44); - BZ_ITER(45); BZ_ITER(46); BZ_ITER(47); BZ_ITER(48); BZ_ITER(49); -#undef BZ_ITER - cost[0] = cost01 & 0xffff; cost[1] = cost01 >> 16; - cost[2] = cost23 & 0xffff; cost[3] = cost23 >> 16; - cost[4] = cost45 & 0xffff; cost[5] = cost45 >> 16; - - } else -#endif - { - /*--- slow version which correctly handles all situations ---*/ - for (i = gs; i <= ge; i++) { - uint16_t icv = mtfv[i]; - for (t = 0; t < nGroups; t++) - cost[t] += s->len[t][icv]; - } - } - /* - * Find the coding table which is best for this group, - * and record its identity in the selector table. - */ - /*bc = 999999999;*/ - /*bt = -1;*/ - bc = cost[0]; - bt = 0; - for (t = 1 /*0*/; t < nGroups; t++) { - if (cost[t] < bc) { - bc = cost[t]; - bt = t; - } - } - totc += bc; - fave[bt]++; - s->selector[nSelectors] = bt; - nSelectors++; - - /* - * Increment the symbol frequencies for the selected table. - */ -/* 1% faster compress. +800 bytes */ -#if CONFIG_BZIP2_FEATURE_SPEED >= 4 - if (nGroups == 6 && 50 == ge-gs+1) { - /*--- fast track the common case ---*/ -#define BZ_ITUR(nn) s->rfreq[bt][mtfv[gs + (nn)]]++ - BZ_ITUR(0); BZ_ITUR(1); BZ_ITUR(2); BZ_ITUR(3); BZ_ITUR(4); - BZ_ITUR(5); BZ_ITUR(6); BZ_ITUR(7); BZ_ITUR(8); BZ_ITUR(9); - BZ_ITUR(10); BZ_ITUR(11); BZ_ITUR(12); BZ_ITUR(13); BZ_ITUR(14); - BZ_ITUR(15); BZ_ITUR(16); BZ_ITUR(17); BZ_ITUR(18); BZ_ITUR(19); - BZ_ITUR(20); BZ_ITUR(21); BZ_ITUR(22); BZ_ITUR(23); BZ_ITUR(24); - BZ_ITUR(25); BZ_ITUR(26); BZ_ITUR(27); BZ_ITUR(28); BZ_ITUR(29); - BZ_ITUR(30); BZ_ITUR(31); BZ_ITUR(32); BZ_ITUR(33); BZ_ITUR(34); - BZ_ITUR(35); BZ_ITUR(36); BZ_ITUR(37); BZ_ITUR(38); BZ_ITUR(39); - BZ_ITUR(40); BZ_ITUR(41); BZ_ITUR(42); BZ_ITUR(43); BZ_ITUR(44); - BZ_ITUR(45); BZ_ITUR(46); BZ_ITUR(47); BZ_ITUR(48); BZ_ITUR(49); -#undef BZ_ITUR - gs = ge + 1; - } else -#endif - { - /*--- slow version which correctly handles all situations ---*/ - while (gs <= ge) { - s->rfreq[bt][mtfv[gs]]++; - gs++; - } - /* already is: gs = ge + 1; */ - } - } - - /* - * Recompute the tables based on the accumulated frequencies. - */ - /* maxLen was changed from 20 to 17 in bzip2-1.0.3. See - * comment in huffman.c for details. */ - for (t = 0; t < nGroups; t++) - BZ2_hbMakeCodeLengths(s, &(s->len[t][0]), &(s->rfreq[t][0]), alphaSize, 17 /*20*/); - } - - AssertH(nGroups < 8, 3002); - AssertH(nSelectors < 32768 && nSelectors <= (2 + (900000 / BZ_G_SIZE)), 3003); - - /*--- Compute MTF values for the selectors. ---*/ - { - uint8_t pos[BZ_N_GROUPS], ll_i, tmp2, tmp; - - for (i = 0; i < nGroups; i++) - pos[i] = i; - for (i = 0; i < nSelectors; i++) { - ll_i = s->selector[i]; - j = 0; - tmp = pos[j]; - while (ll_i != tmp) { - j++; - tmp2 = tmp; - tmp = pos[j]; - pos[j] = tmp2; - }; - pos[0] = tmp; - s->selectorMtf[i] = j; - } - }; - - /*--- Assign actual codes for the tables. --*/ - for (t = 0; t < nGroups; t++) { - minLen = 32; - maxLen = 0; - for (i = 0; i < alphaSize; i++) { - if (s->len[t][i] > maxLen) maxLen = s->len[t][i]; - if (s->len[t][i] < minLen) minLen = s->len[t][i]; - } - AssertH(!(maxLen > 17 /*20*/), 3004); - AssertH(!(minLen < 1), 3005); - BZ2_hbAssignCodes(&(s->code[t][0]), &(s->len[t][0]), minLen, maxLen, alphaSize); - } - - /*--- Transmit the mapping table. ---*/ - { - /* bbox: optimized a bit more than in bzip2 */ - int inUse16 = 0; - for (i = 0; i < 16; i++) { - if (sizeof(long) <= 4) { - inUse16 = inUse16*2 + - ((*(uint32_t*)&(s->inUse[i * 16 + 0]) - | *(uint32_t*)&(s->inUse[i * 16 + 4]) - | *(uint32_t*)&(s->inUse[i * 16 + 8]) - | *(uint32_t*)&(s->inUse[i * 16 + 12])) != 0); - } else { /* Our CPU can do better */ - inUse16 = inUse16*2 + - ((*(uint64_t*)&(s->inUse[i * 16 + 0]) - | *(uint64_t*)&(s->inUse[i * 16 + 8])) != 0); - } - } - - nBytes = s->numZ; - bsW(s, 16, inUse16); - - inUse16 <<= (sizeof(int)*8 - 16); /* move 15th bit into sign bit */ - for (i = 0; i < 16; i++) { - if (inUse16 < 0) { - unsigned v16 = 0; - for (j = 0; j < 16; j++) - v16 = v16*2 + s->inUse[i * 16 + j]; - bsW(s, 16, v16); - } - inUse16 <<= 1; - } - } - - /*--- Now the selectors. ---*/ - nBytes = s->numZ; - bsW(s, 3, nGroups); - bsW(s, 15, nSelectors); - for (i = 0; i < nSelectors; i++) { - for (j = 0; j < s->selectorMtf[i]; j++) - bsW(s, 1, 1); - bsW(s, 1, 0); - } - - /*--- Now the coding tables. ---*/ - nBytes = s->numZ; - - for (t = 0; t < nGroups; t++) { - int32_t curr = s->len[t][0]; - bsW(s, 5, curr); - for (i = 0; i < alphaSize; i++) { - while (curr < s->len[t][i]) { bsW(s, 2, 2); curr++; /* 10 */ }; - while (curr > s->len[t][i]) { bsW(s, 2, 3); curr--; /* 11 */ }; - bsW(s, 1, 0); - } - } - - /*--- And finally, the block data proper ---*/ - nBytes = s->numZ; - selCtr = 0; - gs = 0; - while (1) { - if (gs >= s->nMTF) - break; - ge = gs + BZ_G_SIZE - 1; - if (ge >= s->nMTF) - ge = s->nMTF-1; - AssertH(s->selector[selCtr] < nGroups, 3006); - -/* Costs 1300 bytes and is _slower_ (on Intel Core 2) */ -#if 0 - if (nGroups == 6 && 50 == ge-gs+1) { - /*--- fast track the common case ---*/ - uint16_t mtfv_i; - uint8_t* s_len_sel_selCtr = &(s->len[s->selector[selCtr]][0]); - int32_t* s_code_sel_selCtr = &(s->code[s->selector[selCtr]][0]); -#define BZ_ITAH(nn) \ - mtfv_i = mtfv[gs+(nn)]; \ - bsW(s, s_len_sel_selCtr[mtfv_i], s_code_sel_selCtr[mtfv_i]) - BZ_ITAH(0); BZ_ITAH(1); BZ_ITAH(2); BZ_ITAH(3); BZ_ITAH(4); - BZ_ITAH(5); BZ_ITAH(6); BZ_ITAH(7); BZ_ITAH(8); BZ_ITAH(9); - BZ_ITAH(10); BZ_ITAH(11); BZ_ITAH(12); BZ_ITAH(13); BZ_ITAH(14); - BZ_ITAH(15); BZ_ITAH(16); BZ_ITAH(17); BZ_ITAH(18); BZ_ITAH(19); - BZ_ITAH(20); BZ_ITAH(21); BZ_ITAH(22); BZ_ITAH(23); BZ_ITAH(24); - BZ_ITAH(25); BZ_ITAH(26); BZ_ITAH(27); BZ_ITAH(28); BZ_ITAH(29); - BZ_ITAH(30); BZ_ITAH(31); BZ_ITAH(32); BZ_ITAH(33); BZ_ITAH(34); - BZ_ITAH(35); BZ_ITAH(36); BZ_ITAH(37); BZ_ITAH(38); BZ_ITAH(39); - BZ_ITAH(40); BZ_ITAH(41); BZ_ITAH(42); BZ_ITAH(43); BZ_ITAH(44); - BZ_ITAH(45); BZ_ITAH(46); BZ_ITAH(47); BZ_ITAH(48); BZ_ITAH(49); -#undef BZ_ITAH - gs = ge+1; - } else -#endif - { - /*--- slow version which correctly handles all situations ---*/ - /* code is bit bigger, but moves multiply out of the loop */ - uint8_t* s_len_sel_selCtr = &(s->len [s->selector[selCtr]][0]); - int32_t* s_code_sel_selCtr = &(s->code[s->selector[selCtr]][0]); - while (gs <= ge) { - bsW(s, - s_len_sel_selCtr[mtfv[gs]], - s_code_sel_selCtr[mtfv[gs]] - ); - gs++; - } - /* already is: gs = ge+1; */ - } - selCtr++; - } - AssertH(selCtr == nSelectors, 3007); -#undef code -#undef rfreq -#undef len_pack -} - - -/*---------------------------------------------------*/ -static -void BZ2_compressBlock(EState* s, int is_last_block) -{ - if (s->nblock > 0) { - BZ_FINALISE_CRC(s->blockCRC); - s->combinedCRC = (s->combinedCRC << 1) | (s->combinedCRC >> 31); - s->combinedCRC ^= s->blockCRC; - if (s->blockNo > 1) - s->numZ = 0; - - BZ2_blockSort(s); - } - - s->zbits = &((uint8_t*)s->arr2)[s->nblock]; - - /*-- If this is the first block, create the stream header. --*/ - if (s->blockNo == 1) { - BZ2_bsInitWrite(s); - /*bsPutU8(s, BZ_HDR_B);*/ - /*bsPutU8(s, BZ_HDR_Z);*/ - /*bsPutU8(s, BZ_HDR_h);*/ - /*bsPutU8(s, BZ_HDR_0 + s->blockSize100k);*/ - bsPutU32(s, BZ_HDR_BZh0 + s->blockSize100k); - } - - if (s->nblock > 0) { - /*bsPutU8(s, 0x31);*/ - /*bsPutU8(s, 0x41);*/ - /*bsPutU8(s, 0x59);*/ - /*bsPutU8(s, 0x26);*/ - bsPutU32(s, 0x31415926); - /*bsPutU8(s, 0x53);*/ - /*bsPutU8(s, 0x59);*/ - bsPutU16(s, 0x5359); - - /*-- Now the block's CRC, so it is in a known place. --*/ - bsPutU32(s, s->blockCRC); - - /* - * Now a single bit indicating (non-)randomisation. - * As of version 0.9.5, we use a better sorting algorithm - * which makes randomisation unnecessary. So always set - * the randomised bit to 'no'. Of course, the decoder - * still needs to be able to handle randomised blocks - * so as to maintain backwards compatibility with - * older versions of bzip2. - */ - bsW(s, 1, 0); - - bsW(s, 24, s->origPtr); - generateMTFValues(s); - sendMTFValues(s); - } - - /*-- If this is the last block, add the stream trailer. --*/ - if (is_last_block) { - /*bsPutU8(s, 0x17);*/ - /*bsPutU8(s, 0x72);*/ - /*bsPutU8(s, 0x45);*/ - /*bsPutU8(s, 0x38);*/ - bsPutU32(s, 0x17724538); - /*bsPutU8(s, 0x50);*/ - /*bsPutU8(s, 0x90);*/ - bsPutU16(s, 0x5090); - bsPutU32(s, s->combinedCRC); - bsFinishWrite(s); - } -} - - -/*-------------------------------------------------------------*/ -/*--- end compress.c ---*/ -/*-------------------------------------------------------------*/ diff --git a/archival/bz/huffman.c b/archival/bz/huffman.c deleted file mode 100644 index 676b1af66..000000000 --- a/archival/bz/huffman.c +++ /dev/null @@ -1,229 +0,0 @@ -/* - * bzip2 is written by Julian Seward . - * Adapted for busybox by Denys Vlasenko . - * See README and LICENSE files in this directory for more information. - */ - -/*-------------------------------------------------------------*/ -/*--- Huffman coding low-level stuff ---*/ -/*--- huffman.c ---*/ -/*-------------------------------------------------------------*/ - -/* ------------------------------------------------------------------ -This file is part of bzip2/libbzip2, a program and library for -lossless, block-sorting data compression. - -bzip2/libbzip2 version 1.0.4 of 20 December 2006 -Copyright (C) 1996-2006 Julian Seward - -Please read the WARNING, DISCLAIMER and PATENTS sections in the -README file. - -This program is released under the terms of the license contained -in the file LICENSE. ------------------------------------------------------------------- */ - -/* #include "bzlib_private.h" */ - -/*---------------------------------------------------*/ -#define WEIGHTOF(zz0) ((zz0) & 0xffffff00) -#define DEPTHOF(zz1) ((zz1) & 0x000000ff) -#define MYMAX(zz2,zz3) ((zz2) > (zz3) ? (zz2) : (zz3)) - -#define ADDWEIGHTS(zw1,zw2) \ - (WEIGHTOF(zw1)+WEIGHTOF(zw2)) | \ - (1 + MYMAX(DEPTHOF(zw1),DEPTHOF(zw2))) - -#define UPHEAP(z) \ -{ \ - int32_t zz, tmp; \ - zz = z; \ - tmp = heap[zz]; \ - while (weight[tmp] < weight[heap[zz >> 1]]) { \ - heap[zz] = heap[zz >> 1]; \ - zz >>= 1; \ - } \ - heap[zz] = tmp; \ -} - - -/* 90 bytes, 0.3% of overall compress speed */ -#if CONFIG_BZIP2_FEATURE_SPEED >= 1 - -/* macro works better than inline (gcc 4.2.1) */ -#define DOWNHEAP1(heap, weight, Heap) \ -{ \ - int32_t zz, yy, tmp; \ - zz = 1; \ - tmp = heap[zz]; \ - while (1) { \ - yy = zz << 1; \ - if (yy > nHeap) \ - break; \ - if (yy < nHeap \ - && weight[heap[yy+1]] < weight[heap[yy]]) \ - yy++; \ - if (weight[tmp] < weight[heap[yy]]) \ - break; \ - heap[zz] = heap[yy]; \ - zz = yy; \ - } \ - heap[zz] = tmp; \ -} - -#else - -static -void DOWNHEAP1(int32_t *heap, int32_t *weight, int32_t nHeap) -{ - int32_t zz, yy, tmp; - zz = 1; - tmp = heap[zz]; - while (1) { - yy = zz << 1; - if (yy > nHeap) - break; - if (yy < nHeap - && weight[heap[yy + 1]] < weight[heap[yy]]) - yy++; - if (weight[tmp] < weight[heap[yy]]) - break; - heap[zz] = heap[yy]; - zz = yy; - } - heap[zz] = tmp; -} - -#endif - -/*---------------------------------------------------*/ -static -void BZ2_hbMakeCodeLengths(EState *s, - uint8_t *len, - int32_t *freq, - int32_t alphaSize, - int32_t maxLen) -{ - /* - * Nodes and heap entries run from 1. Entry 0 - * for both the heap and nodes is a sentinel. - */ - int32_t nNodes, nHeap, n1, n2, i, j, k; - Bool tooLong; - - /* bbox: moved to EState to save stack - int32_t heap [BZ_MAX_ALPHA_SIZE + 2]; - int32_t weight[BZ_MAX_ALPHA_SIZE * 2]; - int32_t parent[BZ_MAX_ALPHA_SIZE * 2]; - */ -#define heap (s->BZ2_hbMakeCodeLengths__heap) -#define weight (s->BZ2_hbMakeCodeLengths__weight) -#define parent (s->BZ2_hbMakeCodeLengths__parent) - - for (i = 0; i < alphaSize; i++) - weight[i+1] = (freq[i] == 0 ? 1 : freq[i]) << 8; - - while (1) { - nNodes = alphaSize; - nHeap = 0; - - heap[0] = 0; - weight[0] = 0; - parent[0] = -2; - - for (i = 1; i <= alphaSize; i++) { - parent[i] = -1; - nHeap++; - heap[nHeap] = i; - UPHEAP(nHeap); - } - - AssertH(nHeap < (BZ_MAX_ALPHA_SIZE+2), 2001); - - while (nHeap > 1) { - n1 = heap[1]; heap[1] = heap[nHeap]; nHeap--; DOWNHEAP1(heap, weight, nHeap); - n2 = heap[1]; heap[1] = heap[nHeap]; nHeap--; DOWNHEAP1(heap, weight, nHeap); - nNodes++; - parent[n1] = parent[n2] = nNodes; - weight[nNodes] = ADDWEIGHTS(weight[n1], weight[n2]); - parent[nNodes] = -1; - nHeap++; - heap[nHeap] = nNodes; - UPHEAP(nHeap); - } - - AssertH(nNodes < (BZ_MAX_ALPHA_SIZE * 2), 2002); - - tooLong = False; - for (i = 1; i <= alphaSize; i++) { - j = 0; - k = i; - while (parent[k] >= 0) { - k = parent[k]; - j++; - } - len[i-1] = j; - if (j > maxLen) - tooLong = True; - } - - if (!tooLong) - break; - - /* 17 Oct 04: keep-going condition for the following loop used - to be 'i < alphaSize', which missed the last element, - theoretically leading to the possibility of the compressor - looping. However, this count-scaling step is only needed if - one of the generated Huffman code words is longer than - maxLen, which up to and including version 1.0.2 was 20 bits, - which is extremely unlikely. In version 1.0.3 maxLen was - changed to 17 bits, which has minimal effect on compression - ratio, but does mean this scaling step is used from time to - time, enough to verify that it works. - - This means that bzip2-1.0.3 and later will only produce - Huffman codes with a maximum length of 17 bits. However, in - order to preserve backwards compatibility with bitstreams - produced by versions pre-1.0.3, the decompressor must still - handle lengths of up to 20. */ - - for (i = 1; i <= alphaSize; i++) { - j = weight[i] >> 8; - /* bbox: yes, it is a signed division. - * don't replace with shift! */ - j = 1 + (j / 2); - weight[i] = j << 8; - } - } -#undef heap -#undef weight -#undef parent -} - - -/*---------------------------------------------------*/ -static -void BZ2_hbAssignCodes(int32_t *code, - uint8_t *length, - int32_t minLen, - int32_t maxLen, - int32_t alphaSize) -{ - int32_t n, vec, i; - - vec = 0; - for (n = minLen; n <= maxLen; n++) { - for (i = 0; i < alphaSize; i++) { - if (length[i] == n) { - code[i] = vec; - vec++; - }; - } - vec <<= 1; - } -} - - -/*-------------------------------------------------------------*/ -/*--- end huffman.c ---*/ -/*-------------------------------------------------------------*/ diff --git a/archival/bzip2.c b/archival/bzip2.c index fdb8b9306..a6abc931c 100644 --- a/archival/bzip2.c +++ b/archival/bzip2.c @@ -8,7 +8,7 @@ */ #include "libbb.h" -#include "unarchive.h" +#include "archive.h" #define CONFIG_BZIP2_FEATURE_SPEED 1 @@ -33,14 +33,14 @@ /* Takes ~300 bytes, detects corruption caused by bad RAM etc */ #define BZ_LIGHT_DEBUG 0 -#include "bz/bzlib.h" +#include "libarchive/bz/bzlib.h" -#include "bz/bzlib_private.h" +#include "libarchive/bz/bzlib_private.h" -#include "bz/blocksort.c" -#include "bz/bzlib.c" -#include "bz/compress.c" -#include "bz/huffman.c" +#include "libarchive/bz/blocksort.c" +#include "libarchive/bz/bzlib.c" +#include "libarchive/bz/compress.c" +#include "libarchive/bz/huffman.c" /* No point in being shy and having very small buffer here. * bzip2 internal buffers are much bigger anyway, hundreds of kbytes. diff --git a/archival/cpio.c b/archival/cpio.c index a2d74dc79..6ab268821 100644 --- a/archival/cpio.c +++ b/archival/cpio.c @@ -12,7 +12,7 @@ * */ #include "libbb.h" -#include "unarchive.h" +#include "archive.h" /* GNU cpio 2.9 --help (abridged): diff --git a/archival/dpkg.c b/archival/dpkg.c index 53e30d541..c37ae3349 100644 --- a/archival/dpkg.c +++ b/archival/dpkg.c @@ -30,7 +30,7 @@ #include "libbb.h" #include -#include "unarchive.h" +#include "archive.h" /* note: if you vary hash_prime sizes be aware, * 1) tweaking these will have a big effect on how much memory this program uses. diff --git a/archival/dpkg_deb.c b/archival/dpkg_deb.c index 0ce7c02d8..aee7b4cf5 100644 --- a/archival/dpkg_deb.c +++ b/archival/dpkg_deb.c @@ -5,7 +5,7 @@ * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ #include "libbb.h" -#include "unarchive.h" +#include "archive.h" #define DPKG_DEB_OPT_CONTENTS 1 #define DPKG_DEB_OPT_CONTROL 2 diff --git a/archival/gzip.c b/archival/gzip.c index 80141f380..38c5ae7fd 100644 --- a/archival/gzip.c +++ b/archival/gzip.c @@ -40,7 +40,7 @@ aa: 85.1% -- replaced with aa.gz */ #include "libbb.h" -#include "unarchive.h" +#include "archive.h" /* =========================================================================== diff --git a/archival/libarchive/Kbuild.src b/archival/libarchive/Kbuild.src new file mode 100644 index 000000000..b0bc4e5aa --- /dev/null +++ b/archival/libarchive/Kbuild.src @@ -0,0 +1,64 @@ +# Makefile for busybox +# +# Copyright (C) 1999-2004 by Erik Andersen +# +# Licensed under GPLv2 or later, see file LICENSE in this source tree. + +lib-y:= + +COMMON_FILES:= \ +\ + data_skip.o \ + data_extract_all.o \ + data_extract_to_stdout.o \ +\ + filter_accept_all.o \ + filter_accept_list.o \ + filter_accept_reject_list.o \ +\ + header_skip.o \ + header_list.o \ + header_verbose_list.o \ +\ + seek_by_read.o \ + seek_by_jump.o \ +\ + data_align.o \ + find_list_entry.o \ + init_handle.o + +DPKG_FILES:= \ + get_header_ar.o \ + unpack_ar_archive.o \ + get_header_tar.o \ + filter_accept_list_reassign.o + +INSERT + +lib-$(CONFIG_AR) += get_header_ar.o unpack_ar_archive.o +lib-$(CONFIG_BUNZIP2) += decompress_bunzip2.o +lib-$(CONFIG_UNLZMA) += decompress_unlzma.o +lib-$(CONFIG_UNXZ) += decompress_unxz.o +lib-$(CONFIG_CPIO) += get_header_cpio.o +lib-$(CONFIG_DPKG) += $(DPKG_FILES) +lib-$(CONFIG_DPKG_DEB) += $(DPKG_FILES) +lib-$(CONFIG_GUNZIP) += decompress_unzip.o +lib-$(CONFIG_RPM2CPIO) += decompress_unzip.o get_header_cpio.o +lib-$(CONFIG_RPM) += open_transformer.o decompress_unzip.o get_header_cpio.o +lib-$(CONFIG_TAR) += get_header_tar.o +lib-$(CONFIG_UNCOMPRESS) += decompress_uncompress.o +lib-$(CONFIG_UNZIP) += decompress_unzip.o +lib-$(CONFIG_LZOP) += lzo1x_1.o lzo1x_1o.o lzo1x_d.o +lib-$(CONFIG_LZOP_COMPR_HIGH) += lzo1x_9x.o +lib-$(CONFIG_FEATURE_SEAMLESS_Z) += open_transformer.o decompress_uncompress.o +lib-$(CONFIG_FEATURE_SEAMLESS_GZ) += open_transformer.o decompress_unzip.o get_header_tar_gz.o +lib-$(CONFIG_FEATURE_SEAMLESS_BZ2) += open_transformer.o decompress_bunzip2.o get_header_tar_bz2.o +lib-$(CONFIG_FEATURE_SEAMLESS_LZMA) += open_transformer.o decompress_unlzma.o get_header_tar_lzma.o +lib-$(CONFIG_FEATURE_SEAMLESS_XZ) += open_transformer.o decompress_unxz.o +lib-$(CONFIG_FEATURE_COMPRESS_USAGE) += decompress_bunzip2.o +lib-$(CONFIG_FEATURE_COMPRESS_BBCONFIG) += decompress_bunzip2.o +lib-$(CONFIG_FEATURE_TAR_TO_COMMAND) += data_extract_to_command.o + +ifneq ($(lib-y),) +lib-y += $(COMMON_FILES) +endif diff --git a/archival/libarchive/bz/LICENSE b/archival/libarchive/bz/LICENSE new file mode 100644 index 000000000..da4346520 --- /dev/null +++ b/archival/libarchive/bz/LICENSE @@ -0,0 +1,44 @@ +bzip2 applet in busybox is based on lightly-modified source +of bzip2 version 1.0.4. bzip2 source is distributed +under the following conditions (copied verbatim from LICENSE file) +=========================================================== + + +This program, "bzip2", the associated library "libbzip2", and all +documentation, are copyright (C) 1996-2006 Julian R Seward. All +rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + +2. The origin of this software must not be misrepresented; you must + not claim that you wrote the original software. If you use this + software in a product, an acknowledgment in the product + documentation would be appreciated but is not required. + +3. Altered source versions must be plainly marked as such, and must + not be misrepresented as being the original software. + +4. The name of the author may not be used to endorse or promote + products derived from this software without specific prior written + permission. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS +OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE +GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +Julian Seward, Cambridge, UK. +jseward@bzip.org +bzip2/libbzip2 version 1.0.4 of 20 December 2006 diff --git a/archival/libarchive/bz/README b/archival/libarchive/bz/README new file mode 100644 index 000000000..fffd47b8a --- /dev/null +++ b/archival/libarchive/bz/README @@ -0,0 +1,90 @@ +This file is an abridged version of README from bzip2 1.0.4 +Build instructions (which are not relevant to busyboxed bzip2) +are removed. +=========================================================== + + +This is the README for bzip2/libzip2. +This version is fully compatible with the previous public releases. + +------------------------------------------------------------------ +This file is part of bzip2/libbzip2, a program and library for +lossless, block-sorting data compression. + +bzip2/libbzip2 version 1.0.4 of 20 December 2006 +Copyright (C) 1996-2006 Julian Seward + +Please read the WARNING, DISCLAIMER and PATENTS sections in this file. + +This program is released under the terms of the license contained +in the file LICENSE. +------------------------------------------------------------------ + +Please read and be aware of the following: + + +WARNING: + + This program and library (attempts to) compress data by + performing several non-trivial transformations on it. + Unless you are 100% familiar with *all* the algorithms + contained herein, and with the consequences of modifying them, + you should NOT meddle with the compression or decompression + machinery. Incorrect changes can and very likely *will* + lead to disastrous loss of data. + + +DISCLAIMER: + + I TAKE NO RESPONSIBILITY FOR ANY LOSS OF DATA ARISING FROM THE + USE OF THIS PROGRAM/LIBRARY, HOWSOEVER CAUSED. + + Every compression of a file implies an assumption that the + compressed file can be decompressed to reproduce the original. + Great efforts in design, coding and testing have been made to + ensure that this program works correctly. However, the complexity + of the algorithms, and, in particular, the presence of various + special cases in the code which occur with very low but non-zero + probability make it impossible to rule out the possibility of bugs + remaining in the program. DO NOT COMPRESS ANY DATA WITH THIS + PROGRAM UNLESS YOU ARE PREPARED TO ACCEPT THE POSSIBILITY, HOWEVER + SMALL, THAT THE DATA WILL NOT BE RECOVERABLE. + + That is not to say this program is inherently unreliable. + Indeed, I very much hope the opposite is true. bzip2/libbzip2 + has been carefully constructed and extensively tested. + + +PATENTS: + + To the best of my knowledge, bzip2/libbzip2 does not use any + patented algorithms. However, I do not have the resources + to carry out a patent search. Therefore I cannot give any + guarantee of the above statement. + + +I hope you find bzip2 useful. Feel free to contact me at + jseward@bzip.org +if you have any suggestions or queries. Many people mailed me with +comments, suggestions and patches after the releases of bzip-0.15, +bzip-0.21, and bzip2 versions 0.1pl2, 0.9.0, 0.9.5, 1.0.0, 1.0.1, +1.0.2 and 1.0.3, and the changes in bzip2 are largely a result of this +feedback. I thank you for your comments. + +bzip2's "home" is http://www.bzip.org/ + +Julian Seward +jseward@bzip.org +Cambridge, UK. + +18 July 1996 (version 0.15) +25 August 1996 (version 0.21) + 7 August 1997 (bzip2, version 0.1) +29 August 1997 (bzip2, version 0.1pl2) +23 August 1998 (bzip2, version 0.9.0) + 8 June 1999 (bzip2, version 0.9.5) + 4 Sept 1999 (bzip2, version 0.9.5d) + 5 May 2000 (bzip2, version 1.0pre8) +30 December 2001 (bzip2, version 1.0.2pre1) +15 February 2005 (bzip2, version 1.0.3) +20 December 2006 (bzip2, version 1.0.4) diff --git a/archival/libarchive/bz/blocksort.c b/archival/libarchive/bz/blocksort.c new file mode 100644 index 000000000..f70c3701d --- /dev/null +++ b/archival/libarchive/bz/blocksort.c @@ -0,0 +1,1072 @@ +/* + * bzip2 is written by Julian Seward . + * Adapted for busybox by Denys Vlasenko . + * See README and LICENSE files in this directory for more information. + */ + +/*-------------------------------------------------------------*/ +/*--- Block sorting machinery ---*/ +/*--- blocksort.c ---*/ +/*-------------------------------------------------------------*/ + +/* ------------------------------------------------------------------ +This file is part of bzip2/libbzip2, a program and library for +lossless, block-sorting data compression. + +bzip2/libbzip2 version 1.0.4 of 20 December 2006 +Copyright (C) 1996-2006 Julian Seward + +Please read the WARNING, DISCLAIMER and PATENTS sections in the +README file. + +This program is released under the terms of the license contained +in the file LICENSE. +------------------------------------------------------------------ */ + +/* #include "bzlib_private.h" */ + +#define mswap(zz1, zz2) \ +{ \ + int32_t zztmp = zz1; \ + zz1 = zz2; \ + zz2 = zztmp; \ +} + +static +/* No measurable speed gain with inlining */ +/* ALWAYS_INLINE */ +void mvswap(uint32_t* ptr, int32_t zzp1, int32_t zzp2, int32_t zzn) +{ + while (zzn > 0) { + mswap(ptr[zzp1], ptr[zzp2]); + zzp1++; + zzp2++; + zzn--; + } +} + +static +ALWAYS_INLINE +int32_t mmin(int32_t a, int32_t b) +{ + return (a < b) ? a : b; +} + + +/*---------------------------------------------*/ +/*--- Fallback O(N log(N)^2) sorting ---*/ +/*--- algorithm, for repetitive blocks ---*/ +/*---------------------------------------------*/ + +/*---------------------------------------------*/ +static +inline +void fallbackSimpleSort(uint32_t* fmap, + uint32_t* eclass, + int32_t lo, + int32_t hi) +{ + int32_t i, j, tmp; + uint32_t ec_tmp; + + if (lo == hi) return; + + if (hi - lo > 3) { + for (i = hi-4; i >= lo; i--) { + tmp = fmap[i]; + ec_tmp = eclass[tmp]; + for (j = i+4; j <= hi && ec_tmp > eclass[fmap[j]]; j += 4) + fmap[j-4] = fmap[j]; + fmap[j-4] = tmp; + } + } + + for (i = hi-1; i >= lo; i--) { + tmp = fmap[i]; + ec_tmp = eclass[tmp]; + for (j = i+1; j <= hi && ec_tmp > eclass[fmap[j]]; j++) + fmap[j-1] = fmap[j]; + fmap[j-1] = tmp; + } +} + + +/*---------------------------------------------*/ +#define fpush(lz,hz) { \ + stackLo[sp] = lz; \ + stackHi[sp] = hz; \ + sp++; \ +} + +#define fpop(lz,hz) { \ + sp--; \ + lz = stackLo[sp]; \ + hz = stackHi[sp]; \ +} + +#define FALLBACK_QSORT_SMALL_THRESH 10 +#define FALLBACK_QSORT_STACK_SIZE 100 + +static +void fallbackQSort3(uint32_t* fmap, + uint32_t* eclass, + int32_t loSt, + int32_t hiSt) +{ + int32_t unLo, unHi, ltLo, gtHi, n, m; + int32_t sp, lo, hi; + uint32_t med, r, r3; + int32_t stackLo[FALLBACK_QSORT_STACK_SIZE]; + int32_t stackHi[FALLBACK_QSORT_STACK_SIZE]; + + r = 0; + + sp = 0; + fpush(loSt, hiSt); + + while (sp > 0) { + AssertH(sp < FALLBACK_QSORT_STACK_SIZE - 1, 1004); + + fpop(lo, hi); + if (hi - lo < FALLBACK_QSORT_SMALL_THRESH) { + fallbackSimpleSort(fmap, eclass, lo, hi); + continue; + } + + /* Random partitioning. Median of 3 sometimes fails to + * avoid bad cases. Median of 9 seems to help but + * looks rather expensive. This too seems to work but + * is cheaper. Guidance for the magic constants + * 7621 and 32768 is taken from Sedgewick's algorithms + * book, chapter 35. + */ + r = ((r * 7621) + 1) % 32768; + r3 = r % 3; + if (r3 == 0) + med = eclass[fmap[lo]]; + else if (r3 == 1) + med = eclass[fmap[(lo+hi)>>1]]; + else + med = eclass[fmap[hi]]; + + unLo = ltLo = lo; + unHi = gtHi = hi; + + while (1) { + while (1) { + if (unLo > unHi) break; + n = (int32_t)eclass[fmap[unLo]] - (int32_t)med; + if (n == 0) { + mswap(fmap[unLo], fmap[ltLo]); + ltLo++; + unLo++; + continue; + }; + if (n > 0) break; + unLo++; + } + while (1) { + if (unLo > unHi) break; + n = (int32_t)eclass[fmap[unHi]] - (int32_t)med; + if (n == 0) { + mswap(fmap[unHi], fmap[gtHi]); + gtHi--; unHi--; + continue; + }; + if (n < 0) break; + unHi--; + } + if (unLo > unHi) break; + mswap(fmap[unLo], fmap[unHi]); unLo++; unHi--; + } + + AssertD(unHi == unLo-1, "fallbackQSort3(2)"); + + if (gtHi < ltLo) continue; + + n = mmin(ltLo-lo, unLo-ltLo); mvswap(fmap, lo, unLo-n, n); + m = mmin(hi-gtHi, gtHi-unHi); mvswap(fmap, unLo, hi-m+1, m); + + n = lo + unLo - ltLo - 1; + m = hi - (gtHi - unHi) + 1; + + if (n - lo > hi - m) { + fpush(lo, n); + fpush(m, hi); + } else { + fpush(m, hi); + fpush(lo, n); + } + } +} + +#undef fpush +#undef fpop +#undef FALLBACK_QSORT_SMALL_THRESH +#undef FALLBACK_QSORT_STACK_SIZE + + +/*---------------------------------------------*/ +/* Pre: + * nblock > 0 + * eclass exists for [0 .. nblock-1] + * ((uint8_t*)eclass) [0 .. nblock-1] holds block + * ptr exists for [0 .. nblock-1] + * + * Post: + * ((uint8_t*)eclass) [0 .. nblock-1] holds block + * All other areas of eclass destroyed + * fmap [0 .. nblock-1] holds sorted order + * bhtab[0 .. 2+(nblock/32)] destroyed +*/ + +#define SET_BH(zz) bhtab[(zz) >> 5] |= (1 << ((zz) & 31)) +#define CLEAR_BH(zz) bhtab[(zz) >> 5] &= ~(1 << ((zz) & 31)) +#define ISSET_BH(zz) (bhtab[(zz) >> 5] & (1 << ((zz) & 31))) +#define WORD_BH(zz) bhtab[(zz) >> 5] +#define UNALIGNED_BH(zz) ((zz) & 0x01f) + +static +void fallbackSort(uint32_t* fmap, + uint32_t* eclass, + uint32_t* bhtab, + int32_t nblock) +{ + int32_t ftab[257]; + int32_t ftabCopy[256]; + int32_t H, i, j, k, l, r, cc, cc1; + int32_t nNotDone; + int32_t nBhtab; + uint8_t* eclass8 = (uint8_t*)eclass; + + /* + * Initial 1-char radix sort to generate + * initial fmap and initial BH bits. + */ + for (i = 0; i < 257; i++) ftab[i] = 0; + for (i = 0; i < nblock; i++) ftab[eclass8[i]]++; + for (i = 0; i < 256; i++) ftabCopy[i] = ftab[i]; + + j = ftab[0]; /* bbox: optimized */ + for (i = 1; i < 257; i++) { + j += ftab[i]; + ftab[i] = j; + } + + for (i = 0; i < nblock; i++) { + j = eclass8[i]; + k = ftab[j] - 1; + ftab[j] = k; + fmap[k] = i; + } + + nBhtab = 2 + ((uint32_t)nblock / 32); /* bbox: unsigned div is easier */ + for (i = 0; i < nBhtab; i++) bhtab[i] = 0; + for (i = 0; i < 256; i++) SET_BH(ftab[i]); + + /* + * Inductively refine the buckets. Kind-of an + * "exponential radix sort" (!), inspired by the + * Manber-Myers suffix array construction algorithm. + */ + + /*-- set sentinel bits for block-end detection --*/ + for (i = 0; i < 32; i++) { + SET_BH(nblock + 2*i); + CLEAR_BH(nblock + 2*i + 1); + } + + /*-- the log(N) loop --*/ + H = 1; + while (1) { + j = 0; + for (i = 0; i < nblock; i++) { + if (ISSET_BH(i)) + j = i; + k = fmap[i] - H; + if (k < 0) + k += nblock; + eclass[k] = j; + } + + nNotDone = 0; + r = -1; + while (1) { + + /*-- find the next non-singleton bucket --*/ + k = r + 1; + while (ISSET_BH(k) && UNALIGNED_BH(k)) + k++; + if (ISSET_BH(k)) { + while (WORD_BH(k) == 0xffffffff) k += 32; + while (ISSET_BH(k)) k++; + } + l = k - 1; + if (l >= nblock) + break; + while (!ISSET_BH(k) && UNALIGNED_BH(k)) + k++; + if (!ISSET_BH(k)) { + while (WORD_BH(k) == 0x00000000) k += 32; + while (!ISSET_BH(k)) k++; + } + r = k - 1; + if (r >= nblock) + break; + + /*-- now [l, r] bracket current bucket --*/ + if (r > l) { + nNotDone += (r - l + 1); + fallbackQSort3(fmap, eclass, l, r); + + /*-- scan bucket and generate header bits-- */ + cc = -1; + for (i = l; i <= r; i++) { + cc1 = eclass[fmap[i]]; + if (cc != cc1) { + SET_BH(i); + cc = cc1; + }; + } + } + } + + H *= 2; + if (H > nblock || nNotDone == 0) + break; + } + + /* + * Reconstruct the original block in + * eclass8 [0 .. nblock-1], since the + * previous phase destroyed it. + */ + j = 0; + for (i = 0; i < nblock; i++) { + while (ftabCopy[j] == 0) + j++; + ftabCopy[j]--; + eclass8[fmap[i]] = (uint8_t)j; + } + AssertH(j < 256, 1005); +} + +#undef SET_BH +#undef CLEAR_BH +#undef ISSET_BH +#undef WORD_BH +#undef UNALIGNED_BH + + +/*---------------------------------------------*/ +/*--- The main, O(N^2 log(N)) sorting ---*/ +/*--- algorithm. Faster for "normal" ---*/ +/*--- non-repetitive blocks. ---*/ +/*---------------------------------------------*/ + +/*---------------------------------------------*/ +static +NOINLINE +int mainGtU( + uint32_t i1, + uint32_t i2, + uint8_t* block, + uint16_t* quadrant, + uint32_t nblock, + int32_t* budget) +{ + int32_t k; + uint8_t c1, c2; + uint16_t s1, s2; + +/* Loop unrolling here is actually very useful + * (generated code is much simpler), + * code size increase is only 270 bytes (i386) + * but speeds up compression 10% overall + */ + +#if CONFIG_BZIP2_FEATURE_SPEED >= 1 + +#define TIMES_8(code) \ + code; code; code; code; \ + code; code; code; code; +#define TIMES_12(code) \ + code; code; code; code; \ + code; code; code; code; \ + code; code; code; code; + +#else + +#define TIMES_8(code) \ +{ \ + int nn = 8; \ + do { \ + code; \ + } while (--nn); \ +} +#define TIMES_12(code) \ +{ \ + int nn = 12; \ + do { \ + code; \ + } while (--nn); \ +} + +#endif + + AssertD(i1 != i2, "mainGtU"); + TIMES_12( + c1 = block[i1]; c2 = block[i2]; + if (c1 != c2) return (c1 > c2); + i1++; i2++; + ) + + k = nblock + 8; + + do { + TIMES_8( + c1 = block[i1]; c2 = block[i2]; + if (c1 != c2) return (c1 > c2); + s1 = quadrant[i1]; s2 = quadrant[i2]; + if (s1 != s2) return (s1 > s2); + i1++; i2++; + ) + + if (i1 >= nblock) i1 -= nblock; + if (i2 >= nblock) i2 -= nblock; + + (*budget)--; + k -= 8; + } while (k >= 0); + + return False; +} +#undef TIMES_8 +#undef TIMES_12 + +/*---------------------------------------------*/ +/* + * Knuth's increments seem to work better + * than Incerpi-Sedgewick here. Possibly + * because the number of elems to sort is + * usually small, typically <= 20. + */ +static +const int32_t incs[14] = { + 1, 4, 13, 40, 121, 364, 1093, 3280, + 9841, 29524, 88573, 265720, + 797161, 2391484 +}; + +static +void mainSimpleSort(uint32_t* ptr, + uint8_t* block, + uint16_t* quadrant, + int32_t nblock, + int32_t lo, + int32_t hi, + int32_t d, + int32_t* budget) +{ + int32_t i, j, h, bigN, hp; + uint32_t v; + + bigN = hi - lo + 1; + if (bigN < 2) return; + + hp = 0; + while (incs[hp] < bigN) hp++; + hp--; + + for (; hp >= 0; hp--) { + h = incs[hp]; + + i = lo + h; + while (1) { + /*-- copy 1 --*/ + if (i > hi) break; + v = ptr[i]; + j = i; + while (mainGtU(ptr[j-h]+d, v+d, block, quadrant, nblock, budget)) { + ptr[j] = ptr[j-h]; + j = j - h; + if (j <= (lo + h - 1)) break; + } + ptr[j] = v; + i++; + +/* 1.5% overall speedup, +290 bytes */ +#if CONFIG_BZIP2_FEATURE_SPEED >= 3 + /*-- copy 2 --*/ + if (i > hi) break; + v = ptr[i]; + j = i; + while (mainGtU(ptr[j-h]+d, v+d, block, quadrant, nblock, budget)) { + ptr[j] = ptr[j-h]; + j = j - h; + if (j <= (lo + h - 1)) break; + } + ptr[j] = v; + i++; + + /*-- copy 3 --*/ + if (i > hi) break; + v = ptr[i]; + j = i; + while (mainGtU(ptr[j-h]+d, v+d, block, quadrant, nblock, budget)) { + ptr[j] = ptr[j-h]; + j = j - h; + if (j <= (lo + h - 1)) break; + } + ptr[j] = v; + i++; +#endif + if (*budget < 0) return; + } + } +} + + +/*---------------------------------------------*/ +/* + * The following is an implementation of + * an elegant 3-way quicksort for strings, + * described in a paper "Fast Algorithms for + * Sorting and Searching Strings", by Robert + * Sedgewick and Jon L. Bentley. + */ + +static +ALWAYS_INLINE +uint8_t mmed3(uint8_t a, uint8_t b, uint8_t c) +{ + uint8_t t; + if (a > b) { + t = a; + a = b; + b = t; + }; + /* here b >= a */ + if (b > c) { + b = c; + if (a > b) + b = a; + } + return b; +} + +#define mpush(lz,hz,dz) \ +{ \ + stackLo[sp] = lz; \ + stackHi[sp] = hz; \ + stackD [sp] = dz; \ + sp++; \ +} + +#define mpop(lz,hz,dz) \ +{ \ + sp--; \ + lz = stackLo[sp]; \ + hz = stackHi[sp]; \ + dz = stackD [sp]; \ +} + +#define mnextsize(az) (nextHi[az] - nextLo[az]) + +#define mnextswap(az,bz) \ +{ \ + int32_t tz; \ + tz = nextLo[az]; nextLo[az] = nextLo[bz]; nextLo[bz] = tz; \ + tz = nextHi[az]; nextHi[az] = nextHi[bz]; nextHi[bz] = tz; \ + tz = nextD [az]; nextD [az] = nextD [bz]; nextD [bz] = tz; \ +} + +#define MAIN_QSORT_SMALL_THRESH 20 +#define MAIN_QSORT_DEPTH_THRESH (BZ_N_RADIX + BZ_N_QSORT) +#define MAIN_QSORT_STACK_SIZE 100 + +static NOINLINE +void mainQSort3(uint32_t* ptr, + uint8_t* block, + uint16_t* quadrant, + int32_t nblock, + int32_t loSt, + int32_t hiSt, + int32_t dSt, + int32_t* budget) +{ + int32_t unLo, unHi, ltLo, gtHi, n, m, med; + int32_t sp, lo, hi, d; + + int32_t stackLo[MAIN_QSORT_STACK_SIZE]; + int32_t stackHi[MAIN_QSORT_STACK_SIZE]; + int32_t stackD [MAIN_QSORT_STACK_SIZE]; + + int32_t nextLo[3]; + int32_t nextHi[3]; + int32_t nextD [3]; + + sp = 0; + mpush(loSt, hiSt, dSt); + + while (sp > 0) { + AssertH(sp < MAIN_QSORT_STACK_SIZE - 2, 1001); + + mpop(lo, hi, d); + if (hi - lo < MAIN_QSORT_SMALL_THRESH + || d > MAIN_QSORT_DEPTH_THRESH + ) { + mainSimpleSort(ptr, block, quadrant, nblock, lo, hi, d, budget); + if (*budget < 0) + return; + continue; + } + med = (int32_t) mmed3(block[ptr[lo ] + d], + block[ptr[hi ] + d], + block[ptr[(lo+hi) >> 1] + d]); + + unLo = ltLo = lo; + unHi = gtHi = hi; + + while (1) { + while (1) { + if (unLo > unHi) + break; + n = ((int32_t)block[ptr[unLo]+d]) - med; + if (n == 0) { + mswap(ptr[unLo], ptr[ltLo]); + ltLo++; + unLo++; + continue; + }; + if (n > 0) break; + unLo++; + } + while (1) { + if (unLo > unHi) + break; + n = ((int32_t)block[ptr[unHi]+d]) - med; + if (n == 0) { + mswap(ptr[unHi], ptr[gtHi]); + gtHi--; + unHi--; + continue; + }; + if (n < 0) break; + unHi--; + } + if (unLo > unHi) + break; + mswap(ptr[unLo], ptr[unHi]); + unLo++; + unHi--; + } + + AssertD(unHi == unLo-1, "mainQSort3(2)"); + + if (gtHi < ltLo) { + mpush(lo, hi, d + 1); + continue; + } + + n = mmin(ltLo-lo, unLo-ltLo); mvswap(ptr, lo, unLo-n, n); + m = mmin(hi-gtHi, gtHi-unHi); mvswap(ptr, unLo, hi-m+1, m); + + n = lo + unLo - ltLo - 1; + m = hi - (gtHi - unHi) + 1; + + nextLo[0] = lo; nextHi[0] = n; nextD[0] = d; + nextLo[1] = m; nextHi[1] = hi; nextD[1] = d; + nextLo[2] = n+1; nextHi[2] = m-1; nextD[2] = d+1; + + if (mnextsize(0) < mnextsize(1)) mnextswap(0, 1); + if (mnextsize(1) < mnextsize(2)) mnextswap(1, 2); + if (mnextsize(0) < mnextsize(1)) mnextswap(0, 1); + + AssertD (mnextsize(0) >= mnextsize(1), "mainQSort3(8)"); + AssertD (mnextsize(1) >= mnextsize(2), "mainQSort3(9)"); + + mpush(nextLo[0], nextHi[0], nextD[0]); + mpush(nextLo[1], nextHi[1], nextD[1]); + mpush(nextLo[2], nextHi[2], nextD[2]); + } +} + +#undef mpush +#undef mpop +#undef mnextsize +#undef mnextswap +#undef MAIN_QSORT_SMALL_THRESH +#undef MAIN_QSORT_DEPTH_THRESH +#undef MAIN_QSORT_STACK_SIZE + + +/*---------------------------------------------*/ +/* Pre: + * nblock > N_OVERSHOOT + * block32 exists for [0 .. nblock-1 +N_OVERSHOOT] + * ((uint8_t*)block32) [0 .. nblock-1] holds block + * ptr exists for [0 .. nblock-1] + * + * Post: + * ((uint8_t*)block32) [0 .. nblock-1] holds block + * All other areas of block32 destroyed + * ftab[0 .. 65536] destroyed + * ptr [0 .. nblock-1] holds sorted order + * if (*budget < 0), sorting was abandoned + */ + +#define BIGFREQ(b) (ftab[((b)+1) << 8] - ftab[(b) << 8]) +#define SETMASK (1 << 21) +#define CLEARMASK (~(SETMASK)) + +static NOINLINE +void mainSort(EState* state, + uint32_t* ptr, + uint8_t* block, + uint16_t* quadrant, + uint32_t* ftab, + int32_t nblock, + int32_t* budget) +{ + int32_t i, j, k, ss, sb; + uint8_t c1; + int32_t numQSorted; + uint16_t s; + Bool bigDone[256]; + /* bbox: moved to EState to save stack + int32_t runningOrder[256]; + int32_t copyStart[256]; + int32_t copyEnd [256]; + */ +#define runningOrder (state->mainSort__runningOrder) +#define copyStart (state->mainSort__copyStart) +#define copyEnd (state->mainSort__copyEnd) + + /*-- set up the 2-byte frequency table --*/ + /* was: for (i = 65536; i >= 0; i--) ftab[i] = 0; */ + memset(ftab, 0, 65537 * sizeof(ftab[0])); + + j = block[0] << 8; + i = nblock - 1; +/* 3%, +300 bytes */ +#if CONFIG_BZIP2_FEATURE_SPEED >= 2 + for (; i >= 3; i -= 4) { + quadrant[i] = 0; + j = (j >> 8) | (((uint16_t)block[i]) << 8); + ftab[j]++; + quadrant[i-1] = 0; + j = (j >> 8) | (((uint16_t)block[i-1]) << 8); + ftab[j]++; + quadrant[i-2] = 0; + j = (j >> 8) | (((uint16_t)block[i-2]) << 8); + ftab[j]++; + quadrant[i-3] = 0; + j = (j >> 8) | (((uint16_t)block[i-3]) << 8); + ftab[j]++; + } +#endif + for (; i >= 0; i--) { + quadrant[i] = 0; + j = (j >> 8) | (((uint16_t)block[i]) << 8); + ftab[j]++; + } + + /*-- (emphasises close relationship of block & quadrant) --*/ + for (i = 0; i < BZ_N_OVERSHOOT; i++) { + block [nblock+i] = block[i]; + quadrant[nblock+i] = 0; + } + + /*-- Complete the initial radix sort --*/ + j = ftab[0]; /* bbox: optimized */ + for (i = 1; i <= 65536; i++) { + j += ftab[i]; + ftab[i] = j; + } + + s = block[0] << 8; + i = nblock - 1; +#if CONFIG_BZIP2_FEATURE_SPEED >= 2 + for (; i >= 3; i -= 4) { + s = (s >> 8) | (block[i] << 8); + j = ftab[s] - 1; + ftab[s] = j; + ptr[j] = i; + s = (s >> 8) | (block[i-1] << 8); + j = ftab[s] - 1; + ftab[s] = j; + ptr[j] = i-1; + s = (s >> 8) | (block[i-2] << 8); + j = ftab[s] - 1; + ftab[s] = j; + ptr[j] = i-2; + s = (s >> 8) | (block[i-3] << 8); + j = ftab[s] - 1; + ftab[s] = j; + ptr[j] = i-3; + } +#endif + for (; i >= 0; i--) { + s = (s >> 8) | (block[i] << 8); + j = ftab[s] - 1; + ftab[s] = j; + ptr[j] = i; + } + + /* + * Now ftab contains the first loc of every small bucket. + * Calculate the running order, from smallest to largest + * big bucket. + */ + for (i = 0; i <= 255; i++) { + bigDone [i] = False; + runningOrder[i] = i; + } + + { + int32_t vv; + /* bbox: was: int32_t h = 1; */ + /* do h = 3 * h + 1; while (h <= 256); */ + uint32_t h = 364; + + do { + /*h = h / 3;*/ + h = (h * 171) >> 9; /* bbox: fast h/3 */ + for (i = h; i <= 255; i++) { + vv = runningOrder[i]; + j = i; + while (BIGFREQ(runningOrder[j-h]) > BIGFREQ(vv)) { + runningOrder[j] = runningOrder[j-h]; + j = j - h; + if (j <= (h - 1)) + goto zero; + } + zero: + runningOrder[j] = vv; + } + } while (h != 1); + } + + /* + * The main sorting loop. + */ + + numQSorted = 0; + + for (i = 0; i <= 255; i++) { + + /* + * Process big buckets, starting with the least full. + * Basically this is a 3-step process in which we call + * mainQSort3 to sort the small buckets [ss, j], but + * also make a big effort to avoid the calls if we can. + */ + ss = runningOrder[i]; + + /* + * Step 1: + * Complete the big bucket [ss] by quicksorting + * any unsorted small buckets [ss, j], for j != ss. + * Hopefully previous pointer-scanning phases have already + * completed many of the small buckets [ss, j], so + * we don't have to sort them at all. + */ + for (j = 0; j <= 255; j++) { + if (j != ss) { + sb = (ss << 8) + j; + if (!(ftab[sb] & SETMASK)) { + int32_t lo = ftab[sb] & CLEARMASK; + int32_t hi = (ftab[sb+1] & CLEARMASK) - 1; + if (hi > lo) { + mainQSort3( + ptr, block, quadrant, nblock, + lo, hi, BZ_N_RADIX, budget + ); + if (*budget < 0) return; + numQSorted += (hi - lo + 1); + } + } + ftab[sb] |= SETMASK; + } + } + + AssertH(!bigDone[ss], 1006); + + /* + * Step 2: + * Now scan this big bucket [ss] so as to synthesise the + * sorted order for small buckets [t, ss] for all t, + * including, magically, the bucket [ss,ss] too. + * This will avoid doing Real Work in subsequent Step 1's. + */ + { + for (j = 0; j <= 255; j++) { + copyStart[j] = ftab[(j << 8) + ss] & CLEARMASK; + copyEnd [j] = (ftab[(j << 8) + ss + 1] & CLEARMASK) - 1; + } + for (j = ftab[ss << 8] & CLEARMASK; j < copyStart[ss]; j++) { + k = ptr[j] - 1; + if (k < 0) + k += nblock; + c1 = block[k]; + if (!bigDone[c1]) + ptr[copyStart[c1]++] = k; + } + for (j = (ftab[(ss+1) << 8] & CLEARMASK) - 1; j > copyEnd[ss]; j--) { + k = ptr[j]-1; + if (k < 0) + k += nblock; + c1 = block[k]; + if (!bigDone[c1]) + ptr[copyEnd[c1]--] = k; + } + } + + /* Extremely rare case missing in bzip2-1.0.0 and 1.0.1. + * Necessity for this case is demonstrated by compressing + * a sequence of approximately 48.5 million of character + * 251; 1.0.0/1.0.1 will then die here. */ + AssertH((copyStart[ss]-1 == copyEnd[ss]) \ + || (copyStart[ss] == 0 && copyEnd[ss] == nblock-1), 1007); + + for (j = 0; j <= 255; j++) + ftab[(j << 8) + ss] |= SETMASK; + + /* + * Step 3: + * The [ss] big bucket is now done. Record this fact, + * and update the quadrant descriptors. Remember to + * update quadrants in the overshoot area too, if + * necessary. The "if (i < 255)" test merely skips + * this updating for the last bucket processed, since + * updating for the last bucket is pointless. + * + * The quadrant array provides a way to incrementally + * cache sort orderings, as they appear, so as to + * make subsequent comparisons in fullGtU() complete + * faster. For repetitive blocks this makes a big + * difference (but not big enough to be able to avoid + * the fallback sorting mechanism, exponential radix sort). + * + * The precise meaning is: at all times: + * + * for 0 <= i < nblock and 0 <= j <= nblock + * + * if block[i] != block[j], + * + * then the relative values of quadrant[i] and + * quadrant[j] are meaningless. + * + * else { + * if quadrant[i] < quadrant[j] + * then the string starting at i lexicographically + * precedes the string starting at j + * + * else if quadrant[i] > quadrant[j] + * then the string starting at j lexicographically + * precedes the string starting at i + * + * else + * the relative ordering of the strings starting + * at i and j has not yet been determined. + * } + */ + bigDone[ss] = True; + + if (i < 255) { + int32_t bbStart = ftab[ss << 8] & CLEARMASK; + int32_t bbSize = (ftab[(ss+1) << 8] & CLEARMASK) - bbStart; + int32_t shifts = 0; + + while ((bbSize >> shifts) > 65534) shifts++; + + for (j = bbSize-1; j >= 0; j--) { + int32_t a2update = ptr[bbStart + j]; + uint16_t qVal = (uint16_t)(j >> shifts); + quadrant[a2update] = qVal; + if (a2update < BZ_N_OVERSHOOT) + quadrant[a2update + nblock] = qVal; + } + AssertH(((bbSize-1) >> shifts) <= 65535, 1002); + } + } +#undef runningOrder +#undef copyStart +#undef copyEnd +} + +#undef BIGFREQ +#undef SETMASK +#undef CLEARMASK + + +/*---------------------------------------------*/ +/* Pre: + * nblock > 0 + * arr2 exists for [0 .. nblock-1 +N_OVERSHOOT] + * ((uint8_t*)arr2)[0 .. nblock-1] holds block + * arr1 exists for [0 .. nblock-1] + * + * Post: + * ((uint8_t*)arr2) [0 .. nblock-1] holds block + * All other areas of block destroyed + * ftab[0 .. 65536] destroyed + * arr1[0 .. nblock-1] holds sorted order + */ +static NOINLINE +void BZ2_blockSort(EState* s) +{ + /* In original bzip2 1.0.4, it's a parameter, but 30 + * (which was the default) should work ok. */ + enum { wfact = 30 }; + + uint32_t* ptr = s->ptr; + uint8_t* block = s->block; + uint32_t* ftab = s->ftab; + int32_t nblock = s->nblock; + uint16_t* quadrant; + int32_t budget; + int32_t i; + + if (nblock < 10000) { + fallbackSort(s->arr1, s->arr2, ftab, nblock); + } else { + /* Calculate the location for quadrant, remembering to get + * the alignment right. Assumes that &(block[0]) is at least + * 2-byte aligned -- this should be ok since block is really + * the first section of arr2. + */ + i = nblock + BZ_N_OVERSHOOT; + if (i & 1) i++; + quadrant = (uint16_t*)(&(block[i])); + + /* (wfact-1) / 3 puts the default-factor-30 + * transition point at very roughly the same place as + * with v0.1 and v0.9.0. + * Not that it particularly matters any more, since the + * resulting compressed stream is now the same regardless + * of whether or not we use the main sort or fallback sort. + */ + budget = nblock * ((wfact-1) / 3); + + mainSort(s, ptr, block, quadrant, ftab, nblock, &budget); + if (budget < 0) { + fallbackSort(s->arr1, s->arr2, ftab, nblock); + } + } + + s->origPtr = -1; + for (i = 0; i < s->nblock; i++) + if (ptr[i] == 0) { + s->origPtr = i; + break; + }; + + AssertH(s->origPtr != -1, 1003); +} + + +/*-------------------------------------------------------------*/ +/*--- end blocksort.c ---*/ +/*-------------------------------------------------------------*/ diff --git a/archival/libarchive/bz/bzlib.c b/archival/libarchive/bz/bzlib.c new file mode 100644 index 000000000..b3beeabed --- /dev/null +++ b/archival/libarchive/bz/bzlib.c @@ -0,0 +1,431 @@ +/* + * bzip2 is written by Julian Seward . + * Adapted for busybox by Denys Vlasenko . + * See README and LICENSE files in this directory for more information. + */ + +/*-------------------------------------------------------------*/ +/*--- Library top-level functions. ---*/ +/*--- bzlib.c ---*/ +/*-------------------------------------------------------------*/ + +/* ------------------------------------------------------------------ +This file is part of bzip2/libbzip2, a program and library for +lossless, block-sorting data compression. + +bzip2/libbzip2 version 1.0.4 of 20 December 2006 +Copyright (C) 1996-2006 Julian Seward + +Please read the WARNING, DISCLAIMER and PATENTS sections in the +README file. + +This program is released under the terms of the license contained +in the file LICENSE. +------------------------------------------------------------------ */ + +/* CHANGES + * 0.9.0 -- original version. + * 0.9.0a/b -- no changes in this file. + * 0.9.0c -- made zero-length BZ_FLUSH work correctly in bzCompress(). + * fixed bzWrite/bzRead to ignore zero-length requests. + * fixed bzread to correctly handle read requests after EOF. + * wrong parameter order in call to bzDecompressInit in + * bzBuffToBuffDecompress. Fixed. + */ + +/* #include "bzlib_private.h" */ + +/*---------------------------------------------------*/ +/*--- Compression stuff ---*/ +/*---------------------------------------------------*/ + +/*---------------------------------------------------*/ +#if BZ_LIGHT_DEBUG +static +void bz_assert_fail(int errcode) +{ + /* if (errcode == 1007) bb_error_msg_and_die("probably bad RAM"); */ + bb_error_msg_and_die("internal error %d", errcode); +} +#endif + +/*---------------------------------------------------*/ +static +void prepare_new_block(EState* s) +{ + int i; + s->nblock = 0; + s->numZ = 0; + s->state_out_pos = 0; + BZ_INITIALISE_CRC(s->blockCRC); + /* inlined memset would be nice to have here */ + for (i = 0; i < 256; i++) + s->inUse[i] = 0; + s->blockNo++; +} + + +/*---------------------------------------------------*/ +static +ALWAYS_INLINE +void init_RL(EState* s) +{ + s->state_in_ch = 256; + s->state_in_len = 0; +} + + +static +int isempty_RL(EState* s) +{ + return (s->state_in_ch >= 256 || s->state_in_len <= 0); +} + + +/*---------------------------------------------------*/ +static +void BZ2_bzCompressInit(bz_stream *strm, int blockSize100k) +{ + int32_t n; + EState* s; + + s = xzalloc(sizeof(EState)); + s->strm = strm; + + n = 100000 * blockSize100k; + s->arr1 = xmalloc(n * sizeof(uint32_t)); + s->mtfv = (uint16_t*)s->arr1; + s->ptr = (uint32_t*)s->arr1; + s->arr2 = xmalloc((n + BZ_N_OVERSHOOT) * sizeof(uint32_t)); + s->block = (uint8_t*)s->arr2; + s->ftab = xmalloc(65537 * sizeof(uint32_t)); + + s->crc32table = crc32_filltable(NULL, 1); + + s->state = BZ_S_INPUT; + s->mode = BZ_M_RUNNING; + s->blockSize100k = blockSize100k; + s->nblockMAX = n - 19; + + strm->state = s; + /*strm->total_in = 0;*/ + strm->total_out = 0; + init_RL(s); + prepare_new_block(s); +} + + +/*---------------------------------------------------*/ +static +void add_pair_to_block(EState* s) +{ + int32_t i; + uint8_t ch = (uint8_t)(s->state_in_ch); + for (i = 0; i < s->state_in_len; i++) { + BZ_UPDATE_CRC(s, s->blockCRC, ch); + } + s->inUse[s->state_in_ch] = 1; + switch (s->state_in_len) { + case 3: + s->block[s->nblock] = (uint8_t)ch; s->nblock++; + /* fall through */ + case 2: + s->block[s->nblock] = (uint8_t)ch; s->nblock++; + /* fall through */ + case 1: + s->block[s->nblock] = (uint8_t)ch; s->nblock++; + break; + default: + s->inUse[s->state_in_len - 4] = 1; + s->block[s->nblock] = (uint8_t)ch; s->nblock++; + s->block[s->nblock] = (uint8_t)ch; s->nblock++; + s->block[s->nblock] = (uint8_t)ch; s->nblock++; + s->block[s->nblock] = (uint8_t)ch; s->nblock++; + s->block[s->nblock] = (uint8_t)(s->state_in_len - 4); + s->nblock++; + break; + } +} + + +/*---------------------------------------------------*/ +static +void flush_RL(EState* s) +{ + if (s->state_in_ch < 256) add_pair_to_block(s); + init_RL(s); +} + + +/*---------------------------------------------------*/ +#define ADD_CHAR_TO_BLOCK(zs, zchh0) \ +{ \ + uint32_t zchh = (uint32_t)(zchh0); \ + /*-- fast track the common case --*/ \ + if (zchh != zs->state_in_ch && zs->state_in_len == 1) { \ + uint8_t ch = (uint8_t)(zs->state_in_ch); \ + BZ_UPDATE_CRC(zs, zs->blockCRC, ch); \ + zs->inUse[zs->state_in_ch] = 1; \ + zs->block[zs->nblock] = (uint8_t)ch; \ + zs->nblock++; \ + zs->state_in_ch = zchh; \ + } \ + else \ + /*-- general, uncommon cases --*/ \ + if (zchh != zs->state_in_ch || zs->state_in_len == 255) { \ + if (zs->state_in_ch < 256) \ + add_pair_to_block(zs); \ + zs->state_in_ch = zchh; \ + zs->state_in_len = 1; \ + } else { \ + zs->state_in_len++; \ + } \ +} + + +/*---------------------------------------------------*/ +static +void /*Bool*/ copy_input_until_stop(EState* s) +{ + /*Bool progress_in = False;*/ + +#ifdef SAME_CODE_AS_BELOW + if (s->mode == BZ_M_RUNNING) { + /*-- fast track the common case --*/ + while (1) { + /*-- no input? --*/ + if (s->strm->avail_in == 0) break; + /*-- block full? --*/ + if (s->nblock >= s->nblockMAX) break; + /*progress_in = True;*/ + ADD_CHAR_TO_BLOCK(s, (uint32_t)(*(uint8_t*)(s->strm->next_in))); + s->strm->next_in++; + s->strm->avail_in--; + /*s->strm->total_in++;*/ + } + } else +#endif + { + /*-- general, uncommon case --*/ + while (1) { + /*-- no input? --*/ + if (s->strm->avail_in == 0) break; + /*-- block full? --*/ + if (s->nblock >= s->nblockMAX) break; + //# /*-- flush/finish end? --*/ + //# if (s->avail_in_expect == 0) break; + /*progress_in = True;*/ + ADD_CHAR_TO_BLOCK(s, *(uint8_t*)(s->strm->next_in)); + s->strm->next_in++; + s->strm->avail_in--; + /*s->strm->total_in++;*/ + //# s->avail_in_expect--; + } + } + /*return progress_in;*/ +} + + +/*---------------------------------------------------*/ +static +void /*Bool*/ copy_output_until_stop(EState* s) +{ + /*Bool progress_out = False;*/ + + while (1) { + /*-- no output space? --*/ + if (s->strm->avail_out == 0) break; + + /*-- block done? --*/ + if (s->state_out_pos >= s->numZ) break; + + /*progress_out = True;*/ + *(s->strm->next_out) = s->zbits[s->state_out_pos]; + s->state_out_pos++; + s->strm->avail_out--; + s->strm->next_out++; + s->strm->total_out++; + } + /*return progress_out;*/ +} + + +/*---------------------------------------------------*/ +static +void /*Bool*/ handle_compress(bz_stream *strm) +{ + /*Bool progress_in = False;*/ + /*Bool progress_out = False;*/ + EState* s = strm->state; + + while (1) { + if (s->state == BZ_S_OUTPUT) { + /*progress_out |=*/ copy_output_until_stop(s); + if (s->state_out_pos < s->numZ) break; + if (s->mode == BZ_M_FINISHING + //# && s->avail_in_expect == 0 + && s->strm->avail_in == 0 + && isempty_RL(s)) + break; + prepare_new_block(s); + s->state = BZ_S_INPUT; +#ifdef FLUSH_IS_UNUSED + if (s->mode == BZ_M_FLUSHING + && s->avail_in_expect == 0 + && isempty_RL(s)) + break; +#endif + } + + if (s->state == BZ_S_INPUT) { + /*progress_in |=*/ copy_input_until_stop(s); + //#if (s->mode != BZ_M_RUNNING && s->avail_in_expect == 0) { + if (s->mode != BZ_M_RUNNING && s->strm->avail_in == 0) { + flush_RL(s); + BZ2_compressBlock(s, (s->mode == BZ_M_FINISHING)); + s->state = BZ_S_OUTPUT; + } else + if (s->nblock >= s->nblockMAX) { + BZ2_compressBlock(s, 0); + s->state = BZ_S_OUTPUT; + } else + if (s->strm->avail_in == 0) { + break; + } + } + } + + /*return progress_in || progress_out;*/ +} + + +/*---------------------------------------------------*/ +static +int BZ2_bzCompress(bz_stream *strm, int action) +{ + /*Bool progress;*/ + EState* s; + + s = strm->state; + + switch (s->mode) { + case BZ_M_RUNNING: + if (action == BZ_RUN) { + /*progress =*/ handle_compress(strm); + /*return progress ? BZ_RUN_OK : BZ_PARAM_ERROR;*/ + return BZ_RUN_OK; + } +#ifdef FLUSH_IS_UNUSED + else + if (action == BZ_FLUSH) { + //#s->avail_in_expect = strm->avail_in; + s->mode = BZ_M_FLUSHING; + goto case_BZ_M_FLUSHING; + } +#endif + else + /*if (action == BZ_FINISH)*/ { + //#s->avail_in_expect = strm->avail_in; + s->mode = BZ_M_FINISHING; + goto case_BZ_M_FINISHING; + } + +#ifdef FLUSH_IS_UNUSED + case_BZ_M_FLUSHING: + case BZ_M_FLUSHING: + /*if (s->avail_in_expect != s->strm->avail_in) + return BZ_SEQUENCE_ERROR;*/ + /*progress =*/ handle_compress(strm); + if (s->avail_in_expect > 0 || !isempty_RL(s) || s->state_out_pos < s->numZ) + return BZ_FLUSH_OK; + s->mode = BZ_M_RUNNING; + return BZ_RUN_OK; +#endif + + case_BZ_M_FINISHING: + /*case BZ_M_FINISHING:*/ + default: + /*if (s->avail_in_expect != s->strm->avail_in) + return BZ_SEQUENCE_ERROR;*/ + /*progress =*/ handle_compress(strm); + /*if (!progress) return BZ_SEQUENCE_ERROR;*/ + //#if (s->avail_in_expect > 0 || !isempty_RL(s) || s->state_out_pos < s->numZ) + //# return BZ_FINISH_OK; + if (s->strm->avail_in > 0 || !isempty_RL(s) || s->state_out_pos < s->numZ) + return BZ_FINISH_OK; + /*s->mode = BZ_M_IDLE;*/ + return BZ_STREAM_END; + } + /* return BZ_OK; --not reached--*/ +} + + +/*---------------------------------------------------*/ +#if ENABLE_FEATURE_CLEAN_UP +static +void BZ2_bzCompressEnd(bz_stream *strm) +{ + EState* s; + + s = strm->state; + free(s->arr1); + free(s->arr2); + free(s->ftab); + free(s->crc32table); + free(strm->state); +} +#endif + + +/*---------------------------------------------------*/ +/*--- Misc convenience stuff ---*/ +/*---------------------------------------------------*/ + +/*---------------------------------------------------*/ +#ifdef EXAMPLE_CODE_FOR_MEM_TO_MEM_COMPRESSION +static +int BZ2_bzBuffToBuffCompress(char* dest, + unsigned int* destLen, + char* source, + unsigned int sourceLen, + int blockSize100k) +{ + bz_stream strm; + int ret; + + if (dest == NULL || destLen == NULL + || source == NULL + || blockSize100k < 1 || blockSize100k > 9 + ) { + return BZ_PARAM_ERROR; + } + + BZ2_bzCompressInit(&strm, blockSize100k); + + strm.next_in = source; + strm.next_out = dest; + strm.avail_in = sourceLen; + strm.avail_out = *destLen; + + ret = BZ2_bzCompress(&strm, BZ_FINISH); + if (ret == BZ_FINISH_OK) goto output_overflow; + if (ret != BZ_STREAM_END) goto errhandler; + + /* normal termination */ + *destLen -= strm.avail_out; + BZ2_bzCompressEnd(&strm); + return BZ_OK; + + output_overflow: + BZ2_bzCompressEnd(&strm); + return BZ_OUTBUFF_FULL; + + errhandler: + BZ2_bzCompressEnd(&strm); + return ret; +} +#endif + +/*-------------------------------------------------------------*/ +/*--- end bzlib.c ---*/ +/*-------------------------------------------------------------*/ diff --git a/archival/libarchive/bz/bzlib.h b/archival/libarchive/bz/bzlib.h new file mode 100644 index 000000000..1bb811c4a --- /dev/null +++ b/archival/libarchive/bz/bzlib.h @@ -0,0 +1,65 @@ +/* + * bzip2 is written by Julian Seward . + * Adapted for busybox by Denys Vlasenko . + * See README and LICENSE files in this directory for more information. + */ + +/*-------------------------------------------------------------*/ +/*--- Public header file for the library. ---*/ +/*--- bzlib.h ---*/ +/*-------------------------------------------------------------*/ + +/* ------------------------------------------------------------------ +This file is part of bzip2/libbzip2, a program and library for +lossless, block-sorting data compression. + +bzip2/libbzip2 version 1.0.4 of 20 December 2006 +Copyright (C) 1996-2006 Julian Seward + +Please read the WARNING, DISCLAIMER and PATENTS sections in the +README file. + +This program is released under the terms of the license contained +in the file LICENSE. +------------------------------------------------------------------ */ + +#define BZ_RUN 0 +#define BZ_FLUSH 1 +#define BZ_FINISH 2 + +#define BZ_OK 0 +#define BZ_RUN_OK 1 +#define BZ_FLUSH_OK 2 +#define BZ_FINISH_OK 3 +#define BZ_STREAM_END 4 +#define BZ_SEQUENCE_ERROR (-1) +#define BZ_PARAM_ERROR (-2) +#define BZ_MEM_ERROR (-3) +#define BZ_DATA_ERROR (-4) +#define BZ_DATA_ERROR_MAGIC (-5) +#define BZ_IO_ERROR (-6) +#define BZ_UNEXPECTED_EOF (-7) +#define BZ_OUTBUFF_FULL (-8) +#define BZ_CONFIG_ERROR (-9) + +typedef struct bz_stream { + void *state; + char *next_in; + char *next_out; + unsigned avail_in; + unsigned avail_out; + /*unsigned long long total_in;*/ + unsigned long long total_out; +} bz_stream; + +/*-- Core (low-level) library functions --*/ + +static void BZ2_bzCompressInit(bz_stream *strm, int blockSize100k); +static int BZ2_bzCompress(bz_stream *strm, int action); +#if ENABLE_FEATURE_CLEAN_UP +static void BZ2_bzCompressEnd(bz_stream *strm); +#endif + +/*-------------------------------------------------------------*/ +/*--- end bzlib.h ---*/ +/*-------------------------------------------------------------*/ diff --git a/archival/libarchive/bz/bzlib_private.h b/archival/libarchive/bz/bzlib_private.h new file mode 100644 index 000000000..6430ce407 --- /dev/null +++ b/archival/libarchive/bz/bzlib_private.h @@ -0,0 +1,219 @@ +/* + * bzip2 is written by Julian Seward . + * Adapted for busybox by Denys Vlasenko . + * See README and LICENSE files in this directory for more information. + */ + +/*-------------------------------------------------------------*/ +/*--- Private header file for the library. ---*/ +/*--- bzlib_private.h ---*/ +/*-------------------------------------------------------------*/ + +/* ------------------------------------------------------------------ +This file is part of bzip2/libbzip2, a program and library for +lossless, block-sorting data compression. + +bzip2/libbzip2 version 1.0.4 of 20 December 2006 +Copyright (C) 1996-2006 Julian Seward + +Please read the WARNING, DISCLAIMER and PATENTS sections in the +README file. + +This program is released under the terms of the license contained +in the file LICENSE. +------------------------------------------------------------------ */ + +/* #include "bzlib.h" */ + +/*-- General stuff. --*/ + +typedef unsigned char Bool; + +#define True ((Bool)1) +#define False ((Bool)0) + +#if BZ_LIGHT_DEBUG +static void bz_assert_fail(int errcode) NORETURN; +#define AssertH(cond, errcode) \ +do { \ + if (!(cond)) \ + bz_assert_fail(errcode); \ +} while (0) +#else +#define AssertH(cond, msg) do { } while (0) +#endif + +#if BZ_DEBUG +#define AssertD(cond, msg) \ +do { \ + if (!(cond)) \ + bb_error_msg_and_die("(debug build): internal error %s", msg); \ +} while (0) +#else +#define AssertD(cond, msg) do { } while (0) +#endif + + +/*-- Header bytes. --*/ + +#define BZ_HDR_B 0x42 /* 'B' */ +#define BZ_HDR_Z 0x5a /* 'Z' */ +#define BZ_HDR_h 0x68 /* 'h' */ +#define BZ_HDR_0 0x30 /* '0' */ + +#define BZ_HDR_BZh0 0x425a6830 + +/*-- Constants for the back end. --*/ + +#define BZ_MAX_ALPHA_SIZE 258 +#define BZ_MAX_CODE_LEN 23 + +#define BZ_RUNA 0 +#define BZ_RUNB 1 + +#define BZ_N_GROUPS 6 +#define BZ_G_SIZE 50 +#define BZ_N_ITERS 4 + +#define BZ_MAX_SELECTORS (2 + (900000 / BZ_G_SIZE)) + + +/*-- Stuff for doing CRCs. --*/ + +#define BZ_INITIALISE_CRC(crcVar) \ +{ \ + crcVar = 0xffffffffL; \ +} + +#define BZ_FINALISE_CRC(crcVar) \ +{ \ + crcVar = ~(crcVar); \ +} + +#define BZ_UPDATE_CRC(s, crcVar, cha) \ +{ \ + crcVar = (crcVar << 8) ^ s->crc32table[(crcVar >> 24) ^ ((uint8_t)cha)]; \ +} + + +/*-- States and modes for compression. --*/ + +#define BZ_M_IDLE 1 +#define BZ_M_RUNNING 2 +#define BZ_M_FLUSHING 3 +#define BZ_M_FINISHING 4 + +#define BZ_S_OUTPUT 1 +#define BZ_S_INPUT 2 + +#define BZ_N_RADIX 2 +#define BZ_N_QSORT 12 +#define BZ_N_SHELL 18 +#define BZ_N_OVERSHOOT (BZ_N_RADIX + BZ_N_QSORT + BZ_N_SHELL + 2) + + +/*-- Structure holding all the compression-side stuff. --*/ + +typedef struct EState { + /* pointer back to the struct bz_stream */ + bz_stream *strm; + + /* mode this stream is in, and whether inputting */ + /* or outputting data */ + int32_t mode; + int32_t state; + + /* remembers avail_in when flush/finish requested */ +/* bbox: not needed, strm->avail_in always has the same value */ +/* commented out with '//#' throughout the code */ + /* uint32_t avail_in_expect; */ + + /* for doing the block sorting */ + int32_t origPtr; + uint32_t *arr1; + uint32_t *arr2; + uint32_t *ftab; + + /* aliases for arr1 and arr2 */ + uint32_t *ptr; + uint8_t *block; + uint16_t *mtfv; + uint8_t *zbits; + + /* guess what */ + uint32_t *crc32table; + + /* run-length-encoding of the input */ + uint32_t state_in_ch; + int32_t state_in_len; + + /* input and output limits and current posns */ + int32_t nblock; + int32_t nblockMAX; + int32_t numZ; + int32_t state_out_pos; + + /* the buffer for bit stream creation */ + uint32_t bsBuff; + int32_t bsLive; + + /* block and combined CRCs */ + uint32_t blockCRC; + uint32_t combinedCRC; + + /* misc administratium */ + int32_t blockNo; + int32_t blockSize100k; + + /* stuff for coding the MTF values */ + int32_t nMTF; + + /* map of bytes used in block */ + int32_t nInUse; + Bool inUse[256] ALIGNED(sizeof(long)); + uint8_t unseqToSeq[256]; + + /* stuff for coding the MTF values */ + int32_t mtfFreq [BZ_MAX_ALPHA_SIZE]; + uint8_t selector [BZ_MAX_SELECTORS]; + uint8_t selectorMtf[BZ_MAX_SELECTORS]; + + uint8_t len[BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE]; + + /* stack-saving measures: these can be local, but they are too big */ + int32_t sendMTFValues__code [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE]; + int32_t sendMTFValues__rfreq[BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE]; +#if CONFIG_BZIP2_FEATURE_SPEED >= 5 + /* second dimension: only 3 needed; 4 makes index calculations faster */ + uint32_t sendMTFValues__len_pack[BZ_MAX_ALPHA_SIZE][4]; +#endif + int32_t BZ2_hbMakeCodeLengths__heap [BZ_MAX_ALPHA_SIZE + 2]; + int32_t BZ2_hbMakeCodeLengths__weight[BZ_MAX_ALPHA_SIZE * 2]; + int32_t BZ2_hbMakeCodeLengths__parent[BZ_MAX_ALPHA_SIZE * 2]; + + int32_t mainSort__runningOrder[256]; + int32_t mainSort__copyStart[256]; + int32_t mainSort__copyEnd[256]; +} EState; + + +/*-- compression. --*/ + +static void +BZ2_blockSort(EState*); + +static void +BZ2_compressBlock(EState*, int); + +static void +BZ2_bsInitWrite(EState*); + +static void +BZ2_hbAssignCodes(int32_t*, uint8_t*, int32_t, int32_t, int32_t); + +static void +BZ2_hbMakeCodeLengths(EState*, uint8_t*, int32_t*, int32_t, int32_t); + +/*-------------------------------------------------------------*/ +/*--- end bzlib_private.h ---*/ +/*-------------------------------------------------------------*/ diff --git a/archival/libarchive/bz/compress.c b/archival/libarchive/bz/compress.c new file mode 100644 index 000000000..6f1c70a08 --- /dev/null +++ b/archival/libarchive/bz/compress.c @@ -0,0 +1,685 @@ +/* + * bzip2 is written by Julian Seward . + * Adapted for busybox by Denys Vlasenko . + * See README and LICENSE files in this directory for more information. + */ + +/*-------------------------------------------------------------*/ +/*--- Compression machinery (not incl block sorting) ---*/ +/*--- compress.c ---*/ +/*-------------------------------------------------------------*/ + +/* ------------------------------------------------------------------ +This file is part of bzip2/libbzip2, a program and library for +lossless, block-sorting data compression. + +bzip2/libbzip2 version 1.0.4 of 20 December 2006 +Copyright (C) 1996-2006 Julian Seward + +Please read the WARNING, DISCLAIMER and PATENTS sections in the +README file. + +This program is released under the terms of the license contained +in the file LICENSE. +------------------------------------------------------------------ */ + +/* CHANGES + * 0.9.0 -- original version. + * 0.9.0a/b -- no changes in this file. + * 0.9.0c -- changed setting of nGroups in sendMTFValues() + * so as to do a bit better on small files +*/ + +/* #include "bzlib_private.h" */ + +/*---------------------------------------------------*/ +/*--- Bit stream I/O ---*/ +/*---------------------------------------------------*/ + +/*---------------------------------------------------*/ +static +void BZ2_bsInitWrite(EState* s) +{ + s->bsLive = 0; + s->bsBuff = 0; +} + + +/*---------------------------------------------------*/ +static NOINLINE +void bsFinishWrite(EState* s) +{ + while (s->bsLive > 0) { + s->zbits[s->numZ] = (uint8_t)(s->bsBuff >> 24); + s->numZ++; + s->bsBuff <<= 8; + s->bsLive -= 8; + } +} + + +/*---------------------------------------------------*/ +static +/* Helps only on level 5, on other levels hurts. ? */ +#if CONFIG_BZIP2_FEATURE_SPEED >= 5 +ALWAYS_INLINE +#endif +void bsW(EState* s, int32_t n, uint32_t v) +{ + while (s->bsLive >= 8) { + s->zbits[s->numZ] = (uint8_t)(s->bsBuff >> 24); + s->numZ++; + s->bsBuff <<= 8; + s->bsLive -= 8; + } + s->bsBuff |= (v << (32 - s->bsLive - n)); + s->bsLive += n; +} + + +/*---------------------------------------------------*/ +static +void bsPutU32(EState* s, unsigned u) +{ + bsW(s, 8, (u >> 24) & 0xff); + bsW(s, 8, (u >> 16) & 0xff); + bsW(s, 8, (u >> 8) & 0xff); + bsW(s, 8, u & 0xff); +} + + +/*---------------------------------------------------*/ +static +void bsPutU16(EState* s, unsigned u) +{ + bsW(s, 8, (u >> 8) & 0xff); + bsW(s, 8, u & 0xff); +} + + +/*---------------------------------------------------*/ +/*--- The back end proper ---*/ +/*---------------------------------------------------*/ + +/*---------------------------------------------------*/ +static +void makeMaps_e(EState* s) +{ + int i; + s->nInUse = 0; + for (i = 0; i < 256; i++) { + if (s->inUse[i]) { + s->unseqToSeq[i] = s->nInUse; + s->nInUse++; + } + } +} + + +/*---------------------------------------------------*/ +static NOINLINE +void generateMTFValues(EState* s) +{ + uint8_t yy[256]; + int32_t i, j; + int32_t zPend; + int32_t wr; + int32_t EOB; + + /* + * After sorting (eg, here), + * s->arr1[0 .. s->nblock-1] holds sorted order, + * and + * ((uint8_t*)s->arr2)[0 .. s->nblock-1] + * holds the original block data. + * + * The first thing to do is generate the MTF values, + * and put them in ((uint16_t*)s->arr1)[0 .. s->nblock-1]. + * + * Because there are strictly fewer or equal MTF values + * than block values, ptr values in this area are overwritten + * with MTF values only when they are no longer needed. + * + * The final compressed bitstream is generated into the + * area starting at &((uint8_t*)s->arr2)[s->nblock] + * + * These storage aliases are set up in bzCompressInit(), + * except for the last one, which is arranged in + * compressBlock(). + */ + uint32_t* ptr = s->ptr; + uint8_t* block = s->block; + uint16_t* mtfv = s->mtfv; + + makeMaps_e(s); + EOB = s->nInUse+1; + + for (i = 0; i <= EOB; i++) + s->mtfFreq[i] = 0; + + wr = 0; + zPend = 0; + for (i = 0; i < s->nInUse; i++) + yy[i] = (uint8_t) i; + + for (i = 0; i < s->nblock; i++) { + uint8_t ll_i; + AssertD(wr <= i, "generateMTFValues(1)"); + j = ptr[i] - 1; + if (j < 0) + j += s->nblock; + ll_i = s->unseqToSeq[block[j]]; + AssertD(ll_i < s->nInUse, "generateMTFValues(2a)"); + + if (yy[0] == ll_i) { + zPend++; + } else { + if (zPend > 0) { + zPend--; + while (1) { + if (zPend & 1) { + mtfv[wr] = BZ_RUNB; wr++; + s->mtfFreq[BZ_RUNB]++; + } else { + mtfv[wr] = BZ_RUNA; wr++; + s->mtfFreq[BZ_RUNA]++; + } + if (zPend < 2) break; + zPend = (uint32_t)(zPend - 2) / 2; + /* bbox: unsigned div is easier */ + }; + zPend = 0; + } + { + register uint8_t rtmp; + register uint8_t* ryy_j; + register uint8_t rll_i; + rtmp = yy[1]; + yy[1] = yy[0]; + ryy_j = &(yy[1]); + rll_i = ll_i; + while (rll_i != rtmp) { + register uint8_t rtmp2; + ryy_j++; + rtmp2 = rtmp; + rtmp = *ryy_j; + *ryy_j = rtmp2; + }; + yy[0] = rtmp; + j = ryy_j - &(yy[0]); + mtfv[wr] = j+1; + wr++; + s->mtfFreq[j+1]++; + } + } + } + + if (zPend > 0) { + zPend--; + while (1) { + if (zPend & 1) { + mtfv[wr] = BZ_RUNB; + wr++; + s->mtfFreq[BZ_RUNB]++; + } else { + mtfv[wr] = BZ_RUNA; + wr++; + s->mtfFreq[BZ_RUNA]++; + } + if (zPend < 2) + break; + zPend = (uint32_t)(zPend - 2) / 2; + /* bbox: unsigned div is easier */ + }; + zPend = 0; + } + + mtfv[wr] = EOB; + wr++; + s->mtfFreq[EOB]++; + + s->nMTF = wr; +} + + +/*---------------------------------------------------*/ +#define BZ_LESSER_ICOST 0 +#define BZ_GREATER_ICOST 15 + +static NOINLINE +void sendMTFValues(EState* s) +{ + int32_t v, t, i, j, gs, ge, totc, bt, bc, iter; + int32_t nSelectors, alphaSize, minLen, maxLen, selCtr; + int32_t nGroups, nBytes; + + /* + * uint8_t len[BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE]; + * is a global since the decoder also needs it. + * + * int32_t code[BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE]; + * int32_t rfreq[BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE]; + * are also globals only used in this proc. + * Made global to keep stack frame size small. + */ +#define code sendMTFValues__code +#define rfreq sendMTFValues__rfreq +#define len_pack sendMTFValues__len_pack + + uint16_t cost[BZ_N_GROUPS]; + int32_t fave[BZ_N_GROUPS]; + + uint16_t* mtfv = s->mtfv; + + alphaSize = s->nInUse + 2; + for (t = 0; t < BZ_N_GROUPS; t++) + for (v = 0; v < alphaSize; v++) + s->len[t][v] = BZ_GREATER_ICOST; + + /*--- Decide how many coding tables to use ---*/ + AssertH(s->nMTF > 0, 3001); + if (s->nMTF < 200) nGroups = 2; else + if (s->nMTF < 600) nGroups = 3; else + if (s->nMTF < 1200) nGroups = 4; else + if (s->nMTF < 2400) nGroups = 5; else + nGroups = 6; + + /*--- Generate an initial set of coding tables ---*/ + { + int32_t nPart, remF, tFreq, aFreq; + + nPart = nGroups; + remF = s->nMTF; + gs = 0; + while (nPart > 0) { + tFreq = remF / nPart; + ge = gs - 1; + aFreq = 0; + while (aFreq < tFreq && ge < alphaSize-1) { + ge++; + aFreq += s->mtfFreq[ge]; + } + + if (ge > gs + && nPart != nGroups && nPart != 1 + && ((nGroups - nPart) % 2 == 1) /* bbox: can this be replaced by x & 1? */ + ) { + aFreq -= s->mtfFreq[ge]; + ge--; + } + + for (v = 0; v < alphaSize; v++) + if (v >= gs && v <= ge) + s->len[nPart-1][v] = BZ_LESSER_ICOST; + else + s->len[nPart-1][v] = BZ_GREATER_ICOST; + + nPart--; + gs = ge + 1; + remF -= aFreq; + } + } + + /* + * Iterate up to BZ_N_ITERS times to improve the tables. + */ + for (iter = 0; iter < BZ_N_ITERS; iter++) { + for (t = 0; t < nGroups; t++) + fave[t] = 0; + + for (t = 0; t < nGroups; t++) + for (v = 0; v < alphaSize; v++) + s->rfreq[t][v] = 0; + +#if CONFIG_BZIP2_FEATURE_SPEED >= 5 + /* + * Set up an auxiliary length table which is used to fast-track + * the common case (nGroups == 6). + */ + if (nGroups == 6) { + for (v = 0; v < alphaSize; v++) { + s->len_pack[v][0] = (s->len[1][v] << 16) | s->len[0][v]; + s->len_pack[v][1] = (s->len[3][v] << 16) | s->len[2][v]; + s->len_pack[v][2] = (s->len[5][v] << 16) | s->len[4][v]; + } + } +#endif + nSelectors = 0; + totc = 0; + gs = 0; + while (1) { + /*--- Set group start & end marks. --*/ + if (gs >= s->nMTF) + break; + ge = gs + BZ_G_SIZE - 1; + if (ge >= s->nMTF) + ge = s->nMTF-1; + + /* + * Calculate the cost of this group as coded + * by each of the coding tables. + */ + for (t = 0; t < nGroups; t++) + cost[t] = 0; +#if CONFIG_BZIP2_FEATURE_SPEED >= 5 + if (nGroups == 6 && 50 == ge-gs+1) { + /*--- fast track the common case ---*/ + register uint32_t cost01, cost23, cost45; + register uint16_t icv; + cost01 = cost23 = cost45 = 0; +#define BZ_ITER(nn) \ + icv = mtfv[gs+(nn)]; \ + cost01 += s->len_pack[icv][0]; \ + cost23 += s->len_pack[icv][1]; \ + cost45 += s->len_pack[icv][2]; + BZ_ITER(0); BZ_ITER(1); BZ_ITER(2); BZ_ITER(3); BZ_ITER(4); + BZ_ITER(5); BZ_ITER(6); BZ_ITER(7); BZ_ITER(8); BZ_ITER(9); + BZ_ITER(10); BZ_ITER(11); BZ_ITER(12); BZ_ITER(13); BZ_ITER(14); + BZ_ITER(15); BZ_ITER(16); BZ_ITER(17); BZ_ITER(18); BZ_ITER(19); + BZ_ITER(20); BZ_ITER(21); BZ_ITER(22); BZ_ITER(23); BZ_ITER(24); + BZ_ITER(25); BZ_ITER(26); BZ_ITER(27); BZ_ITER(28); BZ_ITER(29); + BZ_ITER(30); BZ_ITER(31); BZ_ITER(32); BZ_ITER(33); BZ_ITER(34); + BZ_ITER(35); BZ_ITER(36); BZ_ITER(37); BZ_ITER(38); BZ_ITER(39); + BZ_ITER(40); BZ_ITER(41); BZ_ITER(42); BZ_ITER(43); BZ_ITER(44); + BZ_ITER(45); BZ_ITER(46); BZ_ITER(47); BZ_ITER(48); BZ_ITER(49); +#undef BZ_ITER + cost[0] = cost01 & 0xffff; cost[1] = cost01 >> 16; + cost[2] = cost23 & 0xffff; cost[3] = cost23 >> 16; + cost[4] = cost45 & 0xffff; cost[5] = cost45 >> 16; + + } else +#endif + { + /*--- slow version which correctly handles all situations ---*/ + for (i = gs; i <= ge; i++) { + uint16_t icv = mtfv[i]; + for (t = 0; t < nGroups; t++) + cost[t] += s->len[t][icv]; + } + } + /* + * Find the coding table which is best for this group, + * and record its identity in the selector table. + */ + /*bc = 999999999;*/ + /*bt = -1;*/ + bc = cost[0]; + bt = 0; + for (t = 1 /*0*/; t < nGroups; t++) { + if (cost[t] < bc) { + bc = cost[t]; + bt = t; + } + } + totc += bc; + fave[bt]++; + s->selector[nSelectors] = bt; + nSelectors++; + + /* + * Increment the symbol frequencies for the selected table. + */ +/* 1% faster compress. +800 bytes */ +#if CONFIG_BZIP2_FEATURE_SPEED >= 4 + if (nGroups == 6 && 50 == ge-gs+1) { + /*--- fast track the common case ---*/ +#define BZ_ITUR(nn) s->rfreq[bt][mtfv[gs + (nn)]]++ + BZ_ITUR(0); BZ_ITUR(1); BZ_ITUR(2); BZ_ITUR(3); BZ_ITUR(4); + BZ_ITUR(5); BZ_ITUR(6); BZ_ITUR(7); BZ_ITUR(8); BZ_ITUR(9); + BZ_ITUR(10); BZ_ITUR(11); BZ_ITUR(12); BZ_ITUR(13); BZ_ITUR(14); + BZ_ITUR(15); BZ_ITUR(16); BZ_ITUR(17); BZ_ITUR(18); BZ_ITUR(19); + BZ_ITUR(20); BZ_ITUR(21); BZ_ITUR(22); BZ_ITUR(23); BZ_ITUR(24); + BZ_ITUR(25); BZ_ITUR(26); BZ_ITUR(27); BZ_ITUR(28); BZ_ITUR(29); + BZ_ITUR(30); BZ_ITUR(31); BZ_ITUR(32); BZ_ITUR(33); BZ_ITUR(34); + BZ_ITUR(35); BZ_ITUR(36); BZ_ITUR(37); BZ_ITUR(38); BZ_ITUR(39); + BZ_ITUR(40); BZ_ITUR(41); BZ_ITUR(42); BZ_ITUR(43); BZ_ITUR(44); + BZ_ITUR(45); BZ_ITUR(46); BZ_ITUR(47); BZ_ITUR(48); BZ_ITUR(49); +#undef BZ_ITUR + gs = ge + 1; + } else +#endif + { + /*--- slow version which correctly handles all situations ---*/ + while (gs <= ge) { + s->rfreq[bt][mtfv[gs]]++; + gs++; + } + /* already is: gs = ge + 1; */ + } + } + + /* + * Recompute the tables based on the accumulated frequencies. + */ + /* maxLen was changed from 20 to 17 in bzip2-1.0.3. See + * comment in huffman.c for details. */ + for (t = 0; t < nGroups; t++) + BZ2_hbMakeCodeLengths(s, &(s->len[t][0]), &(s->rfreq[t][0]), alphaSize, 17 /*20*/); + } + + AssertH(nGroups < 8, 3002); + AssertH(nSelectors < 32768 && nSelectors <= (2 + (900000 / BZ_G_SIZE)), 3003); + + /*--- Compute MTF values for the selectors. ---*/ + { + uint8_t pos[BZ_N_GROUPS], ll_i, tmp2, tmp; + + for (i = 0; i < nGroups; i++) + pos[i] = i; + for (i = 0; i < nSelectors; i++) { + ll_i = s->selector[i]; + j = 0; + tmp = pos[j]; + while (ll_i != tmp) { + j++; + tmp2 = tmp; + tmp = pos[j]; + pos[j] = tmp2; + }; + pos[0] = tmp; + s->selectorMtf[i] = j; + } + }; + + /*--- Assign actual codes for the tables. --*/ + for (t = 0; t < nGroups; t++) { + minLen = 32; + maxLen = 0; + for (i = 0; i < alphaSize; i++) { + if (s->len[t][i] > maxLen) maxLen = s->len[t][i]; + if (s->len[t][i] < minLen) minLen = s->len[t][i]; + } + AssertH(!(maxLen > 17 /*20*/), 3004); + AssertH(!(minLen < 1), 3005); + BZ2_hbAssignCodes(&(s->code[t][0]), &(s->len[t][0]), minLen, maxLen, alphaSize); + } + + /*--- Transmit the mapping table. ---*/ + { + /* bbox: optimized a bit more than in bzip2 */ + int inUse16 = 0; + for (i = 0; i < 16; i++) { + if (sizeof(long) <= 4) { + inUse16 = inUse16*2 + + ((*(uint32_t*)&(s->inUse[i * 16 + 0]) + | *(uint32_t*)&(s->inUse[i * 16 + 4]) + | *(uint32_t*)&(s->inUse[i * 16 + 8]) + | *(uint32_t*)&(s->inUse[i * 16 + 12])) != 0); + } else { /* Our CPU can do better */ + inUse16 = inUse16*2 + + ((*(uint64_t*)&(s->inUse[i * 16 + 0]) + | *(uint64_t*)&(s->inUse[i * 16 + 8])) != 0); + } + } + + nBytes = s->numZ; + bsW(s, 16, inUse16); + + inUse16 <<= (sizeof(int)*8 - 16); /* move 15th bit into sign bit */ + for (i = 0; i < 16; i++) { + if (inUse16 < 0) { + unsigned v16 = 0; + for (j = 0; j < 16; j++) + v16 = v16*2 + s->inUse[i * 16 + j]; + bsW(s, 16, v16); + } + inUse16 <<= 1; + } + } + + /*--- Now the selectors. ---*/ + nBytes = s->numZ; + bsW(s, 3, nGroups); + bsW(s, 15, nSelectors); + for (i = 0; i < nSelectors; i++) { + for (j = 0; j < s->selectorMtf[i]; j++) + bsW(s, 1, 1); + bsW(s, 1, 0); + } + + /*--- Now the coding tables. ---*/ + nBytes = s->numZ; + + for (t = 0; t < nGroups; t++) { + int32_t curr = s->len[t][0]; + bsW(s, 5, curr); + for (i = 0; i < alphaSize; i++) { + while (curr < s->len[t][i]) { bsW(s, 2, 2); curr++; /* 10 */ }; + while (curr > s->len[t][i]) { bsW(s, 2, 3); curr--; /* 11 */ }; + bsW(s, 1, 0); + } + } + + /*--- And finally, the block data proper ---*/ + nBytes = s->numZ; + selCtr = 0; + gs = 0; + while (1) { + if (gs >= s->nMTF) + break; + ge = gs + BZ_G_SIZE - 1; + if (ge >= s->nMTF) + ge = s->nMTF-1; + AssertH(s->selector[selCtr] < nGroups, 3006); + +/* Costs 1300 bytes and is _slower_ (on Intel Core 2) */ +#if 0 + if (nGroups == 6 && 50 == ge-gs+1) { + /*--- fast track the common case ---*/ + uint16_t mtfv_i; + uint8_t* s_len_sel_selCtr = &(s->len[s->selector[selCtr]][0]); + int32_t* s_code_sel_selCtr = &(s->code[s->selector[selCtr]][0]); +#define BZ_ITAH(nn) \ + mtfv_i = mtfv[gs+(nn)]; \ + bsW(s, s_len_sel_selCtr[mtfv_i], s_code_sel_selCtr[mtfv_i]) + BZ_ITAH(0); BZ_ITAH(1); BZ_ITAH(2); BZ_ITAH(3); BZ_ITAH(4); + BZ_ITAH(5); BZ_ITAH(6); BZ_ITAH(7); BZ_ITAH(8); BZ_ITAH(9); + BZ_ITAH(10); BZ_ITAH(11); BZ_ITAH(12); BZ_ITAH(13); BZ_ITAH(14); + BZ_ITAH(15); BZ_ITAH(16); BZ_ITAH(17); BZ_ITAH(18); BZ_ITAH(19); + BZ_ITAH(20); BZ_ITAH(21); BZ_ITAH(22); BZ_ITAH(23); BZ_ITAH(24); + BZ_ITAH(25); BZ_ITAH(26); BZ_ITAH(27); BZ_ITAH(28); BZ_ITAH(29); + BZ_ITAH(30); BZ_ITAH(31); BZ_ITAH(32); BZ_ITAH(33); BZ_ITAH(34); + BZ_ITAH(35); BZ_ITAH(36); BZ_ITAH(37); BZ_ITAH(38); BZ_ITAH(39); + BZ_ITAH(40); BZ_ITAH(41); BZ_ITAH(42); BZ_ITAH(43); BZ_ITAH(44); + BZ_ITAH(45); BZ_ITAH(46); BZ_ITAH(47); BZ_ITAH(48); BZ_ITAH(49); +#undef BZ_ITAH + gs = ge+1; + } else +#endif + { + /*--- slow version which correctly handles all situations ---*/ + /* code is bit bigger, but moves multiply out of the loop */ + uint8_t* s_len_sel_selCtr = &(s->len [s->selector[selCtr]][0]); + int32_t* s_code_sel_selCtr = &(s->code[s->selector[selCtr]][0]); + while (gs <= ge) { + bsW(s, + s_len_sel_selCtr[mtfv[gs]], + s_code_sel_selCtr[mtfv[gs]] + ); + gs++; + } + /* already is: gs = ge+1; */ + } + selCtr++; + } + AssertH(selCtr == nSelectors, 3007); +#undef code +#undef rfreq +#undef len_pack +} + + +/*---------------------------------------------------*/ +static +void BZ2_compressBlock(EState* s, int is_last_block) +{ + if (s->nblock > 0) { + BZ_FINALISE_CRC(s->blockCRC); + s->combinedCRC = (s->combinedCRC << 1) | (s->combinedCRC >> 31); + s->combinedCRC ^= s->blockCRC; + if (s->blockNo > 1) + s->numZ = 0; + + BZ2_blockSort(s); + } + + s->zbits = &((uint8_t*)s->arr2)[s->nblock]; + + /*-- If this is the first block, create the stream header. --*/ + if (s->blockNo == 1) { + BZ2_bsInitWrite(s); + /*bsPutU8(s, BZ_HDR_B);*/ + /*bsPutU8(s, BZ_HDR_Z);*/ + /*bsPutU8(s, BZ_HDR_h);*/ + /*bsPutU8(s, BZ_HDR_0 + s->blockSize100k);*/ + bsPutU32(s, BZ_HDR_BZh0 + s->blockSize100k); + } + + if (s->nblock > 0) { + /*bsPutU8(s, 0x31);*/ + /*bsPutU8(s, 0x41);*/ + /*bsPutU8(s, 0x59);*/ + /*bsPutU8(s, 0x26);*/ + bsPutU32(s, 0x31415926); + /*bsPutU8(s, 0x53);*/ + /*bsPutU8(s, 0x59);*/ + bsPutU16(s, 0x5359); + + /*-- Now the block's CRC, so it is in a known place. --*/ + bsPutU32(s, s->blockCRC); + + /* + * Now a single bit indicating (non-)randomisation. + * As of version 0.9.5, we use a better sorting algorithm + * which makes randomisation unnecessary. So always set + * the randomised bit to 'no'. Of course, the decoder + * still needs to be able to handle randomised blocks + * so as to maintain backwards compatibility with + * older versions of bzip2. + */ + bsW(s, 1, 0); + + bsW(s, 24, s->origPtr); + generateMTFValues(s); + sendMTFValues(s); + } + + /*-- If this is the last block, add the stream trailer. --*/ + if (is_last_block) { + /*bsPutU8(s, 0x17);*/ + /*bsPutU8(s, 0x72);*/ + /*bsPutU8(s, 0x45);*/ + /*bsPutU8(s, 0x38);*/ + bsPutU32(s, 0x17724538); + /*bsPutU8(s, 0x50);*/ + /*bsPutU8(s, 0x90);*/ + bsPutU16(s, 0x5090); + bsPutU32(s, s->combinedCRC); + bsFinishWrite(s); + } +} + + +/*-------------------------------------------------------------*/ +/*--- end compress.c ---*/ +/*-------------------------------------------------------------*/ diff --git a/archival/libarchive/bz/huffman.c b/archival/libarchive/bz/huffman.c new file mode 100644 index 000000000..676b1af66 --- /dev/null +++ b/archival/libarchive/bz/huffman.c @@ -0,0 +1,229 @@ +/* + * bzip2 is written by Julian Seward . + * Adapted for busybox by Denys Vlasenko . + * See README and LICENSE files in this directory for more information. + */ + +/*-------------------------------------------------------------*/ +/*--- Huffman coding low-level stuff ---*/ +/*--- huffman.c ---*/ +/*-------------------------------------------------------------*/ + +/* ------------------------------------------------------------------ +This file is part of bzip2/libbzip2, a program and library for +lossless, block-sorting data compression. + +bzip2/libbzip2 version 1.0.4 of 20 December 2006 +Copyright (C) 1996-2006 Julian Seward + +Please read the WARNING, DISCLAIMER and PATENTS sections in the +README file. + +This program is released under the terms of the license contained +in the file LICENSE. +------------------------------------------------------------------ */ + +/* #include "bzlib_private.h" */ + +/*---------------------------------------------------*/ +#define WEIGHTOF(zz0) ((zz0) & 0xffffff00) +#define DEPTHOF(zz1) ((zz1) & 0x000000ff) +#define MYMAX(zz2,zz3) ((zz2) > (zz3) ? (zz2) : (zz3)) + +#define ADDWEIGHTS(zw1,zw2) \ + (WEIGHTOF(zw1)+WEIGHTOF(zw2)) | \ + (1 + MYMAX(DEPTHOF(zw1),DEPTHOF(zw2))) + +#define UPHEAP(z) \ +{ \ + int32_t zz, tmp; \ + zz = z; \ + tmp = heap[zz]; \ + while (weight[tmp] < weight[heap[zz >> 1]]) { \ + heap[zz] = heap[zz >> 1]; \ + zz >>= 1; \ + } \ + heap[zz] = tmp; \ +} + + +/* 90 bytes, 0.3% of overall compress speed */ +#if CONFIG_BZIP2_FEATURE_SPEED >= 1 + +/* macro works better than inline (gcc 4.2.1) */ +#define DOWNHEAP1(heap, weight, Heap) \ +{ \ + int32_t zz, yy, tmp; \ + zz = 1; \ + tmp = heap[zz]; \ + while (1) { \ + yy = zz << 1; \ + if (yy > nHeap) \ + break; \ + if (yy < nHeap \ + && weight[heap[yy+1]] < weight[heap[yy]]) \ + yy++; \ + if (weight[tmp] < weight[heap[yy]]) \ + break; \ + heap[zz] = heap[yy]; \ + zz = yy; \ + } \ + heap[zz] = tmp; \ +} + +#else + +static +void DOWNHEAP1(int32_t *heap, int32_t *weight, int32_t nHeap) +{ + int32_t zz, yy, tmp; + zz = 1; + tmp = heap[zz]; + while (1) { + yy = zz << 1; + if (yy > nHeap) + break; + if (yy < nHeap + && weight[heap[yy + 1]] < weight[heap[yy]]) + yy++; + if (weight[tmp] < weight[heap[yy]]) + break; + heap[zz] = heap[yy]; + zz = yy; + } + heap[zz] = tmp; +} + +#endif + +/*---------------------------------------------------*/ +static +void BZ2_hbMakeCodeLengths(EState *s, + uint8_t *len, + int32_t *freq, + int32_t alphaSize, + int32_t maxLen) +{ + /* + * Nodes and heap entries run from 1. Entry 0 + * for both the heap and nodes is a sentinel. + */ + int32_t nNodes, nHeap, n1, n2, i, j, k; + Bool tooLong; + + /* bbox: moved to EState to save stack + int32_t heap [BZ_MAX_ALPHA_SIZE + 2]; + int32_t weight[BZ_MAX_ALPHA_SIZE * 2]; + int32_t parent[BZ_MAX_ALPHA_SIZE * 2]; + */ +#define heap (s->BZ2_hbMakeCodeLengths__heap) +#define weight (s->BZ2_hbMakeCodeLengths__weight) +#define parent (s->BZ2_hbMakeCodeLengths__parent) + + for (i = 0; i < alphaSize; i++) + weight[i+1] = (freq[i] == 0 ? 1 : freq[i]) << 8; + + while (1) { + nNodes = alphaSize; + nHeap = 0; + + heap[0] = 0; + weight[0] = 0; + parent[0] = -2; + + for (i = 1; i <= alphaSize; i++) { + parent[i] = -1; + nHeap++; + heap[nHeap] = i; + UPHEAP(nHeap); + } + + AssertH(nHeap < (BZ_MAX_ALPHA_SIZE+2), 2001); + + while (nHeap > 1) { + n1 = heap[1]; heap[1] = heap[nHeap]; nHeap--; DOWNHEAP1(heap, weight, nHeap); + n2 = heap[1]; heap[1] = heap[nHeap]; nHeap--; DOWNHEAP1(heap, weight, nHeap); + nNodes++; + parent[n1] = parent[n2] = nNodes; + weight[nNodes] = ADDWEIGHTS(weight[n1], weight[n2]); + parent[nNodes] = -1; + nHeap++; + heap[nHeap] = nNodes; + UPHEAP(nHeap); + } + + AssertH(nNodes < (BZ_MAX_ALPHA_SIZE * 2), 2002); + + tooLong = False; + for (i = 1; i <= alphaSize; i++) { + j = 0; + k = i; + while (parent[k] >= 0) { + k = parent[k]; + j++; + } + len[i-1] = j; + if (j > maxLen) + tooLong = True; + } + + if (!tooLong) + break; + + /* 17 Oct 04: keep-going condition for the following loop used + to be 'i < alphaSize', which missed the last element, + theoretically leading to the possibility of the compressor + looping. However, this count-scaling step is only needed if + one of the generated Huffman code words is longer than + maxLen, which up to and including version 1.0.2 was 20 bits, + which is extremely unlikely. In version 1.0.3 maxLen was + changed to 17 bits, which has minimal effect on compression + ratio, but does mean this scaling step is used from time to + time, enough to verify that it works. + + This means that bzip2-1.0.3 and later will only produce + Huffman codes with a maximum length of 17 bits. However, in + order to preserve backwards compatibility with bitstreams + produced by versions pre-1.0.3, the decompressor must still + handle lengths of up to 20. */ + + for (i = 1; i <= alphaSize; i++) { + j = weight[i] >> 8; + /* bbox: yes, it is a signed division. + * don't replace with shift! */ + j = 1 + (j / 2); + weight[i] = j << 8; + } + } +#undef heap +#undef weight +#undef parent +} + + +/*---------------------------------------------------*/ +static +void BZ2_hbAssignCodes(int32_t *code, + uint8_t *length, + int32_t minLen, + int32_t maxLen, + int32_t alphaSize) +{ + int32_t n, vec, i; + + vec = 0; + for (n = minLen; n <= maxLen; n++) { + for (i = 0; i < alphaSize; i++) { + if (length[i] == n) { + code[i] = vec; + vec++; + }; + } + vec <<= 1; + } +} + + +/*-------------------------------------------------------------*/ +/*--- end huffman.c ---*/ +/*-------------------------------------------------------------*/ diff --git a/archival/libarchive/data_align.c b/archival/libarchive/data_align.c new file mode 100644 index 000000000..2e56fa8ff --- /dev/null +++ b/archival/libarchive/data_align.c @@ -0,0 +1,15 @@ +/* vi: set sw=4 ts=4: */ +/* + * Licensed under GPLv2 or later, see file LICENSE in this source tree. + */ + +#include "libbb.h" +#include "archive.h" + +void FAST_FUNC data_align(archive_handle_t *archive_handle, unsigned boundary) +{ + unsigned skip_amount = (boundary - (archive_handle->offset % boundary)) % boundary; + + archive_handle->seek(archive_handle->src_fd, skip_amount); + archive_handle->offset += skip_amount; +} diff --git a/archival/libarchive/data_extract_all.c b/archival/libarchive/data_extract_all.c new file mode 100644 index 000000000..1b25c8bd6 --- /dev/null +++ b/archival/libarchive/data_extract_all.c @@ -0,0 +1,200 @@ +/* vi: set sw=4 ts=4: */ +/* + * Licensed under GPLv2 or later, see file LICENSE in this source tree. + */ + +#include "libbb.h" +#include "archive.h" + +void FAST_FUNC data_extract_all(archive_handle_t *archive_handle) +{ + file_header_t *file_header = archive_handle->file_header; + int dst_fd; + int res; + +#if ENABLE_FEATURE_TAR_SELINUX + char *sctx = archive_handle->tar__next_file_sctx; + if (!sctx) + sctx = archive_handle->tar__global_sctx; + if (sctx) { /* setfscreatecon is 4 syscalls, avoid if possible */ + setfscreatecon(sctx); + free(archive_handle->tar__next_file_sctx); + archive_handle->tar__next_file_sctx = NULL; + } +#endif + + if (archive_handle->ah_flags & ARCHIVE_CREATE_LEADING_DIRS) { + char *slash = strrchr(file_header->name, '/'); + if (slash) { + *slash = '\0'; + bb_make_directory(file_header->name, -1, FILEUTILS_RECUR); + *slash = '/'; + } + } + + if (archive_handle->ah_flags & ARCHIVE_UNLINK_OLD) { + /* Remove the entry if it exists */ + if (!S_ISDIR(file_header->mode)) { + /* Is it hardlink? + * We encode hard links as regular files of size 0 with a symlink */ + if (S_ISREG(file_header->mode) + && file_header->link_target + && file_header->size == 0 + ) { + /* Ugly special case: + * tar cf t.tar hardlink1 hardlink2 hardlink1 + * results in this tarball structure: + * hardlink1 + * hardlink2 -> hardlink1 + * hardlink1 -> hardlink1 <== !!! + */ + if (strcmp(file_header->link_target, file_header->name) == 0) + goto ret; + } + /* Proceed with deleting */ + if (unlink(file_header->name) == -1 + && errno != ENOENT + ) { + bb_perror_msg_and_die("can't remove old file %s", + file_header->name); + } + } + } + else if (archive_handle->ah_flags & ARCHIVE_EXTRACT_NEWER) { + /* Remove the existing entry if its older than the extracted entry */ + struct stat existing_sb; + if (lstat(file_header->name, &existing_sb) == -1) { + if (errno != ENOENT) { + bb_perror_msg_and_die("can't stat old file"); + } + } + else if (existing_sb.st_mtime >= file_header->mtime) { + if (!(archive_handle->ah_flags & ARCHIVE_EXTRACT_QUIET) + && !S_ISDIR(file_header->mode) + ) { + bb_error_msg("%s not created: newer or " + "same age file exists", file_header->name); + } + data_skip(archive_handle); + goto ret; + } + else if ((unlink(file_header->name) == -1) && (errno != EISDIR)) { + bb_perror_msg_and_die("can't remove old file %s", + file_header->name); + } + } + + /* Handle hard links separately + * We encode hard links as regular files of size 0 with a symlink */ + if (S_ISREG(file_header->mode) + && file_header->link_target + && file_header->size == 0 + ) { + /* hard link */ + res = link(file_header->link_target, file_header->name); + if ((res == -1) && !(archive_handle->ah_flags & ARCHIVE_EXTRACT_QUIET)) { + bb_perror_msg("can't create %slink " + "from %s to %s", "hard", + file_header->name, + file_header->link_target); + } + /* Hardlinks have no separate mode/ownership, skip chown/chmod */ + goto ret; + } + + /* Create the filesystem entry */ + switch (file_header->mode & S_IFMT) { + case S_IFREG: { + /* Regular file */ + int flags = O_WRONLY | O_CREAT | O_EXCL; + if (archive_handle->ah_flags & ARCHIVE_O_TRUNC) + flags = O_WRONLY | O_CREAT | O_TRUNC; + dst_fd = xopen3(file_header->name, + flags, + file_header->mode + ); + bb_copyfd_exact_size(archive_handle->src_fd, dst_fd, file_header->size); + close(dst_fd); + break; + } + case S_IFDIR: + res = mkdir(file_header->name, file_header->mode); + if ((res == -1) + && (errno != EISDIR) /* btw, Linux doesn't return this */ + && (errno != EEXIST) + && !(archive_handle->ah_flags & ARCHIVE_EXTRACT_QUIET) + ) { + bb_perror_msg("can't make dir %s", file_header->name); + } + break; + case S_IFLNK: + /* Symlink */ +//TODO: what if file_header->link_target == NULL (say, corrupted tarball?) + res = symlink(file_header->link_target, file_header->name); + if ((res == -1) + && !(archive_handle->ah_flags & ARCHIVE_EXTRACT_QUIET) + ) { + bb_perror_msg("can't create %slink " + "from %s to %s", "sym", + file_header->name, + file_header->link_target); + } + break; + case S_IFSOCK: + case S_IFBLK: + case S_IFCHR: + case S_IFIFO: + res = mknod(file_header->name, file_header->mode, file_header->device); + if ((res == -1) + && !(archive_handle->ah_flags & ARCHIVE_EXTRACT_QUIET) + ) { + bb_perror_msg("can't create node %s", file_header->name); + } + break; + default: + bb_error_msg_and_die("unrecognized file type"); + } + + if (!S_ISLNK(file_header->mode)) { + if (!(archive_handle->ah_flags & ARCHIVE_DONT_RESTORE_OWNER)) { + uid_t uid = file_header->uid; + gid_t gid = file_header->gid; +#if ENABLE_FEATURE_TAR_UNAME_GNAME + if (!(archive_handle->ah_flags & ARCHIVE_NUMERIC_OWNER)) { + if (file_header->tar__uname) { +//TODO: cache last name/id pair? + struct passwd *pwd = getpwnam(file_header->tar__uname); + if (pwd) uid = pwd->pw_uid; + } + if (file_header->tar__gname) { + struct group *grp = getgrnam(file_header->tar__gname); + if (grp) gid = grp->gr_gid; + } + } +#endif + /* GNU tar 1.15.1 uses chown, not lchown */ + chown(file_header->name, uid, gid); + } + /* uclibc has no lchmod, glibc is even stranger - + * it has lchmod which seems to do nothing! + * so we use chmod... */ + if (!(archive_handle->ah_flags & ARCHIVE_DONT_RESTORE_PERM)) { + chmod(file_header->name, file_header->mode); + } + if (archive_handle->ah_flags & ARCHIVE_RESTORE_DATE) { + struct timeval t[2]; + + t[1].tv_sec = t[0].tv_sec = file_header->mtime; + t[1].tv_usec = t[0].tv_usec = 0; + utimes(file_header->name, t); + } + } + + ret: ; +#if ENABLE_FEATURE_TAR_SELINUX + if (sctx) { + /* reset the context after creating an entry */ + setfscreatecon(NULL); + } +#endif +} diff --git a/archival/libarchive/data_extract_to_command.c b/archival/libarchive/data_extract_to_command.c new file mode 100644 index 000000000..2bbab7641 --- /dev/null +++ b/archival/libarchive/data_extract_to_command.c @@ -0,0 +1,134 @@ +/* vi: set sw=4 ts=4: */ +/* + * Licensed under GPLv2 or later, see file LICENSE in this source tree. + */ + +#include "libbb.h" +#include "archive.h" + +enum { + //TAR_FILETYPE, + TAR_MODE, + TAR_FILENAME, + TAR_REALNAME, +#if ENABLE_FEATURE_TAR_UNAME_GNAME + TAR_UNAME, + TAR_GNAME, +#endif + TAR_SIZE, + TAR_UID, + TAR_GID, + TAR_MAX, +}; + +static const char *const tar_var[] = { + // "FILETYPE", + "MODE", + "FILENAME", + "REALNAME", +#if ENABLE_FEATURE_TAR_UNAME_GNAME + "UNAME", + "GNAME", +#endif + "SIZE", + "UID", + "GID", +}; + +static void xputenv(char *str) +{ + if (putenv(str)) + bb_error_msg_and_die(bb_msg_memory_exhausted); +} + +static void str2env(char *env[], int idx, const char *str) +{ + env[idx] = xasprintf("TAR_%s=%s", tar_var[idx], str); + xputenv(env[idx]); +} + +static void dec2env(char *env[], int idx, unsigned long long val) +{ + env[idx] = xasprintf("TAR_%s=%llu", tar_var[idx], val); + xputenv(env[idx]); +} + +static void oct2env(char *env[], int idx, unsigned long val) +{ + env[idx] = xasprintf("TAR_%s=%lo", tar_var[idx], val); + xputenv(env[idx]); +} + +void FAST_FUNC data_extract_to_command(archive_handle_t *archive_handle) +{ + file_header_t *file_header = archive_handle->file_header; + +#if 0 /* do we need this? ENABLE_FEATURE_TAR_SELINUX */ + char *sctx = archive_handle->tar__next_file_sctx; + if (!sctx) + sctx = archive_handle->tar__global_sctx; + if (sctx) { /* setfscreatecon is 4 syscalls, avoid if possible */ + setfscreatecon(sctx); + free(archive_handle->tar__next_file_sctx); + archive_handle->tar__next_file_sctx = NULL; + } +#endif + + if ((file_header->mode & S_IFMT) == S_IFREG) { + pid_t pid; + int p[2], status; + char *tar_env[TAR_MAX]; + + memset(tar_env, 0, sizeof(tar_env)); + + xpipe(p); + pid = BB_MMU ? xfork() : xvfork(); + if (pid == 0) { + /* Child */ + /* str2env(tar_env, TAR_FILETYPE, "f"); - parent should do it once */ + oct2env(tar_env, TAR_MODE, file_header->mode); + str2env(tar_env, TAR_FILENAME, file_header->name); + str2env(tar_env, TAR_REALNAME, file_header->name); +#if ENABLE_FEATURE_TAR_UNAME_GNAME + str2env(tar_env, TAR_UNAME, file_header->tar__uname); + str2env(tar_env, TAR_GNAME, file_header->tar__gname); +#endif + dec2env(tar_env, TAR_SIZE, file_header->size); + dec2env(tar_env, TAR_UID, file_header->uid); + dec2env(tar_env, TAR_GID, file_header->gid); + close(p[1]); + xdup2(p[0], STDIN_FILENO); + signal(SIGPIPE, SIG_DFL); + execl(DEFAULT_SHELL, DEFAULT_SHELL_SHORT_NAME, "-c", archive_handle->tar__to_command, NULL); + bb_perror_msg_and_die("can't execute '%s'", DEFAULT_SHELL); + } + close(p[0]); + /* Our caller is expected to do signal(SIGPIPE, SIG_IGN) + * so that we don't die if child don't read all the input: */ + bb_copyfd_exact_size(archive_handle->src_fd, p[1], -file_header->size); + close(p[1]); + + if (safe_waitpid(pid, &status, 0) == -1) + bb_perror_msg_and_die("waitpid"); + if (WIFEXITED(status) && WEXITSTATUS(status)) + bb_error_msg_and_die("'%s' returned status %d", + archive_handle->tar__to_command, WEXITSTATUS(status)); + if (WIFSIGNALED(status)) + bb_error_msg_and_die("'%s' terminated on signal %d", + archive_handle->tar__to_command, WTERMSIG(status)); + + if (!BB_MMU) { + int i; + for (i = 0; i < TAR_MAX; i++) { + if (tar_env[i]) + bb_unsetenv_and_free(tar_env[i]); + } + } + } + +#if 0 /* ENABLE_FEATURE_TAR_SELINUX */ + if (sctx) + /* reset the context after creating an entry */ + setfscreatecon(NULL); +#endif +} diff --git a/archival/libarchive/data_extract_to_stdout.c b/archival/libarchive/data_extract_to_stdout.c new file mode 100644 index 000000000..91f3f3539 --- /dev/null +++ b/archival/libarchive/data_extract_to_stdout.c @@ -0,0 +1,14 @@ +/* vi: set sw=4 ts=4: */ +/* + * Licensed under GPLv2 or later, see file LICENSE in this source tree. + */ + +#include "libbb.h" +#include "archive.h" + +void FAST_FUNC data_extract_to_stdout(archive_handle_t *archive_handle) +{ + bb_copyfd_exact_size(archive_handle->src_fd, + STDOUT_FILENO, + archive_handle->file_header->size); +} diff --git a/archival/libarchive/data_skip.c b/archival/libarchive/data_skip.c new file mode 100644 index 000000000..a055424e2 --- /dev/null +++ b/archival/libarchive/data_skip.c @@ -0,0 +1,12 @@ +/* vi: set sw=4 ts=4: */ +/* + * Licensed under GPLv2 or later, see file LICENSE in this source tree. + */ + +#include "libbb.h" +#include "archive.h" + +void FAST_FUNC data_skip(archive_handle_t *archive_handle) +{ + archive_handle->seek(archive_handle->src_fd, archive_handle->file_header->size); +} diff --git a/archival/libarchive/decompress_bunzip2.c b/archival/libarchive/decompress_bunzip2.c new file mode 100644 index 000000000..4e46e6849 --- /dev/null +++ b/archival/libarchive/decompress_bunzip2.c @@ -0,0 +1,822 @@ +/* vi: set sw=4 ts=4: */ +/* Small bzip2 deflate implementation, by Rob Landley (rob@landley.net). + + Based on bzip2 decompression code by Julian R Seward (jseward@acm.org), + which also acknowledges contributions by Mike Burrows, David Wheeler, + Peter Fenwick, Alistair Moffat, Radford Neal, Ian H. Witten, + Robert Sedgewick, and Jon L. Bentley. + + Licensed under GPLv2 or later, see file LICENSE in this source tree. +*/ + +/* + Size and speed optimizations by Manuel Novoa III (mjn3@codepoet.org). + + More efficient reading of Huffman codes, a streamlined read_bunzip() + function, and various other tweaks. In (limited) tests, approximately + 20% faster than bzcat on x86 and about 10% faster on arm. + + Note that about 2/3 of the time is spent in read_bunzip() reversing + the Burrows-Wheeler transformation. Much of that time is delay + resulting from cache misses. + + (2010 update by vda: profiled "bzcat <84mbyte.bz2 >/dev/null" + on x86-64 CPU with L2 > 1M: get_next_block is hotter than read_bunzip: + %time seconds calls function + 71.01 12.69 444 get_next_block + 28.65 5.12 93065 read_bunzip + 00.22 0.04 7736490 get_bits + 00.11 0.02 47 dealloc_bunzip + 00.00 0.00 93018 full_write + ...) + + + I would ask that anyone benefiting from this work, especially those + using it in commercial products, consider making a donation to my local + non-profit hospice organization (www.hospiceacadiana.com) in the name of + the woman I loved, Toni W. Hagan, who passed away Feb. 12, 2003. + + Manuel + */ + +#include "libbb.h" +#include "archive.h" + +/* Constants for Huffman coding */ +#define MAX_GROUPS 6 +#define GROUP_SIZE 50 /* 64 would have been more efficient */ +#define MAX_HUFCODE_BITS 20 /* Longest Huffman code allowed */ +#define MAX_SYMBOLS 258 /* 256 literals + RUNA + RUNB */ +#define SYMBOL_RUNA 0 +#define SYMBOL_RUNB 1 + +/* Status return values */ +#define RETVAL_OK 0 +#define RETVAL_LAST_BLOCK (-1) +#define RETVAL_NOT_BZIP_DATA (-2) +#define RETVAL_UNEXPECTED_INPUT_EOF (-3) +#define RETVAL_SHORT_WRITE (-4) +#define RETVAL_DATA_ERROR (-5) +#define RETVAL_OUT_OF_MEMORY (-6) +#define RETVAL_OBSOLETE_INPUT (-7) + +/* Other housekeeping constants */ +#define IOBUF_SIZE 4096 + +/* This is what we know about each Huffman coding group */ +struct group_data { + /* We have an extra slot at the end of limit[] for a sentinel value. */ + int limit[MAX_HUFCODE_BITS+1], base[MAX_HUFCODE_BITS], permute[MAX_SYMBOLS]; + int minLen, maxLen; +}; + +/* Structure holding all the housekeeping data, including IO buffers and + * memory that persists between calls to bunzip + * Found the most used member: + * cat this_file.c | sed -e 's/"/ /g' -e "s/'/ /g" | xargs -n1 \ + * | grep 'bd->' | sed 's/^.*bd->/bd->/' | sort | $PAGER + * and moved it (inbufBitCount) to offset 0. + */ +struct bunzip_data { + /* I/O tracking data (file handles, buffers, positions, etc.) */ + unsigned inbufBitCount, inbufBits; + int in_fd, out_fd, inbufCount, inbufPos /*, outbufPos*/; + uint8_t *inbuf /*,*outbuf*/; + + /* State for interrupting output loop */ + int writeCopies, writePos, writeRunCountdown, writeCount; + int writeCurrent; /* actually a uint8_t */ + + /* The CRC values stored in the block header and calculated from the data */ + uint32_t headerCRC, totalCRC, writeCRC; + + /* Intermediate buffer and its size (in bytes) */ + uint32_t *dbuf; + unsigned dbufSize; + + /* For I/O error handling */ + jmp_buf jmpbuf; + + /* Big things go last (register-relative addressing can be larger for big offsets) */ + uint32_t crc32Table[256]; + 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 */ + + +/* Return the next nnn bits of input. All reads from the compressed input + are done through this function. All reads are big endian */ +static unsigned get_bits(bunzip_data *bd, int bits_wanted) +{ + unsigned bits = 0; + /* Cache bd->inbufBitCount in a CPU register (hopefully): */ + int bit_count = bd->inbufBitCount; + + /* If we need to get more data from the byte buffer, do so. (Loop getting + one byte at a time to enforce endianness and avoid unaligned access.) */ + while (bit_count < bits_wanted) { + + /* If we need to read more data from file into byte buffer, do so */ + if (bd->inbufPos == bd->inbufCount) { + /* if "no input fd" case: in_fd == -1, read fails, we jump */ + bd->inbufCount = read(bd->in_fd, bd->inbuf, IOBUF_SIZE); + if (bd->inbufCount <= 0) + longjmp(bd->jmpbuf, RETVAL_UNEXPECTED_INPUT_EOF); + bd->inbufPos = 0; + } + + /* Avoid 32-bit overflow (dump bit buffer to top of output) */ + if (bit_count >= 24) { + bits = bd->inbufBits & ((1 << bit_count) - 1); + bits_wanted -= bit_count; + bits <<= bits_wanted; + bit_count = 0; + } + + /* Grab next 8 bits of input from buffer. */ + bd->inbufBits = (bd->inbufBits << 8) | bd->inbuf[bd->inbufPos++]; + bit_count += 8; + } + + /* Calculate result */ + bit_count -= bits_wanted; + bd->inbufBitCount = bit_count; + bits |= (bd->inbufBits >> bit_count) & ((1 << bits_wanted) - 1); + + return bits; +} + +/* Unpacks the next block and sets up for the inverse Burrows-Wheeler step. */ +static int get_next_block(bunzip_data *bd) +{ + struct group_data *hufGroup; + int dbufCount, dbufSize, groupCount, *base, *limit, selector, + i, j, t, runPos, symCount, symTotal, nSelectors, byteCount[256]; + int runCnt = runCnt; /* for compiler */ + uint8_t uc, symToByte[256], mtfSymbol[256], *selectors; + uint32_t *dbuf; + unsigned origPtr; + + dbuf = bd->dbuf; + dbufSize = bd->dbufSize; + selectors = bd->selectors; + +/* In bbox, we are ok with aborting through setjmp which is set up in start_bunzip */ +#if 0 + /* Reset longjmp I/O error handling */ + i = setjmp(bd->jmpbuf); + if (i) return i; +#endif + + /* Read in header signature and CRC, then validate signature. + (last block signature means CRC is for whole file, return now) */ + i = get_bits(bd, 24); + j = get_bits(bd, 24); + bd->headerCRC = get_bits(bd, 32); + if ((i == 0x177245) && (j == 0x385090)) return RETVAL_LAST_BLOCK; + if ((i != 0x314159) || (j != 0x265359)) return RETVAL_NOT_BZIP_DATA; + + /* We can add support for blockRandomised if anybody complains. There was + some code for this in busybox 1.0.0-pre3, but nobody ever noticed that + it didn't actually work. */ + if (get_bits(bd, 1)) return RETVAL_OBSOLETE_INPUT; + origPtr = get_bits(bd, 24); + if ((int)origPtr > dbufSize) return RETVAL_DATA_ERROR; + + /* mapping table: if some byte values are never used (encoding things + like ascii text), the compression code removes the gaps to have fewer + symbols to deal with, and writes a sparse bitfield indicating which + values were present. We make a translation table to convert the symbols + back to the corresponding bytes. */ + symTotal = 0; + i = 0; + t = get_bits(bd, 16); + do { + if (t & (1 << 15)) { + unsigned inner_map = get_bits(bd, 16); + do { + if (inner_map & (1 << 15)) + symToByte[symTotal++] = i; + inner_map <<= 1; + i++; + } while (i & 15); + i -= 16; + } + t <<= 1; + i += 16; + } while (i < 256); + + /* How many different Huffman coding groups does this block use? */ + groupCount = get_bits(bd, 3); + if (groupCount < 2 || groupCount > MAX_GROUPS) + return RETVAL_DATA_ERROR; + + /* nSelectors: Every GROUP_SIZE many symbols we select a new Huffman coding + group. Read in the group selector list, which is stored as MTF encoded + bit runs. (MTF=Move To Front, as each value is used it's moved to the + start of the list.) */ + for (i = 0; i < groupCount; i++) + mtfSymbol[i] = i; + nSelectors = get_bits(bd, 15); + if (!nSelectors) + return RETVAL_DATA_ERROR; + for (i = 0; i < nSelectors; i++) { + uint8_t tmp_byte; + /* Get next value */ + int n = 0; + while (get_bits(bd, 1)) { + if (n >= groupCount) return RETVAL_DATA_ERROR; + n++; + } + /* Decode MTF to get the next selector */ + tmp_byte = mtfSymbol[n]; + while (--n >= 0) + mtfSymbol[n + 1] = mtfSymbol[n]; + mtfSymbol[0] = selectors[i] = tmp_byte; + } + + /* Read the Huffman coding tables for each group, which code for symTotal + literal symbols, plus two run symbols (RUNA, RUNB) */ + symCount = symTotal + 2; + for (j = 0; j < groupCount; j++) { + uint8_t length[MAX_SYMBOLS]; + /* 8 bits is ALMOST enough for temp[], see below */ + unsigned temp[MAX_HUFCODE_BITS+1]; + int minLen, maxLen, pp, len_m1; + + /* Read Huffman code lengths for each symbol. They're stored in + a way similar to mtf; record a starting value for the first symbol, + and an offset from the previous value for every symbol after that. + (Subtracting 1 before the loop and then adding it back at the end is + an optimization that makes the test inside the loop simpler: symbol + length 0 becomes negative, so an unsigned inequality catches it.) */ + len_m1 = get_bits(bd, 5) - 1; + for (i = 0; i < symCount; i++) { + for (;;) { + int two_bits; + if ((unsigned)len_m1 > (MAX_HUFCODE_BITS-1)) + return RETVAL_DATA_ERROR; + + /* If first bit is 0, stop. Else second bit indicates whether + to increment or decrement the value. Optimization: grab 2 + bits and unget the second if the first was 0. */ + two_bits = get_bits(bd, 2); + if (two_bits < 2) { + bd->inbufBitCount++; + break; + } + + /* Add one if second bit 1, else subtract 1. Avoids if/else */ + len_m1 += (((two_bits+1) & 2) - 1); + } + + /* Correct for the initial -1, to get the final symbol length */ + length[i] = len_m1 + 1; + } + + /* Find largest and smallest lengths in this group */ + minLen = maxLen = length[0]; + for (i = 1; i < symCount; i++) { + if (length[i] > maxLen) maxLen = length[i]; + else if (length[i] < minLen) minLen = length[i]; + } + + /* Calculate permute[], base[], and limit[] tables from length[]. + * + * permute[] is the lookup table for converting Huffman coded symbols + * into decoded symbols. base[] is the amount to subtract from the + * value of a Huffman symbol of a given length when using permute[]. + * + * limit[] indicates the largest numerical value a symbol with a given + * number of bits can have. This is how the Huffman codes can vary in + * length: each code with a value>limit[length] needs another bit. + */ + hufGroup = bd->groups + j; + hufGroup->minLen = minLen; + hufGroup->maxLen = maxLen; + + /* Note that minLen can't be smaller than 1, so we adjust the base + and limit array pointers so we're not always wasting the first + entry. We do this again when using them (during symbol decoding). */ + base = hufGroup->base - 1; + limit = hufGroup->limit - 1; + + /* Calculate permute[]. Concurently, initialize temp[] and limit[]. */ + pp = 0; + for (i = minLen; i <= maxLen; i++) { + int k; + temp[i] = limit[i] = 0; + for (k = 0; k < symCount; k++) + if (length[k] == i) + hufGroup->permute[pp++] = k; + } + + /* Count symbols coded for at each bit length */ + /* NB: in pathological cases, temp[8] can end ip being 256. + * That's why uint8_t is too small for temp[]. */ + for (i = 0; i < symCount; i++) temp[length[i]]++; + + /* Calculate limit[] (the largest symbol-coding value at each bit + * length, which is (previous limit<<1)+symbols at this level), and + * base[] (number of symbols to ignore at each bit length, which is + * limit minus the cumulative count of symbols coded for already). */ + pp = t = 0; + for (i = minLen; i < maxLen;) { + unsigned temp_i = temp[i]; + + pp += temp_i; + + /* We read the largest possible symbol size and then unget bits + after determining how many we need, and those extra bits could + be set to anything. (They're noise from future symbols.) At + each level we're really only interested in the first few bits, + so here we set all the trailing to-be-ignored bits to 1 so they + don't affect the value>limit[length] comparison. */ + limit[i] = (pp << (maxLen - i)) - 1; + pp <<= 1; + t += temp_i; + base[++i] = pp - t; + } + limit[maxLen] = pp + temp[maxLen] - 1; + limit[maxLen+1] = INT_MAX; /* Sentinel value for reading next sym. */ + base[minLen] = 0; + } + + /* We've finished reading and digesting the block header. Now read this + block's Huffman coded symbols from the file and undo the Huffman coding + and run length encoding, saving the result into dbuf[dbufCount++] = uc */ + + /* Initialize symbol occurrence counters and symbol Move To Front table */ + /*memset(byteCount, 0, sizeof(byteCount)); - smaller, but slower */ + for (i = 0; i < 256; i++) { + byteCount[i] = 0; + mtfSymbol[i] = (uint8_t)i; + } + + /* Loop through compressed symbols. */ + + runPos = dbufCount = selector = 0; + for (;;) { + int nextSym; + + /* Fetch next Huffman coding group from list. */ + symCount = GROUP_SIZE - 1; + if (selector >= nSelectors) return RETVAL_DATA_ERROR; + hufGroup = bd->groups + selectors[selector++]; + base = hufGroup->base - 1; + limit = hufGroup->limit - 1; + + continue_this_group: + /* Read next Huffman-coded symbol. */ + + /* Note: It is far cheaper to read maxLen bits and back up than it is + to read minLen bits and then add additional bit at a time, testing + as we go. Because there is a trailing last block (with file CRC), + there is no danger of the overread causing an unexpected EOF for a + valid compressed file. + */ + if (1) { + /* As a further optimization, we do the read inline + (falling back to a call to get_bits if the buffer runs dry). + */ + int new_cnt; + while ((new_cnt = bd->inbufBitCount - hufGroup->maxLen) < 0) { + /* bd->inbufBitCount < hufGroup->maxLen */ + if (bd->inbufPos == bd->inbufCount) { + nextSym = get_bits(bd, hufGroup->maxLen); + goto got_huff_bits; + } + bd->inbufBits = (bd->inbufBits << 8) | bd->inbuf[bd->inbufPos++]; + bd->inbufBitCount += 8; + }; + bd->inbufBitCount = new_cnt; /* "bd->inbufBitCount -= hufGroup->maxLen;" */ + nextSym = (bd->inbufBits >> new_cnt) & ((1 << hufGroup->maxLen) - 1); + got_huff_bits: ; + } else { /* unoptimized equivalent */ + nextSym = get_bits(bd, hufGroup->maxLen); + } + /* Figure how many bits are in next symbol and unget extras */ + i = hufGroup->minLen; + while (nextSym > limit[i]) ++i; + j = hufGroup->maxLen - i; + if (j < 0) + return RETVAL_DATA_ERROR; + bd->inbufBitCount += j; + + /* Huffman decode value to get nextSym (with bounds checking) */ + nextSym = (nextSym >> j) - base[i]; + if ((unsigned)nextSym >= MAX_SYMBOLS) + return RETVAL_DATA_ERROR; + nextSym = hufGroup->permute[nextSym]; + + /* We have now decoded the symbol, which indicates either a new literal + byte, or a repeated run of the most recent literal byte. First, + check if nextSym indicates a repeated run, and if so loop collecting + how many times to repeat the last literal. */ + if ((unsigned)nextSym <= SYMBOL_RUNB) { /* RUNA or RUNB */ + + /* If this is the start of a new run, zero out counter */ + if (runPos == 0) { + runPos = 1; + runCnt = 0; + } + + /* Neat trick that saves 1 symbol: instead of or-ing 0 or 1 at + each bit position, add 1 or 2 instead. For example, + 1011 is 1<<0 + 1<<1 + 2<<2. 1010 is 2<<0 + 2<<1 + 1<<2. + You can make any bit pattern that way using 1 less symbol than + the basic or 0/1 method (except all bits 0, which would use no + symbols, but a run of length 0 doesn't mean anything in this + context). Thus space is saved. */ + runCnt += (runPos << nextSym); /* +runPos if RUNA; +2*runPos if RUNB */ + if (runPos < dbufSize) runPos <<= 1; + goto end_of_huffman_loop; + } + + /* When we hit the first non-run symbol after a run, we now know + how many times to repeat the last literal, so append that many + copies to our buffer of decoded symbols (dbuf) now. (The last + literal used is the one at the head of the mtfSymbol array.) */ + if (runPos != 0) { + uint8_t tmp_byte; + if (dbufCount + runCnt >= dbufSize) return RETVAL_DATA_ERROR; + tmp_byte = symToByte[mtfSymbol[0]]; + byteCount[tmp_byte] += runCnt; + while (--runCnt >= 0) dbuf[dbufCount++] = (uint32_t)tmp_byte; + runPos = 0; + } + + /* Is this the terminating symbol? */ + if (nextSym > symTotal) break; + + /* At this point, nextSym indicates a new literal character. Subtract + one to get the position in the MTF array at which this literal is + currently to be found. (Note that the result can't be -1 or 0, + because 0 and 1 are RUNA and RUNB. But another instance of the + first symbol in the mtf array, position 0, would have been handled + as part of a run above. Therefore 1 unused mtf position minus + 2 non-literal nextSym values equals -1.) */ + if (dbufCount >= dbufSize) return RETVAL_DATA_ERROR; + i = nextSym - 1; + uc = mtfSymbol[i]; + + /* Adjust the MTF array. Since we typically expect to move only a + * small number of symbols, and are bound by 256 in any case, using + * memmove here would typically be bigger and slower due to function + * call overhead and other assorted setup costs. */ + do { + mtfSymbol[i] = mtfSymbol[i-1]; + } while (--i); + mtfSymbol[0] = uc; + uc = symToByte[uc]; + + /* We have our literal byte. Save it into dbuf. */ + byteCount[uc]++; + dbuf[dbufCount++] = (uint32_t)uc; + + /* Skip group initialization if we're not done with this group. Done + * this way to avoid compiler warning. */ + end_of_huffman_loop: + if (--symCount >= 0) goto continue_this_group; + } + + /* At this point, we've read all the Huffman-coded symbols (and repeated + runs) for this block from the input stream, and decoded them into the + intermediate buffer. There are dbufCount many decoded bytes in dbuf[]. + Now undo the Burrows-Wheeler transform on dbuf. + See http://dogma.net/markn/articles/bwt/bwt.htm + */ + + /* Turn byteCount into cumulative occurrence counts of 0 to n-1. */ + j = 0; + for (i = 0; i < 256; i++) { + int tmp_count = j + byteCount[i]; + byteCount[i] = j; + j = tmp_count; + } + + /* Figure out what order dbuf would be in if we sorted it. */ + for (i = 0; i < dbufCount; i++) { + uint8_t tmp_byte = (uint8_t)dbuf[i]; + int tmp_count = byteCount[tmp_byte]; + dbuf[tmp_count] |= (i << 8); + byteCount[tmp_byte] = tmp_count + 1; + } + + /* Decode first byte by hand to initialize "previous" byte. Note that it + doesn't get output, and if the first three characters are identical + it doesn't qualify as a run (hence writeRunCountdown=5). */ + if (dbufCount) { + uint32_t tmp; + if ((int)origPtr >= dbufCount) return RETVAL_DATA_ERROR; + tmp = dbuf[origPtr]; + bd->writeCurrent = (uint8_t)tmp; + bd->writePos = (tmp >> 8); + bd->writeRunCountdown = 5; + } + bd->writeCount = dbufCount; + + return RETVAL_OK; +} + +/* Undo Burrows-Wheeler transform on intermediate buffer to produce output. + If start_bunzip was initialized with out_fd=-1, then up to len bytes of + data are written to outbuf. Return value is number of bytes written or + error (all errors are negative numbers). If out_fd!=-1, outbuf and len + are ignored, data is written to out_fd and return is RETVAL_OK or error. + + 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. + (Why? This allows to get rid of one local variable) +*/ +int FAST_FUNC read_bunzip(bunzip_data *bd, char *outbuf, int len) +{ + const uint32_t *dbuf; + int pos, current, previous; + uint32_t CRC; + + /* If we already have error/end indicator, return it */ + if (bd->writeCount < 0) + return bd->writeCount; + + dbuf = bd->dbuf; + + /* Register-cached state (hopefully): */ + pos = bd->writePos; + current = bd->writeCurrent; + CRC = bd->writeCRC; /* small loss on x86-32 (not enough regs), win on x86-64 */ + + /* We will always have pending decoded data to write into the output + buffer unless this is the very first call (in which case we haven't + Huffman-decoded a block into the intermediate buffer yet). */ + if (bd->writeCopies) { + + dec_writeCopies: + /* Inside the loop, writeCopies means extra copies (beyond 1) */ + --bd->writeCopies; + + /* Loop outputting bytes */ + for (;;) { + + /* If the output buffer is full, save cached state and return */ + if (--len < 0) { + /* Unlikely branch. + * Use of "goto" instead of keeping code here + * helps compiler to realize this. */ + goto outbuf_full; + } + + /* Write next byte into output buffer, updating CRC */ + *outbuf++ = current; + CRC = (CRC << 8) ^ bd->crc32Table[(CRC >> 24) ^ current]; + + /* Loop now if we're outputting multiple copies of this byte */ + if (bd->writeCopies) { + /* Unlikely branch */ + /*--bd->writeCopies;*/ + /*continue;*/ + /* Same, but (ab)using other existing --writeCopies operation + * (and this if() compiles into just test+branch pair): */ + goto dec_writeCopies; + } + decode_next_byte: + if (--bd->writeCount < 0) + break; /* input block is fully consumed, need next one */ + + /* Follow sequence vector to undo Burrows-Wheeler transform */ + previous = current; + pos = dbuf[pos]; + current = (uint8_t)pos; + pos >>= 8; + + /* After 3 consecutive copies of the same byte, the 4th + * is a repeat count. We count down from 4 instead + * of counting up because testing for non-zero is faster */ + if (--bd->writeRunCountdown != 0) { + if (current != previous) + bd->writeRunCountdown = 4; + } else { + /* Unlikely branch */ + /* We have a repeated run, this byte indicates the count */ + bd->writeCopies = current; + current = previous; + bd->writeRunCountdown = 5; + + /* Sometimes there are just 3 bytes (run length 0) */ + if (!bd->writeCopies) goto decode_next_byte; + + /* Subtract the 1 copy we'd output anyway to get extras */ + --bd->writeCopies; + } + } /* for(;;) */ + + /* Decompression of this input block completed successfully */ + bd->writeCRC = CRC = ~CRC; + bd->totalCRC = ((bd->totalCRC << 1) | (bd->totalCRC >> 31)) ^ CRC; + + /* If this block had a CRC error, force file level CRC error */ + if (CRC != bd->headerCRC) { + bd->totalCRC = bd->headerCRC + 1; + return RETVAL_LAST_BLOCK; + } + } + + /* Refill the intermediate buffer by Huffman-decoding next block of input */ + { + int r = get_next_block(bd); + if (r) { /* error/end */ + bd->writeCount = r; + return (r != RETVAL_LAST_BLOCK) ? r : len; + } + } + + CRC = ~0; + pos = bd->writePos; + current = bd->writeCurrent; + goto decode_next_byte; + + outbuf_full: + /* Output buffer is full, save cached state and return */ + bd->writePos = pos; + bd->writeCurrent = current; + bd->writeCRC = CRC; + + bd->writeCopies++; + + return 0; +} + +/* Allocate the structure, read file header. If in_fd==-1, inbuf must contain + a complete bunzip file (len bytes long). If in_fd!=-1, inbuf and len are + ignored, and data is read from file handle into temporary buffer. */ + +/* 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(bunzip_data **bdp, int in_fd, + const void *inbuf, int len) +{ + bunzip_data *bd; + unsigned i; + enum { + BZh0 = ('B' << 24) + ('Z' << 16) + ('h' << 8) + '0', + h0 = ('h' << 8) + '0', + }; + + /* Figure out how much data to allocate */ + i = sizeof(bunzip_data); + if (in_fd != -1) i += IOBUF_SIZE; + + /* Allocate bunzip_data. Most fields initialize to zero. */ + bd = *bdp = xzalloc(i); + + /* Setup input buffer */ + bd->in_fd = in_fd; + if (-1 == in_fd) { + /* in this case, bd->inbuf is read-only */ + bd->inbuf = (void*)inbuf; /* cast away const-ness */ + } else { + bd->inbuf = (uint8_t*)(bd + 1); + memcpy(bd->inbuf, inbuf, len); + } + bd->inbufCount = len; + + /* Init the CRC32 table (big endian) */ + crc32_filltable(bd->crc32Table, 1); + + /* Setup for I/O error handling via longjmp */ + i = setjmp(bd->jmpbuf); + if (i) return i; + + /* Ensure that file starts with "BZh['1'-'9']." */ + /* Update: now caller verifies 1st two bytes, makes .gz/.bz2 + * integration easier */ + /* was: */ + /* i = get_bits(bd, 32); */ + /* if ((unsigned)(i - BZh0 - 1) >= 9) return RETVAL_NOT_BZIP_DATA; */ + i = get_bits(bd, 16); + if ((unsigned)(i - h0 - 1) >= 9) return RETVAL_NOT_BZIP_DATA; + + /* Fourth byte (ascii '1'-'9') indicates block size in units of 100k of + uncompressed data. Allocate intermediate buffer for block. */ + /* bd->dbufSize = 100000 * (i - BZh0); */ + bd->dbufSize = 100000 * (i - h0); + + /* Cannot use xmalloc - may leak bd in NOFORK case! */ + bd->dbuf = malloc_or_warn(bd->dbufSize * sizeof(bd->dbuf[0])); + if (!bd->dbuf) { + free(bd); + xfunc_die(); + } + return RETVAL_OK; +} + +void FAST_FUNC dealloc_bunzip(bunzip_data *bd) +{ + free(bd->dbuf); + free(bd); +} + + +/* Decompress src_fd to dst_fd. Stops at end of bzip data, not end of file. */ +IF_DESKTOP(long long) int FAST_FUNC +unpack_bz2_stream(int src_fd, int dst_fd) +{ + IF_DESKTOP(long long total_written = 0;) + bunzip_data *bd; + char *outbuf; + int i; + unsigned len; + + outbuf = xmalloc(IOBUF_SIZE); + len = 0; + while (1) { /* "Process one BZ... stream" loop */ + + i = start_bunzip(&bd, src_fd, outbuf + 2, len); + + if (i == 0) { + while (1) { /* "Produce some output bytes" loop */ + i = read_bunzip(bd, outbuf, IOBUF_SIZE); + if (i < 0) /* error? */ + break; + i = IOBUF_SIZE - i; /* number of bytes produced */ + if (i == 0) /* EOF? */ + break; + if (i != full_write(dst_fd, outbuf, i)) { + bb_error_msg("short write"); + i = RETVAL_SHORT_WRITE; + goto release_mem; + } + IF_DESKTOP(total_written += i;) + } + } + + if (i != RETVAL_LAST_BLOCK) { + bb_error_msg("bunzip error %d", i); + break; + } + if (bd->headerCRC != bd->totalCRC) { + bb_error_msg("CRC error"); + break; + } + + /* Successfully unpacked one BZ stream */ + i = RETVAL_OK; + + /* Do we have "BZ..." after last processed byte? + * pbzip2 (parallelized bzip2) produces such files. + */ + len = bd->inbufCount - bd->inbufPos; + memcpy(outbuf, &bd->inbuf[bd->inbufPos], len); + if (len < 2) { + if (safe_read(src_fd, outbuf + len, 2 - len) != 2 - len) + break; + len = 2; + } + if (*(uint16_t*)outbuf != BZIP2_MAGIC) /* "BZ"? */ + break; + dealloc_bunzip(bd); + len -= 2; + } + + release_mem: + dealloc_bunzip(bd); + free(outbuf); + + return i ? i : IF_DESKTOP(total_written) + 0; +} + +IF_DESKTOP(long long) int FAST_FUNC +unpack_bz2_stream_prime(int src_fd, int dst_fd) +{ + uint16_t magic2; + xread(src_fd, &magic2, 2); + if (magic2 != BZIP2_MAGIC) { + bb_error_msg_and_die("invalid magic"); + } + return unpack_bz2_stream(src_fd, dst_fd); +} + +#ifdef TESTING + +static char *const bunzip_errors[] = { + NULL, "Bad file checksum", "Not bzip data", + "Unexpected input EOF", "Unexpected output EOF", "Data error", + "Out of memory", "Obsolete (pre 0.9.5) bzip format not supported" +}; + +/* Dumb little test thing, decompress stdin to stdout */ +int main(int argc, char **argv) +{ + int i; + char c; + + int i = unpack_bz2_stream_prime(0, 1); + if (i < 0) + fprintf(stderr, "%s\n", bunzip_errors[-i]); + else if (read(STDIN_FILENO, &c, 1)) + fprintf(stderr, "Trailing garbage ignored\n"); + return -i; +} +#endif diff --git a/archival/libarchive/decompress_uncompress.c b/archival/libarchive/decompress_uncompress.c new file mode 100644 index 000000000..44d894244 --- /dev/null +++ b/archival/libarchive/decompress_uncompress.c @@ -0,0 +1,307 @@ +/* vi: set sw=4 ts=4: */ +/* uncompress for busybox -- (c) 2002 Robert Griebl + * + * based on the original compress42.c source + * (see disclaimer below) + */ + +/* (N)compress42.c - File compression ala IEEE Computer, Mar 1992. + * + * Authors: + * Spencer W. Thomas (decvax!harpo!utah-cs!utah-gr!thomas) + * Jim McKie (decvax!mcvax!jim) + * Steve Davies (decvax!vax135!petsd!peora!srd) + * Ken Turkowski (decvax!decwrl!turtlevax!ken) + * James A. Woods (decvax!ihnp4!ames!jaw) + * Joe Orost (decvax!vax135!petsd!joe) + * Dave Mack (csu@alembic.acs.com) + * Peter Jannesen, Network Communication Systems + * (peter@ncs.nl) + * + * marc@suse.de : a small security fix for a buffer overflow + * + * [... History snipped ...] + * + */ + +#include "libbb.h" +#include "archive.h" + + +/* Default input buffer size */ +#define IBUFSIZ 2048 + +/* Default output buffer size */ +#define OBUFSIZ 2048 + +/* Defines for third byte of header */ +#define BIT_MASK 0x1f /* Mask for 'number of compresssion bits' */ + /* Masks 0x20 and 0x40 are free. */ + /* I think 0x20 should mean that there is */ + /* a fourth header byte (for expansion). */ +#define BLOCK_MODE 0x80 /* Block compression if table is full and */ + /* compression rate is dropping flush tables */ + /* the next two codes should not be changed lightly, as they must not */ + /* lie within the contiguous general code space. */ +#define FIRST 257 /* first free entry */ +#define CLEAR 256 /* table clear output code */ + +#define INIT_BITS 9 /* initial number of bits/code */ + + +/* machine variants which require cc -Dmachine: pdp11, z8000, DOS */ +#define HBITS 17 /* 50% occupancy */ +#define HSIZE (1< BITS) { + bb_error_msg("compressed with %d bits, can only handle " + BITS_STR" bits", maxbits); + goto err; + } + + n_bits = INIT_BITS; + maxcode = MAXCODE(INIT_BITS) - 1; + bitmask = (1 << INIT_BITS) - 1; + oldcode = -1; + finchar = 0; + outpos = 0; + posbits = 0 << 3; + + free_ent = ((block_mode) ? FIRST : 256); + + /* As above, initialize the first 256 entries in the table. */ + /*clear_tab_prefixof(); - done by xzalloc */ + + for (code = 255; code >= 0; --code) { + tab_suffixof(code) = (unsigned char) code; + } + + do { + resetbuf: + { + int i; + int e; + int o; + + o = posbits >> 3; + e = insize - o; + + for (i = 0; i < e; ++i) + inbuf[i] = inbuf[i + o]; + + insize = e; + posbits = 0; + } + + if (insize < (int) (IBUFSIZ + 64) - IBUFSIZ) { + rsize = safe_read(fd_in, inbuf + insize, IBUFSIZ); +//error check?? + insize += rsize; + } + + inbits = ((rsize > 0) ? (insize - insize % n_bits) << 3 : + (insize << 3) - (n_bits - 1)); + + while (inbits > posbits) { + if (free_ent > maxcode) { + posbits = + ((posbits - 1) + + ((n_bits << 3) - + (posbits - 1 + (n_bits << 3)) % (n_bits << 3))); + ++n_bits; + if (n_bits == maxbits) { + maxcode = maxmaxcode; + } else { + maxcode = MAXCODE(n_bits) - 1; + } + bitmask = (1 << n_bits) - 1; + goto resetbuf; + } + { + unsigned char *p = &inbuf[posbits >> 3]; + + code = ((((long) (p[0])) | ((long) (p[1]) << 8) | + ((long) (p[2]) << 16)) >> (posbits & 0x7)) & bitmask; + } + posbits += n_bits; + + + if (oldcode == -1) { + oldcode = code; + finchar = (int) oldcode; + outbuf[outpos++] = (unsigned char) finchar; + continue; + } + + if (code == CLEAR && block_mode) { + clear_tab_prefixof(); + free_ent = FIRST - 1; + posbits = + ((posbits - 1) + + ((n_bits << 3) - + (posbits - 1 + (n_bits << 3)) % (n_bits << 3))); + n_bits = INIT_BITS; + maxcode = MAXCODE(INIT_BITS) - 1; + bitmask = (1 << INIT_BITS) - 1; + goto resetbuf; + } + + incode = code; + stackp = de_stack; + + /* Special case for KwKwK string. */ + if (code >= free_ent) { + if (code > free_ent) { + unsigned char *p; + + posbits -= n_bits; + p = &inbuf[posbits >> 3]; + + bb_error_msg + ("insize:%d posbits:%d inbuf:%02X %02X %02X %02X %02X (%d)", + insize, posbits, p[-1], p[0], p[1], p[2], p[3], + (posbits & 07)); + bb_error_msg("corrupted data"); + goto err; + } + + *--stackp = (unsigned char) finchar; + code = oldcode; + } + + /* Generate output characters in reverse order */ + while ((long) code >= (long) 256) { + *--stackp = tab_suffixof(code); + code = tab_prefixof(code); + } + + finchar = tab_suffixof(code); + *--stackp = (unsigned char) finchar; + + /* And put them out in forward order */ + { + int i; + + i = de_stack - stackp; + if (outpos + i >= OBUFSIZ) { + do { + if (i > OBUFSIZ - outpos) { + i = OBUFSIZ - outpos; + } + + if (i > 0) { + memcpy(outbuf + outpos, stackp, i); + outpos += i; + } + + if (outpos >= OBUFSIZ) { + full_write(fd_out, outbuf, outpos); +//error check?? + IF_DESKTOP(total_written += outpos;) + outpos = 0; + } + stackp += i; + i = de_stack - stackp; + } while (i > 0); + } else { + memcpy(outbuf + outpos, stackp, i); + outpos += i; + } + } + + /* Generate the new entry. */ + code = free_ent; + if (code < maxmaxcode) { + tab_prefixof(code) = (unsigned short) oldcode; + tab_suffixof(code) = (unsigned char) finchar; + free_ent = code + 1; + } + + /* Remember previous code. */ + oldcode = incode; + } + + } while (rsize > 0); + + if (outpos > 0) { + full_write(fd_out, outbuf, outpos); +//error check?? + IF_DESKTOP(total_written += outpos;) + } + + retval = IF_DESKTOP(total_written) + 0; + err: + free(inbuf); + free(outbuf); + free(htab); + free(codetab); + return retval; +} diff --git a/archival/libarchive/decompress_unlzma.c b/archival/libarchive/decompress_unlzma.c new file mode 100644 index 000000000..a04714341 --- /dev/null +++ b/archival/libarchive/decompress_unlzma.c @@ -0,0 +1,465 @@ +/* vi: set sw=4 ts=4: */ +/* + * Small lzma deflate implementation. + * Copyright (C) 2006 Aurelien Jacobs + * + * Based on LzmaDecode.c from the LZMA SDK 4.22 (http://www.7-zip.org/) + * Copyright (C) 1999-2005 Igor Pavlov + * + * Licensed under GPLv2 or later, see file LICENSE in this source tree. + */ +#include "libbb.h" +#include "archive.h" + +#if ENABLE_FEATURE_LZMA_FAST +# define speed_inline ALWAYS_INLINE +# define size_inline +#else +# define speed_inline +# define size_inline ALWAYS_INLINE +#endif + + +typedef struct { + int fd; + uint8_t *ptr; + +/* Was keeping rc on stack in unlzma and separately allocating buffer, + * but with "buffer 'attached to' allocated rc" code is smaller: */ + /* uint8_t *buffer; */ +#define RC_BUFFER ((uint8_t*)(rc+1)) + + uint8_t *buffer_end; + +/* Had provisions for variable buffer, but we don't need it here */ + /* int buffer_size; */ +#define RC_BUFFER_SIZE 0x10000 + + uint32_t code; + uint32_t range; + uint32_t bound; +} rc_t; + +#define RC_TOP_BITS 24 +#define RC_MOVE_BITS 5 +#define RC_MODEL_TOTAL_BITS 11 + + +/* Called twice: once at startup (LZMA_FAST only) and once in rc_normalize() */ +static size_inline void rc_read(rc_t *rc) +{ + int buffer_size = safe_read(rc->fd, RC_BUFFER, RC_BUFFER_SIZE); +//TODO: return -1 instead +//This will make unlzma delete broken unpacked file on unpack errors + if (buffer_size <= 0) + bb_error_msg_and_die("unexpected EOF"); + rc->ptr = RC_BUFFER; + rc->buffer_end = RC_BUFFER + buffer_size; +} + +/* Called twice, but one callsite is in speed_inline'd rc_is_bit_1() */ +static void rc_do_normalize(rc_t *rc) +{ + if (rc->ptr >= rc->buffer_end) + rc_read(rc); + rc->range <<= 8; + rc->code = (rc->code << 8) | *rc->ptr++; +} + +/* Called once */ +static ALWAYS_INLINE rc_t* rc_init(int fd) /*, int buffer_size) */ +{ + int i; + rc_t *rc; + + rc = xzalloc(sizeof(*rc) + RC_BUFFER_SIZE); + + rc->fd = fd; + /* rc->ptr = rc->buffer_end; */ + + for (i = 0; i < 5; i++) { +#if ENABLE_FEATURE_LZMA_FAST + if (rc->ptr >= rc->buffer_end) + rc_read(rc); + rc->code = (rc->code << 8) | *rc->ptr++; +#else + rc_do_normalize(rc); +#endif + } + rc->range = 0xFFFFFFFF; + return rc; +} + +/* Called once */ +static ALWAYS_INLINE void rc_free(rc_t *rc) +{ + free(rc); +} + +static ALWAYS_INLINE void rc_normalize(rc_t *rc) +{ + if (rc->range < (1 << RC_TOP_BITS)) { + rc_do_normalize(rc); + } +} + +/* rc_is_bit_1 is called 9 times */ +static speed_inline int rc_is_bit_1(rc_t *rc, uint16_t *p) +{ + rc_normalize(rc); + rc->bound = *p * (rc->range >> RC_MODEL_TOTAL_BITS); + if (rc->code < rc->bound) { + rc->range = rc->bound; + *p += ((1 << RC_MODEL_TOTAL_BITS) - *p) >> RC_MOVE_BITS; + return 0; + } + rc->range -= rc->bound; + rc->code -= rc->bound; + *p -= *p >> RC_MOVE_BITS; + return 1; +} + +/* Called 4 times in unlzma loop */ +static speed_inline int rc_get_bit(rc_t *rc, uint16_t *p, int *symbol) +{ + int ret = rc_is_bit_1(rc, p); + *symbol = *symbol * 2 + ret; + return ret; +} + +/* Called once */ +static ALWAYS_INLINE int rc_direct_bit(rc_t *rc) +{ + rc_normalize(rc); + rc->range >>= 1; + if (rc->code >= rc->range) { + rc->code -= rc->range; + return 1; + } + return 0; +} + +/* Called twice */ +static speed_inline void +rc_bit_tree_decode(rc_t *rc, uint16_t *p, int num_levels, int *symbol) +{ + int i = num_levels; + + *symbol = 1; + while (i--) + rc_get_bit(rc, p + *symbol, symbol); + *symbol -= 1 << num_levels; +} + + +typedef struct { + uint8_t pos; + uint32_t dict_size; + uint64_t dst_size; +} PACKED lzma_header_t; + + +/* #defines will force compiler to compute/optimize each one with each usage. + * Have heart and use enum instead. */ +enum { + LZMA_BASE_SIZE = 1846, + LZMA_LIT_SIZE = 768, + + LZMA_NUM_POS_BITS_MAX = 4, + + LZMA_LEN_NUM_LOW_BITS = 3, + LZMA_LEN_NUM_MID_BITS = 3, + LZMA_LEN_NUM_HIGH_BITS = 8, + + LZMA_LEN_CHOICE = 0, + LZMA_LEN_CHOICE_2 = (LZMA_LEN_CHOICE + 1), + LZMA_LEN_LOW = (LZMA_LEN_CHOICE_2 + 1), + LZMA_LEN_MID = (LZMA_LEN_LOW \ + + (1 << (LZMA_NUM_POS_BITS_MAX + LZMA_LEN_NUM_LOW_BITS))), + LZMA_LEN_HIGH = (LZMA_LEN_MID \ + + (1 << (LZMA_NUM_POS_BITS_MAX + LZMA_LEN_NUM_MID_BITS))), + LZMA_NUM_LEN_PROBS = (LZMA_LEN_HIGH + (1 << LZMA_LEN_NUM_HIGH_BITS)), + + LZMA_NUM_STATES = 12, + LZMA_NUM_LIT_STATES = 7, + + LZMA_START_POS_MODEL_INDEX = 4, + LZMA_END_POS_MODEL_INDEX = 14, + LZMA_NUM_FULL_DISTANCES = (1 << (LZMA_END_POS_MODEL_INDEX >> 1)), + + LZMA_NUM_POS_SLOT_BITS = 6, + LZMA_NUM_LEN_TO_POS_STATES = 4, + + LZMA_NUM_ALIGN_BITS = 4, + + LZMA_MATCH_MIN_LEN = 2, + + LZMA_IS_MATCH = 0, + LZMA_IS_REP = (LZMA_IS_MATCH + (LZMA_NUM_STATES << LZMA_NUM_POS_BITS_MAX)), + LZMA_IS_REP_G0 = (LZMA_IS_REP + LZMA_NUM_STATES), + LZMA_IS_REP_G1 = (LZMA_IS_REP_G0 + LZMA_NUM_STATES), + LZMA_IS_REP_G2 = (LZMA_IS_REP_G1 + LZMA_NUM_STATES), + LZMA_IS_REP_0_LONG = (LZMA_IS_REP_G2 + LZMA_NUM_STATES), + LZMA_POS_SLOT = (LZMA_IS_REP_0_LONG \ + + (LZMA_NUM_STATES << LZMA_NUM_POS_BITS_MAX)), + LZMA_SPEC_POS = (LZMA_POS_SLOT \ + + (LZMA_NUM_LEN_TO_POS_STATES << LZMA_NUM_POS_SLOT_BITS)), + LZMA_ALIGN = (LZMA_SPEC_POS \ + + LZMA_NUM_FULL_DISTANCES - LZMA_END_POS_MODEL_INDEX), + LZMA_LEN_CODER = (LZMA_ALIGN + (1 << LZMA_NUM_ALIGN_BITS)), + LZMA_REP_LEN_CODER = (LZMA_LEN_CODER + LZMA_NUM_LEN_PROBS), + LZMA_LITERAL = (LZMA_REP_LEN_CODER + LZMA_NUM_LEN_PROBS), +}; + + +IF_DESKTOP(long long) int FAST_FUNC +unpack_lzma_stream(int src_fd, int dst_fd) +{ + IF_DESKTOP(long long total_written = 0;) + lzma_header_t header; + int lc, pb, lp; + uint32_t pos_state_mask; + uint32_t literal_pos_mask; + uint16_t *p; + int num_bits; + int num_probs; + rc_t *rc; + int i; + uint8_t *buffer; + uint8_t previous_byte = 0; + size_t buffer_pos = 0, global_pos = 0; + int len = 0; + int state = 0; + uint32_t rep0 = 1, rep1 = 1, rep2 = 1, rep3 = 1; + + if (full_read(src_fd, &header, sizeof(header)) != sizeof(header) + || header.pos >= (9 * 5 * 5) + ) { + bb_error_msg("bad lzma header"); + return -1; + } + + i = header.pos / 9; + lc = header.pos % 9; + pb = i / 5; + lp = i % 5; + pos_state_mask = (1 << pb) - 1; + literal_pos_mask = (1 << lp) - 1; + + header.dict_size = SWAP_LE32(header.dict_size); + header.dst_size = SWAP_LE64(header.dst_size); + + if (header.dict_size == 0) + header.dict_size++; + + buffer = xmalloc(MIN(header.dst_size, header.dict_size)); + + num_probs = LZMA_BASE_SIZE + (LZMA_LIT_SIZE << (lc + lp)); + p = xmalloc(num_probs * sizeof(*p)); + num_probs += LZMA_LITERAL - LZMA_BASE_SIZE; + for (i = 0; i < num_probs; i++) + p[i] = (1 << RC_MODEL_TOTAL_BITS) >> 1; + + rc = rc_init(src_fd); /*, RC_BUFFER_SIZE); */ + + while (global_pos + buffer_pos < header.dst_size) { + int pos_state = (buffer_pos + global_pos) & pos_state_mask; + uint16_t *prob = p + LZMA_IS_MATCH + (state << LZMA_NUM_POS_BITS_MAX) + pos_state; + + if (!rc_is_bit_1(rc, prob)) { + static const char next_state[LZMA_NUM_STATES] = + { 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 4, 5 }; + int mi = 1; + + prob = (p + LZMA_LITERAL + + (LZMA_LIT_SIZE * ((((buffer_pos + global_pos) & literal_pos_mask) << lc) + + (previous_byte >> (8 - lc)) + ) + ) + ); + + if (state >= LZMA_NUM_LIT_STATES) { + int match_byte; + uint32_t pos = buffer_pos - rep0; + + while (pos >= header.dict_size) + pos += header.dict_size; + match_byte = buffer[pos]; + do { + int bit; + + match_byte <<= 1; + bit = match_byte & 0x100; + bit ^= (rc_get_bit(rc, prob + 0x100 + bit + mi, &mi) << 8); /* 0x100 or 0 */ + if (bit) + break; + } while (mi < 0x100); + } + while (mi < 0x100) { + rc_get_bit(rc, prob + mi, &mi); + } + + state = next_state[state]; + + previous_byte = (uint8_t) mi; +#if ENABLE_FEATURE_LZMA_FAST + one_byte1: + buffer[buffer_pos++] = previous_byte; + if (buffer_pos == header.dict_size) { + buffer_pos = 0; + global_pos += header.dict_size; + if (full_write(dst_fd, buffer, header.dict_size) != (ssize_t)header.dict_size) + goto bad; + IF_DESKTOP(total_written += header.dict_size;) + } +#else + len = 1; + goto one_byte2; +#endif + } else { + int offset; + uint16_t *prob2; +#define prob_len prob2 + + prob2 = p + LZMA_IS_REP + state; + if (!rc_is_bit_1(rc, prob2)) { + rep3 = rep2; + rep2 = rep1; + rep1 = rep0; + state = state < LZMA_NUM_LIT_STATES ? 0 : 3; + prob2 = p + LZMA_LEN_CODER; + } else { + prob2 += LZMA_IS_REP_G0 - LZMA_IS_REP; + if (!rc_is_bit_1(rc, prob2)) { + prob2 = (p + LZMA_IS_REP_0_LONG + + (state << LZMA_NUM_POS_BITS_MAX) + + pos_state + ); + if (!rc_is_bit_1(rc, prob2)) { +#if ENABLE_FEATURE_LZMA_FAST + uint32_t pos = buffer_pos - rep0; + state = state < LZMA_NUM_LIT_STATES ? 9 : 11; + while (pos >= header.dict_size) + pos += header.dict_size; + previous_byte = buffer[pos]; + goto one_byte1; +#else + state = state < LZMA_NUM_LIT_STATES ? 9 : 11; + len = 1; + goto string; +#endif + } + } else { + uint32_t distance; + + prob2 += LZMA_IS_REP_G1 - LZMA_IS_REP_G0; + distance = rep1; + if (rc_is_bit_1(rc, prob2)) { + prob2 += LZMA_IS_REP_G2 - LZMA_IS_REP_G1; + distance = rep2; + if (rc_is_bit_1(rc, prob2)) { + distance = rep3; + rep3 = rep2; + } + rep2 = rep1; + } + rep1 = rep0; + rep0 = distance; + } + state = state < LZMA_NUM_LIT_STATES ? 8 : 11; + prob2 = p + LZMA_REP_LEN_CODER; + } + + prob_len = prob2 + LZMA_LEN_CHOICE; + num_bits = LZMA_LEN_NUM_LOW_BITS; + if (!rc_is_bit_1(rc, prob_len)) { + prob_len += LZMA_LEN_LOW - LZMA_LEN_CHOICE + + (pos_state << LZMA_LEN_NUM_LOW_BITS); + offset = 0; + } else { + prob_len += LZMA_LEN_CHOICE_2 - LZMA_LEN_CHOICE; + if (!rc_is_bit_1(rc, prob_len)) { + prob_len += LZMA_LEN_MID - LZMA_LEN_CHOICE_2 + + (pos_state << LZMA_LEN_NUM_MID_BITS); + offset = 1 << LZMA_LEN_NUM_LOW_BITS; + num_bits += LZMA_LEN_NUM_MID_BITS - LZMA_LEN_NUM_LOW_BITS; + } else { + prob_len += LZMA_LEN_HIGH - LZMA_LEN_CHOICE_2; + offset = ((1 << LZMA_LEN_NUM_LOW_BITS) + + (1 << LZMA_LEN_NUM_MID_BITS)); + num_bits += LZMA_LEN_NUM_HIGH_BITS - LZMA_LEN_NUM_LOW_BITS; + } + } + rc_bit_tree_decode(rc, prob_len, num_bits, &len); + len += offset; + + if (state < 4) { + int pos_slot; + uint16_t *prob3; + + state += LZMA_NUM_LIT_STATES; + prob3 = p + LZMA_POS_SLOT + + ((len < LZMA_NUM_LEN_TO_POS_STATES ? len : + LZMA_NUM_LEN_TO_POS_STATES - 1) + << LZMA_NUM_POS_SLOT_BITS); + rc_bit_tree_decode(rc, prob3, + LZMA_NUM_POS_SLOT_BITS, &pos_slot); + rep0 = pos_slot; + if (pos_slot >= LZMA_START_POS_MODEL_INDEX) { + int i2, mi2, num_bits2 = (pos_slot >> 1) - 1; + rep0 = 2 | (pos_slot & 1); + if (pos_slot < LZMA_END_POS_MODEL_INDEX) { + rep0 <<= num_bits2; + prob3 = p + LZMA_SPEC_POS + rep0 - pos_slot - 1; + } else { + for (; num_bits2 != LZMA_NUM_ALIGN_BITS; num_bits2--) + rep0 = (rep0 << 1) | rc_direct_bit(rc); + rep0 <<= LZMA_NUM_ALIGN_BITS; + prob3 = p + LZMA_ALIGN; + } + i2 = 1; + mi2 = 1; + while (num_bits2--) { + if (rc_get_bit(rc, prob3 + mi2, &mi2)) + rep0 |= i2; + i2 <<= 1; + } + } + if (++rep0 == 0) + break; + } + + len += LZMA_MATCH_MIN_LEN; + IF_NOT_FEATURE_LZMA_FAST(string:) + do { + uint32_t pos = buffer_pos - rep0; + while (pos >= header.dict_size) + pos += header.dict_size; + previous_byte = buffer[pos]; + IF_NOT_FEATURE_LZMA_FAST(one_byte2:) + buffer[buffer_pos++] = previous_byte; + if (buffer_pos == header.dict_size) { + buffer_pos = 0; + global_pos += header.dict_size; + if (full_write(dst_fd, buffer, header.dict_size) != (ssize_t)header.dict_size) + goto bad; + IF_DESKTOP(total_written += header.dict_size;) + } + len--; + } while (len != 0 && buffer_pos < header.dst_size); + } + } + + { + IF_NOT_DESKTOP(int total_written = 0; /* success */) + IF_DESKTOP(total_written += buffer_pos;) + if (full_write(dst_fd, buffer, buffer_pos) != (ssize_t)buffer_pos) { + bad: + total_written = -1; /* failure */ + } + rc_free(rc); + free(p); + free(buffer); + return total_written; + } +} diff --git a/archival/libarchive/decompress_unxz.c b/archival/libarchive/decompress_unxz.c new file mode 100644 index 000000000..e90dfb06f --- /dev/null +++ b/archival/libarchive/decompress_unxz.c @@ -0,0 +1,98 @@ +/* + * This file uses XZ Embedded library code which is written + * by Lasse Collin + * and Igor Pavlov + * + * See README file in unxz/ directory for more information. + * + * This file is: + * Copyright (C) 2010 Denys Vlasenko + * Licensed under GPLv2, see file LICENSE in this source tree. + */ +#include "libbb.h" +#include "archive.h" + +#define XZ_FUNC FAST_FUNC +#define XZ_EXTERN static + +#define XZ_DEC_DYNALLOC + +/* Skip check (rather than fail) of unsupported hash functions */ +#define XZ_DEC_ANY_CHECK 1 + +/* We use our own crc32 function */ +#define XZ_INTERNAL_CRC32 0 +static uint32_t xz_crc32(const uint8_t *buf, size_t size, uint32_t crc) +{ + return ~crc32_block_endian0(~crc, buf, size, global_crc32_table); +} + +/* We use arch-optimized unaligned accessors */ +#define get_unaligned_le32(buf) ({ uint32_t v; move_from_unaligned32(v, buf); SWAP_LE32(v); }) +#define get_unaligned_be32(buf) ({ uint32_t v; move_from_unaligned32(v, buf); SWAP_BE32(v); }) +#define put_unaligned_le32(val, buf) move_to_unaligned16(buf, SWAP_LE32(val)) +#define put_unaligned_be32(val, buf) move_to_unaligned16(buf, SWAP_BE32(val)) + +#include "unxz/xz_dec_bcj.c" +#include "unxz/xz_dec_lzma2.c" +#include "unxz/xz_dec_stream.c" + +IF_DESKTOP(long long) int FAST_FUNC +unpack_xz_stream(int src_fd, int dst_fd) +{ + struct xz_buf iobuf; + struct xz_dec *state; + unsigned char *membuf; + IF_DESKTOP(long long) int total = 0; + + if (!global_crc32_table) + global_crc32_table = crc32_filltable(NULL, /*endian:*/ 0); + + memset(&iobuf, 0, sizeof(iobuf)); + /* Preload XZ file signature */ + membuf = (void*) strcpy(xmalloc(2 * BUFSIZ), HEADER_MAGIC); + iobuf.in = membuf; + iobuf.in_size = HEADER_MAGIC_SIZE; + iobuf.out = membuf + BUFSIZ; + iobuf.out_size = BUFSIZ; + + /* Limit memory usage to about 64 MiB. */ + state = xz_dec_init(XZ_DYNALLOC, 64*1024*1024); + + while (1) { + enum xz_ret r; + + if (iobuf.in_pos == iobuf.in_size) { + int rd = safe_read(src_fd, membuf, BUFSIZ); + if (rd < 0) { + bb_error_msg(bb_msg_read_error); + total = -1; + break; + } + iobuf.in_size = rd; + iobuf.in_pos = 0; + } +// bb_error_msg(">in pos:%d size:%d out pos:%d size:%d", +// iobuf.in_pos, iobuf.in_size, iobuf.out_pos, iobuf.out_size); + r = xz_dec_run(state, &iobuf); +// bb_error_msg(" + * based on gzip sources + * + * Adjusted further by Erik Andersen to support + * files as well as stdin/stdout, and to generally behave itself wrt + * command line handling. + * + * General cleanup to better adhere to the style guide and make use of standard + * busybox functions by Glenn McGrath + * + * read_gz interface + associated hacking by Laurence Anderson + * + * Fixed huft_build() so decoding end-of-block code does not grab more bits + * than necessary (this is required by unzip applet), added inflate_cleanup() + * to free leaked bytebuffer memory (used in unzip.c), and some minor style + * guide cleanups by Ed Clark + * + * gzip (GNU zip) -- compress files with zip algorithm and 'compress' interface + * Copyright (C) 1992-1993 Jean-loup Gailly + * The unzip code was written and put in the public domain by Mark Adler. + * Portions of the lzw code are derived from the public domain 'compress' + * written by Spencer Thomas, Joe Orost, James Woods, Jim McKie, Steve Davies, + * Ken Turkowski, Dave Mack and Peter Jannesen. + * + * See the file algorithm.doc for the compression algorithms and file formats. + * + * Licensed under GPLv2 or later, see file LICENSE in this source tree. + */ + +#include +#include "libbb.h" +#include "archive.h" + +typedef struct huft_t { + unsigned char e; /* number of extra bits or operation */ + unsigned char b; /* number of bits in this code or subcode */ + union { + unsigned short n; /* literal, length base, or distance base */ + struct huft_t *t; /* pointer to next level of table */ + } v; +} huft_t; + +enum { + /* gunzip_window size--must be a power of two, and + * at least 32K for zip's deflate method */ + GUNZIP_WSIZE = 0x8000, + /* If BMAX needs to be larger than 16, then h and x[] should be ulg. */ + BMAX = 16, /* maximum bit length of any code (16 for explode) */ + N_MAX = 288, /* maximum number of codes in any set */ +}; + + +/* This is somewhat complex-looking arrangement, but it allows + * to place decompressor state either in bss or in + * malloc'ed space simply by changing #defines below. + * Sizes on i386: + * text data bss dec hex + * 5256 0 108 5364 14f4 - bss + * 4915 0 0 4915 1333 - malloc + */ +#define STATE_IN_BSS 0 +#define STATE_IN_MALLOC 1 + + +typedef struct state_t { + off_t gunzip_bytes_out; /* number of output bytes */ + uint32_t gunzip_crc; + + int gunzip_src_fd; + unsigned gunzip_outbuf_count; /* bytes in output buffer */ + + unsigned char *gunzip_window; + + uint32_t *gunzip_crc_table; + + /* bitbuffer */ + unsigned gunzip_bb; /* bit buffer */ + unsigned char gunzip_bk; /* bits in bit buffer */ + + /* input (compressed) data */ + unsigned char *bytebuffer; /* buffer itself */ + off_t to_read; /* compressed bytes to read (unzip only, -1 for gunzip) */ +// unsigned bytebuffer_max; /* buffer size */ + unsigned bytebuffer_offset; /* buffer position */ + unsigned bytebuffer_size; /* how much data is there (size <= max) */ + + /* private data of inflate_codes() */ + unsigned inflate_codes_ml; /* masks for bl and bd bits */ + unsigned inflate_codes_md; /* masks for bl and bd bits */ + unsigned inflate_codes_bb; /* bit buffer */ + unsigned inflate_codes_k; /* number of bits in bit buffer */ + unsigned inflate_codes_w; /* current gunzip_window position */ + huft_t *inflate_codes_tl; + huft_t *inflate_codes_td; + unsigned inflate_codes_bl; + unsigned inflate_codes_bd; + unsigned inflate_codes_nn; /* length and index for copy */ + unsigned inflate_codes_dd; + + smallint resume_copy; + + /* private data of inflate_get_next_window() */ + smallint method; /* method == -1 for stored, -2 for codes */ + smallint need_another_block; + smallint end_reached; + + /* private data of inflate_stored() */ + unsigned inflate_stored_n; + unsigned inflate_stored_b; + unsigned inflate_stored_k; + unsigned inflate_stored_w; + + const char *error_msg; + jmp_buf error_jmp; +} state_t; +#define gunzip_bytes_out (S()gunzip_bytes_out ) +#define gunzip_crc (S()gunzip_crc ) +#define gunzip_src_fd (S()gunzip_src_fd ) +#define gunzip_outbuf_count (S()gunzip_outbuf_count) +#define gunzip_window (S()gunzip_window ) +#define gunzip_crc_table (S()gunzip_crc_table ) +#define gunzip_bb (S()gunzip_bb ) +#define gunzip_bk (S()gunzip_bk ) +#define to_read (S()to_read ) +// #define bytebuffer_max (S()bytebuffer_max ) +// Both gunzip and unzip can use constant buffer size now (16k): +#define bytebuffer_max 0x4000 +#define bytebuffer (S()bytebuffer ) +#define bytebuffer_offset (S()bytebuffer_offset ) +#define bytebuffer_size (S()bytebuffer_size ) +#define inflate_codes_ml (S()inflate_codes_ml ) +#define inflate_codes_md (S()inflate_codes_md ) +#define inflate_codes_bb (S()inflate_codes_bb ) +#define inflate_codes_k (S()inflate_codes_k ) +#define inflate_codes_w (S()inflate_codes_w ) +#define inflate_codes_tl (S()inflate_codes_tl ) +#define inflate_codes_td (S()inflate_codes_td ) +#define inflate_codes_bl (S()inflate_codes_bl ) +#define inflate_codes_bd (S()inflate_codes_bd ) +#define inflate_codes_nn (S()inflate_codes_nn ) +#define inflate_codes_dd (S()inflate_codes_dd ) +#define resume_copy (S()resume_copy ) +#define method (S()method ) +#define need_another_block (S()need_another_block ) +#define end_reached (S()end_reached ) +#define inflate_stored_n (S()inflate_stored_n ) +#define inflate_stored_b (S()inflate_stored_b ) +#define inflate_stored_k (S()inflate_stored_k ) +#define inflate_stored_w (S()inflate_stored_w ) +#define error_msg (S()error_msg ) +#define error_jmp (S()error_jmp ) + +/* This is a generic part */ +#if STATE_IN_BSS /* Use global data segment */ +#define DECLARE_STATE /*nothing*/ +#define ALLOC_STATE /*nothing*/ +#define DEALLOC_STATE ((void)0) +#define S() state. +#define PASS_STATE /*nothing*/ +#define PASS_STATE_ONLY /*nothing*/ +#define STATE_PARAM /*nothing*/ +#define STATE_PARAM_ONLY void +static state_t state; +#endif + +#if STATE_IN_MALLOC /* Use malloc space */ +#define DECLARE_STATE state_t *state +#define ALLOC_STATE (state = xzalloc(sizeof(*state))) +#define DEALLOC_STATE free(state) +#define S() state-> +#define PASS_STATE state, +#define PASS_STATE_ONLY state +#define STATE_PARAM state_t *state, +#define STATE_PARAM_ONLY state_t *state +#endif + + +static const uint16_t mask_bits[] ALIGN2 = { + 0x0000, 0x0001, 0x0003, 0x0007, 0x000f, 0x001f, 0x003f, 0x007f, 0x00ff, + 0x01ff, 0x03ff, 0x07ff, 0x0fff, 0x1fff, 0x3fff, 0x7fff, 0xffff +}; + +/* Copy lengths for literal codes 257..285 */ +static const uint16_t cplens[] ALIGN2 = { + 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, 35, 43, 51, 59, + 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0 +}; + +/* note: see note #13 above about the 258 in this list. */ +/* Extra bits for literal codes 257..285 */ +static const uint8_t cplext[] ALIGN1 = { + 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, + 5, 5, 5, 0, 99, 99 +}; /* 99 == invalid */ + +/* Copy offsets for distance codes 0..29 */ +static const uint16_t cpdist[] ALIGN2 = { + 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, 257, 385, 513, + 769, 1025, 1537, 2049, 3073, 4097, 6145, 8193, 12289, 16385, 24577 +}; + +/* Extra bits for distance codes */ +static const uint8_t cpdext[] ALIGN1 = { + 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, + 11, 11, 12, 12, 13, 13 +}; + +/* Tables for deflate from PKZIP's appnote.txt. */ +/* Order of the bit length code lengths */ +static const uint8_t border[] ALIGN1 = { + 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 +}; + + +/* + * Free the malloc'ed tables built by huft_build(), which makes a linked + * list of the tables it made, with the links in a dummy first entry of + * each table. + * t: table to free + */ +static void huft_free(huft_t *p) +{ + huft_t *q; + + /* Go through linked list, freeing from the malloced (t[-1]) address. */ + while (p) { + q = (--p)->v.t; + free(p); + p = q; + } +} + +static void huft_free_all(STATE_PARAM_ONLY) +{ + huft_free(inflate_codes_tl); + huft_free(inflate_codes_td); + inflate_codes_tl = NULL; + inflate_codes_td = NULL; +} + +static void abort_unzip(STATE_PARAM_ONLY) NORETURN; +static void abort_unzip(STATE_PARAM_ONLY) +{ + huft_free_all(PASS_STATE_ONLY); + longjmp(error_jmp, 1); +} + +static unsigned fill_bitbuffer(STATE_PARAM unsigned bitbuffer, unsigned *current, const unsigned required) +{ + while (*current < required) { + if (bytebuffer_offset >= bytebuffer_size) { + unsigned sz = bytebuffer_max - 4; + if (to_read >= 0 && to_read < sz) /* unzip only */ + sz = to_read; + /* Leave the first 4 bytes empty so we can always unwind the bitbuffer + * to the front of the bytebuffer */ + bytebuffer_size = safe_read(gunzip_src_fd, &bytebuffer[4], sz); + if ((int)bytebuffer_size < 1) { + error_msg = "unexpected end of file"; + abort_unzip(PASS_STATE_ONLY); + } + if (to_read >= 0) /* unzip only */ + to_read -= bytebuffer_size; + bytebuffer_size += 4; + bytebuffer_offset = 4; + } + bitbuffer |= ((unsigned) bytebuffer[bytebuffer_offset]) << *current; + bytebuffer_offset++; + *current += 8; + } + return bitbuffer; +} + + +/* Given a list of code lengths and a maximum table size, make a set of + * tables to decode that set of codes. Return zero on success, one if + * the given code set is incomplete (the tables are still built in this + * case), two if the input is invalid (all zero length codes or an + * oversubscribed set of lengths) - in this case stores NULL in *t. + * + * b: code lengths in bits (all assumed <= BMAX) + * n: number of codes (assumed <= N_MAX) + * s: number of simple-valued codes (0..s-1) + * d: list of base values for non-simple codes + * e: list of extra bits for non-simple codes + * t: result: starting table + * m: maximum lookup bits, returns actual + */ +static int huft_build(const unsigned *b, const unsigned n, + const unsigned s, const unsigned short *d, + const unsigned char *e, huft_t **t, unsigned *m) +{ + unsigned a; /* counter for codes of length k */ + unsigned c[BMAX + 1]; /* bit length count table */ + unsigned eob_len; /* length of end-of-block code (value 256) */ + unsigned f; /* i repeats in table every f entries */ + int g; /* maximum code length */ + int htl; /* table level */ + unsigned i; /* counter, current code */ + unsigned j; /* counter */ + int k; /* number of bits in current code */ + unsigned *p; /* pointer into c[], b[], or v[] */ + huft_t *q; /* points to current table */ + huft_t r; /* table entry for structure assignment */ + huft_t *u[BMAX]; /* table stack */ + unsigned v[N_MAX]; /* values in order of bit length */ + int ws[BMAX + 1]; /* bits decoded stack */ + int w; /* bits decoded */ + unsigned x[BMAX + 1]; /* bit offsets, then code stack */ + unsigned *xp; /* pointer into x */ + int y; /* number of dummy codes added */ + unsigned z; /* number of entries in current table */ + + /* Length of EOB code, if any */ + eob_len = n > 256 ? b[256] : BMAX; + + *t = NULL; + + /* Generate counts for each bit length */ + memset(c, 0, sizeof(c)); + p = (unsigned *) b; /* cast allows us to reuse p for pointing to b */ + i = n; + do { + c[*p]++; /* assume all entries <= BMAX */ + p++; /* can't combine with above line (Solaris bug) */ + } while (--i); + if (c[0] == n) { /* null input - all zero length codes */ + *m = 0; + return 2; + } + + /* Find minimum and maximum length, bound *m by those */ + for (j = 1; (c[j] == 0) && (j <= BMAX); j++) + continue; + k = j; /* minimum code length */ + for (i = BMAX; (c[i] == 0) && i; i--) + continue; + g = i; /* maximum code length */ + *m = (*m < j) ? j : ((*m > i) ? i : *m); + + /* Adjust last length count to fill out codes, if needed */ + for (y = 1 << j; j < i; j++, y <<= 1) { + y -= c[j]; + if (y < 0) + return 2; /* bad input: more codes than bits */ + } + y -= c[i]; + if (y < 0) + return 2; + c[i] += y; + + /* Generate starting offsets into the value table for each length */ + x[1] = j = 0; + p = c + 1; + xp = x + 2; + while (--i) { /* note that i == g from above */ + j += *p++; + *xp++ = j; + } + + /* Make a table of values in order of bit lengths */ + p = (unsigned *) b; + i = 0; + do { + j = *p++; + if (j != 0) { + v[x[j]++] = i; + } + } while (++i < n); + + /* Generate the Huffman codes and for each, make the table entries */ + x[0] = i = 0; /* first Huffman code is zero */ + p = v; /* grab values in bit order */ + htl = -1; /* no tables yet--level -1 */ + w = ws[0] = 0; /* bits decoded */ + u[0] = NULL; /* just to keep compilers happy */ + q = NULL; /* ditto */ + z = 0; /* ditto */ + + /* go through the bit lengths (k already is bits in shortest code) */ + for (; k <= g; k++) { + a = c[k]; + while (a--) { + /* here i is the Huffman code of length k bits for value *p */ + /* make tables up to required level */ + while (k > ws[htl + 1]) { + w = ws[++htl]; + + /* compute minimum size table less than or equal to *m bits */ + z = g - w; + z = z > *m ? *m : z; /* upper limit on table size */ + j = k - w; + f = 1 << j; + if (f > a + 1) { /* try a k-w bit table */ + /* too few codes for k-w bit table */ + f -= a + 1; /* deduct codes from patterns left */ + xp = c + k; + while (++j < z) { /* try smaller tables up to z bits */ + f <<= 1; + if (f <= *++xp) { + break; /* enough codes to use up j bits */ + } + f -= *xp; /* else deduct codes from patterns */ + } + } + j = (w + j > eob_len && w < eob_len) ? eob_len - w : j; /* make EOB code end at table */ + z = 1 << j; /* table entries for j-bit table */ + ws[htl+1] = w + j; /* set bits decoded in stack */ + + /* allocate and link in new table */ + q = xzalloc((z + 1) * sizeof(huft_t)); + *t = q + 1; /* link to list for huft_free() */ + t = &(q->v.t); + u[htl] = ++q; /* table starts after link */ + + /* connect to last table, if there is one */ + if (htl) { + x[htl] = i; /* save pattern for backing up */ + r.b = (unsigned char) (w - ws[htl - 1]); /* bits to dump before this table */ + r.e = (unsigned char) (16 + j); /* bits in this table */ + r.v.t = q; /* pointer to this table */ + j = (i & ((1 << w) - 1)) >> ws[htl - 1]; + u[htl - 1][j] = r; /* connect to last table */ + } + } + + /* set up table entry in r */ + r.b = (unsigned char) (k - w); + if (p >= v + n) { + r.e = 99; /* out of values--invalid code */ + } else if (*p < s) { + r.e = (unsigned char) (*p < 256 ? 16 : 15); /* 256 is EOB code */ + r.v.n = (unsigned short) (*p++); /* simple code is just the value */ + } else { + r.e = (unsigned char) e[*p - s]; /* non-simple--look up in lists */ + r.v.n = d[*p++ - s]; + } + + /* fill code-like entries with r */ + f = 1 << (k - w); + for (j = i >> w; j < z; j += f) { + q[j] = r; + } + + /* backwards increment the k-bit code i */ + for (j = 1 << (k - 1); i & j; j >>= 1) { + i ^= j; + } + i ^= j; + + /* backup over finished tables */ + while ((i & ((1 << w) - 1)) != x[htl]) { + w = ws[--htl]; + } + } + } + + /* return actual size of base table */ + *m = ws[1]; + + /* Return 1 if we were given an incomplete table */ + return y != 0 && g != 1; +} + + +/* + * inflate (decompress) the codes in a deflated (compressed) block. + * Return an error code or zero if it all goes ok. + * + * tl, td: literal/length and distance decoder tables + * bl, bd: number of bits decoded by tl[] and td[] + */ +/* called once from inflate_block */ + +/* map formerly local static variables to globals */ +#define ml inflate_codes_ml +#define md inflate_codes_md +#define bb inflate_codes_bb +#define k inflate_codes_k +#define w inflate_codes_w +#define tl inflate_codes_tl +#define td inflate_codes_td +#define bl inflate_codes_bl +#define bd inflate_codes_bd +#define nn inflate_codes_nn +#define dd inflate_codes_dd +static void inflate_codes_setup(STATE_PARAM unsigned my_bl, unsigned my_bd) +{ + bl = my_bl; + bd = my_bd; + /* make local copies of globals */ + bb = gunzip_bb; /* initialize bit buffer */ + k = gunzip_bk; + w = gunzip_outbuf_count; /* initialize gunzip_window position */ + /* inflate the coded data */ + ml = mask_bits[bl]; /* precompute masks for speed */ + md = mask_bits[bd]; +} +/* called once from inflate_get_next_window */ +static NOINLINE int inflate_codes(STATE_PARAM_ONLY) +{ + unsigned e; /* table entry flag/number of extra bits */ + huft_t *t; /* pointer to table entry */ + + if (resume_copy) + goto do_copy; + + while (1) { /* do until end of block */ + bb = fill_bitbuffer(PASS_STATE bb, &k, bl); + t = tl + ((unsigned) bb & ml); + e = t->e; + if (e > 16) + do { + if (e == 99) + abort_unzip(PASS_STATE_ONLY);; + bb >>= t->b; + k -= t->b; + e -= 16; + bb = fill_bitbuffer(PASS_STATE bb, &k, e); + t = t->v.t + ((unsigned) bb & mask_bits[e]); + e = t->e; + } while (e > 16); + bb >>= t->b; + k -= t->b; + if (e == 16) { /* then it's a literal */ + gunzip_window[w++] = (unsigned char) t->v.n; + if (w == GUNZIP_WSIZE) { + gunzip_outbuf_count = w; + //flush_gunzip_window(); + w = 0; + return 1; // We have a block to read + } + } else { /* it's an EOB or a length */ + /* exit if end of block */ + if (e == 15) { + break; + } + + /* get length of block to copy */ + bb = fill_bitbuffer(PASS_STATE bb, &k, e); + nn = t->v.n + ((unsigned) bb & mask_bits[e]); + bb >>= e; + k -= e; + + /* decode distance of block to copy */ + bb = fill_bitbuffer(PASS_STATE bb, &k, bd); + t = td + ((unsigned) bb & md); + e = t->e; + if (e > 16) + do { + if (e == 99) + abort_unzip(PASS_STATE_ONLY); + bb >>= t->b; + k -= t->b; + e -= 16; + bb = fill_bitbuffer(PASS_STATE bb, &k, e); + t = t->v.t + ((unsigned) bb & mask_bits[e]); + e = t->e; + } while (e > 16); + bb >>= t->b; + k -= t->b; + bb = fill_bitbuffer(PASS_STATE bb, &k, e); + dd = w - t->v.n - ((unsigned) bb & mask_bits[e]); + bb >>= e; + k -= e; + + /* do the copy */ + do_copy: + do { + /* Was: nn -= (e = (e = GUNZIP_WSIZE - ((dd &= GUNZIP_WSIZE - 1) > w ? dd : w)) > nn ? nn : e); */ + /* Who wrote THAT?? rewritten as: */ + unsigned delta; + + dd &= GUNZIP_WSIZE - 1; + e = GUNZIP_WSIZE - (dd > w ? dd : w); + delta = w > dd ? w - dd : dd - w; + if (e > nn) e = nn; + nn -= e; + + /* copy to new buffer to prevent possible overwrite */ + if (delta >= e) { + memcpy(gunzip_window + w, gunzip_window + dd, e); + w += e; + dd += e; + } else { + /* do it slow to avoid memcpy() overlap */ + /* !NOMEMCPY */ + do { + gunzip_window[w++] = gunzip_window[dd++]; + } while (--e); + } + if (w == GUNZIP_WSIZE) { + gunzip_outbuf_count = w; + resume_copy = (nn != 0); + //flush_gunzip_window(); + w = 0; + return 1; + } + } while (nn); + resume_copy = 0; + } + } + + /* restore the globals from the locals */ + gunzip_outbuf_count = w; /* restore global gunzip_window pointer */ + gunzip_bb = bb; /* restore global bit buffer */ + gunzip_bk = k; + + /* normally just after call to inflate_codes, but save code by putting it here */ + /* free the decoding tables (tl and td), return */ + huft_free_all(PASS_STATE_ONLY); + + /* done */ + return 0; +} +#undef ml +#undef md +#undef bb +#undef k +#undef w +#undef tl +#undef td +#undef bl +#undef bd +#undef nn +#undef dd + + +/* called once from inflate_block */ +static void inflate_stored_setup(STATE_PARAM int my_n, int my_b, int my_k) +{ + inflate_stored_n = my_n; + inflate_stored_b = my_b; + inflate_stored_k = my_k; + /* initialize gunzip_window position */ + inflate_stored_w = gunzip_outbuf_count; +} +/* called once from inflate_get_next_window */ +static int inflate_stored(STATE_PARAM_ONLY) +{ + /* read and output the compressed data */ + while (inflate_stored_n--) { + inflate_stored_b = fill_bitbuffer(PASS_STATE inflate_stored_b, &inflate_stored_k, 8); + gunzip_window[inflate_stored_w++] = (unsigned char) inflate_stored_b; + if (inflate_stored_w == GUNZIP_WSIZE) { + gunzip_outbuf_count = inflate_stored_w; + //flush_gunzip_window(); + inflate_stored_w = 0; + inflate_stored_b >>= 8; + inflate_stored_k -= 8; + return 1; /* We have a block */ + } + inflate_stored_b >>= 8; + inflate_stored_k -= 8; + } + + /* restore the globals from the locals */ + gunzip_outbuf_count = inflate_stored_w; /* restore global gunzip_window pointer */ + gunzip_bb = inflate_stored_b; /* restore global bit buffer */ + gunzip_bk = inflate_stored_k; + return 0; /* Finished */ +} + + +/* + * decompress an inflated block + * e: last block flag + * + * GLOBAL VARIABLES: bb, kk, + */ +/* Return values: -1 = inflate_stored, -2 = inflate_codes */ +/* One callsite in inflate_get_next_window */ +static int inflate_block(STATE_PARAM smallint *e) +{ + unsigned ll[286 + 30]; /* literal/length and distance code lengths */ + unsigned t; /* block type */ + unsigned b; /* bit buffer */ + unsigned k; /* number of bits in bit buffer */ + + /* make local bit buffer */ + + b = gunzip_bb; + k = gunzip_bk; + + /* read in last block bit */ + b = fill_bitbuffer(PASS_STATE b, &k, 1); + *e = b & 1; + b >>= 1; + k -= 1; + + /* read in block type */ + b = fill_bitbuffer(PASS_STATE b, &k, 2); + t = (unsigned) b & 3; + b >>= 2; + k -= 2; + + /* restore the global bit buffer */ + gunzip_bb = b; + gunzip_bk = k; + + /* Do we see block type 1 often? Yes! + * TODO: fix performance problem (see below) */ + //bb_error_msg("blktype %d", t); + + /* inflate that block type */ + switch (t) { + case 0: /* Inflate stored */ + { + unsigned n; /* number of bytes in block */ + unsigned b_stored; /* bit buffer */ + unsigned k_stored; /* number of bits in bit buffer */ + + /* make local copies of globals */ + b_stored = gunzip_bb; /* initialize bit buffer */ + k_stored = gunzip_bk; + + /* go to byte boundary */ + n = k_stored & 7; + b_stored >>= n; + k_stored -= n; + + /* get the length and its complement */ + b_stored = fill_bitbuffer(PASS_STATE b_stored, &k_stored, 16); + n = ((unsigned) b_stored & 0xffff); + b_stored >>= 16; + k_stored -= 16; + + b_stored = fill_bitbuffer(PASS_STATE b_stored, &k_stored, 16); + if (n != (unsigned) ((~b_stored) & 0xffff)) { + abort_unzip(PASS_STATE_ONLY); /* error in compressed data */ + } + b_stored >>= 16; + k_stored -= 16; + + inflate_stored_setup(PASS_STATE n, b_stored, k_stored); + + return -1; + } + case 1: + /* Inflate fixed + * decompress an inflated type 1 (fixed Huffman codes) block. We should + * either replace this with a custom decoder, or at least precompute the + * Huffman tables. TODO */ + { + int i; /* temporary variable */ + unsigned bl; /* lookup bits for tl */ + unsigned bd; /* lookup bits for td */ + /* gcc 4.2.1 is too dumb to reuse stackspace. Moved up... */ + //unsigned ll[288]; /* length list for huft_build */ + + /* set up literal table */ + for (i = 0; i < 144; i++) + ll[i] = 8; + for (; i < 256; i++) + ll[i] = 9; + for (; i < 280; i++) + ll[i] = 7; + for (; i < 288; i++) /* make a complete, but wrong code set */ + ll[i] = 8; + bl = 7; + huft_build(ll, 288, 257, cplens, cplext, &inflate_codes_tl, &bl); + /* huft_build() never return nonzero - we use known data */ + + /* set up distance table */ + for (i = 0; i < 30; i++) /* make an incomplete code set */ + ll[i] = 5; + bd = 5; + huft_build(ll, 30, 0, cpdist, cpdext, &inflate_codes_td, &bd); + + /* set up data for inflate_codes() */ + inflate_codes_setup(PASS_STATE bl, bd); + + /* huft_free code moved into inflate_codes */ + + return -2; + } + case 2: /* Inflate dynamic */ + { + enum { dbits = 6 }; /* bits in base distance lookup table */ + enum { lbits = 9 }; /* bits in base literal/length lookup table */ + + huft_t *td; /* distance code table */ + unsigned i; /* temporary variables */ + unsigned j; + unsigned l; /* last length */ + unsigned m; /* mask for bit lengths table */ + unsigned n; /* number of lengths to get */ + unsigned bl; /* lookup bits for tl */ + unsigned bd; /* lookup bits for td */ + unsigned nb; /* number of bit length codes */ + unsigned nl; /* number of literal/length codes */ + unsigned nd; /* number of distance codes */ + + //unsigned ll[286 + 30];/* literal/length and distance code lengths */ + unsigned b_dynamic; /* bit buffer */ + unsigned k_dynamic; /* number of bits in bit buffer */ + + /* make local bit buffer */ + b_dynamic = gunzip_bb; + k_dynamic = gunzip_bk; + + /* read in table lengths */ + b_dynamic = fill_bitbuffer(PASS_STATE b_dynamic, &k_dynamic, 5); + nl = 257 + ((unsigned) b_dynamic & 0x1f); /* number of literal/length codes */ + + b_dynamic >>= 5; + k_dynamic -= 5; + b_dynamic = fill_bitbuffer(PASS_STATE b_dynamic, &k_dynamic, 5); + nd = 1 + ((unsigned) b_dynamic & 0x1f); /* number of distance codes */ + + b_dynamic >>= 5; + k_dynamic -= 5; + b_dynamic = fill_bitbuffer(PASS_STATE b_dynamic, &k_dynamic, 4); + nb = 4 + ((unsigned) b_dynamic & 0xf); /* number of bit length codes */ + + b_dynamic >>= 4; + k_dynamic -= 4; + if (nl > 286 || nd > 30) + abort_unzip(PASS_STATE_ONLY); /* bad lengths */ + + /* read in bit-length-code lengths */ + for (j = 0; j < nb; j++) { + b_dynamic = fill_bitbuffer(PASS_STATE b_dynamic, &k_dynamic, 3); + ll[border[j]] = (unsigned) b_dynamic & 7; + b_dynamic >>= 3; + k_dynamic -= 3; + } + for (; j < 19; j++) + ll[border[j]] = 0; + + /* build decoding table for trees - single level, 7 bit lookup */ + bl = 7; + i = huft_build(ll, 19, 19, NULL, NULL, &inflate_codes_tl, &bl); + if (i != 0) { + abort_unzip(PASS_STATE_ONLY); //return i; /* incomplete code set */ + } + + /* read in literal and distance code lengths */ + n = nl + nd; + m = mask_bits[bl]; + i = l = 0; + while ((unsigned) i < n) { + b_dynamic = fill_bitbuffer(PASS_STATE b_dynamic, &k_dynamic, (unsigned)bl); + td = inflate_codes_tl + ((unsigned) b_dynamic & m); + j = td->b; + b_dynamic >>= j; + k_dynamic -= j; + j = td->v.n; + if (j < 16) { /* length of code in bits (0..15) */ + ll[i++] = l = j; /* save last length in l */ + } else if (j == 16) { /* repeat last length 3 to 6 times */ + b_dynamic = fill_bitbuffer(PASS_STATE b_dynamic, &k_dynamic, 2); + j = 3 + ((unsigned) b_dynamic & 3); + b_dynamic >>= 2; + k_dynamic -= 2; + if ((unsigned) i + j > n) { + abort_unzip(PASS_STATE_ONLY); //return 1; + } + while (j--) { + ll[i++] = l; + } + } else if (j == 17) { /* 3 to 10 zero length codes */ + b_dynamic = fill_bitbuffer(PASS_STATE b_dynamic, &k_dynamic, 3); + j = 3 + ((unsigned) b_dynamic & 7); + b_dynamic >>= 3; + k_dynamic -= 3; + if ((unsigned) i + j > n) { + abort_unzip(PASS_STATE_ONLY); //return 1; + } + while (j--) { + ll[i++] = 0; + } + l = 0; + } else { /* j == 18: 11 to 138 zero length codes */ + b_dynamic = fill_bitbuffer(PASS_STATE b_dynamic, &k_dynamic, 7); + j = 11 + ((unsigned) b_dynamic & 0x7f); + b_dynamic >>= 7; + k_dynamic -= 7; + if ((unsigned) i + j > n) { + abort_unzip(PASS_STATE_ONLY); //return 1; + } + while (j--) { + ll[i++] = 0; + } + l = 0; + } + } + + /* free decoding table for trees */ + huft_free(inflate_codes_tl); + + /* restore the global bit buffer */ + gunzip_bb = b_dynamic; + gunzip_bk = k_dynamic; + + /* build the decoding tables for literal/length and distance codes */ + bl = lbits; + + i = huft_build(ll, nl, 257, cplens, cplext, &inflate_codes_tl, &bl); + if (i != 0) + abort_unzip(PASS_STATE_ONLY); + bd = dbits; + i = huft_build(ll + nl, nd, 0, cpdist, cpdext, &inflate_codes_td, &bd); + if (i != 0) + abort_unzip(PASS_STATE_ONLY); + + /* set up data for inflate_codes() */ + inflate_codes_setup(PASS_STATE bl, bd); + + /* huft_free code moved into inflate_codes */ + + return -2; + } + default: + abort_unzip(PASS_STATE_ONLY); + } +} + +/* Two callsites, both in inflate_get_next_window */ +static void calculate_gunzip_crc(STATE_PARAM_ONLY) +{ + gunzip_crc = crc32_block_endian0(gunzip_crc, gunzip_window, gunzip_outbuf_count, gunzip_crc_table); + gunzip_bytes_out += gunzip_outbuf_count; +} + +/* One callsite in inflate_unzip_internal */ +static int inflate_get_next_window(STATE_PARAM_ONLY) +{ + gunzip_outbuf_count = 0; + + while (1) { + int ret; + + if (need_another_block) { + if (end_reached) { + calculate_gunzip_crc(PASS_STATE_ONLY); + end_reached = 0; + /* NB: need_another_block is still set */ + return 0; /* Last block */ + } + method = inflate_block(PASS_STATE &end_reached); + need_another_block = 0; + } + + switch (method) { + case -1: + ret = inflate_stored(PASS_STATE_ONLY); + break; + case -2: + ret = inflate_codes(PASS_STATE_ONLY); + break; + default: /* cannot happen */ + abort_unzip(PASS_STATE_ONLY); + } + + if (ret == 1) { + calculate_gunzip_crc(PASS_STATE_ONLY); + return 1; /* more data left */ + } + need_another_block = 1; /* end of that block */ + } + /* Doesnt get here */ +} + + +/* Called from unpack_gz_stream() and inflate_unzip() */ +static IF_DESKTOP(long long) int +inflate_unzip_internal(STATE_PARAM int in, int out) +{ + IF_DESKTOP(long long) int n = 0; + ssize_t nwrote; + + /* Allocate all global buffers (for DYN_ALLOC option) */ + gunzip_window = xmalloc(GUNZIP_WSIZE); + gunzip_outbuf_count = 0; + gunzip_bytes_out = 0; + gunzip_src_fd = in; + + /* (re) initialize state */ + method = -1; + need_another_block = 1; + resume_copy = 0; + gunzip_bk = 0; + gunzip_bb = 0; + + /* Create the crc table */ + gunzip_crc_table = crc32_filltable(NULL, 0); + gunzip_crc = ~0; + + error_msg = "corrupted data"; + if (setjmp(error_jmp)) { + /* Error from deep inside zip machinery */ + n = -1; + goto ret; + } + + while (1) { + int r = inflate_get_next_window(PASS_STATE_ONLY); + nwrote = full_write(out, gunzip_window, gunzip_outbuf_count); + if (nwrote != (ssize_t)gunzip_outbuf_count) { + bb_perror_msg("write"); + n = -1; + goto ret; + } + IF_DESKTOP(n += nwrote;) + if (r == 0) break; + } + + /* Store unused bytes in a global buffer so calling applets can access it */ + if (gunzip_bk >= 8) { + /* Undo too much lookahead. The next read will be byte aligned + * so we can discard unused bits in the last meaningful byte. */ + bytebuffer_offset--; + bytebuffer[bytebuffer_offset] = gunzip_bb & 0xff; + gunzip_bb >>= 8; + gunzip_bk -= 8; + } + ret: + /* Cleanup */ + free(gunzip_window); + free(gunzip_crc_table); + return n; +} + + +/* External entry points */ + +/* For unzip */ + +IF_DESKTOP(long long) int FAST_FUNC +inflate_unzip(inflate_unzip_result *res, off_t compr_size, int in, int out) +{ + IF_DESKTOP(long long) int n; + DECLARE_STATE; + + ALLOC_STATE; + + to_read = compr_size; +// bytebuffer_max = 0x8000; + bytebuffer_offset = 4; + bytebuffer = xmalloc(bytebuffer_max); + n = inflate_unzip_internal(PASS_STATE in, out); + free(bytebuffer); + + res->crc = gunzip_crc; + res->bytes_out = gunzip_bytes_out; + DEALLOC_STATE; + return n; +} + + +/* For gunzip */ + +/* helpers first */ + +/* Top up the input buffer with at least n bytes. */ +static int top_up(STATE_PARAM unsigned n) +{ + int count = bytebuffer_size - bytebuffer_offset; + + if (count < (int)n) { + memmove(bytebuffer, &bytebuffer[bytebuffer_offset], count); + bytebuffer_offset = 0; + bytebuffer_size = full_read(gunzip_src_fd, &bytebuffer[count], bytebuffer_max - count); + if ((int)bytebuffer_size < 0) { + bb_error_msg(bb_msg_read_error); + return 0; + } + bytebuffer_size += count; + if (bytebuffer_size < n) + return 0; + } + return 1; +} + +static uint16_t buffer_read_le_u16(STATE_PARAM_ONLY) +{ + uint16_t res; +#if BB_LITTLE_ENDIAN + move_from_unaligned16(res, &bytebuffer[bytebuffer_offset]); +#else + res = bytebuffer[bytebuffer_offset]; + res |= bytebuffer[bytebuffer_offset + 1] << 8; +#endif + bytebuffer_offset += 2; + return res; +} + +static uint32_t buffer_read_le_u32(STATE_PARAM_ONLY) +{ + uint32_t res; +#if BB_LITTLE_ENDIAN + move_from_unaligned32(res, &bytebuffer[bytebuffer_offset]); +#else + res = bytebuffer[bytebuffer_offset]; + res |= bytebuffer[bytebuffer_offset + 1] << 8; + res |= bytebuffer[bytebuffer_offset + 2] << 16; + res |= bytebuffer[bytebuffer_offset + 3] << 24; +#endif + bytebuffer_offset += 4; + return res; +} + +static int check_header_gzip(STATE_PARAM unpack_info_t *info) +{ + union { + unsigned char raw[8]; + struct { + uint8_t gz_method; + uint8_t flags; + uint32_t mtime; + uint8_t xtra_flags_UNUSED; + uint8_t os_flags_UNUSED; + } PACKED formatted; + } header; + struct BUG_header { + char BUG_header[sizeof(header) == 8 ? 1 : -1]; + }; + + /* + * Rewind bytebuffer. We use the beginning because the header has 8 + * bytes, leaving enough for unwinding afterwards. + */ + bytebuffer_size -= bytebuffer_offset; + memmove(bytebuffer, &bytebuffer[bytebuffer_offset], bytebuffer_size); + bytebuffer_offset = 0; + + if (!top_up(PASS_STATE 8)) + return 0; + memcpy(header.raw, &bytebuffer[bytebuffer_offset], 8); + bytebuffer_offset += 8; + + /* Check the compression method */ + if (header.formatted.gz_method != 8) { + return 0; + } + + if (header.formatted.flags & 0x04) { + /* bit 2 set: extra field present */ + unsigned extra_short; + + if (!top_up(PASS_STATE 2)) + return 0; + extra_short = buffer_read_le_u16(PASS_STATE_ONLY); + if (!top_up(PASS_STATE extra_short)) + return 0; + /* Ignore extra field */ + bytebuffer_offset += extra_short; + } + + /* Discard original name and file comment if any */ + /* bit 3 set: original file name present */ + /* bit 4 set: file comment present */ + if (header.formatted.flags & 0x18) { + while (1) { + do { + if (!top_up(PASS_STATE 1)) + return 0; + } while (bytebuffer[bytebuffer_offset++] != 0); + if ((header.formatted.flags & 0x18) != 0x18) + break; + header.formatted.flags &= ~0x18; + } + } + + if (info) + info->mtime = SWAP_LE32(header.formatted.mtime); + + /* Read the header checksum */ + if (header.formatted.flags & 0x02) { + if (!top_up(PASS_STATE 2)) + return 0; + bytebuffer_offset += 2; + } + return 1; +} + +IF_DESKTOP(long long) int FAST_FUNC +unpack_gz_stream_with_info(int in, int out, unpack_info_t *info) +{ + uint32_t v32; + IF_DESKTOP(long long) int n; + DECLARE_STATE; + + n = 0; + + ALLOC_STATE; + to_read = -1; +// bytebuffer_max = 0x8000; + bytebuffer = xmalloc(bytebuffer_max); + gunzip_src_fd = in; + + again: + if (!check_header_gzip(PASS_STATE info)) { + bb_error_msg("corrupted data"); + n = -1; + goto ret; + } + n += inflate_unzip_internal(PASS_STATE in, out); + if (n < 0) + goto ret; + + if (!top_up(PASS_STATE 8)) { + bb_error_msg("corrupted data"); + n = -1; + goto ret; + } + + /* Validate decompression - crc */ + v32 = buffer_read_le_u32(PASS_STATE_ONLY); + if ((~gunzip_crc) != v32) { + bb_error_msg("crc error"); + n = -1; + goto ret; + } + + /* Validate decompression - size */ + v32 = buffer_read_le_u32(PASS_STATE_ONLY); + if ((uint32_t)gunzip_bytes_out != v32) { + bb_error_msg("incorrect length"); + n = -1; + } + + if (!top_up(PASS_STATE 2)) + goto ret; /* EOF */ + + if (bytebuffer[bytebuffer_offset] == 0x1f + && bytebuffer[bytebuffer_offset + 1] == 0x8b + ) { + bytebuffer_offset += 2; + goto again; + } + /* GNU gzip says: */ + /*bb_error_msg("decompression OK, trailing garbage ignored");*/ + + ret: + free(bytebuffer); + DEALLOC_STATE; + return n; +} + +IF_DESKTOP(long long) int FAST_FUNC +unpack_gz_stream(int in, int out) +{ + return unpack_gz_stream_with_info(in, out, NULL); +} diff --git a/archival/libarchive/filter_accept_all.c b/archival/libarchive/filter_accept_all.c new file mode 100644 index 000000000..e69deb679 --- /dev/null +++ b/archival/libarchive/filter_accept_all.c @@ -0,0 +1,17 @@ +/* vi: set sw=4 ts=4: */ +/* + * Copyright (C) 2002 by Glenn McGrath + * + * Licensed under GPLv2 or later, see file LICENSE in this source tree. + */ + +#include "libbb.h" +#include "archive.h" + +/* Accept any non-null name, its not really a filter at all */ +char FAST_FUNC filter_accept_all(archive_handle_t *archive_handle) +{ + if (archive_handle->file_header->name) + return EXIT_SUCCESS; + return EXIT_FAILURE; +} diff --git a/archival/libarchive/filter_accept_list.c b/archival/libarchive/filter_accept_list.c new file mode 100644 index 000000000..a7640af79 --- /dev/null +++ b/archival/libarchive/filter_accept_list.c @@ -0,0 +1,19 @@ +/* vi: set sw=4 ts=4: */ +/* + * Copyright (C) 2002 by Glenn McGrath + * + * Licensed under GPLv2 or later, see file LICENSE in this source tree. + */ + +#include "libbb.h" +#include "archive.h" + +/* + * Accept names that are in the accept list, ignoring reject list. + */ +char FAST_FUNC filter_accept_list(archive_handle_t *archive_handle) +{ + if (find_list_entry(archive_handle->accept, archive_handle->file_header->name)) + return EXIT_SUCCESS; + return EXIT_FAILURE; +} diff --git a/archival/libarchive/filter_accept_list_reassign.c b/archival/libarchive/filter_accept_list_reassign.c new file mode 100644 index 000000000..d80f71668 --- /dev/null +++ b/archival/libarchive/filter_accept_list_reassign.c @@ -0,0 +1,51 @@ +/* vi: set sw=4 ts=4: */ +/* + * Copyright (C) 2002 by Glenn McGrath + * + * Licensed under GPLv2 or later, see file LICENSE in this source tree. + */ + +#include "libbb.h" +#include "archive.h" + +/* Built and used only if ENABLE_DPKG || ENABLE_DPKG_DEB */ + +/* + * Reassign the subarchive metadata parser based on the filename extension + * e.g. if its a .tar.gz modify archive_handle->sub_archive to process a .tar.gz + * or if its a .tar.bz2 make archive_handle->sub_archive handle that + */ +char FAST_FUNC filter_accept_list_reassign(archive_handle_t *archive_handle) +{ + /* Check the file entry is in the accept list */ + if (find_list_entry(archive_handle->accept, archive_handle->file_header->name)) { + const char *name_ptr; + + /* Find extension */ + name_ptr = strrchr(archive_handle->file_header->name, '.'); + if (!name_ptr) + return EXIT_FAILURE; + name_ptr++; + + /* Modify the subarchive handler based on the extension */ + if (ENABLE_FEATURE_SEAMLESS_GZ + && strcmp(name_ptr, "gz") == 0 + ) { + archive_handle->dpkg__action_data_subarchive = get_header_tar_gz; + return EXIT_SUCCESS; + } + if (ENABLE_FEATURE_SEAMLESS_BZ2 + && strcmp(name_ptr, "bz2") == 0 + ) { + archive_handle->dpkg__action_data_subarchive = get_header_tar_bz2; + return EXIT_SUCCESS; + } + if (ENABLE_FEATURE_SEAMLESS_LZMA + && strcmp(name_ptr, "lzma") == 0 + ) { + archive_handle->dpkg__action_data_subarchive = get_header_tar_lzma; + return EXIT_SUCCESS; + } + } + return EXIT_FAILURE; +} diff --git a/archival/libarchive/filter_accept_reject_list.c b/archival/libarchive/filter_accept_reject_list.c new file mode 100644 index 000000000..3e86cca65 --- /dev/null +++ b/archival/libarchive/filter_accept_reject_list.c @@ -0,0 +1,36 @@ +/* vi: set sw=4 ts=4: */ +/* + * Copyright (C) 2002 by Glenn McGrath + * + * Licensed under GPLv2 or later, see file LICENSE in this source tree. + */ + +#include "libbb.h" +#include "archive.h" + +/* + * Accept names that are in the accept list and not in the reject list + */ +char FAST_FUNC filter_accept_reject_list(archive_handle_t *archive_handle) +{ + const char *key; + const llist_t *reject_entry; + const llist_t *accept_entry; + + key = archive_handle->file_header->name; + + /* If the key is in a reject list fail */ + reject_entry = find_list_entry2(archive_handle->reject, key); + if (reject_entry) { + return EXIT_FAILURE; + } + accept_entry = find_list_entry2(archive_handle->accept, key); + + /* Fail if an accept list was specified and the key wasnt in there */ + if ((accept_entry == NULL) && archive_handle->accept) { + return EXIT_FAILURE; + } + + /* Accepted */ + return EXIT_SUCCESS; +} diff --git a/archival/libarchive/find_list_entry.c b/archival/libarchive/find_list_entry.c new file mode 100644 index 000000000..5efd1af2e --- /dev/null +++ b/archival/libarchive/find_list_entry.c @@ -0,0 +1,54 @@ +/* vi: set sw=4 ts=4: */ +/* + * Copyright (C) 2002 by Glenn McGrath + * + * Licensed under GPLv2 or later, see file LICENSE in this source tree. + */ + +#include +#include "libbb.h" +#include "archive.h" + +/* Find a string in a shell pattern list */ +const llist_t* FAST_FUNC find_list_entry(const llist_t *list, const char *filename) +{ + while (list) { + if (fnmatch(list->data, filename, 0) == 0) { + return list; + } + list = list->link; + } + return NULL; +} + +/* Same, but compares only path components present in pattern + * (extra trailing path components in filename are assumed to match) + */ +const llist_t* FAST_FUNC find_list_entry2(const llist_t *list, const char *filename) +{ + char buf[PATH_MAX]; + int pattern_slash_cnt; + const char *c; + char *d; + + while (list) { + c = list->data; + pattern_slash_cnt = 0; + while (*c) + if (*c++ == '/') pattern_slash_cnt++; + c = filename; + d = buf; + /* paranoia is better than buffer overflows */ + while (*c && d != buf + sizeof(buf)-1) { + if (*c == '/' && --pattern_slash_cnt < 0) + break; + *d++ = *c++; + } + *d = '\0'; + if (fnmatch(list->data, buf, 0) == 0) { + return list; + } + list = list->link; + } + return NULL; +} diff --git a/archival/libarchive/get_header_ar.c b/archival/libarchive/get_header_ar.c new file mode 100644 index 000000000..df603b111 --- /dev/null +++ b/archival/libarchive/get_header_ar.c @@ -0,0 +1,133 @@ +/* vi: set sw=4 ts=4: */ +/* Copyright 2001 Glenn McGrath. + * + * Licensed under GPLv2 or later, see file LICENSE in this source tree. + */ + +#include "libbb.h" +#include "archive.h" +#include "ar.h" + +static unsigned read_num(const char *str, int base) +{ + /* This code works because + * on misformatted numbers bb_strtou returns all-ones */ + int err = bb_strtou(str, NULL, base); + if (err == -1) + bb_error_msg_and_die("invalid ar header"); + return err; +} + +char FAST_FUNC get_header_ar(archive_handle_t *archive_handle) +{ + file_header_t *typed = archive_handle->file_header; + unsigned size; + union { + char raw[60]; + struct ar_header formatted; + } ar; +#if ENABLE_FEATURE_AR_LONG_FILENAMES + static char *ar_long_names; + static unsigned ar_long_name_size; +#endif + + /* dont use xread as we want to handle the error ourself */ + if (read(archive_handle->src_fd, ar.raw, 60) != 60) { + /* End Of File */ + return EXIT_FAILURE; + } + + /* ar header starts on an even byte (2 byte aligned) + * '\n' is used for padding + */ + if (ar.raw[0] == '\n') { + /* fix up the header, we started reading 1 byte too early */ + memmove(ar.raw, &ar.raw[1], 59); + ar.raw[59] = xread_char(archive_handle->src_fd); + archive_handle->offset++; + } + archive_handle->offset += 60; + + if (ar.formatted.magic[0] != '`' || ar.formatted.magic[1] != '\n') + bb_error_msg_and_die("invalid ar header"); + + /* FIXME: more thorough routine would be in order here + * (we have something like that in tar) + * but for now we are lax. */ + ar.formatted.magic[0] = '\0'; /* else 4G-2 file will have size="4294967294`\n..." */ + typed->size = size = read_num(ar.formatted.size, 10); + + /* special filenames have '/' as the first character */ + if (ar.formatted.name[0] == '/') { + if (ar.formatted.name[1] == ' ') { + /* This is the index of symbols in the file for compilers */ + data_skip(archive_handle); + archive_handle->offset += size; + return get_header_ar(archive_handle); /* Return next header */ + } +#if ENABLE_FEATURE_AR_LONG_FILENAMES + if (ar.formatted.name[1] == '/') { + /* If the second char is a '/' then this entries data section + * stores long filename for multiple entries, they are stored + * in static variable long_names for use in future entries + */ + ar_long_name_size = size; + free(ar_long_names); + ar_long_names = xmalloc(size); + xread(archive_handle->src_fd, ar_long_names, size); + archive_handle->offset += size; + /* Return next header */ + return get_header_ar(archive_handle); + } +#else + bb_error_msg_and_die("long filenames not supported"); +#endif + } + /* Only size is always present, the rest may be missing in + * long filename pseudo file. Thus we decode the rest + * after dealing with long filename pseudo file. + */ + typed->mode = read_num(ar.formatted.mode, 8); + typed->mtime = read_num(ar.formatted.date, 10); + typed->uid = read_num(ar.formatted.uid, 10); + typed->gid = read_num(ar.formatted.gid, 10); + +#if ENABLE_FEATURE_AR_LONG_FILENAMES + if (ar.formatted.name[0] == '/') { + unsigned long_offset; + + /* The number after the '/' indicates the offset in the ar data section + * (saved in ar_long_names) that conatains the real filename */ + long_offset = read_num(&ar.formatted.name[1], 10); + if (long_offset >= ar_long_name_size) { + bb_error_msg_and_die("can't resolve long filename"); + } + typed->name = xstrdup(ar_long_names + long_offset); + } else +#endif + { + /* short filenames */ + typed->name = xstrndup(ar.formatted.name, 16); + } + + typed->name[strcspn(typed->name, " /")] = '\0'; + + if (archive_handle->filter(archive_handle) == EXIT_SUCCESS) { + archive_handle->action_header(typed); +#if ENABLE_DPKG || ENABLE_DPKG_DEB + if (archive_handle->dpkg__sub_archive) { + while (archive_handle->dpkg__action_data_subarchive(archive_handle->dpkg__sub_archive) == EXIT_SUCCESS) + continue; + } else +#endif + archive_handle->action_data(archive_handle); + } else { + data_skip(archive_handle); + } + + archive_handle->offset += typed->size; + /* Set the file pointer to the correct spot, we may have been reading a compressed file */ + lseek(archive_handle->src_fd, archive_handle->offset, SEEK_SET); + + return EXIT_SUCCESS; +} diff --git a/archival/libarchive/get_header_cpio.c b/archival/libarchive/get_header_cpio.c new file mode 100644 index 000000000..3d99b492a --- /dev/null +++ b/archival/libarchive/get_header_cpio.c @@ -0,0 +1,186 @@ +/* vi: set sw=4 ts=4: */ +/* Copyright 2002 Laurence Anderson + * + * Licensed under GPLv2 or later, see file LICENSE in this source tree. + */ + +#include "libbb.h" +#include "archive.h" + +typedef struct hardlinks_t { + struct hardlinks_t *next; + int inode; /* TODO: must match maj/min too! */ + int mode ; + int mtime; /* These three are useful only in corner case */ + int uid ; /* of hardlinks with zero size body */ + int gid ; + char name[1]; +} hardlinks_t; + +char FAST_FUNC get_header_cpio(archive_handle_t *archive_handle) +{ + file_header_t *file_header = archive_handle->file_header; + char cpio_header[110]; + int namesize; + int major, minor, nlink, mode, inode; + unsigned size, uid, gid, mtime; + + /* There can be padding before archive header */ + data_align(archive_handle, 4); + + size = full_read(archive_handle->src_fd, cpio_header, 110); + if (size == 0) { + goto create_hardlinks; + } + if (size != 110) { + bb_error_msg_and_die("short read"); + } + archive_handle->offset += 110; + + if (strncmp(&cpio_header[0], "07070", 5) != 0 + || (cpio_header[5] != '1' && cpio_header[5] != '2') + ) { + bb_error_msg_and_die("unsupported cpio format, use newc or crc"); + } + + if (sscanf(cpio_header + 6, + "%8x" "%8x" "%8x" "%8x" + "%8x" "%8x" "%8x" /*maj,min:*/ "%*16c" + /*rmaj,rmin:*/"%8x" "%8x" "%8x" /*chksum: "%*8c"*/, + &inode, &mode, &uid, &gid, + &nlink, &mtime, &size, + &major, &minor, &namesize) != 10) + bb_error_msg_and_die("damaged cpio file"); + file_header->mode = mode; + file_header->uid = uid; + file_header->gid = gid; + file_header->mtime = mtime; + file_header->size = size; + + namesize &= 0x1fff; /* paranoia: limit names to 8k chars */ + file_header->name = xzalloc(namesize + 1); + /* Read in filename */ + xread(archive_handle->src_fd, file_header->name, namesize); + if (file_header->name[0] == '/') { + /* Testcase: echo /etc/hosts | cpio -pvd /tmp + * Without this code, it tries to unpack /etc/hosts + * into "/etc/hosts", not "etc/hosts". + */ + char *p = file_header->name; + do p++; while (*p == '/'); + overlapping_strcpy(file_header->name, p); + } + archive_handle->offset += namesize; + + /* Update offset amount and skip padding before file contents */ + data_align(archive_handle, 4); + + if (strcmp(file_header->name, "TRAILER!!!") == 0) { + /* Always round up. ">> 9" divides by 512 */ + archive_handle->cpio__blocks = (uoff_t)(archive_handle->offset + 511) >> 9; + goto create_hardlinks; + } + + file_header->link_target = NULL; + if (S_ISLNK(file_header->mode)) { + file_header->size &= 0x1fff; /* paranoia: limit names to 8k chars */ + file_header->link_target = xzalloc(file_header->size + 1); + xread(archive_handle->src_fd, file_header->link_target, file_header->size); + archive_handle->offset += file_header->size; + file_header->size = 0; /* Stop possible seeks in future */ + } + +// TODO: data_extract_all can't deal with hardlinks to non-files... +// when fixed, change S_ISREG to !S_ISDIR here + + if (nlink > 1 && S_ISREG(file_header->mode)) { + hardlinks_t *new = xmalloc(sizeof(*new) + namesize); + new->inode = inode; + new->mode = mode ; + new->mtime = mtime; + new->uid = uid ; + new->gid = gid ; + strcpy(new->name, file_header->name); + /* Put file on a linked list for later */ + if (size == 0) { + new->next = archive_handle->cpio__hardlinks_to_create; + archive_handle->cpio__hardlinks_to_create = new; + return EXIT_SUCCESS; /* Skip this one */ + /* TODO: this breaks cpio -t (it does not show hardlinks) */ + } + new->next = archive_handle->cpio__created_hardlinks; + archive_handle->cpio__created_hardlinks = new; + } + file_header->device = makedev(major, minor); + + if (archive_handle->filter(archive_handle) == EXIT_SUCCESS) { + archive_handle->action_data(archive_handle); +//TODO: run "echo /etc/hosts | cpio -pv /tmp" twice. On 2nd run: +//cpio: etc/hosts not created: newer or same age file exists +//etc/hosts <-- should NOT show it +//2 blocks <-- should say "0 blocks" + archive_handle->action_header(file_header); + } else { + data_skip(archive_handle); + } + + archive_handle->offset += file_header->size; + + free(file_header->link_target); + free(file_header->name); + file_header->link_target = NULL; + file_header->name = NULL; + + return EXIT_SUCCESS; + + create_hardlinks: + free(file_header->link_target); + free(file_header->name); + + while (archive_handle->cpio__hardlinks_to_create) { + hardlinks_t *cur; + hardlinks_t *make_me = archive_handle->cpio__hardlinks_to_create; + + archive_handle->cpio__hardlinks_to_create = make_me->next; + + memset(file_header, 0, sizeof(*file_header)); + file_header->mtime = make_me->mtime; + file_header->name = make_me->name; + file_header->mode = make_me->mode; + file_header->uid = make_me->uid; + file_header->gid = make_me->gid; + /*file_header->size = 0;*/ + /*file_header->link_target = NULL;*/ + + /* Try to find a file we are hardlinked to */ + cur = archive_handle->cpio__created_hardlinks; + while (cur) { + /* TODO: must match maj/min too! */ + if (cur->inode == make_me->inode) { + file_header->link_target = cur->name; + /* link_target != NULL, size = 0: "I am a hardlink" */ + if (archive_handle->filter(archive_handle) == EXIT_SUCCESS) + archive_handle->action_data(archive_handle); + free(make_me); + goto next_link; + } + cur = cur->next; + } + /* Oops... no file with such inode was created... do it now + * (happens when hardlinked files are empty (zero length)) */ + if (archive_handle->filter(archive_handle) == EXIT_SUCCESS) + archive_handle->action_data(archive_handle); + /* Move to the list of created hardlinked files */ + make_me->next = archive_handle->cpio__created_hardlinks; + archive_handle->cpio__created_hardlinks = make_me; + next_link: ; + } + + while (archive_handle->cpio__created_hardlinks) { + hardlinks_t *p = archive_handle->cpio__created_hardlinks; + archive_handle->cpio__created_hardlinks = p->next; + free(p); + } + + return EXIT_FAILURE; /* "No more files to process" */ +} diff --git a/archival/libarchive/get_header_tar.c b/archival/libarchive/get_header_tar.c new file mode 100644 index 000000000..78b0ae25f --- /dev/null +++ b/archival/libarchive/get_header_tar.c @@ -0,0 +1,461 @@ +/* vi: set sw=4 ts=4: */ +/* Licensed under GPLv2 or later, see file LICENSE in this source tree. + * + * FIXME: + * In privileged mode if uname and gname map to a uid and gid then use the + * mapped value instead of the uid/gid values in tar header + * + * References: + * GNU tar and star man pages, + * Opengroup's ustar interchange format, + * http://www.opengroup.org/onlinepubs/007904975/utilities/pax.html + */ + +#include "libbb.h" +#include "archive.h" + +typedef uint32_t aliased_uint32_t FIX_ALIASING; +typedef off_t aliased_off_t FIX_ALIASING; + + +/* NB: _DESTROYS_ str[len] character! */ +static unsigned long long getOctal(char *str, int len) +{ + unsigned long long v; + char *end; + /* NB: leading spaces are allowed. Using strtoull to handle that. + * The downside is that we accept e.g. "-123" too :( + */ + str[len] = '\0'; + v = strtoull(str, &end, 8); + /* std: "Each numeric field is terminated by one or more + * or NUL characters". We must support ' '! */ + if (*end != '\0' && *end != ' ') { + int8_t first = str[0]; + if (!(first & 0x80)) + bb_error_msg_and_die("corrupted octal value in tar header"); + /* + * GNU tar uses "base-256 encoding" for very large numbers. + * Encoding is binary, with highest bit always set as a marker + * and sign in next-highest bit: + * 80 00 .. 00 - zero + * bf ff .. ff - largest positive number + * ff ff .. ff - minus 1 + * c0 00 .. 00 - smallest negative number + * + * Example of tar file with 8914993153 (0x213600001) byte file. + * Field starts at offset 7c: + * 00070 30 30 30 00 30 30 30 30 30 30 30 00 80 00 00 00 |000.0000000.....| + * 00080 00 00 00 02 13 60 00 01 31 31 31 32 30 33 33 36 |.....`..11120336| + * + * NB: tarballs with NEGATIVE unix times encoded that way were seen! + */ + v = first; + /* Sign-extend using 6th bit: */ + v <<= sizeof(unsigned long long)*8 - 7; + v = (long long)v >> (sizeof(unsigned long long)*8 - 7); + while (--len != 0) + v = (v << 8) + (unsigned char) *str++; + } + return v; +} +#define GET_OCTAL(a) getOctal((a), sizeof(a)) + +#if ENABLE_FEATURE_TAR_SELINUX +/* Scan a PAX header for SELinux contexts, via "RHT.security.selinux" keyword. + * This is what Red Hat's patched version of tar uses. + */ +# define SELINUX_CONTEXT_KEYWORD "RHT.security.selinux" +static char *get_selinux_sctx_from_pax_hdr(archive_handle_t *archive_handle, unsigned sz) +{ + char *buf, *p; + char *result; + + p = buf = xmalloc(sz + 1); + /* prevent bb_strtou from running off the buffer */ + buf[sz] = '\0'; + xread(archive_handle->src_fd, buf, sz); + archive_handle->offset += sz; + + result = NULL; + while (sz != 0) { + char *end, *value; + unsigned len; + + /* Every record has this format: "LEN NAME=VALUE\n" */ + len = bb_strtou(p, &end, 10); + /* expect errno to be EINVAL, because the character + * following the digits should be a space + */ + p += len; + sz -= len; + if ((int)sz < 0 + || len == 0 + || errno != EINVAL + || *end != ' ' + ) { + bb_error_msg("malformed extended header, skipped"); + // More verbose version: + //bb_error_msg("malformed extended header at %"OFF_FMT"d, skipped", + // archive_handle->offset - (sz + len)); + break; + } + /* overwrite the terminating newline with NUL + * (we do not bother to check that it *was* a newline) + */ + p[-1] = '\0'; + /* Is it selinux security context? */ + value = end + 1; + if (strncmp(value, SELINUX_CONTEXT_KEYWORD"=", sizeof(SELINUX_CONTEXT_KEYWORD"=") - 1) == 0) { + value += sizeof(SELINUX_CONTEXT_KEYWORD"=") - 1; + result = xstrdup(value); + break; + } + } + + free(buf); + return result; +} +#endif + +char FAST_FUNC get_header_tar(archive_handle_t *archive_handle) +{ + file_header_t *file_header = archive_handle->file_header; + struct tar_header_t tar; + char *cp; + int i, sum_u, sum; +#if ENABLE_FEATURE_TAR_OLDSUN_COMPATIBILITY + int sum_s; +#endif + int parse_names; + + /* Our "private data" */ +#if ENABLE_FEATURE_TAR_GNU_EXTENSIONS +# define p_longname (archive_handle->tar__longname) +# define p_linkname (archive_handle->tar__linkname) +#else +# define p_longname 0 +# define p_linkname 0 +#endif + +#if ENABLE_FEATURE_TAR_GNU_EXTENSIONS || ENABLE_FEATURE_TAR_SELINUX + again: +#endif + /* Align header */ + data_align(archive_handle, 512); + + again_after_align: + +#if ENABLE_DESKTOP || ENABLE_FEATURE_TAR_AUTODETECT + /* to prevent misdetection of bz2 sig */ + *(aliased_uint32_t*)&tar = 0; + i = full_read(archive_handle->src_fd, &tar, 512); + /* If GNU tar sees EOF in above read, it says: + * "tar: A lone zero block at N", where N = kilobyte + * where EOF was met (not EOF block, actual EOF!), + * and exits with EXIT_SUCCESS. + * We will mimic exit(EXIT_SUCCESS), although we will not mimic + * the message and we don't check whether we indeed + * saw zero block directly before this. */ + if (i == 0) { + xfunc_error_retval = 0; + short_read: + bb_error_msg_and_die("short read"); + } + if (i != 512) { + IF_FEATURE_TAR_AUTODETECT(goto autodetect;) + goto short_read; + } + +#else + i = 512; + xread(archive_handle->src_fd, &tar, i); +#endif + archive_handle->offset += i; + + /* If there is no filename its an empty header */ + if (tar.name[0] == 0 && tar.prefix[0] == 0) { + if (archive_handle->tar__end) { + /* Second consecutive empty header - end of archive. + * Read until the end to empty the pipe from gz or bz2 + */ + while (full_read(archive_handle->src_fd, &tar, 512) == 512) + continue; + return EXIT_FAILURE; + } + archive_handle->tar__end = 1; + return EXIT_SUCCESS; + } + archive_handle->tar__end = 0; + + /* Check header has valid magic, "ustar" is for the proper tar, + * five NULs are for the old tar format */ + if (strncmp(tar.magic, "ustar", 5) != 0 + && (!ENABLE_FEATURE_TAR_OLDGNU_COMPATIBILITY + || memcmp(tar.magic, "\0\0\0\0", 5) != 0) + ) { +#if ENABLE_FEATURE_TAR_AUTODETECT + char FAST_FUNC (*get_header_ptr)(archive_handle_t *); + uint16_t magic2; + + autodetect: + magic2 = *(uint16_t*)tar.name; + /* tar gz/bz autodetect: check for gz/bz2 magic. + * If we see the magic, and it is the very first block, + * we can switch to get_header_tar_gz/bz2/lzma(). + * Needs seekable fd. I wish recv(MSG_PEEK) works + * on any fd... */ +# if ENABLE_FEATURE_SEAMLESS_GZ + if (magic2 == GZIP_MAGIC) { + get_header_ptr = get_header_tar_gz; + } else +# endif +# if ENABLE_FEATURE_SEAMLESS_BZ2 + if (magic2 == BZIP2_MAGIC + && tar.name[2] == 'h' && isdigit(tar.name[3]) + ) { /* bzip2 */ + get_header_ptr = get_header_tar_bz2; + } else +# endif +# if ENABLE_FEATURE_SEAMLESS_XZ + //TODO: if (magic2 == XZ_MAGIC1)... + //else +# endif + goto err; + /* Two different causes for lseek() != 0: + * unseekable fd (would like to support that too, but...), + * or not first block (false positive, it's not .gz/.bz2!) */ + if (lseek(archive_handle->src_fd, -i, SEEK_CUR) != 0) + goto err; + while (get_header_ptr(archive_handle) == EXIT_SUCCESS) + continue; + return EXIT_FAILURE; + err: +#endif /* FEATURE_TAR_AUTODETECT */ + bb_error_msg_and_die("invalid tar magic"); + } + + /* Do checksum on headers. + * POSIX says that checksum is done on unsigned bytes, but + * Sun and HP-UX gets it wrong... more details in + * GNU tar source. */ +#if ENABLE_FEATURE_TAR_OLDSUN_COMPATIBILITY + sum_s = ' ' * sizeof(tar.chksum); +#endif + sum_u = ' ' * sizeof(tar.chksum); + for (i = 0; i < 148; i++) { + sum_u += ((unsigned char*)&tar)[i]; +#if ENABLE_FEATURE_TAR_OLDSUN_COMPATIBILITY + sum_s += ((signed char*)&tar)[i]; +#endif + } + for (i = 156; i < 512; i++) { + sum_u += ((unsigned char*)&tar)[i]; +#if ENABLE_FEATURE_TAR_OLDSUN_COMPATIBILITY + sum_s += ((signed char*)&tar)[i]; +#endif + } + /* This field does not need special treatment (getOctal) */ + { + char *endp; /* gcc likes temp var for &endp */ + sum = strtoul(tar.chksum, &endp, 8); + if ((*endp != '\0' && *endp != ' ') + || (sum_u != sum IF_FEATURE_TAR_OLDSUN_COMPATIBILITY(&& sum_s != sum)) + ) { + bb_error_msg_and_die("invalid tar header checksum"); + } + } + /* don't use xstrtoul, tar.chksum may have leading spaces */ + sum = strtoul(tar.chksum, NULL, 8); + if (sum_u != sum IF_FEATURE_TAR_OLDSUN_COMPATIBILITY(&& sum_s != sum)) { + bb_error_msg_and_die("invalid tar header checksum"); + } + + /* 0 is reserved for high perf file, treat as normal file */ + if (!tar.typeflag) tar.typeflag = '0'; + parse_names = (tar.typeflag >= '0' && tar.typeflag <= '7'); + + /* getOctal trashes subsequent field, therefore we call it + * on fields in reverse order */ + if (tar.devmajor[0]) { + char t = tar.prefix[0]; + /* we trash prefix[0] here, but we DO need it later! */ + unsigned minor = GET_OCTAL(tar.devminor); + unsigned major = GET_OCTAL(tar.devmajor); + file_header->device = makedev(major, minor); + tar.prefix[0] = t; + } + file_header->link_target = NULL; + if (!p_linkname && parse_names && tar.linkname[0]) { + file_header->link_target = xstrndup(tar.linkname, sizeof(tar.linkname)); + /* FIXME: what if we have non-link object with link_target? */ + /* Will link_target be free()ed? */ + } +#if ENABLE_FEATURE_TAR_UNAME_GNAME + file_header->tar__uname = tar.uname[0] ? xstrndup(tar.uname, sizeof(tar.uname)) : NULL; + file_header->tar__gname = tar.gname[0] ? xstrndup(tar.gname, sizeof(tar.gname)) : NULL; +#endif + file_header->mtime = GET_OCTAL(tar.mtime); + file_header->size = GET_OCTAL(tar.size); + file_header->gid = GET_OCTAL(tar.gid); + file_header->uid = GET_OCTAL(tar.uid); + /* Set bits 0-11 of the files mode */ + file_header->mode = 07777 & GET_OCTAL(tar.mode); + + file_header->name = NULL; + if (!p_longname && parse_names) { + /* we trash mode[0] here, it's ok */ + //tar.name[sizeof(tar.name)] = '\0'; - gcc 4.3.0 would complain + tar.mode[0] = '\0'; + if (tar.prefix[0]) { + /* and padding[0] */ + //tar.prefix[sizeof(tar.prefix)] = '\0'; - gcc 4.3.0 would complain + tar.padding[0] = '\0'; + file_header->name = concat_path_file(tar.prefix, tar.name); + } else + file_header->name = xstrdup(tar.name); + } + + /* Set bits 12-15 of the files mode */ + /* (typeflag was not trashed because chksum does not use getOctal) */ + switch (tar.typeflag) { + /* busybox identifies hard links as being regular files with 0 size and a link name */ + case '1': + file_header->mode |= S_IFREG; + break; + case '7': + /* case 0: */ + case '0': +#if ENABLE_FEATURE_TAR_OLDGNU_COMPATIBILITY + if (last_char_is(file_header->name, '/')) { + goto set_dir; + } +#endif + file_header->mode |= S_IFREG; + break; + case '2': + file_header->mode |= S_IFLNK; + /* have seen tarballs with size field containing + * the size of the link target's name */ + size0: + file_header->size = 0; + break; + case '3': + file_header->mode |= S_IFCHR; + goto size0; /* paranoia */ + case '4': + file_header->mode |= S_IFBLK; + goto size0; + case '5': + IF_FEATURE_TAR_OLDGNU_COMPATIBILITY(set_dir:) + file_header->mode |= S_IFDIR; + goto size0; + case '6': + file_header->mode |= S_IFIFO; + goto size0; +#if ENABLE_FEATURE_TAR_GNU_EXTENSIONS + case 'L': + /* free: paranoia: tar with several consecutive longnames */ + free(p_longname); + /* For paranoia reasons we allocate extra NUL char */ + p_longname = xzalloc(file_header->size + 1); + /* We read ASCIZ string, including NUL */ + xread(archive_handle->src_fd, p_longname, file_header->size); + archive_handle->offset += file_header->size; + /* return get_header_tar(archive_handle); */ + /* gcc 4.1.1 didn't optimize it into jump */ + /* so we will do it ourself, this also saves stack */ + goto again; + case 'K': + free(p_linkname); + p_linkname = xzalloc(file_header->size + 1); + xread(archive_handle->src_fd, p_linkname, file_header->size); + archive_handle->offset += file_header->size; + /* return get_header_tar(archive_handle); */ + goto again; + case 'D': /* GNU dump dir */ + case 'M': /* Continuation of multi volume archive */ + case 'N': /* Old GNU for names > 100 characters */ + case 'S': /* Sparse file */ + case 'V': /* Volume header */ +#endif +#if !ENABLE_FEATURE_TAR_SELINUX + case 'g': /* pax global header */ + case 'x': /* pax extended header */ +#else + skip_ext_hdr: +#endif + { + off_t sz; + bb_error_msg("warning: skipping header '%c'", tar.typeflag); + sz = (file_header->size + 511) & ~(off_t)511; + archive_handle->offset += sz; + sz >>= 9; /* sz /= 512 but w/o contortions for signed div */ + while (sz--) + xread(archive_handle->src_fd, &tar, 512); + /* return get_header_tar(archive_handle); */ + goto again_after_align; + } +#if ENABLE_FEATURE_TAR_SELINUX + case 'g': /* pax global header */ + case 'x': { /* pax extended header */ + char **pp; + if ((uoff_t)file_header->size > 0xfffff) /* paranoia */ + goto skip_ext_hdr; + pp = (tar.typeflag == 'g') ? &archive_handle->tar__global_sctx : &archive_handle->tar__next_file_sctx; + free(*pp); + *pp = get_selinux_sctx_from_pax_hdr(archive_handle, file_header->size); + goto again; + } +#endif + default: + bb_error_msg_and_die("unknown typeflag: 0x%x", tar.typeflag); + } + +#if ENABLE_FEATURE_TAR_GNU_EXTENSIONS + if (p_longname) { + file_header->name = p_longname; + p_longname = NULL; + } + if (p_linkname) { + file_header->link_target = p_linkname; + p_linkname = NULL; + } +#endif + if (strncmp(file_header->name, "/../"+1, 3) == 0 + || strstr(file_header->name, "/../") + ) { + bb_error_msg_and_die("name with '..' encountered: '%s'", + file_header->name); + } + + /* Strip trailing '/' in directories */ + /* Must be done after mode is set as '/' is used to check if it's a directory */ + cp = last_char_is(file_header->name, '/'); + + if (archive_handle->filter(archive_handle) == EXIT_SUCCESS) { + archive_handle->action_header(/*archive_handle->*/ file_header); + /* Note that we kill the '/' only after action_header() */ + /* (like GNU tar 1.15.1: verbose mode outputs "dir/dir/") */ + if (cp) + *cp = '\0'; + archive_handle->action_data(archive_handle); + if (archive_handle->accept || archive_handle->reject) + llist_add_to(&archive_handle->passed, file_header->name); + else /* Caller isn't interested in list of unpacked files */ + free(file_header->name); + } else { + data_skip(archive_handle); + free(file_header->name); + } + archive_handle->offset += file_header->size; + + free(file_header->link_target); + /* Do not free(file_header->name)! + * It might be inserted in archive_handle->passed - see above */ +#if ENABLE_FEATURE_TAR_UNAME_GNAME + free(file_header->tar__uname); + free(file_header->tar__gname); +#endif + return EXIT_SUCCESS; +} diff --git a/archival/libarchive/get_header_tar_bz2.c b/archival/libarchive/get_header_tar_bz2.c new file mode 100644 index 000000000..60d32069f --- /dev/null +++ b/archival/libarchive/get_header_tar_bz2.c @@ -0,0 +1,21 @@ +/* vi: set sw=4 ts=4: */ +/* + * Licensed under GPLv2 or later, see file LICENSE in this source tree. + */ + +#include "libbb.h" +#include "archive.h" + +char FAST_FUNC get_header_tar_bz2(archive_handle_t *archive_handle) +{ + /* Can't lseek over pipes */ + archive_handle->seek = seek_by_read; + + open_transformer(archive_handle->src_fd, unpack_bz2_stream_prime, "bunzip2"); + archive_handle->offset = 0; + while (get_header_tar(archive_handle) == EXIT_SUCCESS) + continue; + + /* Can only do one file at a time */ + return EXIT_FAILURE; +} diff --git a/archival/libarchive/get_header_tar_gz.c b/archival/libarchive/get_header_tar_gz.c new file mode 100644 index 000000000..b09f8691c --- /dev/null +++ b/archival/libarchive/get_header_tar_gz.c @@ -0,0 +1,36 @@ +/* vi: set sw=4 ts=4: */ +/* + * Licensed under GPLv2 or later, see file LICENSE in this source tree. + */ + +#include "libbb.h" +#include "archive.h" + +char FAST_FUNC get_header_tar_gz(archive_handle_t *archive_handle) +{ +#if BB_MMU + unsigned char magic[2]; +#endif + + /* Can't lseek over pipes */ + archive_handle->seek = seek_by_read; + + /* Check gzip magic only if open_transformer will invoke unpack_gz_stream (MMU case). + * Otherwise, it will invoke an external helper "gunzip -cf" (NOMMU case) which will + * need the header. */ +#if BB_MMU + xread(archive_handle->src_fd, &magic, 2); + /* Can skip this check, but error message will be less clear */ + if ((magic[0] != 0x1f) || (magic[1] != 0x8b)) { + bb_error_msg_and_die("invalid gzip magic"); + } +#endif + + open_transformer(archive_handle->src_fd, unpack_gz_stream, "gunzip"); + archive_handle->offset = 0; + while (get_header_tar(archive_handle) == EXIT_SUCCESS) + continue; + + /* Can only do one file at a time */ + return EXIT_FAILURE; +} diff --git a/archival/libarchive/get_header_tar_lzma.c b/archival/libarchive/get_header_tar_lzma.c new file mode 100644 index 000000000..da08e0c72 --- /dev/null +++ b/archival/libarchive/get_header_tar_lzma.c @@ -0,0 +1,24 @@ +/* vi: set sw=4 ts=4: */ +/* + * Small lzma deflate implementation. + * Copyright (C) 2006 Aurelien Jacobs + * + * Licensed under GPLv2, see file LICENSE in this source tree. + */ + +#include "libbb.h" +#include "archive.h" + +char FAST_FUNC get_header_tar_lzma(archive_handle_t *archive_handle) +{ + /* Can't lseek over pipes */ + archive_handle->seek = seek_by_read; + + open_transformer(archive_handle->src_fd, unpack_lzma_stream, "unlzma"); + archive_handle->offset = 0; + while (get_header_tar(archive_handle) == EXIT_SUCCESS) + continue; + + /* Can only do one file at a time */ + return EXIT_FAILURE; +} diff --git a/archival/libarchive/header_list.c b/archival/libarchive/header_list.c new file mode 100644 index 000000000..c4fc75f38 --- /dev/null +++ b/archival/libarchive/header_list.c @@ -0,0 +1,12 @@ +/* vi: set sw=4 ts=4: */ +/* + * Licensed under GPLv2 or later, see file LICENSE in this source tree. + */ +#include "libbb.h" +#include "archive.h" + +void FAST_FUNC header_list(const file_header_t *file_header) +{ +//TODO: cpio -vp DIR should output "DIR/NAME", not just "NAME" */ + puts(file_header->name); +} diff --git a/archival/libarchive/header_skip.c b/archival/libarchive/header_skip.c new file mode 100644 index 000000000..2bfc5253c --- /dev/null +++ b/archival/libarchive/header_skip.c @@ -0,0 +1,10 @@ +/* vi: set sw=4 ts=4: */ +/* + * Licensed under GPLv2 or later, see file LICENSE in this source tree. + */ +#include "libbb.h" +#include "archive.h" + +void FAST_FUNC header_skip(const file_header_t *file_header UNUSED_PARAM) +{ +} diff --git a/archival/libarchive/header_verbose_list.c b/archival/libarchive/header_verbose_list.c new file mode 100644 index 000000000..bc4e4154b --- /dev/null +++ b/archival/libarchive/header_verbose_list.c @@ -0,0 +1,69 @@ +/* vi: set sw=4 ts=4: */ +/* + * Licensed under GPLv2 or later, see file LICENSE in this source tree. + */ + +#include "libbb.h" +#include "archive.h" + +void FAST_FUNC header_verbose_list(const file_header_t *file_header) +{ + struct tm tm_time; + struct tm *ptm = &tm_time; //localtime(&file_header->mtime); + +#if ENABLE_FEATURE_TAR_UNAME_GNAME + char uid[sizeof(int)*3 + 2]; + /*char gid[sizeof(int)*3 + 2];*/ + char *user; + char *group; + + localtime_r(&file_header->mtime, ptm); + + user = file_header->tar__uname; + if (user == NULL) { + sprintf(uid, "%u", (unsigned)file_header->uid); + user = uid; + } + group = file_header->tar__gname; + if (group == NULL) { + /*sprintf(gid, "%u", (unsigned)file_header->gid);*/ + group = utoa(file_header->gid); + } + printf("%s %s/%s %9"OFF_FMT"u %4u-%02u-%02u %02u:%02u:%02u %s", + bb_mode_string(file_header->mode), + user, + group, + file_header->size, + 1900 + ptm->tm_year, + 1 + ptm->tm_mon, + ptm->tm_mday, + ptm->tm_hour, + ptm->tm_min, + ptm->tm_sec, + file_header->name); + +#else /* !FEATURE_TAR_UNAME_GNAME */ + + localtime_r(&file_header->mtime, ptm); + + printf("%s %u/%u %9"OFF_FMT"u %4u-%02u-%02u %02u:%02u:%02u %s", + bb_mode_string(file_header->mode), + (unsigned)file_header->uid, + (unsigned)file_header->gid, + file_header->size, + 1900 + ptm->tm_year, + 1 + ptm->tm_mon, + ptm->tm_mday, + ptm->tm_hour, + ptm->tm_min, + ptm->tm_sec, + file_header->name); + +#endif /* FEATURE_TAR_UNAME_GNAME */ + + /* NB: GNU tar shows "->" for symlinks and "link to" for hardlinks */ + if (file_header->link_target) { + printf(" -> %s", file_header->link_target); + } + bb_putchar('\n'); +} diff --git a/archival/libarchive/init_handle.c b/archival/libarchive/init_handle.c new file mode 100644 index 000000000..6644ea13b --- /dev/null +++ b/archival/libarchive/init_handle.c @@ -0,0 +1,22 @@ +/* vi: set sw=4 ts=4: */ +/* + * Licensed under GPLv2 or later, see file LICENSE in this source tree. + */ + +#include "libbb.h" +#include "archive.h" + +archive_handle_t* FAST_FUNC init_handle(void) +{ + archive_handle_t *archive_handle; + + /* Initialize default values */ + archive_handle = xzalloc(sizeof(archive_handle_t)); + archive_handle->file_header = xzalloc(sizeof(file_header_t)); + archive_handle->action_header = header_skip; + archive_handle->action_data = data_skip; + archive_handle->filter = filter_accept_all; + archive_handle->seek = seek_by_jump; + + return archive_handle; +} diff --git a/archival/libarchive/liblzo.h b/archival/libarchive/liblzo.h new file mode 100644 index 000000000..843997cb9 --- /dev/null +++ b/archival/libarchive/liblzo.h @@ -0,0 +1,93 @@ +/* + This file is part of the LZO real-time data compression library. + + Copyright (C) 1996..2008 Markus Franz Xaver Johannes Oberhumer + All Rights Reserved. + + Markus F.X.J. Oberhumer + http://www.oberhumer.com/opensource/lzo/ + + The LZO library is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of + the License, or (at your option) any later version. + + The LZO library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with the LZO library; see the file COPYING. + If not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "liblzo_interface.h" + +/* lzo-2.03/src/config1x.h */ +#define M2_MIN_LEN 3 +#define M2_MAX_LEN 8 +#define M3_MAX_LEN 33 +#define M4_MAX_LEN 9 +#define M1_MAX_OFFSET 0x0400 +#define M2_MAX_OFFSET 0x0800 +#define M3_MAX_OFFSET 0x4000 +#define M4_MAX_OFFSET 0xbfff +#define M1_MARKER 0 +#define M3_MARKER 32 +#define M4_MARKER 16 + +#define MX_MAX_OFFSET (M1_MAX_OFFSET + M2_MAX_OFFSET) +#define MIN_LOOKAHEAD (M2_MAX_LEN + 1) + +#define LZO_EOF_CODE + +/* lzo-2.03/src/lzo_dict.h */ +#define GINDEX(m_pos,m_off,dict,dindex,in) m_pos = dict[dindex] +#define DX2(p,s1,s2) \ + (((((unsigned)((p)[2]) << (s2)) ^ (p)[1]) << (s1)) ^ (p)[0]) +//#define DA3(p,s1,s2,s3) ((DA2((p)+1,s2,s3) << (s1)) + (p)[0]) +//#define DS3(p,s1,s2,s3) ((DS2((p)+1,s2,s3) << (s1)) - (p)[0]) +#define DX3(p,s1,s2,s3) ((DX2((p)+1,s2,s3) << (s1)) ^ (p)[0]) + +#define D_SIZE (1U << D_BITS) +#define D_MASK ((1U << D_BITS) - 1) +#define D_HIGH ((D_MASK >> 1) + 1) + +#define LZO_CHECK_MPOS_NON_DET(m_pos,m_off,in,ip,max_offset) \ + ( \ + m_pos = ip - (unsigned)(ip - m_pos), \ + ((uintptr_t)m_pos < (uintptr_t)in \ + || (m_off = (unsigned)(ip - m_pos)) <= 0 \ + || m_off > max_offset) \ + ) + +#define DENTRY(p,in) (p) +#define UPDATE_I(dict,drun,index,p,in) dict[index] = DENTRY(p,in) + +#define DMS(v,s) ((unsigned) (((v) & (D_MASK >> (s))) << (s))) +#define DM(v) ((unsigned) ((v) & D_MASK)) +#define DMUL(a,b) ((unsigned) ((a) * (b))) + +/* lzo-2.03/src/lzo_ptr.h */ +#define pd(a,b) ((unsigned)((a)-(b))) + +# define TEST_IP (ip < ip_end) +# define NEED_IP(x) \ + if ((unsigned)(ip_end - ip) < (unsigned)(x)) goto input_overrun + +# undef TEST_OP /* don't need both of the tests here */ +# define TEST_OP 1 +# define NEED_OP(x) \ + if ((unsigned)(op_end - op) < (unsigned)(x)) goto output_overrun + +#define HAVE_ANY_OP 1 + +//#if defined(LZO_TEST_OVERRUN_LOOKBEHIND) +# define TEST_LB(m_pos) if (m_pos < out || m_pos >= op) goto lookbehind_overrun +//# define TEST_LBO(m_pos,o) if (m_pos < out || m_pos >= op - (o)) goto lookbehind_overrun +//#else +//# define TEST_LB(m_pos) ((void) 0) +//# define TEST_LBO(m_pos,o) ((void) 0) +//#endif diff --git a/archival/libarchive/lzo1x_1.c b/archival/libarchive/lzo1x_1.c new file mode 100644 index 000000000..a88839846 --- /dev/null +++ b/archival/libarchive/lzo1x_1.c @@ -0,0 +1,35 @@ +/* LZO1X-1 compression + + This file is part of the LZO real-time data compression library. + + Copyright (C) 1996..2008 Markus Franz Xaver Johannes Oberhumer + All Rights Reserved. + + Markus F.X.J. Oberhumer + http://www.oberhumer.com/opensource/lzo/ + + The LZO library is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of + the License, or (at your option) any later version. + + The LZO library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with the LZO library; see the file COPYING. + If not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#include "libbb.h" +#include "liblzo.h" + +#define D_BITS 14 +#define D_INDEX1(d,p) d = DM(DMUL(0x21,DX3(p,5,5,6)) >> 5) +#define D_INDEX2(d,p) d = (d & (D_MASK & 0x7ff)) ^ (D_HIGH | 0x1f) + +#define DO_COMPRESS lzo1x_1_compress + +#include "lzo1x_c.c" diff --git a/archival/libarchive/lzo1x_1o.c b/archival/libarchive/lzo1x_1o.c new file mode 100644 index 000000000..3c61253e0 --- /dev/null +++ b/archival/libarchive/lzo1x_1o.c @@ -0,0 +1,35 @@ +/* LZO1X-1(15) compression + + This file is part of the LZO real-time data compression library. + + Copyright (C) 1996..2008 Markus Franz Xaver Johannes Oberhumer + All Rights Reserved. + + Markus F.X.J. Oberhumer + http://www.oberhumer.com/opensource/lzo/ + + The LZO library is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of + the License, or (at your option) any later version. + + The LZO library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with the LZO library; see the file COPYING. + If not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#include "libbb.h" +#include "liblzo.h" + +#define D_BITS 15 +#define D_INDEX1(d,p) d = DM(DMUL(0x21,DX3(p,5,5,6)) >> 5) +#define D_INDEX2(d,p) d = (d & (D_MASK & 0x7ff)) ^ (D_HIGH | 0x1f) + +#define DO_COMPRESS lzo1x_1_15_compress + +#include "lzo1x_c.c" diff --git a/archival/libarchive/lzo1x_9x.c b/archival/libarchive/lzo1x_9x.c new file mode 100644 index 000000000..483205155 --- /dev/null +++ b/archival/libarchive/lzo1x_9x.c @@ -0,0 +1,921 @@ +/* lzo1x_9x.c -- implementation of the LZO1X-999 compression algorithm + + This file is part of the LZO real-time data compression library. + + Copyright (C) 2008 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 2007 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 2006 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 2005 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 2004 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 2003 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 2002 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 2001 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 2000 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 1999 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 1998 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 1997 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 1996 Markus Franz Xaver Johannes Oberhumer + All Rights Reserved. + + The LZO library is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of + the License, or (at your option) any later version. + + The LZO library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with the LZO library; see the file COPYING. + If not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + Markus F.X.J. Oberhumer + + http://www.oberhumer.com/opensource/lzo/ +*/ +#include "libbb.h" + +/* The following is probably only safe on Intel-compatible processors ... */ +#define LZO_UNALIGNED_OK_2 +#define LZO_UNALIGNED_OK_4 + +#include "liblzo.h" + +#define LZO_MAX(a,b) ((a) >= (b) ? (a) : (b)) +#define LZO_MIN(a,b) ((a) <= (b) ? (a) : (b)) +#define LZO_MAX3(a,b,c) ((a) >= (b) ? LZO_MAX(a,c) : LZO_MAX(b,c)) + +/*********************************************************************** +// +************************************************************************/ +#define SWD_N M4_MAX_OFFSET /* size of ring buffer */ +#define SWD_F 2048 /* upper limit for match length */ + +#define SWD_BEST_OFF (LZO_MAX3(M2_MAX_LEN, M3_MAX_LEN, M4_MAX_LEN) + 1) + +typedef struct { + int init; + + unsigned look; /* bytes in lookahead buffer */ + + unsigned m_len; + unsigned m_off; + + const uint8_t *bp; + const uint8_t *ip; + const uint8_t *in; + const uint8_t *in_end; + uint8_t *out; + + unsigned r1_lit; + +} lzo1x_999_t; + +#define getbyte(c) ((c).ip < (c).in_end ? *((c).ip)++ : (-1)) + +/* lzo_swd.c -- sliding window dictionary */ + +/*********************************************************************** +// +************************************************************************/ +#define SWD_UINT_MAX USHRT_MAX + +#ifndef SWD_HSIZE +# define SWD_HSIZE 16384 +#endif +#ifndef SWD_MAX_CHAIN +# define SWD_MAX_CHAIN 2048 +#endif + +#define HEAD3(b, p) \ + ( ((0x9f5f * ((((b[p]<<5)^b[p+1])<<5) ^ b[p+2])) >> 5) & (SWD_HSIZE-1) ) + +#if defined(LZO_UNALIGNED_OK_2) +# define HEAD2(b,p) (* (uint16_t *) &(b[p])) +#else +# define HEAD2(b,p) (b[p] ^ ((unsigned)b[p+1]<<8)) +#endif +#define NIL2 SWD_UINT_MAX + +typedef struct lzo_swd { + /* public - "built-in" */ + + /* public - configuration */ + unsigned max_chain; + int use_best_off; + + /* public - output */ + unsigned m_len; + unsigned m_off; + unsigned look; + int b_char; +#if defined(SWD_BEST_OFF) + unsigned best_off[SWD_BEST_OFF]; +#endif + + /* semi public */ + lzo1x_999_t *c; + unsigned m_pos; +#if defined(SWD_BEST_OFF) + unsigned best_pos[SWD_BEST_OFF]; +#endif + + /* private */ + unsigned ip; /* input pointer (lookahead) */ + unsigned bp; /* buffer pointer */ + unsigned rp; /* remove pointer */ + + unsigned node_count; + unsigned first_rp; + + uint8_t b[SWD_N + SWD_F]; + uint8_t b_wrap[SWD_F]; /* must follow b */ + uint16_t head3[SWD_HSIZE]; + uint16_t succ3[SWD_N + SWD_F]; + uint16_t best3[SWD_N + SWD_F]; + uint16_t llen3[SWD_HSIZE]; +#ifdef HEAD2 + uint16_t head2[65536L]; +#endif +} lzo_swd_t, *lzo_swd_p; + +#define SIZEOF_LZO_SWD_T (sizeof(lzo_swd_t)) + + +/* Access macro for head3. + * head3[key] may be uninitialized, but then its value will never be used. + */ +#define s_get_head3(s,key) s->head3[key] + + +/*********************************************************************** +// +************************************************************************/ +#define B_SIZE (SWD_N + SWD_F) + +static int swd_init(lzo_swd_p s) +{ + /* defaults */ + s->node_count = SWD_N; + + memset(s->llen3, 0, sizeof(s->llen3[0]) * (unsigned)SWD_HSIZE); +#ifdef HEAD2 + memset(s->head2, 0xff, sizeof(s->head2[0]) * 65536L); + assert(s->head2[0] == NIL2); +#endif + + s->ip = 0; + s->bp = s->ip; + s->first_rp = s->ip; + + assert(s->ip + SWD_F <= B_SIZE); + s->look = (unsigned) (s->c->in_end - s->c->ip); + if (s->look > 0) { + if (s->look > SWD_F) + s->look = SWD_F; + memcpy(&s->b[s->ip], s->c->ip, s->look); + s->c->ip += s->look; + s->ip += s->look; + } + if (s->ip == B_SIZE) + s->ip = 0; + + s->rp = s->first_rp; + if (s->rp >= s->node_count) + s->rp -= s->node_count; + else + s->rp += B_SIZE - s->node_count; + + return LZO_E_OK; +} + +#define swd_pos2off(s,pos) \ + (s->bp > (pos) ? s->bp - (pos) : B_SIZE - ((pos) - s->bp)) + + +/*********************************************************************** +// +************************************************************************/ +static void swd_getbyte(lzo_swd_p s) +{ + int c; + + if ((c = getbyte(*(s->c))) < 0) { + if (s->look > 0) + --s->look; + } else { + s->b[s->ip] = c; + if (s->ip < SWD_F) + s->b_wrap[s->ip] = c; + } + if (++s->ip == B_SIZE) + s->ip = 0; + if (++s->bp == B_SIZE) + s->bp = 0; + if (++s->rp == B_SIZE) + s->rp = 0; +} + + +/*********************************************************************** +// remove node from lists +************************************************************************/ +static void swd_remove_node(lzo_swd_p s, unsigned node) +{ + if (s->node_count == 0) { + unsigned key; + + key = HEAD3(s->b,node); + assert(s->llen3[key] > 0); + --s->llen3[key]; + +#ifdef HEAD2 + key = HEAD2(s->b,node); + assert(s->head2[key] != NIL2); + if ((unsigned) s->head2[key] == node) + s->head2[key] = NIL2; +#endif + } else + --s->node_count; +} + + +/*********************************************************************** +// +************************************************************************/ +static void swd_accept(lzo_swd_p s, unsigned n) +{ + assert(n <= s->look); + + while (n--) { + unsigned key; + + swd_remove_node(s,s->rp); + + /* add bp into HEAD3 */ + key = HEAD3(s->b, s->bp); + s->succ3[s->bp] = s_get_head3(s, key); + s->head3[key] = s->bp; + s->best3[s->bp] = SWD_F + 1; + s->llen3[key]++; + assert(s->llen3[key] <= SWD_N); + +#ifdef HEAD2 + /* add bp into HEAD2 */ + key = HEAD2(s->b, s->bp); + s->head2[key] = s->bp; +#endif + + swd_getbyte(s); + } +} + + +/*********************************************************************** +// +************************************************************************/ +static void swd_search(lzo_swd_p s, unsigned node, unsigned cnt) +{ + const uint8_t *p1; + const uint8_t *p2; + const uint8_t *px; + unsigned m_len = s->m_len; + const uint8_t *b = s->b; + const uint8_t *bp = s->b + s->bp; + const uint8_t *bx = s->b + s->bp + s->look; + unsigned char scan_end1; + + assert(s->m_len > 0); + + scan_end1 = bp[m_len - 1]; + for ( ; cnt-- > 0; node = s->succ3[node]) { + p1 = bp; + p2 = b + node; + px = bx; + + assert(m_len < s->look); + + if (p2[m_len - 1] == scan_end1 + && p2[m_len] == p1[m_len] + && p2[0] == p1[0] + && p2[1] == p1[1] + ) { + unsigned i; + assert(lzo_memcmp(bp, &b[node], 3) == 0); + + p1 += 2; p2 += 2; + do {} while (++p1 < px && *p1 == *++p2); + i = p1-bp; + + assert(lzo_memcmp(bp, &b[node], i) == 0); + +#if defined(SWD_BEST_OFF) + if (i < SWD_BEST_OFF) { + if (s->best_pos[i] == 0) + s->best_pos[i] = node + 1; + } +#endif + if (i > m_len) { + s->m_len = m_len = i; + s->m_pos = node; + if (m_len == s->look) + return; + if (m_len >= SWD_F) + return; + if (m_len > (unsigned) s->best3[node]) + return; + scan_end1 = bp[m_len - 1]; + } + } + } +} + + +/*********************************************************************** +// +************************************************************************/ +#ifdef HEAD2 + +static int swd_search2(lzo_swd_p s) +{ + unsigned key; + + assert(s->look >= 2); + assert(s->m_len > 0); + + key = s->head2[HEAD2(s->b, s->bp)]; + if (key == NIL2) + return 0; + assert(lzo_memcmp(&s->b[s->bp], &s->b[key], 2) == 0); +#if defined(SWD_BEST_OFF) + if (s->best_pos[2] == 0) + s->best_pos[2] = key + 1; +#endif + + if (s->m_len < 2) { + s->m_len = 2; + s->m_pos = key; + } + return 1; +} + +#endif + + +/*********************************************************************** +// +************************************************************************/ +static void swd_findbest(lzo_swd_p s) +{ + unsigned key; + unsigned cnt, node; + unsigned len; + + assert(s->m_len > 0); + + /* get current head, add bp into HEAD3 */ + key = HEAD3(s->b,s->bp); + node = s->succ3[s->bp] = s_get_head3(s, key); + cnt = s->llen3[key]++; + assert(s->llen3[key] <= SWD_N + SWD_F); + if (cnt > s->max_chain) + cnt = s->max_chain; + s->head3[key] = s->bp; + + s->b_char = s->b[s->bp]; + len = s->m_len; + if (s->m_len >= s->look) { + if (s->look == 0) + s->b_char = -1; + s->m_off = 0; + s->best3[s->bp] = SWD_F + 1; + } else { +#ifdef HEAD2 + if (swd_search2(s)) +#endif + if (s->look >= 3) + swd_search(s, node, cnt); + if (s->m_len > len) + s->m_off = swd_pos2off(s,s->m_pos); + s->best3[s->bp] = s->m_len; + +#if defined(SWD_BEST_OFF) + if (s->use_best_off) { + int i; + for (i = 2; i < SWD_BEST_OFF; i++) { + if (s->best_pos[i] > 0) + s->best_off[i] = swd_pos2off(s, s->best_pos[i]-1); + else + s->best_off[i] = 0; + } + } +#endif + } + + swd_remove_node(s,s->rp); + +#ifdef HEAD2 + /* add bp into HEAD2 */ + key = HEAD2(s->b, s->bp); + s->head2[key] = s->bp; +#endif +} + +#undef HEAD3 +#undef HEAD2 +#undef s_get_head3 + + +/*********************************************************************** +// +************************************************************************/ +static int init_match(lzo1x_999_t *c, lzo_swd_p s, uint32_t use_best_off) +{ + int r; + + assert(!c->init); + c->init = 1; + + s->c = c; + + r = swd_init(s); + if (r != 0) + return r; + + s->use_best_off = use_best_off; + return r; +} + + +/*********************************************************************** +// +************************************************************************/ +static int find_match(lzo1x_999_t *c, lzo_swd_p s, + unsigned this_len, unsigned skip) +{ + assert(c->init); + + if (skip > 0) { + assert(this_len >= skip); + swd_accept(s, this_len - skip); + } else { + assert(this_len <= 1); + } + + s->m_len = 1; + s->m_len = 1; +#ifdef SWD_BEST_OFF + if (s->use_best_off) + memset(s->best_pos, 0, sizeof(s->best_pos)); +#endif + swd_findbest(s); + c->m_len = s->m_len; + c->m_off = s->m_off; + + swd_getbyte(s); + + if (s->b_char < 0) { + c->look = 0; + c->m_len = 0; + } else { + c->look = s->look + 1; + } + c->bp = c->ip - c->look; + + return LZO_E_OK; +} + +/* this is a public functions, but there is no prototype in a header file */ +static int lzo1x_999_compress_internal(const uint8_t *in , unsigned in_len, + uint8_t *out, unsigned *out_len, + void *wrkmem, + unsigned good_length, + unsigned max_lazy, + unsigned max_chain, + uint32_t use_best_off); + + +/*********************************************************************** +// +************************************************************************/ +static uint8_t *code_match(lzo1x_999_t *c, + uint8_t *op, unsigned m_len, unsigned m_off) +{ + assert(op > c->out); + if (m_len == 2) { + assert(m_off <= M1_MAX_OFFSET); + assert(c->r1_lit > 0); + assert(c->r1_lit < 4); + m_off -= 1; + *op++ = M1_MARKER | ((m_off & 3) << 2); + *op++ = m_off >> 2; + } else if (m_len <= M2_MAX_LEN && m_off <= M2_MAX_OFFSET) { + assert(m_len >= 3); + m_off -= 1; + *op++ = ((m_len - 1) << 5) | ((m_off & 7) << 2); + *op++ = m_off >> 3; + assert(op[-2] >= M2_MARKER); + } else if (m_len == M2_MIN_LEN && m_off <= MX_MAX_OFFSET && c->r1_lit >= 4) { + assert(m_len == 3); + assert(m_off > M2_MAX_OFFSET); + m_off -= 1 + M2_MAX_OFFSET; + *op++ = M1_MARKER | ((m_off & 3) << 2); + *op++ = m_off >> 2; + } else if (m_off <= M3_MAX_OFFSET) { + assert(m_len >= 3); + m_off -= 1; + if (m_len <= M3_MAX_LEN) + *op++ = M3_MARKER | (m_len - 2); + else { + m_len -= M3_MAX_LEN; + *op++ = M3_MARKER | 0; + while (m_len > 255) { + m_len -= 255; + *op++ = 0; + } + assert(m_len > 0); + *op++ = m_len; + } + *op++ = m_off << 2; + *op++ = m_off >> 6; + } else { + unsigned k; + + assert(m_len >= 3); + assert(m_off > 0x4000); + assert(m_off <= 0xbfff); + m_off -= 0x4000; + k = (m_off & 0x4000) >> 11; + if (m_len <= M4_MAX_LEN) + *op++ = M4_MARKER | k | (m_len - 2); + else { + m_len -= M4_MAX_LEN; + *op++ = M4_MARKER | k | 0; + while (m_len > 255) { + m_len -= 255; + *op++ = 0; + } + assert(m_len > 0); + *op++ = m_len; + } + *op++ = m_off << 2; + *op++ = m_off >> 6; + } + + return op; +} + + +static uint8_t *STORE_RUN(lzo1x_999_t *c, uint8_t *op, + const uint8_t *ii, unsigned t) +{ + if (op == c->out && t <= 238) { + *op++ = 17 + t; + } else if (t <= 3) { + op[-2] |= t; + } else if (t <= 18) { + *op++ = t - 3; + } else { + unsigned tt = t - 18; + + *op++ = 0; + while (tt > 255) { + tt -= 255; + *op++ = 0; + } + assert(tt > 0); + *op++ = tt; + } + do *op++ = *ii++; while (--t > 0); + + return op; +} + + +static uint8_t *code_run(lzo1x_999_t *c, uint8_t *op, const uint8_t *ii, + unsigned lit) +{ + if (lit > 0) { + assert(m_len >= 2); + op = STORE_RUN(c, op, ii, lit); + } else { + assert(m_len >= 3); + } + c->r1_lit = lit; + + return op; +} + + +/*********************************************************************** +// +************************************************************************/ +static int len_of_coded_match(unsigned m_len, unsigned m_off, unsigned lit) +{ + int n = 4; + + if (m_len < 2) + return -1; + if (m_len == 2) + return (m_off <= M1_MAX_OFFSET && lit > 0 && lit < 4) ? 2 : -1; + if (m_len <= M2_MAX_LEN && m_off <= M2_MAX_OFFSET) + return 2; + if (m_len == M2_MIN_LEN && m_off <= MX_MAX_OFFSET && lit >= 4) + return 2; + if (m_off <= M3_MAX_OFFSET) { + if (m_len <= M3_MAX_LEN) + return 3; + m_len -= M3_MAX_LEN; + } else if (m_off <= M4_MAX_OFFSET) { + if (m_len <= M4_MAX_LEN) + return 3; + m_len -= M4_MAX_LEN; + } else + return -1; + while (m_len > 255) { + m_len -= 255; + n++; + } + return n; +} + + +static int min_gain(unsigned ahead, unsigned lit1, + unsigned lit2, int l1, int l2, int l3) +{ + int lazy_match_min_gain = 0; + + assert (ahead >= 1); + lazy_match_min_gain += ahead; + + if (lit1 <= 3) + lazy_match_min_gain += (lit2 <= 3) ? 0 : 2; + else if (lit1 <= 18) + lazy_match_min_gain += (lit2 <= 18) ? 0 : 1; + + lazy_match_min_gain += (l2 - l1) * 2; + if (l3 > 0) + lazy_match_min_gain -= (ahead - l3) * 2; + + if (lazy_match_min_gain < 0) + lazy_match_min_gain = 0; + + return lazy_match_min_gain; +} + + +/*********************************************************************** +// +************************************************************************/ +#if defined(SWD_BEST_OFF) + +static void better_match(const lzo_swd_p swd, + unsigned *m_len, unsigned *m_off) +{ + if (*m_len <= M2_MIN_LEN) + return; + + if (*m_off <= M2_MAX_OFFSET) + return; + + /* M3/M4 -> M2 */ + if (*m_off > M2_MAX_OFFSET + && *m_len >= M2_MIN_LEN + 1 && *m_len <= M2_MAX_LEN + 1 + && swd->best_off[*m_len-1] && swd->best_off[*m_len-1] <= M2_MAX_OFFSET + ) { + *m_len = *m_len - 1; + *m_off = swd->best_off[*m_len]; + return; + } + + /* M4 -> M2 */ + if (*m_off > M3_MAX_OFFSET + && *m_len >= M4_MAX_LEN + 1 && *m_len <= M2_MAX_LEN + 2 + && swd->best_off[*m_len-2] && swd->best_off[*m_len-2] <= M2_MAX_OFFSET + ) { + *m_len = *m_len - 2; + *m_off = swd->best_off[*m_len]; + return; + } + /* M4 -> M3 */ + if (*m_off > M3_MAX_OFFSET + && *m_len >= M4_MAX_LEN + 1 && *m_len <= M3_MAX_LEN + 1 + && swd->best_off[*m_len-1] && swd->best_off[*m_len-1] <= M3_MAX_OFFSET + ) { + *m_len = *m_len - 1; + *m_off = swd->best_off[*m_len]; + } +} + +#endif + + +/*********************************************************************** +// +************************************************************************/ +static int lzo1x_999_compress_internal(const uint8_t *in, unsigned in_len, + uint8_t *out, unsigned *out_len, + void *wrkmem, + unsigned good_length, + unsigned max_lazy, + unsigned max_chain, + uint32_t use_best_off) +{ + uint8_t *op; + const uint8_t *ii; + unsigned lit; + unsigned m_len, m_off; + lzo1x_999_t cc; + lzo1x_999_t *const c = &cc; + const lzo_swd_p swd = (lzo_swd_p) wrkmem; + int r; + + c->init = 0; + c->ip = c->in = in; + c->in_end = in + in_len; + c->out = out; + + op = out; + ii = c->ip; /* point to start of literal run */ + lit = 0; + c->r1_lit = 0; + + r = init_match(c, swd, use_best_off); + if (r != 0) + return r; + swd->max_chain = max_chain; + + r = find_match(c, swd, 0, 0); + if (r != 0) + return r; + + while (c->look > 0) { + unsigned ahead; + unsigned max_ahead; + int l1, l2, l3; + + m_len = c->m_len; + m_off = c->m_off; + + assert(c->bp == c->ip - c->look); + assert(c->bp >= in); + if (lit == 0) + ii = c->bp; + assert(ii + lit == c->bp); + assert(swd->b_char == *(c->bp)); + + if (m_len < 2 + || (m_len == 2 && (m_off > M1_MAX_OFFSET || lit == 0 || lit >= 4)) + /* Do not accept this match for compressed-data compatibility + * with LZO v1.01 and before + * [ might be a problem for decompress() and optimize() ] + */ + || (m_len == 2 && op == out) + || (op == out && lit == 0) + ) { + /* a literal */ + m_len = 0; + } + else if (m_len == M2_MIN_LEN) { + /* compression ratio improves if we code a literal in some cases */ + if (m_off > MX_MAX_OFFSET && lit >= 4) + m_len = 0; + } + + if (m_len == 0) { + /* a literal */ + lit++; + swd->max_chain = max_chain; + r = find_match(c, swd, 1, 0); + assert(r == 0); + continue; + } + + /* a match */ +#if defined(SWD_BEST_OFF) + if (swd->use_best_off) + better_match(swd, &m_len, &m_off); +#endif + + /* shall we try a lazy match ? */ + ahead = 0; + if (m_len >= max_lazy) { + /* no */ + l1 = 0; + max_ahead = 0; + } else { + /* yes, try a lazy match */ + l1 = len_of_coded_match(m_len, m_off, lit); + assert(l1 > 0); + max_ahead = LZO_MIN(2, (unsigned)l1 - 1); + } + + + while (ahead < max_ahead && c->look > m_len) { + int lazy_match_min_gain; + + if (m_len >= good_length) + swd->max_chain = max_chain >> 2; + else + swd->max_chain = max_chain; + r = find_match(c, swd, 1, 0); + ahead++; + + assert(r == 0); + assert(c->look > 0); + assert(ii + lit + ahead == c->bp); + + if (c->m_len < m_len) + continue; + if (c->m_len == m_len && c->m_off >= m_off) + continue; +#if defined(SWD_BEST_OFF) + if (swd->use_best_off) + better_match(swd, &c->m_len, &c->m_off); +#endif + l2 = len_of_coded_match(c->m_len, c->m_off, lit+ahead); + if (l2 < 0) + continue; + + /* compressed-data compatibility [see above] */ + l3 = (op == out) ? -1 : len_of_coded_match(ahead, m_off, lit); + + lazy_match_min_gain = min_gain(ahead, lit, lit+ahead, l1, l2, l3); + if (c->m_len >= m_len + lazy_match_min_gain) { + if (l3 > 0) { + /* code previous run */ + op = code_run(c, op, ii, lit); + lit = 0; + /* code shortened match */ + op = code_match(c, op, ahead, m_off); + } else { + lit += ahead; + assert(ii + lit == c->bp); + } + goto lazy_match_done; + } + } + + assert(ii + lit + ahead == c->bp); + + /* 1 - code run */ + op = code_run(c, op, ii, lit); + lit = 0; + + /* 2 - code match */ + op = code_match(c, op, m_len, m_off); + swd->max_chain = max_chain; + r = find_match(c, swd, m_len, 1+ahead); + assert(r == 0); + + lazy_match_done: ; + } + + /* store final run */ + if (lit > 0) + op = STORE_RUN(c, op, ii, lit); + +#if defined(LZO_EOF_CODE) + *op++ = M4_MARKER | 1; + *op++ = 0; + *op++ = 0; +#endif + + *out_len = op - out; + + return LZO_E_OK; +} + + +/*********************************************************************** +// +************************************************************************/ +int lzo1x_999_compress_level(const uint8_t *in, unsigned in_len, + uint8_t *out, unsigned *out_len, + void *wrkmem, + int compression_level) +{ + static const struct { + uint16_t good_length; + uint16_t max_lazy; + uint16_t max_chain; + uint16_t use_best_off; + } c[3] = { + { 8, 32, 256, 0 }, + { 32, 128, 2048, 1 }, + { SWD_F, SWD_F, 4096, 1 } /* max. compression */ + }; + + if (compression_level < 7 || compression_level > 9) + return LZO_E_ERROR; + + compression_level -= 7; + return lzo1x_999_compress_internal(in, in_len, out, out_len, wrkmem, + c[compression_level].good_length, + c[compression_level].max_lazy, + c[compression_level].max_chain, + c[compression_level].use_best_off); +} diff --git a/archival/libarchive/lzo1x_c.c b/archival/libarchive/lzo1x_c.c new file mode 100644 index 000000000..cc86f74b1 --- /dev/null +++ b/archival/libarchive/lzo1x_c.c @@ -0,0 +1,296 @@ +/* implementation of the LZO1[XY]-1 compression algorithm + + This file is part of the LZO real-time data compression library. + + Copyright (C) 1996..2008 Markus Franz Xaver Johannes Oberhumer + All Rights Reserved. + + Markus F.X.J. Oberhumer + http://www.oberhumer.com/opensource/lzo/ + + The LZO library is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of + the License, or (at your option) any later version. + + The LZO library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with the LZO library; see the file COPYING. + If not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +/*********************************************************************** +// compress a block of data. +************************************************************************/ +static NOINLINE unsigned +do_compress(const uint8_t* in, unsigned in_len, + uint8_t* out, unsigned* out_len, + void* wrkmem) +{ + register const uint8_t* ip; + uint8_t* op; + const uint8_t* const in_end = in + in_len; + const uint8_t* const ip_end = in + in_len - M2_MAX_LEN - 5; + const uint8_t* ii; + const void* *const dict = (const void**) wrkmem; + + op = out; + ip = in; + ii = ip; + + ip += 4; + for (;;) { + register const uint8_t* m_pos; + unsigned m_off; + unsigned m_len; + unsigned dindex; + + D_INDEX1(dindex,ip); + GINDEX(m_pos,m_off,dict,dindex,in); + if (LZO_CHECK_MPOS_NON_DET(m_pos,m_off,in,ip,M4_MAX_OFFSET)) + goto literal; +#if 1 + if (m_off <= M2_MAX_OFFSET || m_pos[3] == ip[3]) + goto try_match; + D_INDEX2(dindex,ip); +#endif + GINDEX(m_pos,m_off,dict,dindex,in); + if (LZO_CHECK_MPOS_NON_DET(m_pos,m_off,in,ip,M4_MAX_OFFSET)) + goto literal; + if (m_off <= M2_MAX_OFFSET || m_pos[3] == ip[3]) + goto try_match; + goto literal; + + try_match: +#if 1 && defined(LZO_UNALIGNED_OK_2) + if (* (const lzo_ushortp) m_pos != * (const lzo_ushortp) ip) +#else + if (m_pos[0] != ip[0] || m_pos[1] != ip[1]) +#endif + { + } else { + if (m_pos[2] == ip[2]) { +#if 0 + if (m_off <= M2_MAX_OFFSET) + goto match; + if (lit <= 3) + goto match; + if (lit == 3) { /* better compression, but slower */ + assert(op - 2 > out); op[-2] |= (uint8_t)(3); + *op++ = *ii++; *op++ = *ii++; *op++ = *ii++; + goto code_match; + } + if (m_pos[3] == ip[3]) +#endif + goto match; + } + else { + /* still need a better way for finding M1 matches */ +#if 0 + /* a M1 match */ +#if 0 + if (m_off <= M1_MAX_OFFSET && lit > 0 && lit <= 3) +#else + if (m_off <= M1_MAX_OFFSET && lit == 3) +#endif + { + register unsigned t; + + t = lit; + assert(op - 2 > out); op[-2] |= (uint8_t)(t); + do *op++ = *ii++; while (--t > 0); + assert(ii == ip); + m_off -= 1; + *op++ = (uint8_t)(M1_MARKER | ((m_off & 3) << 2)); + *op++ = (uint8_t)(m_off >> 2); + ip += 2; + goto match_done; + } +#endif + } + } + + /* a literal */ + literal: + UPDATE_I(dict, 0, dindex, ip, in); + ++ip; + if (ip >= ip_end) + break; + continue; + + /* a match */ +match: + UPDATE_I(dict, 0, dindex, ip, in); + /* store current literal run */ + if (pd(ip, ii) > 0) { + register unsigned t = pd(ip, ii); + + if (t <= 3) { + assert(op - 2 > out); + op[-2] |= (uint8_t)(t); + } + else if (t <= 18) + *op++ = (uint8_t)(t - 3); + else { + register unsigned tt = t - 18; + + *op++ = 0; + while (tt > 255) { + tt -= 255; + *op++ = 0; + } + assert(tt > 0); + *op++ = (uint8_t)(tt); + } + do *op++ = *ii++; while (--t > 0); + } + + /* code the match */ + assert(ii == ip); + ip += 3; + if (m_pos[3] != *ip++ || m_pos[4] != *ip++ || m_pos[5] != *ip++ + || m_pos[6] != *ip++ || m_pos[7] != *ip++ || m_pos[8] != *ip++ +#ifdef LZO1Y + || m_pos[ 9] != *ip++ || m_pos[10] != *ip++ || m_pos[11] != *ip++ + || m_pos[12] != *ip++ || m_pos[13] != *ip++ || m_pos[14] != *ip++ +#endif + ) { + --ip; + m_len = pd(ip, ii); + assert(m_len >= 3); + assert(m_len <= M2_MAX_LEN); + + if (m_off <= M2_MAX_OFFSET) { + m_off -= 1; +#if defined(LZO1X) + *op++ = (uint8_t)(((m_len - 1) << 5) | ((m_off & 7) << 2)); + *op++ = (uint8_t)(m_off >> 3); +#elif defined(LZO1Y) + *op++ = (uint8_t)(((m_len + 1) << 4) | ((m_off & 3) << 2)); + *op++ = (uint8_t)(m_off >> 2); +#endif + } + else if (m_off <= M3_MAX_OFFSET) { + m_off -= 1; + *op++ = (uint8_t)(M3_MARKER | (m_len - 2)); + goto m3_m4_offset; + } else { +#if defined(LZO1X) + m_off -= 0x4000; + assert(m_off > 0); + assert(m_off <= 0x7fff); + *op++ = (uint8_t)(M4_MARKER | ((m_off & 0x4000) >> 11) | (m_len - 2)); + goto m3_m4_offset; +#elif defined(LZO1Y) + goto m4_match; +#endif + } + } + else { + { + const uint8_t* end = in_end; + const uint8_t* m = m_pos + M2_MAX_LEN + 1; + while (ip < end && *m == *ip) + m++, ip++; + m_len = pd(ip, ii); + } + assert(m_len > M2_MAX_LEN); + + if (m_off <= M3_MAX_OFFSET) { + m_off -= 1; + if (m_len <= 33) + *op++ = (uint8_t)(M3_MARKER | (m_len - 2)); + else { + m_len -= 33; + *op++ = M3_MARKER | 0; + goto m3_m4_len; + } + } else { +#if defined(LZO1Y) + m4_match: +#endif + m_off -= 0x4000; + assert(m_off > 0); + assert(m_off <= 0x7fff); + if (m_len <= M4_MAX_LEN) + *op++ = (uint8_t)(M4_MARKER | ((m_off & 0x4000) >> 11) | (m_len - 2)); + else { + m_len -= M4_MAX_LEN; + *op++ = (uint8_t)(M4_MARKER | ((m_off & 0x4000) >> 11)); + m3_m4_len: + while (m_len > 255) { + m_len -= 255; + *op++ = 0; + } + assert(m_len > 0); + *op++ = (uint8_t)(m_len); + } + } + m3_m4_offset: + *op++ = (uint8_t)((m_off & 63) << 2); + *op++ = (uint8_t)(m_off >> 6); + } +#if 0 + match_done: +#endif + ii = ip; + if (ip >= ip_end) + break; + } + + *out_len = pd(op, out); + return pd(in_end, ii); +} + +/*********************************************************************** +// public entry point +************************************************************************/ +int DO_COMPRESS(const uint8_t* in, unsigned in_len, + uint8_t* out, unsigned* out_len, + void* wrkmem) +{ + uint8_t* op = out; + unsigned t; + + if (in_len <= M2_MAX_LEN + 5) + t = in_len; + else { + t = do_compress(in,in_len,op,out_len,wrkmem); + op += *out_len; + } + + if (t > 0) { + const uint8_t* ii = in + in_len - t; + + if (op == out && t <= 238) + *op++ = (uint8_t)(17 + t); + else if (t <= 3) + op[-2] |= (uint8_t)(t); + else if (t <= 18) + *op++ = (uint8_t)(t - 3); + else { + unsigned tt = t - 18; + + *op++ = 0; + while (tt > 255) { + tt -= 255; + *op++ = 0; + } + assert(tt > 0); + *op++ = (uint8_t)(tt); + } + do *op++ = *ii++; while (--t > 0); + } + + *op++ = M4_MARKER | 1; + *op++ = 0; + *op++ = 0; + + *out_len = pd(op, out); + return 0; /*LZO_E_OK*/ +} diff --git a/archival/libarchive/lzo1x_d.c b/archival/libarchive/lzo1x_d.c new file mode 100644 index 000000000..348a85510 --- /dev/null +++ b/archival/libarchive/lzo1x_d.c @@ -0,0 +1,420 @@ +/* implementation of the LZO1X decompression algorithm + + This file is part of the LZO real-time data compression library. + + Copyright (C) 1996..2008 Markus Franz Xaver Johannes Oberhumer + All Rights Reserved. + + Markus F.X.J. Oberhumer + http://www.oberhumer.com/opensource/lzo/ + + The LZO library is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of + the License, or (at your option) any later version. + + The LZO library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with the LZO library; see the file COPYING. + If not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#include "libbb.h" +#include "liblzo.h" + +/*********************************************************************** +// decompress a block of data. +************************************************************************/ +/* safe decompression with overrun testing */ +int lzo1x_decompress_safe(const uint8_t* in, unsigned in_len, + uint8_t* out, unsigned* out_len, + void* wrkmem UNUSED_PARAM) +{ + register uint8_t* op; + register const uint8_t* ip; + register unsigned t; +#if defined(COPY_DICT) + unsigned m_off; + const uint8_t* dict_end; +#else + register const uint8_t* m_pos = NULL; /* possibly not needed */ +#endif + const uint8_t* const ip_end = in + in_len; +#if defined(HAVE_ANY_OP) + uint8_t* const op_end = out + *out_len; +#endif +#if defined(LZO1Z) + unsigned last_m_off = 0; +#endif + +// LZO_UNUSED(wrkmem); + +#if defined(COPY_DICT) + if (dict) { + if (dict_len > M4_MAX_OFFSET) { + dict += dict_len - M4_MAX_OFFSET; + dict_len = M4_MAX_OFFSET; + } + dict_end = dict + dict_len; + } else { + dict_len = 0; + dict_end = NULL; + } +#endif /* COPY_DICT */ + + *out_len = 0; + + op = out; + ip = in; + + if (*ip > 17) { + t = *ip++ - 17; + if (t < 4) + goto match_next; + assert(t > 0); NEED_OP(t); NEED_IP(t+1); + do *op++ = *ip++; while (--t > 0); + goto first_literal_run; + } + + while (TEST_IP && TEST_OP) { + t = *ip++; + if (t >= 16) + goto match; + /* a literal run */ + if (t == 0) { + NEED_IP(1); + while (*ip == 0) { + t += 255; + ip++; + NEED_IP(1); + } + t += 15 + *ip++; + } + /* copy literals */ + assert(t > 0); + NEED_OP(t+3); + NEED_IP(t+4); +#if defined(LZO_UNALIGNED_OK_4) || defined(LZO_ALIGNED_OK_4) +# if !defined(LZO_UNALIGNED_OK_4) + if (PTR_ALIGNED2_4(op, ip)) +# endif + { + COPY4(op, ip); + op += 4; + ip += 4; + if (--t > 0) { + if (t >= 4) { + do { + COPY4(op, ip); + op += 4; + ip += 4; + t -= 4; + } while (t >= 4); + if (t > 0) + do *op++ = *ip++; while (--t > 0); + } else { + do *op++ = *ip++; while (--t > 0); + } + } + } +# if !defined(LZO_UNALIGNED_OK_4) + else +# endif +#endif +#if !defined(LZO_UNALIGNED_OK_4) + { + *op++ = *ip++; + *op++ = *ip++; + *op++ = *ip++; + do *op++ = *ip++; while (--t > 0); + } +#endif + + first_literal_run: + t = *ip++; + if (t >= 16) + goto match; +#if defined(COPY_DICT) +#if defined(LZO1Z) + m_off = (1 + M2_MAX_OFFSET) + (t << 6) + (*ip++ >> 2); + last_m_off = m_off; +#else + m_off = (1 + M2_MAX_OFFSET) + (t >> 2) + (*ip++ << 2); +#endif + NEED_OP(3); + t = 3; COPY_DICT(t,m_off) +#else /* !COPY_DICT */ +#if defined(LZO1Z) + t = (1 + M2_MAX_OFFSET) + (t << 6) + (*ip++ >> 2); + m_pos = op - t; + last_m_off = t; +#else + m_pos = op - (1 + M2_MAX_OFFSET); + m_pos -= t >> 2; + m_pos -= *ip++ << 2; +#endif + TEST_LB(m_pos); NEED_OP(3); + *op++ = *m_pos++; + *op++ = *m_pos++; + *op++ = *m_pos; +#endif /* COPY_DICT */ + goto match_done; + + /* handle matches */ + do { + match: + if (t >= 64) { /* a M2 match */ +#if defined(COPY_DICT) +#if defined(LZO1X) + m_off = 1 + ((t >> 2) & 7) + (*ip++ << 3); + t = (t >> 5) - 1; +#elif defined(LZO1Y) + m_off = 1 + ((t >> 2) & 3) + (*ip++ << 2); + t = (t >> 4) - 3; +#elif defined(LZO1Z) + m_off = t & 0x1f; + if (m_off >= 0x1c) + m_off = last_m_off; + else { + m_off = 1 + (m_off << 6) + (*ip++ >> 2); + last_m_off = m_off; + } + t = (t >> 5) - 1; +#endif +#else /* !COPY_DICT */ +#if defined(LZO1X) + m_pos = op - 1; + m_pos -= (t >> 2) & 7; + m_pos -= *ip++ << 3; + t = (t >> 5) - 1; +#elif defined(LZO1Y) + m_pos = op - 1; + m_pos -= (t >> 2) & 3; + m_pos -= *ip++ << 2; + t = (t >> 4) - 3; +#elif defined(LZO1Z) + { + unsigned off = t & 0x1f; + m_pos = op; + if (off >= 0x1c) { + assert(last_m_off > 0); + m_pos -= last_m_off; + } else { + off = 1 + (off << 6) + (*ip++ >> 2); + m_pos -= off; + last_m_off = off; + } + } + t = (t >> 5) - 1; +#endif + TEST_LB(m_pos); assert(t > 0); NEED_OP(t+3-1); + goto copy_match; +#endif /* COPY_DICT */ + } + else if (t >= 32) { /* a M3 match */ + t &= 31; + if (t == 0) { + NEED_IP(1); + while (*ip == 0) { + t += 255; + ip++; + NEED_IP(1); + } + t += 31 + *ip++; + } +#if defined(COPY_DICT) +#if defined(LZO1Z) + m_off = 1 + (ip[0] << 6) + (ip[1] >> 2); + last_m_off = m_off; +#else + m_off = 1 + (ip[0] >> 2) + (ip[1] << 6); +#endif +#else /* !COPY_DICT */ +#if defined(LZO1Z) + { + unsigned off = 1 + (ip[0] << 6) + (ip[1] >> 2); + m_pos = op - off; + last_m_off = off; + } +#elif defined(LZO_UNALIGNED_OK_2) && defined(LZO_ABI_LITTLE_ENDIAN) + m_pos = op - 1; + m_pos -= (* (const lzo_ushortp) ip) >> 2; +#else + m_pos = op - 1; + m_pos -= (ip[0] >> 2) + (ip[1] << 6); +#endif +#endif /* COPY_DICT */ + ip += 2; + } + else if (t >= 16) { /* a M4 match */ +#if defined(COPY_DICT) + m_off = (t & 8) << 11; +#else /* !COPY_DICT */ + m_pos = op; + m_pos -= (t & 8) << 11; +#endif /* COPY_DICT */ + t &= 7; + if (t == 0) { + NEED_IP(1); + while (*ip == 0) { + t += 255; + ip++; + NEED_IP(1); + } + t += 7 + *ip++; + } +#if defined(COPY_DICT) +#if defined(LZO1Z) + m_off += (ip[0] << 6) + (ip[1] >> 2); +#else + m_off += (ip[0] >> 2) + (ip[1] << 6); +#endif + ip += 2; + if (m_off == 0) + goto eof_found; + m_off += 0x4000; +#if defined(LZO1Z) + last_m_off = m_off; +#endif +#else /* !COPY_DICT */ +#if defined(LZO1Z) + m_pos -= (ip[0] << 6) + (ip[1] >> 2); +#elif defined(LZO_UNALIGNED_OK_2) && defined(LZO_ABI_LITTLE_ENDIAN) + m_pos -= (* (const lzo_ushortp) ip) >> 2; +#else + m_pos -= (ip[0] >> 2) + (ip[1] << 6); +#endif + ip += 2; + if (m_pos == op) + goto eof_found; + m_pos -= 0x4000; +#if defined(LZO1Z) + last_m_off = pd((const uint8_t*)op, m_pos); +#endif +#endif /* COPY_DICT */ + } + else { /* a M1 match */ +#if defined(COPY_DICT) +#if defined(LZO1Z) + m_off = 1 + (t << 6) + (*ip++ >> 2); + last_m_off = m_off; +#else + m_off = 1 + (t >> 2) + (*ip++ << 2); +#endif + NEED_OP(2); + t = 2; COPY_DICT(t,m_off) +#else /* !COPY_DICT */ +#if defined(LZO1Z) + t = 1 + (t << 6) + (*ip++ >> 2); + m_pos = op - t; + last_m_off = t; +#else + m_pos = op - 1; + m_pos -= t >> 2; + m_pos -= *ip++ << 2; +#endif + TEST_LB(m_pos); NEED_OP(2); + *op++ = *m_pos++; + *op++ = *m_pos; +#endif /* COPY_DICT */ + goto match_done; + } + + /* copy match */ +#if defined(COPY_DICT) + + NEED_OP(t+3-1); + t += 3-1; COPY_DICT(t,m_off) + +#else /* !COPY_DICT */ + + TEST_LB(m_pos); assert(t > 0); NEED_OP(t+3-1); +#if defined(LZO_UNALIGNED_OK_4) || defined(LZO_ALIGNED_OK_4) +# if !defined(LZO_UNALIGNED_OK_4) + if (t >= 2 * 4 - (3 - 1) && PTR_ALIGNED2_4(op,m_pos)) { + assert((op - m_pos) >= 4); /* both pointers are aligned */ +# else + if (t >= 2 * 4 - (3 - 1) && (op - m_pos) >= 4) { +# endif + COPY4(op,m_pos); + op += 4; m_pos += 4; t -= 4 - (3 - 1); + do { + COPY4(op,m_pos); + op += 4; m_pos += 4; t -= 4; + } while (t >= 4); + if (t > 0) + do *op++ = *m_pos++; while (--t > 0); + } + else +#endif + { + copy_match: + *op++ = *m_pos++; *op++ = *m_pos++; + do *op++ = *m_pos++; while (--t > 0); + } + +#endif /* COPY_DICT */ + + match_done: +#if defined(LZO1Z) + t = ip[-1] & 3; +#else + t = ip[-2] & 3; +#endif + if (t == 0) + break; + + /* copy literals */ + match_next: + assert(t > 0); + assert(t < 4); + NEED_OP(t); + NEED_IP(t+1); +#if 0 + do *op++ = *ip++; while (--t > 0); +#else + *op++ = *ip++; + if (t > 1) { + *op++ = *ip++; + if (t > 2) + *op++ = *ip++; + } +#endif + t = *ip++; + } while (TEST_IP && TEST_OP); + } + +//#if defined(HAVE_TEST_IP) || defined(HAVE_TEST_OP) + /* no EOF code was found */ + *out_len = pd(op, out); + return LZO_E_EOF_NOT_FOUND; +//#endif + + eof_found: + assert(t == 1); + *out_len = pd(op, out); + return (ip == ip_end ? LZO_E_OK : + (ip < ip_end ? LZO_E_INPUT_NOT_CONSUMED : LZO_E_INPUT_OVERRUN)); + +//#if defined(HAVE_NEED_IP) + input_overrun: + *out_len = pd(op, out); + return LZO_E_INPUT_OVERRUN; +//#endif + +//#if defined(HAVE_NEED_OP) + output_overrun: + *out_len = pd(op, out); + return LZO_E_OUTPUT_OVERRUN; +//#endif + +//#if defined(LZO_TEST_OVERRUN_LOOKBEHIND) + lookbehind_overrun: + *out_len = pd(op, out); + return LZO_E_LOOKBEHIND_OVERRUN; +//#endif +} diff --git a/archival/libarchive/open_transformer.c b/archival/libarchive/open_transformer.c new file mode 100644 index 000000000..26ae565f5 --- /dev/null +++ b/archival/libarchive/open_transformer.c @@ -0,0 +1,54 @@ +/* vi: set sw=4 ts=4: */ +/* + * Licensed under GPLv2 or later, see file LICENSE in this source tree. + */ + +#include "libbb.h" +#include "archive.h" + +/* transformer(), more than meets the eye */ +/* + * On MMU machine, the transform_prog is removed by macro magic + * in include/archive.h. On NOMMU, transformer is removed. + */ +void FAST_FUNC open_transformer(int fd, + IF_DESKTOP(long long) int FAST_FUNC (*transformer)(int src_fd, int dst_fd), + const char *transform_prog) +{ + struct fd_pair fd_pipe; + int pid; + + xpiped_pair(fd_pipe); + pid = BB_MMU ? xfork() : xvfork(); + if (pid == 0) { + /* Child */ + close(fd_pipe.rd); /* we don't want to read from the parent */ + // FIXME: error check? +#if BB_MMU + transformer(fd, fd_pipe.wr); + if (ENABLE_FEATURE_CLEAN_UP) { + close(fd_pipe.wr); /* send EOF */ + close(fd); + } + /* must be _exit! bug was actually seen here */ + _exit(EXIT_SUCCESS); +#else + { + char *argv[4]; + xmove_fd(fd, 0); + xmove_fd(fd_pipe.wr, 1); + argv[0] = (char*)transform_prog; + argv[1] = (char*)"-cf"; + argv[2] = (char*)"-"; + argv[3] = NULL; + BB_EXECVP(transform_prog, argv); + bb_perror_msg_and_die("can't execute '%s'", transform_prog); + } +#endif + /* notreached */ + } + + /* parent process */ + close(fd_pipe.wr); /* don't want to write to the child */ + xmove_fd(fd_pipe.rd, fd); +} diff --git a/archival/libarchive/seek_by_jump.c b/archival/libarchive/seek_by_jump.c new file mode 100644 index 000000000..7c2c52ae1 --- /dev/null +++ b/archival/libarchive/seek_by_jump.c @@ -0,0 +1,19 @@ +/* vi: set sw=4 ts=4: */ +/* + * Licensed under GPLv2 or later, see file LICENSE in this source tree. + */ + +#include "libbb.h" +#include "archive.h" + +void FAST_FUNC seek_by_jump(int fd, off_t amount) +{ + if (amount + && lseek(fd, amount, SEEK_CUR) == (off_t) -1 + ) { + if (errno == ESPIPE) + seek_by_read(fd, amount); + else + bb_perror_msg_and_die("seek failure"); + } +} diff --git a/archival/libarchive/seek_by_read.c b/archival/libarchive/seek_by_read.c new file mode 100644 index 000000000..ad931a8de --- /dev/null +++ b/archival/libarchive/seek_by_read.c @@ -0,0 +1,16 @@ +/* vi: set sw=4 ts=4: */ +/* + * Licensed under GPLv2 or later, see file LICENSE in this source tree. + */ + +#include "libbb.h" +#include "archive.h" + +/* If we are reading through a pipe, or from stdin then we can't lseek, + * we must read and discard the data to skip over it. + */ +void FAST_FUNC seek_by_read(int fd, off_t amount) +{ + if (amount) + bb_copyfd_exact_size(fd, -1, amount); +} diff --git a/archival/libarchive/unpack_ar_archive.c b/archival/libarchive/unpack_ar_archive.c new file mode 100644 index 000000000..18dbfd54d --- /dev/null +++ b/archival/libarchive/unpack_ar_archive.c @@ -0,0 +1,22 @@ +/* vi: set sw=4 ts=4: */ +/* + * Licensed under GPLv2 or later, see file LICENSE in this source tree. + */ + +#include "libbb.h" +#include "archive.h" +#include "ar.h" + +void FAST_FUNC unpack_ar_archive(archive_handle_t *ar_archive) +{ + char magic[7]; + + xread(ar_archive->src_fd, magic, AR_MAGIC_LEN); + if (strncmp(magic, AR_MAGIC, AR_MAGIC_LEN) != 0) { + bb_error_msg_and_die("invalid ar magic"); + } + ar_archive->offset += AR_MAGIC_LEN; + + while (get_header_ar(ar_archive) == EXIT_SUCCESS) + continue; +} diff --git a/archival/libarchive/unxz/README b/archival/libarchive/unxz/README new file mode 100644 index 000000000..c5972f6b8 --- /dev/null +++ b/archival/libarchive/unxz/README @@ -0,0 +1,135 @@ + +XZ Embedded +=========== + + XZ Embedded is a relatively small, limited implementation of the .xz + file format. Currently only decoding is implemented. + + XZ Embedded was written for use in the Linux kernel, but the code can + be easily used in other environments too, including regular userspace + applications. + + This README contains information that is useful only when the copy + of XZ Embedded isn't part of the Linux kernel tree. You should also + read linux/Documentation/xz.txt even if you aren't using XZ Embedded + as part of Linux; information in that file is not repeated in this + README. + +Compiling the Linux kernel module + + The xz_dec module depends on crc32 module, so make sure that you have + it enabled (CONFIG_CRC32). + + Building the xz_dec and xz_dec_test modules without support for BCJ + filters: + + cd linux/lib/xz + make -C /path/to/kernel/source \ + KCPPFLAGS=-I"$(pwd)/../../include" M="$(pwd)" \ + CONFIG_XZ_DEC=m CONFIG_XZ_DEC_TEST=m + + Building the xz_dec and xz_dec_test modules with support for BCJ + filters: + + cd linux/lib/xz + make -C /path/to/kernel/source \ + KCPPFLAGS=-I"$(pwd)/../../include" M="$(pwd)" \ + CONFIG_XZ_DEC=m CONFIG_XZ_DEC_TEST=m CONFIG_XZ_DEC_BCJ=y \ + CONFIG_XZ_DEC_X86=y CONFIG_XZ_DEC_POWERPC=y \ + CONFIG_XZ_DEC_IA64=y CONFIG_XZ_DEC_ARM=y \ + CONFIG_XZ_DEC_ARMTHUMB=y CONFIG_XZ_DEC_SPARC=y + + If you want only one or a few of the BCJ filters, omit the appropriate + variables. CONFIG_XZ_DEC_BCJ=y is always required to build the support + code shared between all BCJ filters. + + Most people don't need the xz_dec_test module. You can skip building + it by omitting CONFIG_XZ_DEC_TEST=m from the make command line. + +Compiler requirements + + XZ Embedded should compile as either GNU-C89 (used in the Linux + kernel) or with any C99 compiler. Getting the code to compile with + non-GNU C89 compiler or a C++ compiler should be quite easy as + long as there is a data type for unsigned 64-bit integer (or the + code is modified not to support large files, which needs some more + care than just using 32-bit integer instead of 64-bit). + + If you use GCC, try to use a recent version. For example, on x86, + xz_dec_lzma2.c compiled with GCC 3.3.6 is 15-25 % slower than when + compiled with GCC 4.3.3. + +Embedding into userspace applications + + To embed the XZ decoder, copy the following files into a single + directory in your source code tree: + + linux/include/linux/xz.h + linux/lib/xz/xz_crc32.c + linux/lib/xz/xz_dec_lzma2.c + linux/lib/xz/xz_dec_stream.c + linux/lib/xz/xz_lzma2.h + linux/lib/xz/xz_private.h + linux/lib/xz/xz_stream.h + userspace/xz_config.h + + Alternatively, xz.h may be placed into a different directory but then + that directory must be in the compiler include path when compiling + the .c files. + + Your code should use only the functions declared in xz.h. The rest of + the .h files are meant only for internal use in XZ Embedded. + + You may want to modify xz_config.h to be more suitable for your build + environment. Probably you should at least skim through it even if the + default file works as is. + +BCJ filter support + + If you want support for one or more BCJ filters, you need to copy also + linux/lib/xz/xz_dec_bcj.c into your application, and use appropriate + #defines in xz_config.h or in compiler flags. You don't need these + #defines in the code that just uses XZ Embedded via xz.h, but having + them always #defined doesn't hurt either. + + #define Instruction set BCJ filter endianness + XZ_DEC_X86 x86 or x86-64 Little endian only + XZ_DEC_POWERPC PowerPC Big endian only + XZ_DEC_IA64 Itanium (IA-64) Big or little endian + XZ_DEC_ARM ARM Little endian only + XZ_DEC_ARMTHUMB ARM-Thumb Little endian only + XZ_DEC_SPARC SPARC Big or little endian + + While some architectures are (partially) bi-endian, the endianness + setting doesn't change the endianness of the instructions on all + architectures. That's why Itanium and SPARC filters work for both big + and little endian executables (Itanium has little endian instructions + and SPARC has big endian instructions). + + There currently is no filter for little endian PowerPC or big endian + ARM or ARM-Thumb. Implementing filters for them can be considered if + there is a need for such filters in real-world applications. + +Notes about shared libraries + + If you are including XZ Embedded into a shared library, you very + probably should rename the xz_* functions to prevent symbol + conflicts in case your library is linked against some other library + or application that also has XZ Embedded in it (which may even be + a different version of XZ Embedded). TODO: Provide an easy way + to do this. + + Please don't create a shared library of XZ Embedded itself unless + it is fine to rebuild everything depending on that shared library + everytime you upgrade to a newer version of XZ Embedded. There are + no API or ABI stability guarantees between different versions of + XZ Embedded. + +Specifying the calling convention + + XZ_FUNC macro was included to support declaring functions with __init + in Linux. Outside Linux, it can be used to specify the calling + convention on systems that support multiple calling conventions. + For example, on Windows, you may make all functions use the stdcall + calling convention by defining XZ_FUNC=__stdcall when building and + using the functions from XZ Embedded. diff --git a/archival/libarchive/unxz/xz.h b/archival/libarchive/unxz/xz.h new file mode 100644 index 000000000..c6c071c4a --- /dev/null +++ b/archival/libarchive/unxz/xz.h @@ -0,0 +1,271 @@ +/* + * XZ decompressor + * + * Authors: Lasse Collin + * Igor Pavlov + * + * This file has been put into the public domain. + * You can do whatever you want with this file. + */ + +#ifndef XZ_H +#define XZ_H + +#ifdef __KERNEL__ +# include +# include +#else +# include +# include +#endif + +/* In Linux, this is used to make extern functions static when needed. */ +#ifndef XZ_EXTERN +# define XZ_EXTERN extern +#endif + +/* In Linux, this is used to mark the functions with __init when needed. */ +#ifndef XZ_FUNC +# define XZ_FUNC +#endif + +/** + * enum xz_mode - Operation mode + * + * @XZ_SINGLE: Single-call mode. This uses less RAM than + * than multi-call modes, because the LZMA2 + * dictionary doesn't need to be allocated as + * part of the decoder state. All required data + * structures are allocated at initialization, + * so xz_dec_run() cannot return XZ_MEM_ERROR. + * @XZ_PREALLOC: Multi-call mode with preallocated LZMA2 + * dictionary buffer. All data structures are + * allocated at initialization, so xz_dec_run() + * cannot return XZ_MEM_ERROR. + * @XZ_DYNALLOC: Multi-call mode. The LZMA2 dictionary is + * allocated once the required size has been + * parsed from the stream headers. If the + * allocation fails, xz_dec_run() will return + * XZ_MEM_ERROR. + * + * It is possible to enable support only for a subset of the above + * modes at compile time by defining XZ_DEC_SINGLE, XZ_DEC_PREALLOC, + * or XZ_DEC_DYNALLOC. The xz_dec kernel module is always compiled + * with support for all operation modes, but the preboot code may + * be built with fewer features to minimize code size. + */ +enum xz_mode { + XZ_SINGLE, + XZ_PREALLOC, + XZ_DYNALLOC +}; + +/** + * enum xz_ret - Return codes + * @XZ_OK: Everything is OK so far. More input or more + * output space is required to continue. This + * return code is possible only in multi-call mode + * (XZ_PREALLOC or XZ_DYNALLOC). + * @XZ_STREAM_END: Operation finished successfully. + * @XZ_UNSUPPORTED_CHECK: Integrity check type is not supported. Decoding + * is still possible in multi-call mode by simply + * calling xz_dec_run() again. + * NOTE: This return value is used only if + * XZ_DEC_ANY_CHECK was defined at build time, + * which is not used in the kernel. Unsupported + * check types return XZ_OPTIONS_ERROR if + * XZ_DEC_ANY_CHECK was not defined at build time. + * @XZ_MEM_ERROR: Allocating memory failed. This return code is + * possible only if the decoder was initialized + * with XZ_DYNALLOC. The amount of memory that was + * tried to be allocated was no more than the + * dict_max argument given to xz_dec_init(). + * @XZ_MEMLIMIT_ERROR: A bigger LZMA2 dictionary would be needed than + * allowed by the dict_max argument given to + * xz_dec_init(). This return value is possible + * only in multi-call mode (XZ_PREALLOC or + * XZ_DYNALLOC); the single-call mode (XZ_SINGLE) + * ignores the dict_max argument. + * @XZ_FORMAT_ERROR: File format was not recognized (wrong magic + * bytes). + * @XZ_OPTIONS_ERROR: This implementation doesn't support the requested + * compression options. In the decoder this means + * that the header CRC32 matches, but the header + * itself specifies something that we don't support. + * @XZ_DATA_ERROR: Compressed data is corrupt. + * @XZ_BUF_ERROR: Cannot make any progress. Details are slightly + * different between multi-call and single-call + * mode; more information below. + * + * In multi-call mode, XZ_BUF_ERROR is returned when two consecutive calls + * to XZ code cannot consume any input and cannot produce any new output. + * This happens when there is no new input available, or the output buffer + * is full while at least one output byte is still pending. Assuming your + * code is not buggy, you can get this error only when decoding a compressed + * stream that is truncated or otherwise corrupt. + * + * In single-call mode, XZ_BUF_ERROR is returned only when the output buffer + * is too small, or the compressed input is corrupt in a way that makes the + * decoder produce more output than the caller expected. When it is + * (relatively) clear that the compressed input is truncated, XZ_DATA_ERROR + * is used instead of XZ_BUF_ERROR. + */ +enum xz_ret { + XZ_OK, + XZ_STREAM_END, + XZ_UNSUPPORTED_CHECK, + XZ_MEM_ERROR, + XZ_MEMLIMIT_ERROR, + XZ_FORMAT_ERROR, + XZ_OPTIONS_ERROR, + XZ_DATA_ERROR, + XZ_BUF_ERROR +}; + +/** + * struct xz_buf - Passing input and output buffers to XZ code + * @in: Beginning of the input buffer. This may be NULL if and only + * if in_pos is equal to in_size. + * @in_pos: Current position in the input buffer. This must not exceed + * in_size. + * @in_size: Size of the input buffer + * @out: Beginning of the output buffer. This may be NULL if and only + * if out_pos is equal to out_size. + * @out_pos: Current position in the output buffer. This must not exceed + * out_size. + * @out_size: Size of the output buffer + * + * Only the contents of the output buffer from out[out_pos] onward, and + * the variables in_pos and out_pos are modified by the XZ code. + */ +struct xz_buf { + const uint8_t *in; + size_t in_pos; + size_t in_size; + + uint8_t *out; + size_t out_pos; + size_t out_size; +}; + +/** + * struct xz_dec - Opaque type to hold the XZ decoder state + */ +struct xz_dec; + +/** + * xz_dec_init() - Allocate and initialize a XZ decoder state + * @mode: Operation mode + * @dict_max: Maximum size of the LZMA2 dictionary (history buffer) for + * multi-call decoding. This is ignored in single-call mode + * (mode == XZ_SINGLE). LZMA2 dictionary is always 2^n bytes + * or 2^n + 2^(n-1) bytes (the latter sizes are less common + * in practice), so other values for dict_max don't make sense. + * In the kernel, dictionary sizes of 64 KiB, 128 KiB, 256 KiB, + * 512 KiB, and 1 MiB are probably the only reasonable values, + * except for kernel and initramfs images where a bigger + * dictionary can be fine and useful. + * + * Single-call mode (XZ_SINGLE): xz_dec_run() decodes the whole stream at + * once. The caller must provide enough output space or the decoding will + * fail. The output space is used as the dictionary buffer, which is why + * there is no need to allocate the dictionary as part of the decoder's + * internal state. + * + * Because the output buffer is used as the workspace, streams encoded using + * a big dictionary are not a problem in single-call mode. It is enough that + * the output buffer is big enough to hold the actual uncompressed data; it + * can be smaller than the dictionary size stored in the stream headers. + * + * Multi-call mode with preallocated dictionary (XZ_PREALLOC): dict_max bytes + * of memory is preallocated for the LZMA2 dictionary. This way there is no + * risk that xz_dec_run() could run out of memory, since xz_dec_run() will + * never allocate any memory. Instead, if the preallocated dictionary is too + * small for decoding the given input stream, xz_dec_run() will return + * XZ_MEMLIMIT_ERROR. Thus, it is important to know what kind of data will be + * decoded to avoid allocating excessive amount of memory for the dictionary. + * + * Multi-call mode with dynamically allocated dictionary (XZ_DYNALLOC): + * dict_max specifies the maximum allowed dictionary size that xz_dec_run() + * may allocate once it has parsed the dictionary size from the stream + * headers. This way excessive allocations can be avoided while still + * limiting the maximum memory usage to a sane value to prevent running the + * system out of memory when decompressing streams from untrusted sources. + * + * On success, xz_dec_init() returns a pointer to struct xz_dec, which is + * ready to be used with xz_dec_run(). If memory allocation fails, + * xz_dec_init() returns NULL. + */ +XZ_EXTERN struct xz_dec * XZ_FUNC xz_dec_init( + enum xz_mode mode, uint32_t dict_max); + +/** + * xz_dec_run() - Run the XZ decoder + * @s: Decoder state allocated using xz_dec_init() + * @b: Input and output buffers + * + * The possible return values depend on build options and operation mode. + * See enum xz_ret for details. + * + * NOTE: If an error occurs in single-call mode (return value is not + * XZ_STREAM_END), b->in_pos and b->out_pos are not modified, and the + * contents of the output buffer from b->out[b->out_pos] onward are + * undefined. This is true even after XZ_BUF_ERROR, because with some filter + * chains, there may be a second pass over the output buffer, and this pass + * cannot be properly done if the output buffer is truncated. Thus, you + * cannot give the single-call decoder a too small buffer and then expect to + * get that amount valid data from the beginning of the stream. You must use + * the multi-call decoder if you don't want to uncompress the whole stream. + */ +XZ_EXTERN enum xz_ret XZ_FUNC xz_dec_run(struct xz_dec *s, struct xz_buf *b); + +/** + * xz_dec_reset() - Reset an already allocated decoder state + * @s: Decoder state allocated using xz_dec_init() + * + * This function can be used to reset the multi-call decoder state without + * freeing and reallocating memory with xz_dec_end() and xz_dec_init(). + * + * In single-call mode, xz_dec_reset() is always called in the beginning of + * xz_dec_run(). Thus, explicit call to xz_dec_reset() is useful only in + * multi-call mode. + */ +XZ_EXTERN void XZ_FUNC xz_dec_reset(struct xz_dec *s); + +/** + * xz_dec_end() - Free the memory allocated for the decoder state + * @s: Decoder state allocated using xz_dec_init(). If s is NULL, + * this function does nothing. + */ +XZ_EXTERN void XZ_FUNC xz_dec_end(struct xz_dec *s); + +/* + * Standalone build (userspace build or in-kernel build for boot time use) + * needs a CRC32 implementation. For normal in-kernel use, kernel's own + * CRC32 module is used instead, and users of this module don't need to + * care about the functions below. + */ +#ifndef XZ_INTERNAL_CRC32 +# ifdef __KERNEL__ +# define XZ_INTERNAL_CRC32 0 +# else +# define XZ_INTERNAL_CRC32 1 +# endif +#endif + +#if XZ_INTERNAL_CRC32 +/* + * This must be called before any other xz_* function to initialize + * the CRC32 lookup table. + */ +XZ_EXTERN void XZ_FUNC xz_crc32_init(void); + +/* + * Update CRC32 value using the polynomial from IEEE-802.3. To start a new + * calculation, the third argument must be zero. To continue the calculation, + * the previously returned value is passed as the third argument. + */ +XZ_EXTERN uint32_t XZ_FUNC xz_crc32( + const uint8_t *buf, size_t size, uint32_t crc); +#endif +#endif diff --git a/archival/libarchive/unxz/xz_config.h b/archival/libarchive/unxz/xz_config.h new file mode 100644 index 000000000..187e1cbed --- /dev/null +++ b/archival/libarchive/unxz/xz_config.h @@ -0,0 +1,123 @@ +/* + * Private includes and definitions for userspace use of XZ Embedded + * + * Author: Lasse Collin + * + * This file has been put into the public domain. + * You can do whatever you want with this file. + */ + +#ifndef XZ_CONFIG_H +#define XZ_CONFIG_H + +/* Uncomment as needed to enable BCJ filter decoders. */ +/* #define XZ_DEC_X86 */ +/* #define XZ_DEC_POWERPC */ +/* #define XZ_DEC_IA64 */ +/* #define XZ_DEC_ARM */ +/* #define XZ_DEC_ARMTHUMB */ +/* #define XZ_DEC_SPARC */ + +#include +#include +#include + +#include "xz.h" + +#define kmalloc(size, flags) malloc(size) +#define kfree(ptr) free(ptr) +#define vmalloc(size) malloc(size) +#define vfree(ptr) free(ptr) + +#define memeq(a, b, size) (memcmp(a, b, size) == 0) +#define memzero(buf, size) memset(buf, 0, size) + +#undef min +#undef min_t +#define min(x, y) ((x) < (y) ? (x) : (y)) +#define min_t(type, x, y) min(x, y) + +/* + * Some functions have been marked with __always_inline to keep the + * performance reasonable even when the compiler is optimizing for + * small code size. You may be able to save a few bytes by #defining + * __always_inline to plain inline, but don't complain if the code + * becomes slow. + * + * NOTE: System headers on GNU/Linux may #define this macro already, + * so if you want to change it, you need to #undef it first. + */ +#ifndef __always_inline +# ifdef __GNUC__ +# define __always_inline \ + inline __attribute__((__always_inline__)) +# else +# define __always_inline inline +# endif +#endif + +/* + * Some functions are marked to never be inlined to reduce stack usage. + * If you don't care about stack usage, you may want to modify this so + * that noinline_for_stack is #defined to be empty even when using GCC. + * Doing so may save a few bytes in binary size. + */ +#ifndef noinline_for_stack +# ifdef __GNUC__ +# define noinline_for_stack __attribute__((__noinline__)) +# else +# define noinline_for_stack +# endif +#endif + +/* Inline functions to access unaligned unsigned 32-bit integers */ +#ifndef get_unaligned_le32 +static inline uint32_t XZ_FUNC get_unaligned_le32(const uint8_t *buf) +{ + return (uint32_t)buf[0] + | ((uint32_t)buf[1] << 8) + | ((uint32_t)buf[2] << 16) + | ((uint32_t)buf[3] << 24); +} +#endif + +#ifndef get_unaligned_be32 +static inline uint32_t XZ_FUNC get_unaligned_be32(const uint8_t *buf) +{ + return (uint32_t)(buf[0] << 24) + | ((uint32_t)buf[1] << 16) + | ((uint32_t)buf[2] << 8) + | (uint32_t)buf[3]; +} +#endif + +#ifndef put_unaligned_le32 +static inline void XZ_FUNC put_unaligned_le32(uint32_t val, uint8_t *buf) +{ + buf[0] = (uint8_t)val; + buf[1] = (uint8_t)(val >> 8); + buf[2] = (uint8_t)(val >> 16); + buf[3] = (uint8_t)(val >> 24); +} +#endif + +#ifndef put_unaligned_be32 +static inline void XZ_FUNC put_unaligned_be32(uint32_t val, uint8_t *buf) +{ + buf[0] = (uint8_t)(val >> 24); + buf[1] = (uint8_t)(val >> 16); + buf[2] = (uint8_t)(val >> 8); + buf[3] = (uint8_t)val; +} +#endif + +/* + * Use get_unaligned_le32() also for aligned access for simplicity. On + * little endian systems, #define get_le32(ptr) (*(const uint32_t *)(ptr)) + * could save a few bytes in code size. + */ +#ifndef get_le32 +# define get_le32 get_unaligned_le32 +#endif + +#endif diff --git a/archival/libarchive/unxz/xz_dec_bcj.c b/archival/libarchive/unxz/xz_dec_bcj.c new file mode 100644 index 000000000..09162b51f --- /dev/null +++ b/archival/libarchive/unxz/xz_dec_bcj.c @@ -0,0 +1,564 @@ +/* + * Branch/Call/Jump (BCJ) filter decoders + * + * Authors: Lasse Collin + * Igor Pavlov + * + * This file has been put into the public domain. + * You can do whatever you want with this file. + */ + +#include "xz_private.h" + +/* + * The rest of the file is inside this ifdef. It makes things a little more + * convenient when building without support for any BCJ filters. + */ +#ifdef XZ_DEC_BCJ + +struct xz_dec_bcj { + /* Type of the BCJ filter being used */ + enum { + BCJ_X86 = 4, /* x86 or x86-64 */ + BCJ_POWERPC = 5, /* Big endian only */ + BCJ_IA64 = 6, /* Big or little endian */ + BCJ_ARM = 7, /* Little endian only */ + BCJ_ARMTHUMB = 8, /* Little endian only */ + BCJ_SPARC = 9 /* Big or little endian */ + } type; + + /* + * Return value of the next filter in the chain. We need to preserve + * this information across calls, because we must not call the next + * filter anymore once it has returned XZ_STREAM_END. + */ + enum xz_ret ret; + + /* True if we are operating in single-call mode. */ + bool single_call; + + /* + * Absolute position relative to the beginning of the uncompressed + * data (in a single .xz Block). We care only about the lowest 32 + * bits so this doesn't need to be uint64_t even with big files. + */ + uint32_t pos; + + /* x86 filter state */ + uint32_t x86_prev_mask; + + /* Temporary space to hold the variables from struct xz_buf */ + uint8_t *out; + size_t out_pos; + size_t out_size; + + struct { + /* Amount of already filtered data in the beginning of buf */ + size_t filtered; + + /* Total amount of data currently stored in buf */ + size_t size; + + /* + * Buffer to hold a mix of filtered and unfiltered data. This + * needs to be big enough to hold Alignment + 2 * Look-ahead: + * + * Type Alignment Look-ahead + * x86 1 4 + * PowerPC 4 0 + * IA-64 16 0 + * ARM 4 0 + * ARM-Thumb 2 2 + * SPARC 4 0 + */ + uint8_t buf[16]; + } temp; +}; + +#ifdef XZ_DEC_X86 +/* + * This is macro used to test the most significant byte of a memory address + * in an x86 instruction. + */ +#define bcj_x86_test_msbyte(b) ((b) == 0x00 || (b) == 0xFF) + +static noinline_for_stack size_t XZ_FUNC bcj_x86( + struct xz_dec_bcj *s, uint8_t *buf, size_t size) +{ + static const bool mask_to_allowed_status[8] + = { true, true, true, false, true, false, false, false }; + + static const uint8_t mask_to_bit_num[8] = { 0, 1, 2, 2, 3, 3, 3, 3 }; + + size_t i; + size_t prev_pos = (size_t)-1; + uint32_t prev_mask = s->x86_prev_mask; + uint32_t src; + uint32_t dest; + uint32_t j; + uint8_t b; + + if (size <= 4) + return 0; + + size -= 4; + for (i = 0; i < size; ++i) { + if ((buf[i] & 0xFE) != 0xE8) + continue; + + prev_pos = i - prev_pos; + if (prev_pos > 3) { + prev_mask = 0; + } else { + prev_mask = (prev_mask << (prev_pos - 1)) & 7; + if (prev_mask != 0) { + b = buf[i + 4 - mask_to_bit_num[prev_mask]]; + if (!mask_to_allowed_status[prev_mask] + || bcj_x86_test_msbyte(b)) { + prev_pos = i; + prev_mask = (prev_mask << 1) | 1; + continue; + } + } + } + + prev_pos = i; + + if (bcj_x86_test_msbyte(buf[i + 4])) { + src = get_unaligned_le32(buf + i + 1); + while (true) { + dest = src - (s->pos + (uint32_t)i + 5); + if (prev_mask == 0) + break; + + j = mask_to_bit_num[prev_mask] * 8; + b = (uint8_t)(dest >> (24 - j)); + if (!bcj_x86_test_msbyte(b)) + break; + + src = dest ^ (((uint32_t)1 << (32 - j)) - 1); + } + + dest &= 0x01FFFFFF; + dest |= (uint32_t)0 - (dest & 0x01000000); + put_unaligned_le32(dest, buf + i + 1); + i += 4; + } else { + prev_mask = (prev_mask << 1) | 1; + } + } + + prev_pos = i - prev_pos; + s->x86_prev_mask = prev_pos > 3 ? 0 : prev_mask << (prev_pos - 1); + return i; +} +#endif + +#ifdef XZ_DEC_POWERPC +static noinline_for_stack size_t XZ_FUNC bcj_powerpc( + struct xz_dec_bcj *s, uint8_t *buf, size_t size) +{ + size_t i; + uint32_t instr; + + for (i = 0; i + 4 <= size; i += 4) { + instr = get_unaligned_be32(buf + i); + if ((instr & 0xFC000003) == 0x48000001) { + instr &= 0x03FFFFFC; + instr -= s->pos + (uint32_t)i; + instr &= 0x03FFFFFC; + instr |= 0x48000001; + put_unaligned_be32(instr, buf + i); + } + } + + return i; +} +#endif + +#ifdef XZ_DEC_IA64 +static noinline_for_stack size_t XZ_FUNC bcj_ia64( + struct xz_dec_bcj *s, uint8_t *buf, size_t size) +{ + static const uint8_t branch_table[32] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 4, 4, 6, 6, 0, 0, 7, 7, + 4, 4, 0, 0, 4, 4, 0, 0 + }; + + /* + * The local variables take a little bit stack space, but it's less + * than what LZMA2 decoder takes, so it doesn't make sense to reduce + * stack usage here without doing that for the LZMA2 decoder too. + */ + + /* Loop counters */ + size_t i; + size_t j; + + /* Instruction slot (0, 1, or 2) in the 128-bit instruction word */ + uint32_t slot; + + /* Bitwise offset of the instruction indicated by slot */ + uint32_t bit_pos; + + /* bit_pos split into byte and bit parts */ + uint32_t byte_pos; + uint32_t bit_res; + + /* Address part of an instruction */ + uint32_t addr; + + /* Mask used to detect which instructions to convert */ + uint32_t mask; + + /* 41-bit instruction stored somewhere in the lowest 48 bits */ + uint64_t instr; + + /* Instruction normalized with bit_res for easier manipulation */ + uint64_t norm; + + for (i = 0; i + 16 <= size; i += 16) { + mask = branch_table[buf[i] & 0x1F]; + for (slot = 0, bit_pos = 5; slot < 3; ++slot, bit_pos += 41) { + if (((mask >> slot) & 1) == 0) + continue; + + byte_pos = bit_pos >> 3; + bit_res = bit_pos & 7; + instr = 0; + for (j = 0; j < 6; ++j) + instr |= (uint64_t)(buf[i + j + byte_pos]) + << (8 * j); + + norm = instr >> bit_res; + + if (((norm >> 37) & 0x0F) == 0x05 + && ((norm >> 9) & 0x07) == 0) { + addr = (norm >> 13) & 0x0FFFFF; + addr |= ((uint32_t)(norm >> 36) & 1) << 20; + addr <<= 4; + addr -= s->pos + (uint32_t)i; + addr >>= 4; + + norm &= ~((uint64_t)0x8FFFFF << 13); + norm |= (uint64_t)(addr & 0x0FFFFF) << 13; + norm |= (uint64_t)(addr & 0x100000) + << (36 - 20); + + instr &= (1 << bit_res) - 1; + instr |= norm << bit_res; + + for (j = 0; j < 6; j++) + buf[i + j + byte_pos] + = (uint8_t)(instr >> (8 * j)); + } + } + } + + return i; +} +#endif + +#ifdef XZ_DEC_ARM +static noinline_for_stack size_t XZ_FUNC bcj_arm( + struct xz_dec_bcj *s, uint8_t *buf, size_t size) +{ + size_t i; + uint32_t addr; + + for (i = 0; i + 4 <= size; i += 4) { + if (buf[i + 3] == 0xEB) { + addr = (uint32_t)buf[i] | ((uint32_t)buf[i + 1] << 8) + | ((uint32_t)buf[i + 2] << 16); + addr <<= 2; + addr -= s->pos + (uint32_t)i + 8; + addr >>= 2; + buf[i] = (uint8_t)addr; + buf[i + 1] = (uint8_t)(addr >> 8); + buf[i + 2] = (uint8_t)(addr >> 16); + } + } + + return i; +} +#endif + +#ifdef XZ_DEC_ARMTHUMB +static noinline_for_stack size_t XZ_FUNC bcj_armthumb( + struct xz_dec_bcj *s, uint8_t *buf, size_t size) +{ + size_t i; + uint32_t addr; + + for (i = 0; i + 4 <= size; i += 2) { + if ((buf[i + 1] & 0xF8) == 0xF0 + && (buf[i + 3] & 0xF8) == 0xF8) { + addr = (((uint32_t)buf[i + 1] & 0x07) << 19) + | ((uint32_t)buf[i] << 11) + | (((uint32_t)buf[i + 3] & 0x07) << 8) + | (uint32_t)buf[i + 2]; + addr <<= 1; + addr -= s->pos + (uint32_t)i + 4; + addr >>= 1; + buf[i + 1] = (uint8_t)(0xF0 | ((addr >> 19) & 0x07)); + buf[i] = (uint8_t)(addr >> 11); + buf[i + 3] = (uint8_t)(0xF8 | ((addr >> 8) & 0x07)); + buf[i + 2] = (uint8_t)addr; + i += 2; + } + } + + return i; +} +#endif + +#ifdef XZ_DEC_SPARC +static noinline_for_stack size_t XZ_FUNC bcj_sparc( + struct xz_dec_bcj *s, uint8_t *buf, size_t size) +{ + size_t i; + uint32_t instr; + + for (i = 0; i + 4 <= size; i += 4) { + instr = get_unaligned_be32(buf + i); + if ((instr >> 22) == 0x100 || (instr >> 22) == 0x1FF) { + instr <<= 2; + instr -= s->pos + (uint32_t)i; + instr >>= 2; + instr = ((uint32_t)0x40000000 - (instr & 0x400000)) + | 0x40000000 | (instr & 0x3FFFFF); + put_unaligned_be32(instr, buf + i); + } + } + + return i; +} +#endif + +/* + * Apply the selected BCJ filter. Update *pos and s->pos to match the amount + * of data that got filtered. + * + * NOTE: This is implemented as a switch statement to avoid using function + * pointers, which could be problematic in the kernel boot code, which must + * avoid pointers to static data (at least on x86). + */ +static void XZ_FUNC bcj_apply(struct xz_dec_bcj *s, + uint8_t *buf, size_t *pos, size_t size) +{ + size_t filtered; + + buf += *pos; + size -= *pos; + + switch (s->type) { +#ifdef XZ_DEC_X86 + case BCJ_X86: + filtered = bcj_x86(s, buf, size); + break; +#endif +#ifdef XZ_DEC_POWERPC + case BCJ_POWERPC: + filtered = bcj_powerpc(s, buf, size); + break; +#endif +#ifdef XZ_DEC_IA64 + case BCJ_IA64: + filtered = bcj_ia64(s, buf, size); + break; +#endif +#ifdef XZ_DEC_ARM + case BCJ_ARM: + filtered = bcj_arm(s, buf, size); + break; +#endif +#ifdef XZ_DEC_ARMTHUMB + case BCJ_ARMTHUMB: + filtered = bcj_armthumb(s, buf, size); + break; +#endif +#ifdef XZ_DEC_SPARC + case BCJ_SPARC: + filtered = bcj_sparc(s, buf, size); + break; +#endif + default: + /* Never reached but silence compiler warnings. */ + filtered = 0; + break; + } + + *pos += filtered; + s->pos += filtered; +} + +/* + * Flush pending filtered data from temp to the output buffer. + * Move the remaining mixture of possibly filtered and unfiltered + * data to the beginning of temp. + */ +static void XZ_FUNC bcj_flush(struct xz_dec_bcj *s, struct xz_buf *b) +{ + size_t copy_size; + + copy_size = min_t(size_t, s->temp.filtered, b->out_size - b->out_pos); + memcpy(b->out + b->out_pos, s->temp.buf, copy_size); + b->out_pos += copy_size; + + s->temp.filtered -= copy_size; + s->temp.size -= copy_size; + memmove(s->temp.buf, s->temp.buf + copy_size, s->temp.size); +} + +/* + * The BCJ filter functions are primitive in sense that they process the + * data in chunks of 1-16 bytes. To hide this issue, this function does + * some buffering. + */ +XZ_EXTERN enum xz_ret XZ_FUNC xz_dec_bcj_run(struct xz_dec_bcj *s, + struct xz_dec_lzma2 *lzma2, struct xz_buf *b) +{ + size_t out_start; + + /* + * Flush pending already filtered data to the output buffer. Return + * immediatelly if we couldn't flush everything, or if the next + * filter in the chain had already returned XZ_STREAM_END. + */ + if (s->temp.filtered > 0) { + bcj_flush(s, b); + if (s->temp.filtered > 0) + return XZ_OK; + + if (s->ret == XZ_STREAM_END) + return XZ_STREAM_END; + } + + /* + * If we have more output space than what is currently pending in + * temp, copy the unfiltered data from temp to the output buffer + * and try to fill the output buffer by decoding more data from the + * next filter in the chain. Apply the BCJ filter on the new data + * in the output buffer. If everything cannot be filtered, copy it + * to temp and rewind the output buffer position accordingly. + */ + if (s->temp.size < b->out_size - b->out_pos) { + out_start = b->out_pos; + memcpy(b->out + b->out_pos, s->temp.buf, s->temp.size); + b->out_pos += s->temp.size; + + s->ret = xz_dec_lzma2_run(lzma2, b); + if (s->ret != XZ_STREAM_END + && (s->ret != XZ_OK || s->single_call)) + return s->ret; + + bcj_apply(s, b->out, &out_start, b->out_pos); + + /* + * As an exception, if the next filter returned XZ_STREAM_END, + * we can do that too, since the last few bytes that remain + * unfiltered are meant to remain unfiltered. + */ + if (s->ret == XZ_STREAM_END) + return XZ_STREAM_END; + + s->temp.size = b->out_pos - out_start; + b->out_pos -= s->temp.size; + memcpy(s->temp.buf, b->out + b->out_pos, s->temp.size); + } + + /* + * If we have unfiltered data in temp, try to fill by decoding more + * data from the next filter. Apply the BCJ filter on temp. Then we + * hopefully can fill the actual output buffer by copying filtered + * data from temp. A mix of filtered and unfiltered data may be left + * in temp; it will be taken care on the next call to this function. + */ + if (s->temp.size > 0) { + /* Make b->out{,_pos,_size} temporarily point to s->temp. */ + s->out = b->out; + s->out_pos = b->out_pos; + s->out_size = b->out_size; + b->out = s->temp.buf; + b->out_pos = s->temp.size; + b->out_size = sizeof(s->temp.buf); + + s->ret = xz_dec_lzma2_run(lzma2, b); + + s->temp.size = b->out_pos; + b->out = s->out; + b->out_pos = s->out_pos; + b->out_size = s->out_size; + + if (s->ret != XZ_OK && s->ret != XZ_STREAM_END) + return s->ret; + + bcj_apply(s, s->temp.buf, &s->temp.filtered, s->temp.size); + + /* + * If the next filter returned XZ_STREAM_END, we mark that + * everything is filtered, since the last unfiltered bytes + * of the stream are meant to be left as is. + */ + if (s->ret == XZ_STREAM_END) + s->temp.filtered = s->temp.size; + + bcj_flush(s, b); + if (s->temp.filtered > 0) + return XZ_OK; + } + + return s->ret; +} + +XZ_EXTERN struct xz_dec_bcj * XZ_FUNC xz_dec_bcj_create(bool single_call) +{ + struct xz_dec_bcj *s = kmalloc(sizeof(*s), GFP_KERNEL); + if (s != NULL) + s->single_call = single_call; + + return s; +} + +XZ_EXTERN enum xz_ret XZ_FUNC xz_dec_bcj_reset( + struct xz_dec_bcj *s, uint8_t id) +{ + switch (id) { +#ifdef XZ_DEC_X86 + case BCJ_X86: +#endif +#ifdef XZ_DEC_POWERPC + case BCJ_POWERPC: +#endif +#ifdef XZ_DEC_IA64 + case BCJ_IA64: +#endif +#ifdef XZ_DEC_ARM + case BCJ_ARM: +#endif +#ifdef XZ_DEC_ARMTHUMB + case BCJ_ARMTHUMB: +#endif +#ifdef XZ_DEC_SPARC + case BCJ_SPARC: +#endif + break; + + default: + /* Unsupported Filter ID */ + return XZ_OPTIONS_ERROR; + } + + s->type = id; + s->ret = XZ_OK; + s->pos = 0; + s->x86_prev_mask = 0; + s->temp.filtered = 0; + s->temp.size = 0; + + return XZ_OK; +} + +#endif diff --git a/archival/libarchive/unxz/xz_dec_lzma2.c b/archival/libarchive/unxz/xz_dec_lzma2.c new file mode 100644 index 000000000..da71cb4d4 --- /dev/null +++ b/archival/libarchive/unxz/xz_dec_lzma2.c @@ -0,0 +1,1175 @@ +/* + * LZMA2 decoder + * + * Authors: Lasse Collin + * Igor Pavlov + * + * This file has been put into the public domain. + * You can do whatever you want with this file. + */ + +#include "xz_private.h" +#include "xz_lzma2.h" + +/* + * Range decoder initialization eats the first five bytes of each LZMA chunk. + */ +#define RC_INIT_BYTES 5 + +/* + * Minimum number of usable input buffer to safely decode one LZMA symbol. + * The worst case is that we decode 22 bits using probabilities and 26 + * direct bits. This may decode at maximum of 20 bytes of input. However, + * lzma_main() does an extra normalization before returning, thus we + * need to put 21 here. + */ +#define LZMA_IN_REQUIRED 21 + +/* + * Dictionary (history buffer) + * + * These are always true: + * start <= pos <= full <= end + * pos <= limit <= end + * + * In multi-call mode, also these are true: + * end == size + * size <= size_max + * allocated <= size + * + * Most of these variables are size_t to support single-call mode, + * in which the dictionary variables address the actual output + * buffer directly. + */ +struct dictionary { + /* Beginning of the history buffer */ + uint8_t *buf; + + /* Old position in buf (before decoding more data) */ + size_t start; + + /* Position in buf */ + size_t pos; + + /* + * How full dictionary is. This is used to detect corrupt input that + * would read beyond the beginning of the uncompressed stream. + */ + size_t full; + + /* Write limit; we don't write to buf[limit] or later bytes. */ + size_t limit; + + /* + * End of the dictionary buffer. In multi-call mode, this is + * the same as the dictionary size. In single-call mode, this + * indicates the size of the output buffer. + */ + size_t end; + + /* + * Size of the dictionary as specified in Block Header. This is used + * together with "full" to detect corrupt input that would make us + * read beyond the beginning of the uncompressed stream. + */ + uint32_t size; + + /* + * Maximum allowed dictionary size in multi-call mode. + * This is ignored in single-call mode. + */ + uint32_t size_max; + + /* + * Amount of memory currently allocated for the dictionary. + * This is used only with XZ_DYNALLOC. (With XZ_PREALLOC, + * size_max is always the same as the allocated size.) + */ + uint32_t allocated; + + /* Operation mode */ + enum xz_mode mode; +}; + +/* Range decoder */ +struct rc_dec { + uint32_t range; + uint32_t code; + + /* + * Number of initializing bytes remaining to be read + * by rc_read_init(). + */ + uint32_t init_bytes_left; + + /* + * Buffer from which we read our input. It can be either + * temp.buf or the caller-provided input buffer. + */ + const uint8_t *in; + size_t in_pos; + size_t in_limit; +}; + +/* Probabilities for a length decoder. */ +struct lzma_len_dec { + /* Probability of match length being at least 10 */ + uint16_t choice; + + /* Probability of match length being at least 18 */ + uint16_t choice2; + + /* Probabilities for match lengths 2-9 */ + uint16_t low[POS_STATES_MAX][LEN_LOW_SYMBOLS]; + + /* Probabilities for match lengths 10-17 */ + uint16_t mid[POS_STATES_MAX][LEN_MID_SYMBOLS]; + + /* Probabilities for match lengths 18-273 */ + uint16_t high[LEN_HIGH_SYMBOLS]; +}; + +struct lzma_dec { + /* Distances of latest four matches */ + uint32_t rep0; + uint32_t rep1; + uint32_t rep2; + uint32_t rep3; + + /* Types of the most recently seen LZMA symbols */ + enum lzma_state state; + + /* + * Length of a match. This is updated so that dict_repeat can + * be called again to finish repeating the whole match. + */ + uint32_t len; + + /* + * LZMA properties or related bit masks (number of literal + * context bits, a mask dervied from the number of literal + * position bits, and a mask dervied from the number + * position bits) + */ + uint32_t lc; + uint32_t literal_pos_mask; /* (1 << lp) - 1 */ + uint32_t pos_mask; /* (1 << pb) - 1 */ + + /* If 1, it's a match. Otherwise it's a single 8-bit literal. */ + uint16_t is_match[STATES][POS_STATES_MAX]; + + /* If 1, it's a repeated match. The distance is one of rep0 .. rep3. */ + uint16_t is_rep[STATES]; + + /* + * If 0, distance of a repeated match is rep0. + * Otherwise check is_rep1. + */ + uint16_t is_rep0[STATES]; + + /* + * If 0, distance of a repeated match is rep1. + * Otherwise check is_rep2. + */ + uint16_t is_rep1[STATES]; + + /* If 0, distance of a repeated match is rep2. Otherwise it is rep3. */ + uint16_t is_rep2[STATES]; + + /* + * If 1, the repeated match has length of one byte. Otherwise + * the length is decoded from rep_len_decoder. + */ + uint16_t is_rep0_long[STATES][POS_STATES_MAX]; + + /* + * Probability tree for the highest two bits of the match + * distance. There is a separate probability tree for match + * lengths of 2 (i.e. MATCH_LEN_MIN), 3, 4, and [5, 273]. + */ + uint16_t dist_slot[DIST_STATES][DIST_SLOTS]; + + /* + * Probility trees for additional bits for match distance + * when the distance is in the range [4, 127]. + */ + uint16_t dist_special[FULL_DISTANCES - DIST_MODEL_END]; + + /* + * Probability tree for the lowest four bits of a match + * distance that is equal to or greater than 128. + */ + uint16_t dist_align[ALIGN_SIZE]; + + /* Length of a normal match */ + struct lzma_len_dec match_len_dec; + + /* Length of a repeated match */ + struct lzma_len_dec rep_len_dec; + + /* Probabilities of literals */ + uint16_t literal[LITERAL_CODERS_MAX][LITERAL_CODER_SIZE]; +}; + +struct lzma2_dec { + /* Position in xz_dec_lzma2_run(). */ + enum lzma2_seq { + SEQ_CONTROL, + SEQ_UNCOMPRESSED_1, + SEQ_UNCOMPRESSED_2, + SEQ_COMPRESSED_0, + SEQ_COMPRESSED_1, + SEQ_PROPERTIES, + SEQ_LZMA_PREPARE, + SEQ_LZMA_RUN, + SEQ_COPY + } sequence; + + /* Next position after decoding the compressed size of the chunk. */ + enum lzma2_seq next_sequence; + + /* Uncompressed size of LZMA chunk (2 MiB at maximum) */ + uint32_t uncompressed; + + /* + * Compressed size of LZMA chunk or compressed/uncompressed + * size of uncompressed chunk (64 KiB at maximum) + */ + uint32_t compressed; + + /* + * True if dictionary reset is needed. This is false before + * the first chunk (LZMA or uncompressed). + */ + bool need_dict_reset; + + /* + * True if new LZMA properties are needed. This is false + * before the first LZMA chunk. + */ + bool need_props; +}; + +struct xz_dec_lzma2 { + /* + * The order below is important on x86 to reduce code size and + * it shouldn't hurt on other platforms. Everything up to and + * including lzma.pos_mask are in the first 128 bytes on x86-32, + * which allows using smaller instructions to access those + * variables. On x86-64, fewer variables fit into the first 128 + * bytes, but this is still the best order without sacrificing + * the readability by splitting the structures. + */ + struct rc_dec rc; + struct dictionary dict; + struct lzma2_dec lzma2; + struct lzma_dec lzma; + + /* + * Temporary buffer which holds small number of input bytes between + * decoder calls. See lzma2_lzma() for details. + */ + struct { + uint32_t size; + uint8_t buf[3 * LZMA_IN_REQUIRED]; + } temp; +}; + +/************** + * Dictionary * + **************/ + +/* + * Reset the dictionary state. When in single-call mode, set up the beginning + * of the dictionary to point to the actual output buffer. + */ +static void XZ_FUNC dict_reset(struct dictionary *dict, struct xz_buf *b) +{ + if (DEC_IS_SINGLE(dict->mode)) { + dict->buf = b->out + b->out_pos; + dict->end = b->out_size - b->out_pos; + } + + dict->start = 0; + dict->pos = 0; + dict->limit = 0; + dict->full = 0; +} + +/* Set dictionary write limit */ +static void XZ_FUNC dict_limit(struct dictionary *dict, size_t out_max) +{ + if (dict->end - dict->pos <= out_max) + dict->limit = dict->end; + else + dict->limit = dict->pos + out_max; +} + +/* Return true if at least one byte can be written into the dictionary. */ +static __always_inline bool XZ_FUNC dict_has_space(const struct dictionary *dict) +{ + return dict->pos < dict->limit; +} + +/* + * Get a byte from the dictionary at the given distance. The distance is + * assumed to valid, or as a special case, zero when the dictionary is + * still empty. This special case is needed for single-call decoding to + * avoid writing a '\0' to the end of the destination buffer. + */ +static __always_inline uint32_t XZ_FUNC dict_get( + const struct dictionary *dict, uint32_t dist) +{ + size_t offset = dict->pos - dist - 1; + + if (dist >= dict->pos) + offset += dict->end; + + return dict->full > 0 ? dict->buf[offset] : 0; +} + +/* + * Put one byte into the dictionary. It is assumed that there is space for it. + */ +static inline void XZ_FUNC dict_put(struct dictionary *dict, uint8_t byte) +{ + dict->buf[dict->pos++] = byte; + + if (dict->full < dict->pos) + dict->full = dict->pos; +} + +/* + * Repeat given number of bytes from the given distance. If the distance is + * invalid, false is returned. On success, true is returned and *len is + * updated to indicate how many bytes were left to be repeated. + */ +static bool XZ_FUNC dict_repeat( + struct dictionary *dict, uint32_t *len, uint32_t dist) +{ + size_t back; + uint32_t left; + + if (dist >= dict->full || dist >= dict->size) + return false; + + left = min_t(size_t, dict->limit - dict->pos, *len); + *len -= left; + + back = dict->pos - dist - 1; + if (dist >= dict->pos) + back += dict->end; + + do { + dict->buf[dict->pos++] = dict->buf[back++]; + if (back == dict->end) + back = 0; + } while (--left > 0); + + if (dict->full < dict->pos) + dict->full = dict->pos; + + return true; +} + +/* Copy uncompressed data as is from input to dictionary and output buffers. */ +static void XZ_FUNC dict_uncompressed( + struct dictionary *dict, struct xz_buf *b, uint32_t *left) +{ + size_t copy_size; + + while (*left > 0 && b->in_pos < b->in_size + && b->out_pos < b->out_size) { + copy_size = min(b->in_size - b->in_pos, + b->out_size - b->out_pos); + if (copy_size > dict->end - dict->pos) + copy_size = dict->end - dict->pos; + if (copy_size > *left) + copy_size = *left; + + *left -= copy_size; + + memcpy(dict->buf + dict->pos, b->in + b->in_pos, copy_size); + dict->pos += copy_size; + + if (dict->full < dict->pos) + dict->full = dict->pos; + + if (DEC_IS_MULTI(dict->mode)) { + if (dict->pos == dict->end) + dict->pos = 0; + + memcpy(b->out + b->out_pos, b->in + b->in_pos, + copy_size); + } + + dict->start = dict->pos; + + b->out_pos += copy_size; + b->in_pos += copy_size; + + } +} + +/* + * Flush pending data from dictionary to b->out. It is assumed that there is + * enough space in b->out. This is guaranteed because caller uses dict_limit() + * before decoding data into the dictionary. + */ +static uint32_t XZ_FUNC dict_flush(struct dictionary *dict, struct xz_buf *b) +{ + size_t copy_size = dict->pos - dict->start; + + if (DEC_IS_MULTI(dict->mode)) { + if (dict->pos == dict->end) + dict->pos = 0; + + memcpy(b->out + b->out_pos, dict->buf + dict->start, + copy_size); + } + + dict->start = dict->pos; + b->out_pos += copy_size; + return copy_size; +} + +/***************** + * Range decoder * + *****************/ + +/* Reset the range decoder. */ +static void XZ_FUNC rc_reset(struct rc_dec *rc) +{ + rc->range = (uint32_t)-1; + rc->code = 0; + rc->init_bytes_left = RC_INIT_BYTES; +} + +/* + * Read the first five initial bytes into rc->code if they haven't been + * read already. (Yes, the first byte gets completely ignored.) + */ +static bool XZ_FUNC rc_read_init(struct rc_dec *rc, struct xz_buf *b) +{ + while (rc->init_bytes_left > 0) { + if (b->in_pos == b->in_size) + return false; + + rc->code = (rc->code << 8) + b->in[b->in_pos++]; + --rc->init_bytes_left; + } + + return true; +} + +/* Return true if there may not be enough input for the next decoding loop. */ +static inline bool XZ_FUNC rc_limit_exceeded(const struct rc_dec *rc) +{ + return rc->in_pos > rc->in_limit; +} + +/* + * Return true if it is possible (from point of view of range decoder) that + * we have reached the end of the LZMA chunk. + */ +static inline bool XZ_FUNC rc_is_finished(const struct rc_dec *rc) +{ + return rc->code == 0; +} + +/* Read the next input byte if needed. */ +static __always_inline void XZ_FUNC rc_normalize(struct rc_dec *rc) +{ + if (rc->range < RC_TOP_VALUE) { + rc->range <<= RC_SHIFT_BITS; + rc->code = (rc->code << RC_SHIFT_BITS) + rc->in[rc->in_pos++]; + } +} + +/* + * Decode one bit. In some versions, this function has been splitted in three + * functions so that the compiler is supposed to be able to more easily avoid + * an extra branch. In this particular version of the LZMA decoder, this + * doesn't seem to be a good idea (tested with GCC 3.3.6, 3.4.6, and 4.3.3 + * on x86). Using a non-splitted version results in nicer looking code too. + * + * NOTE: This must return an int. Do not make it return a bool or the speed + * of the code generated by GCC 3.x decreases 10-15 %. (GCC 4.3 doesn't care, + * and it generates 10-20 % faster code than GCC 3.x from this file anyway.) + */ +static __always_inline int XZ_FUNC rc_bit(struct rc_dec *rc, uint16_t *prob) +{ + uint32_t bound; + int bit; + + rc_normalize(rc); + bound = (rc->range >> RC_BIT_MODEL_TOTAL_BITS) * *prob; + if (rc->code < bound) { + rc->range = bound; + *prob += (RC_BIT_MODEL_TOTAL - *prob) >> RC_MOVE_BITS; + bit = 0; + } else { + rc->range -= bound; + rc->code -= bound; + *prob -= *prob >> RC_MOVE_BITS; + bit = 1; + } + + return bit; +} + +/* Decode a bittree starting from the most significant bit. */ +static __always_inline uint32_t XZ_FUNC rc_bittree( + struct rc_dec *rc, uint16_t *probs, uint32_t limit) +{ + uint32_t symbol = 1; + + do { + if (rc_bit(rc, &probs[symbol])) + symbol = (symbol << 1) + 1; + else + symbol <<= 1; + } while (symbol < limit); + + return symbol; +} + +/* Decode a bittree starting from the least significant bit. */ +static __always_inline void XZ_FUNC rc_bittree_reverse(struct rc_dec *rc, + uint16_t *probs, uint32_t *dest, uint32_t limit) +{ + uint32_t symbol = 1; + uint32_t i = 0; + + do { + if (rc_bit(rc, &probs[symbol])) { + symbol = (symbol << 1) + 1; + *dest += 1 << i; + } else { + symbol <<= 1; + } + } while (++i < limit); +} + +/* Decode direct bits (fixed fifty-fifty probability) */ +static inline void XZ_FUNC rc_direct( + struct rc_dec *rc, uint32_t *dest, uint32_t limit) +{ + uint32_t mask; + + do { + rc_normalize(rc); + rc->range >>= 1; + rc->code -= rc->range; + mask = (uint32_t)0 - (rc->code >> 31); + rc->code += rc->range & mask; + *dest = (*dest << 1) + (mask + 1); + } while (--limit > 0); +} + +/******** + * LZMA * + ********/ + +/* Get pointer to literal coder probability array. */ +static uint16_t * XZ_FUNC lzma_literal_probs(struct xz_dec_lzma2 *s) +{ + uint32_t prev_byte = dict_get(&s->dict, 0); + uint32_t low = prev_byte >> (8 - s->lzma.lc); + uint32_t high = (s->dict.pos & s->lzma.literal_pos_mask) << s->lzma.lc; + return s->lzma.literal[low + high]; +} + +/* Decode a literal (one 8-bit byte) */ +static void XZ_FUNC lzma_literal(struct xz_dec_lzma2 *s) +{ + uint16_t *probs; + uint32_t symbol; + uint32_t match_byte; + uint32_t match_bit; + uint32_t offset; + uint32_t i; + + probs = lzma_literal_probs(s); + + if (lzma_state_is_literal(s->lzma.state)) { + symbol = rc_bittree(&s->rc, probs, 0x100); + } else { + symbol = 1; + match_byte = dict_get(&s->dict, s->lzma.rep0) << 1; + offset = 0x100; + + do { + match_bit = match_byte & offset; + match_byte <<= 1; + i = offset + match_bit + symbol; + + if (rc_bit(&s->rc, &probs[i])) { + symbol = (symbol << 1) + 1; + offset &= match_bit; + } else { + symbol <<= 1; + offset &= ~match_bit; + } + } while (symbol < 0x100); + } + + dict_put(&s->dict, (uint8_t)symbol); + lzma_state_literal(&s->lzma.state); +} + +/* Decode the length of the match into s->lzma.len. */ +static void XZ_FUNC lzma_len(struct xz_dec_lzma2 *s, struct lzma_len_dec *l, + uint32_t pos_state) +{ + uint16_t *probs; + uint32_t limit; + + if (!rc_bit(&s->rc, &l->choice)) { + probs = l->low[pos_state]; + limit = LEN_LOW_SYMBOLS; + s->lzma.len = MATCH_LEN_MIN; + } else { + if (!rc_bit(&s->rc, &l->choice2)) { + probs = l->mid[pos_state]; + limit = LEN_MID_SYMBOLS; + s->lzma.len = MATCH_LEN_MIN + LEN_LOW_SYMBOLS; + } else { + probs = l->high; + limit = LEN_HIGH_SYMBOLS; + s->lzma.len = MATCH_LEN_MIN + LEN_LOW_SYMBOLS + + LEN_MID_SYMBOLS; + } + } + + s->lzma.len += rc_bittree(&s->rc, probs, limit) - limit; +} + +/* Decode a match. The distance will be stored in s->lzma.rep0. */ +static void XZ_FUNC lzma_match(struct xz_dec_lzma2 *s, uint32_t pos_state) +{ + uint16_t *probs; + uint32_t dist_slot; + uint32_t limit; + + lzma_state_match(&s->lzma.state); + + s->lzma.rep3 = s->lzma.rep2; + s->lzma.rep2 = s->lzma.rep1; + s->lzma.rep1 = s->lzma.rep0; + + lzma_len(s, &s->lzma.match_len_dec, pos_state); + + probs = s->lzma.dist_slot[lzma_get_dist_state(s->lzma.len)]; + dist_slot = rc_bittree(&s->rc, probs, DIST_SLOTS) - DIST_SLOTS; + + if (dist_slot < DIST_MODEL_START) { + s->lzma.rep0 = dist_slot; + } else { + limit = (dist_slot >> 1) - 1; + s->lzma.rep0 = 2 + (dist_slot & 1); + + if (dist_slot < DIST_MODEL_END) { + s->lzma.rep0 <<= limit; + probs = s->lzma.dist_special + s->lzma.rep0 + - dist_slot - 1; + rc_bittree_reverse(&s->rc, probs, + &s->lzma.rep0, limit); + } else { + rc_direct(&s->rc, &s->lzma.rep0, limit - ALIGN_BITS); + s->lzma.rep0 <<= ALIGN_BITS; + rc_bittree_reverse(&s->rc, s->lzma.dist_align, + &s->lzma.rep0, ALIGN_BITS); + } + } +} + +/* + * Decode a repeated match. The distance is one of the four most recently + * seen matches. The distance will be stored in s->lzma.rep0. + */ +static void XZ_FUNC lzma_rep_match(struct xz_dec_lzma2 *s, uint32_t pos_state) +{ + uint32_t tmp; + + if (!rc_bit(&s->rc, &s->lzma.is_rep0[s->lzma.state])) { + if (!rc_bit(&s->rc, &s->lzma.is_rep0_long[ + s->lzma.state][pos_state])) { + lzma_state_short_rep(&s->lzma.state); + s->lzma.len = 1; + return; + } + } else { + if (!rc_bit(&s->rc, &s->lzma.is_rep1[s->lzma.state])) { + tmp = s->lzma.rep1; + } else { + if (!rc_bit(&s->rc, &s->lzma.is_rep2[s->lzma.state])) { + tmp = s->lzma.rep2; + } else { + tmp = s->lzma.rep3; + s->lzma.rep3 = s->lzma.rep2; + } + + s->lzma.rep2 = s->lzma.rep1; + } + + s->lzma.rep1 = s->lzma.rep0; + s->lzma.rep0 = tmp; + } + + lzma_state_long_rep(&s->lzma.state); + lzma_len(s, &s->lzma.rep_len_dec, pos_state); +} + +/* LZMA decoder core */ +static bool XZ_FUNC lzma_main(struct xz_dec_lzma2 *s) +{ + uint32_t pos_state; + + /* + * If the dictionary was reached during the previous call, try to + * finish the possibly pending repeat in the dictionary. + */ + if (dict_has_space(&s->dict) && s->lzma.len > 0) + dict_repeat(&s->dict, &s->lzma.len, s->lzma.rep0); + + /* + * Decode more LZMA symbols. One iteration may consume up to + * LZMA_IN_REQUIRED - 1 bytes. + */ + while (dict_has_space(&s->dict) && !rc_limit_exceeded(&s->rc)) { + pos_state = s->dict.pos & s->lzma.pos_mask; + + if (!rc_bit(&s->rc, &s->lzma.is_match[ + s->lzma.state][pos_state])) { + lzma_literal(s); + } else { + if (rc_bit(&s->rc, &s->lzma.is_rep[s->lzma.state])) + lzma_rep_match(s, pos_state); + else + lzma_match(s, pos_state); + + if (!dict_repeat(&s->dict, &s->lzma.len, s->lzma.rep0)) + return false; + } + } + + /* + * Having the range decoder always normalized when we are outside + * this function makes it easier to correctly handle end of the chunk. + */ + rc_normalize(&s->rc); + + return true; +} + +/* + * Reset the LZMA decoder and range decoder state. Dictionary is nore reset + * here, because LZMA state may be reset without resetting the dictionary. + */ +static void XZ_FUNC lzma_reset(struct xz_dec_lzma2 *s) +{ + uint16_t *probs; + size_t i; + + s->lzma.state = STATE_LIT_LIT; + s->lzma.rep0 = 0; + s->lzma.rep1 = 0; + s->lzma.rep2 = 0; + s->lzma.rep3 = 0; + + /* + * All probabilities are initialized to the same value. This hack + * makes the code smaller by avoiding a separate loop for each + * probability array. + * + * This could be optimized so that only that part of literal + * probabilities that are actually required. In the common case + * we would write 12 KiB less. + */ + probs = s->lzma.is_match[0]; + for (i = 0; i < PROBS_TOTAL; ++i) + probs[i] = RC_BIT_MODEL_TOTAL / 2; + + rc_reset(&s->rc); +} + +/* + * Decode and validate LZMA properties (lc/lp/pb) and calculate the bit masks + * from the decoded lp and pb values. On success, the LZMA decoder state is + * reset and true is returned. + */ +static bool XZ_FUNC lzma_props(struct xz_dec_lzma2 *s, uint8_t props) +{ + if (props > (4 * 5 + 4) * 9 + 8) + return false; + + s->lzma.pos_mask = 0; + while (props >= 9 * 5) { + props -= 9 * 5; + ++s->lzma.pos_mask; + } + + s->lzma.pos_mask = (1 << s->lzma.pos_mask) - 1; + + s->lzma.literal_pos_mask = 0; + while (props >= 9) { + props -= 9; + ++s->lzma.literal_pos_mask; + } + + s->lzma.lc = props; + + if (s->lzma.lc + s->lzma.literal_pos_mask > 4) + return false; + + s->lzma.literal_pos_mask = (1 << s->lzma.literal_pos_mask) - 1; + + lzma_reset(s); + + return true; +} + +/********* + * LZMA2 * + *********/ + +/* + * The LZMA decoder assumes that if the input limit (s->rc.in_limit) hasn't + * been exceeded, it is safe to read up to LZMA_IN_REQUIRED bytes. This + * wrapper function takes care of making the LZMA decoder's assumption safe. + * + * As long as there is plenty of input left to be decoded in the current LZMA + * chunk, we decode directly from the caller-supplied input buffer until + * there's LZMA_IN_REQUIRED bytes left. Those remaining bytes are copied into + * s->temp.buf, which (hopefully) gets filled on the next call to this + * function. We decode a few bytes from the temporary buffer so that we can + * continue decoding from the caller-supplied input buffer again. + */ +static bool XZ_FUNC lzma2_lzma(struct xz_dec_lzma2 *s, struct xz_buf *b) +{ + size_t in_avail; + uint32_t tmp; + + in_avail = b->in_size - b->in_pos; + if (s->temp.size > 0 || s->lzma2.compressed == 0) { + tmp = 2 * LZMA_IN_REQUIRED - s->temp.size; + if (tmp > s->lzma2.compressed - s->temp.size) + tmp = s->lzma2.compressed - s->temp.size; + if (tmp > in_avail) + tmp = in_avail; + + memcpy(s->temp.buf + s->temp.size, b->in + b->in_pos, tmp); + + if (s->temp.size + tmp == s->lzma2.compressed) { + memzero(s->temp.buf + s->temp.size + tmp, + sizeof(s->temp.buf) + - s->temp.size - tmp); + s->rc.in_limit = s->temp.size + tmp; + } else if (s->temp.size + tmp < LZMA_IN_REQUIRED) { + s->temp.size += tmp; + b->in_pos += tmp; + return true; + } else { + s->rc.in_limit = s->temp.size + tmp - LZMA_IN_REQUIRED; + } + + s->rc.in = s->temp.buf; + s->rc.in_pos = 0; + + if (!lzma_main(s) || s->rc.in_pos > s->temp.size + tmp) + return false; + + s->lzma2.compressed -= s->rc.in_pos; + + if (s->rc.in_pos < s->temp.size) { + s->temp.size -= s->rc.in_pos; + memmove(s->temp.buf, s->temp.buf + s->rc.in_pos, + s->temp.size); + return true; + } + + b->in_pos += s->rc.in_pos - s->temp.size; + s->temp.size = 0; + } + + in_avail = b->in_size - b->in_pos; + if (in_avail >= LZMA_IN_REQUIRED) { + s->rc.in = b->in; + s->rc.in_pos = b->in_pos; + + if (in_avail >= s->lzma2.compressed + LZMA_IN_REQUIRED) + s->rc.in_limit = b->in_pos + s->lzma2.compressed; + else + s->rc.in_limit = b->in_size - LZMA_IN_REQUIRED; + + if (!lzma_main(s)) + return false; + + in_avail = s->rc.in_pos - b->in_pos; + if (in_avail > s->lzma2.compressed) + return false; + + s->lzma2.compressed -= in_avail; + b->in_pos = s->rc.in_pos; + } + + in_avail = b->in_size - b->in_pos; + if (in_avail < LZMA_IN_REQUIRED) { + if (in_avail > s->lzma2.compressed) + in_avail = s->lzma2.compressed; + + memcpy(s->temp.buf, b->in + b->in_pos, in_avail); + s->temp.size = in_avail; + b->in_pos += in_avail; + } + + return true; +} + +/* + * Take care of the LZMA2 control layer, and forward the job of actual LZMA + * decoding or copying of uncompressed chunks to other functions. + */ +XZ_EXTERN NOINLINE enum xz_ret XZ_FUNC xz_dec_lzma2_run( + struct xz_dec_lzma2 *s, struct xz_buf *b) +{ + uint32_t tmp; + + while (b->in_pos < b->in_size || s->lzma2.sequence == SEQ_LZMA_RUN) { + switch (s->lzma2.sequence) { + case SEQ_CONTROL: + /* + * LZMA2 control byte + * + * Exact values: + * 0x00 End marker + * 0x01 Dictionary reset followed by + * an uncompressed chunk + * 0x02 Uncompressed chunk (no dictionary reset) + * + * Highest three bits (s->control & 0xE0): + * 0xE0 Dictionary reset, new properties and state + * reset, followed by LZMA compressed chunk + * 0xC0 New properties and state reset, followed + * by LZMA compressed chunk (no dictionary + * reset) + * 0xA0 State reset using old properties, + * followed by LZMA compressed chunk (no + * dictionary reset) + * 0x80 LZMA chunk (no dictionary or state reset) + * + * For LZMA compressed chunks, the lowest five bits + * (s->control & 1F) are the highest bits of the + * uncompressed size (bits 16-20). + * + * A new LZMA2 stream must begin with a dictionary + * reset. The first LZMA chunk must set new + * properties and reset the LZMA state. + * + * Values that don't match anything described above + * are invalid and we return XZ_DATA_ERROR. + */ + tmp = b->in[b->in_pos++]; + + if (tmp >= 0xE0 || tmp == 0x01) { + s->lzma2.need_props = true; + s->lzma2.need_dict_reset = false; + dict_reset(&s->dict, b); + } else if (s->lzma2.need_dict_reset) { + return XZ_DATA_ERROR; + } + + if (tmp >= 0x80) { + s->lzma2.uncompressed = (tmp & 0x1F) << 16; + s->lzma2.sequence = SEQ_UNCOMPRESSED_1; + + if (tmp >= 0xC0) { + /* + * When there are new properties, + * state reset is done at + * SEQ_PROPERTIES. + */ + s->lzma2.need_props = false; + s->lzma2.next_sequence + = SEQ_PROPERTIES; + + } else if (s->lzma2.need_props) { + return XZ_DATA_ERROR; + + } else { + s->lzma2.next_sequence + = SEQ_LZMA_PREPARE; + if (tmp >= 0xA0) + lzma_reset(s); + } + } else { + if (tmp == 0x00) + return XZ_STREAM_END; + + if (tmp > 0x02) + return XZ_DATA_ERROR; + + s->lzma2.sequence = SEQ_COMPRESSED_0; + s->lzma2.next_sequence = SEQ_COPY; + } + + break; + + case SEQ_UNCOMPRESSED_1: + s->lzma2.uncompressed + += (uint32_t)b->in[b->in_pos++] << 8; + s->lzma2.sequence = SEQ_UNCOMPRESSED_2; + break; + + case SEQ_UNCOMPRESSED_2: + s->lzma2.uncompressed + += (uint32_t)b->in[b->in_pos++] + 1; + s->lzma2.sequence = SEQ_COMPRESSED_0; + break; + + case SEQ_COMPRESSED_0: + s->lzma2.compressed + = (uint32_t)b->in[b->in_pos++] << 8; + s->lzma2.sequence = SEQ_COMPRESSED_1; + break; + + case SEQ_COMPRESSED_1: + s->lzma2.compressed + += (uint32_t)b->in[b->in_pos++] + 1; + s->lzma2.sequence = s->lzma2.next_sequence; + break; + + case SEQ_PROPERTIES: + if (!lzma_props(s, b->in[b->in_pos++])) + return XZ_DATA_ERROR; + + s->lzma2.sequence = SEQ_LZMA_PREPARE; + + case SEQ_LZMA_PREPARE: + if (s->lzma2.compressed < RC_INIT_BYTES) + return XZ_DATA_ERROR; + + if (!rc_read_init(&s->rc, b)) + return XZ_OK; + + s->lzma2.compressed -= RC_INIT_BYTES; + s->lzma2.sequence = SEQ_LZMA_RUN; + + case SEQ_LZMA_RUN: + /* + * Set dictionary limit to indicate how much we want + * to be encoded at maximum. Decode new data into the + * dictionary. Flush the new data from dictionary to + * b->out. Check if we finished decoding this chunk. + * In case the dictionary got full but we didn't fill + * the output buffer yet, we may run this loop + * multiple times without changing s->lzma2.sequence. + */ + dict_limit(&s->dict, min_t(size_t, + b->out_size - b->out_pos, + s->lzma2.uncompressed)); + if (!lzma2_lzma(s, b)) + return XZ_DATA_ERROR; + + s->lzma2.uncompressed -= dict_flush(&s->dict, b); + + if (s->lzma2.uncompressed == 0) { + if (s->lzma2.compressed > 0 || s->lzma.len > 0 + || !rc_is_finished(&s->rc)) + return XZ_DATA_ERROR; + + rc_reset(&s->rc); + s->lzma2.sequence = SEQ_CONTROL; + + } else if (b->out_pos == b->out_size + || (b->in_pos == b->in_size + && s->temp.size + < s->lzma2.compressed)) { + return XZ_OK; + } + + break; + + case SEQ_COPY: + dict_uncompressed(&s->dict, b, &s->lzma2.compressed); + if (s->lzma2.compressed > 0) + return XZ_OK; + + s->lzma2.sequence = SEQ_CONTROL; + break; + } + } + + return XZ_OK; +} + +XZ_EXTERN struct xz_dec_lzma2 * XZ_FUNC xz_dec_lzma2_create( + enum xz_mode mode, uint32_t dict_max) +{ + struct xz_dec_lzma2 *s = kmalloc(sizeof(*s), GFP_KERNEL); + if (s == NULL) + return NULL; + + s->dict.mode = mode; + s->dict.size_max = dict_max; + + if (DEC_IS_PREALLOC(mode)) { + s->dict.buf = vmalloc(dict_max); + if (s->dict.buf == NULL) { + kfree(s); + return NULL; + } + } else if (DEC_IS_DYNALLOC(mode)) { + s->dict.buf = NULL; + s->dict.allocated = 0; + } + + return s; +} + +XZ_EXTERN enum xz_ret XZ_FUNC xz_dec_lzma2_reset( + struct xz_dec_lzma2 *s, uint8_t props) +{ + /* This limits dictionary size to 3 GiB to keep parsing simpler. */ + if (props > 39) + return XZ_OPTIONS_ERROR; + + s->dict.size = 2 + (props & 1); + s->dict.size <<= (props >> 1) + 11; + + if (DEC_IS_MULTI(s->dict.mode)) { + if (s->dict.size > s->dict.size_max) + return XZ_MEMLIMIT_ERROR; + + s->dict.end = s->dict.size; + + if (DEC_IS_DYNALLOC(s->dict.mode)) { + if (s->dict.allocated < s->dict.size) { + vfree(s->dict.buf); + s->dict.buf = vmalloc(s->dict.size); + if (s->dict.buf == NULL) { + s->dict.allocated = 0; + return XZ_MEM_ERROR; + } + } + } + } + + s->lzma.len = 0; + + s->lzma2.sequence = SEQ_CONTROL; + s->lzma2.need_dict_reset = true; + + s->temp.size = 0; + + return XZ_OK; +} + +XZ_EXTERN void XZ_FUNC xz_dec_lzma2_end(struct xz_dec_lzma2 *s) +{ + if (DEC_IS_MULTI(s->dict.mode)) + vfree(s->dict.buf); + + kfree(s); +} diff --git a/archival/libarchive/unxz/xz_dec_stream.c b/archival/libarchive/unxz/xz_dec_stream.c new file mode 100644 index 000000000..bdcbf1ba3 --- /dev/null +++ b/archival/libarchive/unxz/xz_dec_stream.c @@ -0,0 +1,822 @@ +/* + * .xz Stream decoder + * + * Author: Lasse Collin + * + * This file has been put into the public domain. + * You can do whatever you want with this file. + */ + +#include "xz_private.h" +#include "xz_stream.h" + +/* Hash used to validate the Index field */ +struct xz_dec_hash { + vli_type unpadded; + vli_type uncompressed; + uint32_t crc32; +}; + +struct xz_dec { + /* Position in dec_main() */ + enum { + SEQ_STREAM_HEADER, + SEQ_BLOCK_START, + SEQ_BLOCK_HEADER, + SEQ_BLOCK_UNCOMPRESS, + SEQ_BLOCK_PADDING, + SEQ_BLOCK_CHECK, + SEQ_INDEX, + SEQ_INDEX_PADDING, + SEQ_INDEX_CRC32, + SEQ_STREAM_FOOTER + } sequence; + + /* Position in variable-length integers and Check fields */ + uint32_t pos; + + /* Variable-length integer decoded by dec_vli() */ + vli_type vli; + + /* Saved in_pos and out_pos */ + size_t in_start; + size_t out_start; + + /* CRC32 value in Block or Index */ + uint32_t crc32; + + /* Type of the integrity check calculated from uncompressed data */ + enum xz_check check_type; + + /* Operation mode */ + enum xz_mode mode; + + /* + * True if the next call to xz_dec_run() is allowed to return + * XZ_BUF_ERROR. + */ + bool allow_buf_error; + + /* Information stored in Block Header */ + struct { + /* + * Value stored in the Compressed Size field, or + * VLI_UNKNOWN if Compressed Size is not present. + */ + vli_type compressed; + + /* + * Value stored in the Uncompressed Size field, or + * VLI_UNKNOWN if Uncompressed Size is not present. + */ + vli_type uncompressed; + + /* Size of the Block Header field */ + uint32_t size; + } block_header; + + /* Information collected when decoding Blocks */ + struct { + /* Observed compressed size of the current Block */ + vli_type compressed; + + /* Observed uncompressed size of the current Block */ + vli_type uncompressed; + + /* Number of Blocks decoded so far */ + vli_type count; + + /* + * Hash calculated from the Block sizes. This is used to + * validate the Index field. + */ + struct xz_dec_hash hash; + } block; + + /* Variables needed when verifying the Index field */ + struct { + /* Position in dec_index() */ + enum { + SEQ_INDEX_COUNT, + SEQ_INDEX_UNPADDED, + SEQ_INDEX_UNCOMPRESSED + } sequence; + + /* Size of the Index in bytes */ + vli_type size; + + /* Number of Records (matches block.count in valid files) */ + vli_type count; + + /* + * Hash calculated from the Records (matches block.hash in + * valid files). + */ + struct xz_dec_hash hash; + } index; + + /* + * Temporary buffer needed to hold Stream Header, Block Header, + * and Stream Footer. The Block Header is the biggest (1 KiB) + * so we reserve space according to that. buf[] has to be aligned + * to a multiple of four bytes; the size_t variables before it + * should guarantee this. + */ + struct { + size_t pos; + size_t size; + uint8_t buf[1024]; + } temp; + + struct xz_dec_lzma2 *lzma2; + +#ifdef XZ_DEC_BCJ + struct xz_dec_bcj *bcj; + bool bcj_active; +#endif +}; + +#ifdef XZ_DEC_ANY_CHECK +/* Sizes of the Check field with different Check IDs */ +static const uint8_t check_sizes[16] = { + 0, + 4, 4, 4, + 8, 8, 8, + 16, 16, 16, + 32, 32, 32, + 64, 64, 64 +}; +#endif + +/* + * Fill s->temp by copying data starting from b->in[b->in_pos]. Caller + * must have set s->temp.pos to indicate how much data we are supposed + * to copy into s->temp.buf. Return true once s->temp.pos has reached + * s->temp.size. + */ +static bool XZ_FUNC fill_temp(struct xz_dec *s, struct xz_buf *b) +{ + size_t copy_size = min_t(size_t, + b->in_size - b->in_pos, s->temp.size - s->temp.pos); + + memcpy(s->temp.buf + s->temp.pos, b->in + b->in_pos, copy_size); + b->in_pos += copy_size; + s->temp.pos += copy_size; + + if (s->temp.pos == s->temp.size) { + s->temp.pos = 0; + return true; + } + + return false; +} + +/* Decode a variable-length integer (little-endian base-128 encoding) */ +static enum xz_ret XZ_FUNC dec_vli(struct xz_dec *s, + const uint8_t *in, size_t *in_pos, size_t in_size) +{ + uint8_t byte; + + if (s->pos == 0) + s->vli = 0; + + while (*in_pos < in_size) { + byte = in[*in_pos]; + ++*in_pos; + + s->vli |= (vli_type)(byte & 0x7F) << s->pos; + + if ((byte & 0x80) == 0) { + /* Don't allow non-minimal encodings. */ + if (byte == 0 && s->pos != 0) + return XZ_DATA_ERROR; + + s->pos = 0; + return XZ_STREAM_END; + } + + s->pos += 7; + if (s->pos == 7 * VLI_BYTES_MAX) + return XZ_DATA_ERROR; + } + + return XZ_OK; +} + +/* + * Decode the Compressed Data field from a Block. Update and validate + * the observed compressed and uncompressed sizes of the Block so that + * they don't exceed the values possibly stored in the Block Header + * (validation assumes that no integer overflow occurs, since vli_type + * is normally uint64_t). Update the CRC32 if presence of the CRC32 + * field was indicated in Stream Header. + * + * Once the decoding is finished, validate that the observed sizes match + * the sizes possibly stored in the Block Header. Update the hash and + * Block count, which are later used to validate the Index field. + */ +static enum xz_ret XZ_FUNC dec_block(struct xz_dec *s, struct xz_buf *b) +{ + enum xz_ret ret; + + s->in_start = b->in_pos; + s->out_start = b->out_pos; + +#ifdef XZ_DEC_BCJ + if (s->bcj_active) + ret = xz_dec_bcj_run(s->bcj, s->lzma2, b); + else +#endif + ret = xz_dec_lzma2_run(s->lzma2, b); + + s->block.compressed += b->in_pos - s->in_start; + s->block.uncompressed += b->out_pos - s->out_start; + + /* + * There is no need to separately check for VLI_UNKNOWN, since + * the observed sizes are always smaller than VLI_UNKNOWN. + */ + if (s->block.compressed > s->block_header.compressed + || s->block.uncompressed + > s->block_header.uncompressed) + return XZ_DATA_ERROR; + + if (s->check_type == XZ_CHECK_CRC32) + s->crc32 = xz_crc32(b->out + s->out_start, + b->out_pos - s->out_start, s->crc32); + + if (ret == XZ_STREAM_END) { + if (s->block_header.compressed != VLI_UNKNOWN + && s->block_header.compressed + != s->block.compressed) + return XZ_DATA_ERROR; + + if (s->block_header.uncompressed != VLI_UNKNOWN + && s->block_header.uncompressed + != s->block.uncompressed) + return XZ_DATA_ERROR; + + s->block.hash.unpadded += s->block_header.size + + s->block.compressed; + +#ifdef XZ_DEC_ANY_CHECK + s->block.hash.unpadded += check_sizes[s->check_type]; +#else + if (s->check_type == XZ_CHECK_CRC32) + s->block.hash.unpadded += 4; +#endif + + s->block.hash.uncompressed += s->block.uncompressed; + s->block.hash.crc32 = xz_crc32( + (const uint8_t *)&s->block.hash, + sizeof(s->block.hash), s->block.hash.crc32); + + ++s->block.count; + } + + return ret; +} + +/* Update the Index size and the CRC32 value. */ +static void XZ_FUNC index_update(struct xz_dec *s, const struct xz_buf *b) +{ + size_t in_used = b->in_pos - s->in_start; + s->index.size += in_used; + s->crc32 = xz_crc32(b->in + s->in_start, in_used, s->crc32); +} + +/* + * Decode the Number of Records, Unpadded Size, and Uncompressed Size + * fields from the Index field. That is, Index Padding and CRC32 are not + * decoded by this function. + * + * This can return XZ_OK (more input needed), XZ_STREAM_END (everything + * successfully decoded), or XZ_DATA_ERROR (input is corrupt). + */ +static enum xz_ret XZ_FUNC dec_index(struct xz_dec *s, struct xz_buf *b) +{ + enum xz_ret ret; + + do { + ret = dec_vli(s, b->in, &b->in_pos, b->in_size); + if (ret != XZ_STREAM_END) { + index_update(s, b); + return ret; + } + + switch (s->index.sequence) { + case SEQ_INDEX_COUNT: + s->index.count = s->vli; + + /* + * Validate that the Number of Records field + * indicates the same number of Records as + * there were Blocks in the Stream. + */ + if (s->index.count != s->block.count) + return XZ_DATA_ERROR; + + s->index.sequence = SEQ_INDEX_UNPADDED; + break; + + case SEQ_INDEX_UNPADDED: + s->index.hash.unpadded += s->vli; + s->index.sequence = SEQ_INDEX_UNCOMPRESSED; + break; + + case SEQ_INDEX_UNCOMPRESSED: + s->index.hash.uncompressed += s->vli; + s->index.hash.crc32 = xz_crc32( + (const uint8_t *)&s->index.hash, + sizeof(s->index.hash), + s->index.hash.crc32); + --s->index.count; + s->index.sequence = SEQ_INDEX_UNPADDED; + break; + } + } while (s->index.count > 0); + + return XZ_STREAM_END; +} + +/* + * Validate that the next four input bytes match the value of s->crc32. + * s->pos must be zero when starting to validate the first byte. + */ +static enum xz_ret XZ_FUNC crc32_validate(struct xz_dec *s, struct xz_buf *b) +{ + do { + if (b->in_pos == b->in_size) + return XZ_OK; + + if (((s->crc32 >> s->pos) & 0xFF) != b->in[b->in_pos++]) + return XZ_DATA_ERROR; + + s->pos += 8; + + } while (s->pos < 32); + + s->crc32 = 0; + s->pos = 0; + + return XZ_STREAM_END; +} + +#ifdef XZ_DEC_ANY_CHECK +/* + * Skip over the Check field when the Check ID is not supported. + * Returns true once the whole Check field has been skipped over. + */ +static bool XZ_FUNC check_skip(struct xz_dec *s, struct xz_buf *b) +{ + while (s->pos < check_sizes[s->check_type]) { + if (b->in_pos == b->in_size) + return false; + + ++b->in_pos; + ++s->pos; + } + + s->pos = 0; + + return true; +} +#endif + +/* Decode the Stream Header field (the first 12 bytes of the .xz Stream). */ +static enum xz_ret XZ_FUNC dec_stream_header(struct xz_dec *s) +{ + if (!memeq(s->temp.buf, HEADER_MAGIC, HEADER_MAGIC_SIZE)) + return XZ_FORMAT_ERROR; + + if (xz_crc32(s->temp.buf + HEADER_MAGIC_SIZE, 2, 0) + != get_le32(s->temp.buf + HEADER_MAGIC_SIZE + 2)) + return XZ_DATA_ERROR; + + if (s->temp.buf[HEADER_MAGIC_SIZE] != 0) + return XZ_OPTIONS_ERROR; + + /* + * Of integrity checks, we support only none (Check ID = 0) and + * CRC32 (Check ID = 1). However, if XZ_DEC_ANY_CHECK is defined, + * we will accept other check types too, but then the check won't + * be verified and a warning (XZ_UNSUPPORTED_CHECK) will be given. + */ + s->check_type = s->temp.buf[HEADER_MAGIC_SIZE + 1]; + +#ifdef XZ_DEC_ANY_CHECK + if (s->check_type > XZ_CHECK_MAX) + return XZ_OPTIONS_ERROR; + + if (s->check_type > XZ_CHECK_CRC32) + return XZ_UNSUPPORTED_CHECK; +#else + if (s->check_type > XZ_CHECK_CRC32) + return XZ_OPTIONS_ERROR; +#endif + + return XZ_OK; +} + +/* Decode the Stream Footer field (the last 12 bytes of the .xz Stream) */ +static enum xz_ret XZ_FUNC dec_stream_footer(struct xz_dec *s) +{ + if (!memeq(s->temp.buf + 10, FOOTER_MAGIC, FOOTER_MAGIC_SIZE)) + return XZ_DATA_ERROR; + + if (xz_crc32(s->temp.buf + 4, 6, 0) != get_le32(s->temp.buf)) + return XZ_DATA_ERROR; + + /* + * Validate Backward Size. Note that we never added the size of the + * Index CRC32 field to s->index.size, thus we use s->index.size / 4 + * instead of s->index.size / 4 - 1. + */ + if ((s->index.size >> 2) != get_le32(s->temp.buf + 4)) + return XZ_DATA_ERROR; + + if (s->temp.buf[8] != 0 || s->temp.buf[9] != s->check_type) + return XZ_DATA_ERROR; + + /* + * Use XZ_STREAM_END instead of XZ_OK to be more convenient + * for the caller. + */ + return XZ_STREAM_END; +} + +/* Decode the Block Header and initialize the filter chain. */ +static enum xz_ret XZ_FUNC dec_block_header(struct xz_dec *s) +{ + enum xz_ret ret; + + /* + * Validate the CRC32. We know that the temp buffer is at least + * eight bytes so this is safe. + */ + s->temp.size -= 4; + if (xz_crc32(s->temp.buf, s->temp.size, 0) + != get_le32(s->temp.buf + s->temp.size)) + return XZ_DATA_ERROR; + + s->temp.pos = 2; + + /* + * Catch unsupported Block Flags. We support only one or two filters + * in the chain, so we catch that with the same test. + */ +#ifdef XZ_DEC_BCJ + if (s->temp.buf[1] & 0x3E) +#else + if (s->temp.buf[1] & 0x3F) +#endif + return XZ_OPTIONS_ERROR; + + /* Compressed Size */ + if (s->temp.buf[1] & 0x40) { + if (dec_vli(s, s->temp.buf, &s->temp.pos, s->temp.size) + != XZ_STREAM_END) + return XZ_DATA_ERROR; + + s->block_header.compressed = s->vli; + } else { + s->block_header.compressed = VLI_UNKNOWN; + } + + /* Uncompressed Size */ + if (s->temp.buf[1] & 0x80) { + if (dec_vli(s, s->temp.buf, &s->temp.pos, s->temp.size) + != XZ_STREAM_END) + return XZ_DATA_ERROR; + + s->block_header.uncompressed = s->vli; + } else { + s->block_header.uncompressed = VLI_UNKNOWN; + } + +#ifdef XZ_DEC_BCJ + /* If there are two filters, the first one must be a BCJ filter. */ + s->bcj_active = s->temp.buf[1] & 0x01; + if (s->bcj_active) { + if (s->temp.size - s->temp.pos < 2) + return XZ_OPTIONS_ERROR; + + ret = xz_dec_bcj_reset(s->bcj, s->temp.buf[s->temp.pos++]); + if (ret != XZ_OK) + return ret; + + /* + * We don't support custom start offset, + * so Size of Properties must be zero. + */ + if (s->temp.buf[s->temp.pos++] != 0x00) + return XZ_OPTIONS_ERROR; + } +#endif + + /* Valid Filter Flags always take at least two bytes. */ + if (s->temp.size - s->temp.pos < 2) + return XZ_DATA_ERROR; + + /* Filter ID = LZMA2 */ + if (s->temp.buf[s->temp.pos++] != 0x21) + return XZ_OPTIONS_ERROR; + + /* Size of Properties = 1-byte Filter Properties */ + if (s->temp.buf[s->temp.pos++] != 0x01) + return XZ_OPTIONS_ERROR; + + /* Filter Properties contains LZMA2 dictionary size. */ + if (s->temp.size - s->temp.pos < 1) + return XZ_DATA_ERROR; + + ret = xz_dec_lzma2_reset(s->lzma2, s->temp.buf[s->temp.pos++]); + if (ret != XZ_OK) + return ret; + + /* The rest must be Header Padding. */ + while (s->temp.pos < s->temp.size) + if (s->temp.buf[s->temp.pos++] != 0x00) + return XZ_OPTIONS_ERROR; + + s->temp.pos = 0; + s->block.compressed = 0; + s->block.uncompressed = 0; + + return XZ_OK; +} + +static enum xz_ret XZ_FUNC dec_main(struct xz_dec *s, struct xz_buf *b) +{ + enum xz_ret ret; + + /* + * Store the start position for the case when we are in the middle + * of the Index field. + */ + s->in_start = b->in_pos; + + while (true) { + switch (s->sequence) { + case SEQ_STREAM_HEADER: + /* + * Stream Header is copied to s->temp, and then + * decoded from there. This way if the caller + * gives us only little input at a time, we can + * still keep the Stream Header decoding code + * simple. Similar approach is used in many places + * in this file. + */ + if (!fill_temp(s, b)) + return XZ_OK; + + /* + * If dec_stream_header() returns + * XZ_UNSUPPORTED_CHECK, it is still possible + * to continue decoding if working in multi-call + * mode. Thus, update s->sequence before calling + * dec_stream_header(). + */ + s->sequence = SEQ_BLOCK_START; + + ret = dec_stream_header(s); + if (ret != XZ_OK) + return ret; + + case SEQ_BLOCK_START: + /* We need one byte of input to continue. */ + if (b->in_pos == b->in_size) + return XZ_OK; + + /* See if this is the beginning of the Index field. */ + if (b->in[b->in_pos] == 0) { + s->in_start = b->in_pos++; + s->sequence = SEQ_INDEX; + break; + } + + /* + * Calculate the size of the Block Header and + * prepare to decode it. + */ + s->block_header.size + = ((uint32_t)b->in[b->in_pos] + 1) * 4; + + s->temp.size = s->block_header.size; + s->temp.pos = 0; + s->sequence = SEQ_BLOCK_HEADER; + + case SEQ_BLOCK_HEADER: + if (!fill_temp(s, b)) + return XZ_OK; + + ret = dec_block_header(s); + if (ret != XZ_OK) + return ret; + + s->sequence = SEQ_BLOCK_UNCOMPRESS; + + case SEQ_BLOCK_UNCOMPRESS: + ret = dec_block(s, b); + if (ret != XZ_STREAM_END) + return ret; + + s->sequence = SEQ_BLOCK_PADDING; + + case SEQ_BLOCK_PADDING: + /* + * Size of Compressed Data + Block Padding + * must be a multiple of four. We don't need + * s->block.compressed for anything else + * anymore, so we use it here to test the size + * of the Block Padding field. + */ + while (s->block.compressed & 3) { + if (b->in_pos == b->in_size) + return XZ_OK; + + if (b->in[b->in_pos++] != 0) + return XZ_DATA_ERROR; + + ++s->block.compressed; + } + + s->sequence = SEQ_BLOCK_CHECK; + + case SEQ_BLOCK_CHECK: + if (s->check_type == XZ_CHECK_CRC32) { + ret = crc32_validate(s, b); + if (ret != XZ_STREAM_END) + return ret; + } +#ifdef XZ_DEC_ANY_CHECK + else if (!check_skip(s, b)) { + return XZ_OK; + } +#endif + + s->sequence = SEQ_BLOCK_START; + break; + + case SEQ_INDEX: + ret = dec_index(s, b); + if (ret != XZ_STREAM_END) + return ret; + + s->sequence = SEQ_INDEX_PADDING; + + case SEQ_INDEX_PADDING: + while ((s->index.size + (b->in_pos - s->in_start)) + & 3) { + if (b->in_pos == b->in_size) { + index_update(s, b); + return XZ_OK; + } + + if (b->in[b->in_pos++] != 0) + return XZ_DATA_ERROR; + } + + /* Finish the CRC32 value and Index size. */ + index_update(s, b); + + /* Compare the hashes to validate the Index field. */ + if (!memeq(&s->block.hash, &s->index.hash, + sizeof(s->block.hash))) + return XZ_DATA_ERROR; + + s->sequence = SEQ_INDEX_CRC32; + + case SEQ_INDEX_CRC32: + ret = crc32_validate(s, b); + if (ret != XZ_STREAM_END) + return ret; + + s->temp.size = STREAM_HEADER_SIZE; + s->sequence = SEQ_STREAM_FOOTER; + + case SEQ_STREAM_FOOTER: + if (!fill_temp(s, b)) + return XZ_OK; + + return dec_stream_footer(s); + } + } + + /* Never reached */ +} + +/* + * xz_dec_run() is a wrapper for dec_main() to handle some special cases in + * multi-call and single-call decoding. + * + * In multi-call mode, we must return XZ_BUF_ERROR when it seems clear that we + * are not going to make any progress anymore. This is to prevent the caller + * from calling us infinitely when the input file is truncated or otherwise + * corrupt. Since zlib-style API allows that the caller fills the input buffer + * only when the decoder doesn't produce any new output, we have to be careful + * to avoid returning XZ_BUF_ERROR too easily: XZ_BUF_ERROR is returned only + * after the second consecutive call to xz_dec_run() that makes no progress. + * + * In single-call mode, if we couldn't decode everything and no error + * occurred, either the input is truncated or the output buffer is too small. + * Since we know that the last input byte never produces any output, we know + * that if all the input was consumed and decoding wasn't finished, the file + * must be corrupt. Otherwise the output buffer has to be too small or the + * file is corrupt in a way that decoding it produces too big output. + * + * If single-call decoding fails, we reset b->in_pos and b->out_pos back to + * their original values. This is because with some filter chains there won't + * be any valid uncompressed data in the output buffer unless the decoding + * actually succeeds (that's the price to pay of using the output buffer as + * the workspace). + */ +XZ_EXTERN enum xz_ret XZ_FUNC xz_dec_run(struct xz_dec *s, struct xz_buf *b) +{ + size_t in_start; + size_t out_start; + enum xz_ret ret; + + if (DEC_IS_SINGLE(s->mode)) + xz_dec_reset(s); + + in_start = b->in_pos; + out_start = b->out_pos; + ret = dec_main(s, b); + + if (DEC_IS_SINGLE(s->mode)) { + if (ret == XZ_OK) + ret = b->in_pos == b->in_size + ? XZ_DATA_ERROR : XZ_BUF_ERROR; + + if (ret != XZ_STREAM_END) { + b->in_pos = in_start; + b->out_pos = out_start; + } + + } else if (ret == XZ_OK && in_start == b->in_pos + && out_start == b->out_pos) { + if (s->allow_buf_error) + ret = XZ_BUF_ERROR; + + s->allow_buf_error = true; + } else { + s->allow_buf_error = false; + } + + return ret; +} + +XZ_EXTERN struct xz_dec * XZ_FUNC xz_dec_init( + enum xz_mode mode, uint32_t dict_max) +{ + struct xz_dec *s = kmalloc(sizeof(*s), GFP_KERNEL); + if (s == NULL) + return NULL; + + s->mode = mode; + +#ifdef XZ_DEC_BCJ + s->bcj = xz_dec_bcj_create(DEC_IS_SINGLE(mode)); + if (s->bcj == NULL) + goto error_bcj; +#endif + + s->lzma2 = xz_dec_lzma2_create(mode, dict_max); + if (s->lzma2 == NULL) + goto error_lzma2; + + xz_dec_reset(s); + return s; + +error_lzma2: +#ifdef XZ_DEC_BCJ + xz_dec_bcj_end(s->bcj); +error_bcj: +#endif + kfree(s); + return NULL; +} + +XZ_EXTERN void XZ_FUNC xz_dec_reset(struct xz_dec *s) +{ + s->sequence = SEQ_STREAM_HEADER; + s->allow_buf_error = false; + s->pos = 0; + s->crc32 = 0; + memzero(&s->block, sizeof(s->block)); + memzero(&s->index, sizeof(s->index)); + s->temp.pos = 0; + s->temp.size = STREAM_HEADER_SIZE; +} + +XZ_EXTERN void XZ_FUNC xz_dec_end(struct xz_dec *s) +{ + if (s != NULL) { + xz_dec_lzma2_end(s->lzma2); +#ifdef XZ_DEC_BCJ + xz_dec_bcj_end(s->bcj); +#endif + kfree(s); + } +} diff --git a/archival/libarchive/unxz/xz_lzma2.h b/archival/libarchive/unxz/xz_lzma2.h new file mode 100644 index 000000000..47f21afbc --- /dev/null +++ b/archival/libarchive/unxz/xz_lzma2.h @@ -0,0 +1,204 @@ +/* + * LZMA2 definitions + * + * Authors: Lasse Collin + * Igor Pavlov + * + * This file has been put into the public domain. + * You can do whatever you want with this file. + */ + +#ifndef XZ_LZMA2_H +#define XZ_LZMA2_H + +/* Range coder constants */ +#define RC_SHIFT_BITS 8 +#define RC_TOP_BITS 24 +#define RC_TOP_VALUE (1 << RC_TOP_BITS) +#define RC_BIT_MODEL_TOTAL_BITS 11 +#define RC_BIT_MODEL_TOTAL (1 << RC_BIT_MODEL_TOTAL_BITS) +#define RC_MOVE_BITS 5 + +/* + * Maximum number of position states. A position state is the lowest pb + * number of bits of the current uncompressed offset. In some places there + * are different sets of probabilities for different position states. + */ +#define POS_STATES_MAX (1 << 4) + +/* + * This enum is used to track which LZMA symbols have occurred most recently + * and in which order. This information is used to predict the next symbol. + * + * Symbols: + * - Literal: One 8-bit byte + * - Match: Repeat a chunk of data at some distance + * - Long repeat: Multi-byte match at a recently seen distance + * - Short repeat: One-byte repeat at a recently seen distance + * + * The symbol names are in from STATE_oldest_older_previous. REP means + * either short or long repeated match, and NONLIT means any non-literal. + */ +enum lzma_state { + STATE_LIT_LIT, + STATE_MATCH_LIT_LIT, + STATE_REP_LIT_LIT, + STATE_SHORTREP_LIT_LIT, + STATE_MATCH_LIT, + STATE_REP_LIT, + STATE_SHORTREP_LIT, + STATE_LIT_MATCH, + STATE_LIT_LONGREP, + STATE_LIT_SHORTREP, + STATE_NONLIT_MATCH, + STATE_NONLIT_REP +}; + +/* Total number of states */ +#define STATES 12 + +/* The lowest 7 states indicate that the previous state was a literal. */ +#define LIT_STATES 7 + +/* Indicate that the latest symbol was a literal. */ +static inline void XZ_FUNC lzma_state_literal(enum lzma_state *state) +{ + if (*state <= STATE_SHORTREP_LIT_LIT) + *state = STATE_LIT_LIT; + else if (*state <= STATE_LIT_SHORTREP) + *state -= 3; + else + *state -= 6; +} + +/* Indicate that the latest symbol was a match. */ +static inline void XZ_FUNC lzma_state_match(enum lzma_state *state) +{ + *state = *state < LIT_STATES ? STATE_LIT_MATCH : STATE_NONLIT_MATCH; +} + +/* Indicate that the latest state was a long repeated match. */ +static inline void XZ_FUNC lzma_state_long_rep(enum lzma_state *state) +{ + *state = *state < LIT_STATES ? STATE_LIT_LONGREP : STATE_NONLIT_REP; +} + +/* Indicate that the latest symbol was a short match. */ +static inline void XZ_FUNC lzma_state_short_rep(enum lzma_state *state) +{ + *state = *state < LIT_STATES ? STATE_LIT_SHORTREP : STATE_NONLIT_REP; +} + +/* Test if the previous symbol was a literal. */ +static inline bool XZ_FUNC lzma_state_is_literal(enum lzma_state state) +{ + return state < LIT_STATES; +} + +/* Each literal coder is divided in three sections: + * - 0x001-0x0FF: Without match byte + * - 0x101-0x1FF: With match byte; match bit is 0 + * - 0x201-0x2FF: With match byte; match bit is 1 + * + * Match byte is used when the previous LZMA symbol was something else than + * a literal (that is, it was some kind of match). + */ +#define LITERAL_CODER_SIZE 0x300 + +/* Maximum number of literal coders */ +#define LITERAL_CODERS_MAX (1 << 4) + +/* Minimum length of a match is two bytes. */ +#define MATCH_LEN_MIN 2 + +/* Match length is encoded with 4, 5, or 10 bits. + * + * Length Bits + * 2-9 4 = Choice=0 + 3 bits + * 10-17 5 = Choice=1 + Choice2=0 + 3 bits + * 18-273 10 = Choice=1 + Choice2=1 + 8 bits + */ +#define LEN_LOW_BITS 3 +#define LEN_LOW_SYMBOLS (1 << LEN_LOW_BITS) +#define LEN_MID_BITS 3 +#define LEN_MID_SYMBOLS (1 << LEN_MID_BITS) +#define LEN_HIGH_BITS 8 +#define LEN_HIGH_SYMBOLS (1 << LEN_HIGH_BITS) +#define LEN_SYMBOLS (LEN_LOW_SYMBOLS + LEN_MID_SYMBOLS + LEN_HIGH_SYMBOLS) + +/* + * Maximum length of a match is 273 which is a result of the encoding + * described above. + */ +#define MATCH_LEN_MAX (MATCH_LEN_MIN + LEN_SYMBOLS - 1) + +/* + * Different sets of probabilities are used for match distances that have + * very short match length: Lengths of 2, 3, and 4 bytes have a separate + * set of probabilities for each length. The matches with longer length + * use a shared set of probabilities. + */ +#define DIST_STATES 4 + +/* + * Get the index of the appropriate probability array for decoding + * the distance slot. + */ +static inline uint32_t XZ_FUNC lzma_get_dist_state(uint32_t len) +{ + return len < DIST_STATES + MATCH_LEN_MIN + ? len - MATCH_LEN_MIN : DIST_STATES - 1; +} + +/* + * The highest two bits of a 32-bit match distance are encoded using six bits. + * This six-bit value is called a distance slot. This way encoding a 32-bit + * value takes 6-36 bits, larger values taking more bits. + */ +#define DIST_SLOT_BITS 6 +#define DIST_SLOTS (1 << DIST_SLOT_BITS) + +/* Match distances up to 127 are fully encoded using probabilities. Since + * the highest two bits (distance slot) are always encoded using six bits, + * the distances 0-3 don't need any additional bits to encode, since the + * distance slot itself is the same as the actual distance. DIST_MODEL_START + * indicates the first distance slot where at least one additional bit is + * needed. + */ +#define DIST_MODEL_START 4 + +/* + * Match distances greater than 127 are encoded in three pieces: + * - distance slot: the highest two bits + * - direct bits: 2-26 bits below the highest two bits + * - alignment bits: four lowest bits + * + * Direct bits don't use any probabilities. + * + * The distance slot value of 14 is for distances 128-191. + */ +#define DIST_MODEL_END 14 + +/* Distance slots that indicate a distance <= 127. */ +#define FULL_DISTANCES_BITS (DIST_MODEL_END / 2) +#define FULL_DISTANCES (1 << FULL_DISTANCES_BITS) + +/* + * For match distances greater than 127, only the highest two bits and the + * lowest four bits (alignment) is encoded using probabilities. + */ +#define ALIGN_BITS 4 +#define ALIGN_SIZE (1 << ALIGN_BITS) +#define ALIGN_MASK (ALIGN_SIZE - 1) + +/* Total number of all probability variables */ +#define PROBS_TOTAL (1846 + LITERAL_CODERS_MAX * LITERAL_CODER_SIZE) + +/* + * LZMA remembers the four most recent match distances. Reusing these + * distances tends to take less space than re-encoding the actual + * distance value. + */ +#define REPS 4 + +#endif diff --git a/archival/libarchive/unxz/xz_private.h b/archival/libarchive/unxz/xz_private.h new file mode 100644 index 000000000..145649a83 --- /dev/null +++ b/archival/libarchive/unxz/xz_private.h @@ -0,0 +1,159 @@ +/* + * Private includes and definitions + * + * Author: Lasse Collin + * + * This file has been put into the public domain. + * You can do whatever you want with this file. + */ + +#ifndef XZ_PRIVATE_H +#define XZ_PRIVATE_H + +#ifdef __KERNEL__ + /* XZ_PREBOOT may be defined only via decompress_unxz.c. */ +# ifndef XZ_PREBOOT +# include +# include +# include +# define memeq(a, b, size) (memcmp(a, b, size) == 0) +# define memzero(buf, size) memset(buf, 0, size) +# endif +# include +# include +# define get_le32(p) le32_to_cpup((const uint32_t *)(p)) + /* XZ_IGNORE_KCONFIG may be defined only via decompress_unxz.c. */ +# ifndef XZ_IGNORE_KCONFIG +# ifdef CONFIG_XZ_DEC_X86 +# define XZ_DEC_X86 +# endif +# ifdef CONFIG_XZ_DEC_POWERPC +# define XZ_DEC_POWERPC +# endif +# ifdef CONFIG_XZ_DEC_IA64 +# define XZ_DEC_IA64 +# endif +# ifdef CONFIG_XZ_DEC_ARM +# define XZ_DEC_ARM +# endif +# ifdef CONFIG_XZ_DEC_ARMTHUMB +# define XZ_DEC_ARMTHUMB +# endif +# ifdef CONFIG_XZ_DEC_SPARC +# define XZ_DEC_SPARC +# endif +# endif +# include +#else + /* + * For userspace builds, use a separate header to define the required + * macros and functions. This makes it easier to adapt the code into + * different environments and avoids clutter in the Linux kernel tree. + */ +# include "xz_config.h" +#endif + +/* If no specific decoding mode is requested, enable support for all modes. */ +#if !defined(XZ_DEC_SINGLE) && !defined(XZ_DEC_PREALLOC) \ + && !defined(XZ_DEC_DYNALLOC) +# define XZ_DEC_SINGLE +# define XZ_DEC_PREALLOC +# define XZ_DEC_DYNALLOC +#endif + +/* + * The DEC_IS_foo(mode) macros are used in "if" statements. If only some + * of the supported modes are enabled, these macros will evaluate to true or + * false at compile time and thus allow the compiler to omit unneeded code. + */ +#ifdef XZ_DEC_SINGLE +# define DEC_IS_SINGLE(mode) ((mode) == XZ_SINGLE) +#else +# define DEC_IS_SINGLE(mode) (false) +#endif + +#ifdef XZ_DEC_PREALLOC +# define DEC_IS_PREALLOC(mode) ((mode) == XZ_PREALLOC) +#else +# define DEC_IS_PREALLOC(mode) (false) +#endif + +#ifdef XZ_DEC_DYNALLOC +# define DEC_IS_DYNALLOC(mode) ((mode) == XZ_DYNALLOC) +#else +# define DEC_IS_DYNALLOC(mode) (false) +#endif + +#if !defined(XZ_DEC_SINGLE) +# define DEC_IS_MULTI(mode) (true) +#elif defined(XZ_DEC_PREALLOC) || defined(XZ_DEC_DYNALLOC) +# define DEC_IS_MULTI(mode) ((mode) != XZ_SINGLE) +#else +# define DEC_IS_MULTI(mode) (false) +#endif + +/* + * If any of the BCJ filter decoders are wanted, define XZ_DEC_BCJ. + * XZ_DEC_BCJ is used to enable generic support for BCJ decoders. + */ +#ifndef XZ_DEC_BCJ +# if defined(XZ_DEC_X86) || defined(XZ_DEC_POWERPC) \ + || defined(XZ_DEC_IA64) || defined(XZ_DEC_ARM) \ + || defined(XZ_DEC_ARM) || defined(XZ_DEC_ARMTHUMB) \ + || defined(XZ_DEC_SPARC) +# define XZ_DEC_BCJ +# endif +#endif + +/* + * Allocate memory for LZMA2 decoder. xz_dec_lzma2_reset() must be used + * before calling xz_dec_lzma2_run(). + */ +XZ_EXTERN struct xz_dec_lzma2 * XZ_FUNC xz_dec_lzma2_create( + enum xz_mode mode, uint32_t dict_max); + +/* + * Decode the LZMA2 properties (one byte) and reset the decoder. Return + * XZ_OK on success, XZ_MEMLIMIT_ERROR if the preallocated dictionary is not + * big enough, and XZ_OPTIONS_ERROR if props indicates something that this + * decoder doesn't support. + */ +XZ_EXTERN enum xz_ret XZ_FUNC xz_dec_lzma2_reset( + struct xz_dec_lzma2 *s, uint8_t props); + +/* Decode raw LZMA2 stream from b->in to b->out. */ +XZ_EXTERN enum xz_ret XZ_FUNC xz_dec_lzma2_run( + struct xz_dec_lzma2 *s, struct xz_buf *b); + +/* Free the memory allocated for the LZMA2 decoder. */ +XZ_EXTERN void XZ_FUNC xz_dec_lzma2_end(struct xz_dec_lzma2 *s); + +#ifdef XZ_DEC_BCJ +/* + * Allocate memory for BCJ decoders. xz_dec_bcj_reset() must be used before + * calling xz_dec_bcj_run(). + */ +XZ_EXTERN struct xz_dec_bcj * XZ_FUNC xz_dec_bcj_create(bool single_call); + +/* + * Decode the Filter ID of a BCJ filter. This implementation doesn't + * support custom start offsets, so no decoding of Filter Properties + * is needed. Returns XZ_OK if the given Filter ID is supported. + * Otherwise XZ_OPTIONS_ERROR is returned. + */ +XZ_EXTERN enum xz_ret XZ_FUNC xz_dec_bcj_reset( + struct xz_dec_bcj *s, uint8_t id); + +/* + * Decode raw BCJ + LZMA2 stream. This must be used only if there actually is + * a BCJ filter in the chain. If the chain has only LZMA2, xz_dec_lzma2_run() + * must be called directly. + */ +XZ_EXTERN enum xz_ret XZ_FUNC xz_dec_bcj_run(struct xz_dec_bcj *s, + struct xz_dec_lzma2 *lzma2, struct xz_buf *b); + +/* Free the memory allocated for the BCJ filters. */ +#define xz_dec_bcj_end(s) kfree(s) +#endif + +#endif diff --git a/archival/libarchive/unxz/xz_stream.h b/archival/libarchive/unxz/xz_stream.h new file mode 100644 index 000000000..36f2a7cbf --- /dev/null +++ b/archival/libarchive/unxz/xz_stream.h @@ -0,0 +1,57 @@ +/* + * Definitions for handling the .xz file format + * + * Author: Lasse Collin + * + * This file has been put into the public domain. + * You can do whatever you want with this file. + */ + +#ifndef XZ_STREAM_H +#define XZ_STREAM_H + +#if defined(__KERNEL__) && !XZ_INTERNAL_CRC32 +# include +# undef crc32 +# define xz_crc32(buf, size, crc) \ + (~crc32_le(~(uint32_t)(crc), buf, size)) +#endif + +/* + * See the .xz file format specification at + * http://tukaani.org/xz/xz-file-format.txt + * to understand the container format. + */ + +#define STREAM_HEADER_SIZE 12 + +#define HEADER_MAGIC "\3757zXZ\0" +#define HEADER_MAGIC_SIZE 6 + +#define FOOTER_MAGIC "YZ" +#define FOOTER_MAGIC_SIZE 2 + +/* + * Variable-length integer can hold a 63-bit unsigned integer, or a special + * value to indicate that the value is unknown. + */ +typedef uint64_t vli_type; + +#define VLI_MAX ((vli_type)-1 / 2) +#define VLI_UNKNOWN ((vli_type)-1) + +/* Maximum encoded size of a VLI */ +#define VLI_BYTES_MAX (sizeof(vli_type) * 8 / 7) + +/* Integrity Check types */ +enum xz_check { + XZ_CHECK_NONE = 0, + XZ_CHECK_CRC32 = 1, + XZ_CHECK_CRC64 = 4, + XZ_CHECK_SHA256 = 10 +}; + +/* Maximum possible Check ID */ +#define XZ_CHECK_MAX 15 + +#endif diff --git a/archival/libunarchive/Kbuild.src b/archival/libunarchive/Kbuild.src deleted file mode 100644 index b0bc4e5aa..000000000 --- a/archival/libunarchive/Kbuild.src +++ /dev/null @@ -1,64 +0,0 @@ -# Makefile for busybox -# -# Copyright (C) 1999-2004 by Erik Andersen -# -# Licensed under GPLv2 or later, see file LICENSE in this source tree. - -lib-y:= - -COMMON_FILES:= \ -\ - data_skip.o \ - data_extract_all.o \ - data_extract_to_stdout.o \ -\ - filter_accept_all.o \ - filter_accept_list.o \ - filter_accept_reject_list.o \ -\ - header_skip.o \ - header_list.o \ - header_verbose_list.o \ -\ - seek_by_read.o \ - seek_by_jump.o \ -\ - data_align.o \ - find_list_entry.o \ - init_handle.o - -DPKG_FILES:= \ - get_header_ar.o \ - unpack_ar_archive.o \ - get_header_tar.o \ - filter_accept_list_reassign.o - -INSERT - -lib-$(CONFIG_AR) += get_header_ar.o unpack_ar_archive.o -lib-$(CONFIG_BUNZIP2) += decompress_bunzip2.o -lib-$(CONFIG_UNLZMA) += decompress_unlzma.o -lib-$(CONFIG_UNXZ) += decompress_unxz.o -lib-$(CONFIG_CPIO) += get_header_cpio.o -lib-$(CONFIG_DPKG) += $(DPKG_FILES) -lib-$(CONFIG_DPKG_DEB) += $(DPKG_FILES) -lib-$(CONFIG_GUNZIP) += decompress_unzip.o -lib-$(CONFIG_RPM2CPIO) += decompress_unzip.o get_header_cpio.o -lib-$(CONFIG_RPM) += open_transformer.o decompress_unzip.o get_header_cpio.o -lib-$(CONFIG_TAR) += get_header_tar.o -lib-$(CONFIG_UNCOMPRESS) += decompress_uncompress.o -lib-$(CONFIG_UNZIP) += decompress_unzip.o -lib-$(CONFIG_LZOP) += lzo1x_1.o lzo1x_1o.o lzo1x_d.o -lib-$(CONFIG_LZOP_COMPR_HIGH) += lzo1x_9x.o -lib-$(CONFIG_FEATURE_SEAMLESS_Z) += open_transformer.o decompress_uncompress.o -lib-$(CONFIG_FEATURE_SEAMLESS_GZ) += open_transformer.o decompress_unzip.o get_header_tar_gz.o -lib-$(CONFIG_FEATURE_SEAMLESS_BZ2) += open_transformer.o decompress_bunzip2.o get_header_tar_bz2.o -lib-$(CONFIG_FEATURE_SEAMLESS_LZMA) += open_transformer.o decompress_unlzma.o get_header_tar_lzma.o -lib-$(CONFIG_FEATURE_SEAMLESS_XZ) += open_transformer.o decompress_unxz.o -lib-$(CONFIG_FEATURE_COMPRESS_USAGE) += decompress_bunzip2.o -lib-$(CONFIG_FEATURE_COMPRESS_BBCONFIG) += decompress_bunzip2.o -lib-$(CONFIG_FEATURE_TAR_TO_COMMAND) += data_extract_to_command.o - -ifneq ($(lib-y),) -lib-y += $(COMMON_FILES) -endif diff --git a/archival/libunarchive/data_align.c b/archival/libunarchive/data_align.c deleted file mode 100644 index 4e21a36b3..000000000 --- a/archival/libunarchive/data_align.c +++ /dev/null @@ -1,15 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Licensed under GPLv2 or later, see file LICENSE in this source tree. - */ - -#include "libbb.h" -#include "unarchive.h" - -void FAST_FUNC data_align(archive_handle_t *archive_handle, unsigned boundary) -{ - unsigned skip_amount = (boundary - (archive_handle->offset % boundary)) % boundary; - - archive_handle->seek(archive_handle->src_fd, skip_amount); - archive_handle->offset += skip_amount; -} diff --git a/archival/libunarchive/data_extract_all.c b/archival/libunarchive/data_extract_all.c deleted file mode 100644 index 5fb1ab2ae..000000000 --- a/archival/libunarchive/data_extract_all.c +++ /dev/null @@ -1,200 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Licensed under GPLv2 or later, see file LICENSE in this source tree. - */ - -#include "libbb.h" -#include "unarchive.h" - -void FAST_FUNC data_extract_all(archive_handle_t *archive_handle) -{ - file_header_t *file_header = archive_handle->file_header; - int dst_fd; - int res; - -#if ENABLE_FEATURE_TAR_SELINUX - char *sctx = archive_handle->tar__next_file_sctx; - if (!sctx) - sctx = archive_handle->tar__global_sctx; - if (sctx) { /* setfscreatecon is 4 syscalls, avoid if possible */ - setfscreatecon(sctx); - free(archive_handle->tar__next_file_sctx); - archive_handle->tar__next_file_sctx = NULL; - } -#endif - - if (archive_handle->ah_flags & ARCHIVE_CREATE_LEADING_DIRS) { - char *slash = strrchr(file_header->name, '/'); - if (slash) { - *slash = '\0'; - bb_make_directory(file_header->name, -1, FILEUTILS_RECUR); - *slash = '/'; - } - } - - if (archive_handle->ah_flags & ARCHIVE_UNLINK_OLD) { - /* Remove the entry if it exists */ - if (!S_ISDIR(file_header->mode)) { - /* Is it hardlink? - * We encode hard links as regular files of size 0 with a symlink */ - if (S_ISREG(file_header->mode) - && file_header->link_target - && file_header->size == 0 - ) { - /* Ugly special case: - * tar cf t.tar hardlink1 hardlink2 hardlink1 - * results in this tarball structure: - * hardlink1 - * hardlink2 -> hardlink1 - * hardlink1 -> hardlink1 <== !!! - */ - if (strcmp(file_header->link_target, file_header->name) == 0) - goto ret; - } - /* Proceed with deleting */ - if (unlink(file_header->name) == -1 - && errno != ENOENT - ) { - bb_perror_msg_and_die("can't remove old file %s", - file_header->name); - } - } - } - else if (archive_handle->ah_flags & ARCHIVE_EXTRACT_NEWER) { - /* Remove the existing entry if its older than the extracted entry */ - struct stat existing_sb; - if (lstat(file_header->name, &existing_sb) == -1) { - if (errno != ENOENT) { - bb_perror_msg_and_die("can't stat old file"); - } - } - else if (existing_sb.st_mtime >= file_header->mtime) { - if (!(archive_handle->ah_flags & ARCHIVE_EXTRACT_QUIET) - && !S_ISDIR(file_header->mode) - ) { - bb_error_msg("%s not created: newer or " - "same age file exists", file_header->name); - } - data_skip(archive_handle); - goto ret; - } - else if ((unlink(file_header->name) == -1) && (errno != EISDIR)) { - bb_perror_msg_and_die("can't remove old file %s", - file_header->name); - } - } - - /* Handle hard links separately - * We encode hard links as regular files of size 0 with a symlink */ - if (S_ISREG(file_header->mode) - && file_header->link_target - && file_header->size == 0 - ) { - /* hard link */ - res = link(file_header->link_target, file_header->name); - if ((res == -1) && !(archive_handle->ah_flags & ARCHIVE_EXTRACT_QUIET)) { - bb_perror_msg("can't create %slink " - "from %s to %s", "hard", - file_header->name, - file_header->link_target); - } - /* Hardlinks have no separate mode/ownership, skip chown/chmod */ - goto ret; - } - - /* Create the filesystem entry */ - switch (file_header->mode & S_IFMT) { - case S_IFREG: { - /* Regular file */ - int flags = O_WRONLY | O_CREAT | O_EXCL; - if (archive_handle->ah_flags & ARCHIVE_O_TRUNC) - flags = O_WRONLY | O_CREAT | O_TRUNC; - dst_fd = xopen3(file_header->name, - flags, - file_header->mode - ); - bb_copyfd_exact_size(archive_handle->src_fd, dst_fd, file_header->size); - close(dst_fd); - break; - } - case S_IFDIR: - res = mkdir(file_header->name, file_header->mode); - if ((res == -1) - && (errno != EISDIR) /* btw, Linux doesn't return this */ - && (errno != EEXIST) - && !(archive_handle->ah_flags & ARCHIVE_EXTRACT_QUIET) - ) { - bb_perror_msg("can't make dir %s", file_header->name); - } - break; - case S_IFLNK: - /* Symlink */ -//TODO: what if file_header->link_target == NULL (say, corrupted tarball?) - res = symlink(file_header->link_target, file_header->name); - if ((res == -1) - && !(archive_handle->ah_flags & ARCHIVE_EXTRACT_QUIET) - ) { - bb_perror_msg("can't create %slink " - "from %s to %s", "sym", - file_header->name, - file_header->link_target); - } - break; - case S_IFSOCK: - case S_IFBLK: - case S_IFCHR: - case S_IFIFO: - res = mknod(file_header->name, file_header->mode, file_header->device); - if ((res == -1) - && !(archive_handle->ah_flags & ARCHIVE_EXTRACT_QUIET) - ) { - bb_perror_msg("can't create node %s", file_header->name); - } - break; - default: - bb_error_msg_and_die("unrecognized file type"); - } - - if (!S_ISLNK(file_header->mode)) { - if (!(archive_handle->ah_flags & ARCHIVE_DONT_RESTORE_OWNER)) { - uid_t uid = file_header->uid; - gid_t gid = file_header->gid; -#if ENABLE_FEATURE_TAR_UNAME_GNAME - if (!(archive_handle->ah_flags & ARCHIVE_NUMERIC_OWNER)) { - if (file_header->tar__uname) { -//TODO: cache last name/id pair? - struct passwd *pwd = getpwnam(file_header->tar__uname); - if (pwd) uid = pwd->pw_uid; - } - if (file_header->tar__gname) { - struct group *grp = getgrnam(file_header->tar__gname); - if (grp) gid = grp->gr_gid; - } - } -#endif - /* GNU tar 1.15.1 uses chown, not lchown */ - chown(file_header->name, uid, gid); - } - /* uclibc has no lchmod, glibc is even stranger - - * it has lchmod which seems to do nothing! - * so we use chmod... */ - if (!(archive_handle->ah_flags & ARCHIVE_DONT_RESTORE_PERM)) { - chmod(file_header->name, file_header->mode); - } - if (archive_handle->ah_flags & ARCHIVE_RESTORE_DATE) { - struct timeval t[2]; - - t[1].tv_sec = t[0].tv_sec = file_header->mtime; - t[1].tv_usec = t[0].tv_usec = 0; - utimes(file_header->name, t); - } - } - - ret: ; -#if ENABLE_FEATURE_TAR_SELINUX - if (sctx) { - /* reset the context after creating an entry */ - setfscreatecon(NULL); - } -#endif -} diff --git a/archival/libunarchive/data_extract_to_command.c b/archival/libunarchive/data_extract_to_command.c deleted file mode 100644 index b54f7f215..000000000 --- a/archival/libunarchive/data_extract_to_command.c +++ /dev/null @@ -1,134 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Licensed under GPLv2 or later, see file LICENSE in this source tree. - */ - -#include "libbb.h" -#include "unarchive.h" - -enum { - //TAR_FILETYPE, - TAR_MODE, - TAR_FILENAME, - TAR_REALNAME, -#if ENABLE_FEATURE_TAR_UNAME_GNAME - TAR_UNAME, - TAR_GNAME, -#endif - TAR_SIZE, - TAR_UID, - TAR_GID, - TAR_MAX, -}; - -static const char *const tar_var[] = { - // "FILETYPE", - "MODE", - "FILENAME", - "REALNAME", -#if ENABLE_FEATURE_TAR_UNAME_GNAME - "UNAME", - "GNAME", -#endif - "SIZE", - "UID", - "GID", -}; - -static void xputenv(char *str) -{ - if (putenv(str)) - bb_error_msg_and_die(bb_msg_memory_exhausted); -} - -static void str2env(char *env[], int idx, const char *str) -{ - env[idx] = xasprintf("TAR_%s=%s", tar_var[idx], str); - xputenv(env[idx]); -} - -static void dec2env(char *env[], int idx, unsigned long long val) -{ - env[idx] = xasprintf("TAR_%s=%llu", tar_var[idx], val); - xputenv(env[idx]); -} - -static void oct2env(char *env[], int idx, unsigned long val) -{ - env[idx] = xasprintf("TAR_%s=%lo", tar_var[idx], val); - xputenv(env[idx]); -} - -void FAST_FUNC data_extract_to_command(archive_handle_t *archive_handle) -{ - file_header_t *file_header = archive_handle->file_header; - -#if 0 /* do we need this? ENABLE_FEATURE_TAR_SELINUX */ - char *sctx = archive_handle->tar__next_file_sctx; - if (!sctx) - sctx = archive_handle->tar__global_sctx; - if (sctx) { /* setfscreatecon is 4 syscalls, avoid if possible */ - setfscreatecon(sctx); - free(archive_handle->tar__next_file_sctx); - archive_handle->tar__next_file_sctx = NULL; - } -#endif - - if ((file_header->mode & S_IFMT) == S_IFREG) { - pid_t pid; - int p[2], status; - char *tar_env[TAR_MAX]; - - memset(tar_env, 0, sizeof(tar_env)); - - xpipe(p); - pid = BB_MMU ? xfork() : xvfork(); - if (pid == 0) { - /* Child */ - /* str2env(tar_env, TAR_FILETYPE, "f"); - parent should do it once */ - oct2env(tar_env, TAR_MODE, file_header->mode); - str2env(tar_env, TAR_FILENAME, file_header->name); - str2env(tar_env, TAR_REALNAME, file_header->name); -#if ENABLE_FEATURE_TAR_UNAME_GNAME - str2env(tar_env, TAR_UNAME, file_header->tar__uname); - str2env(tar_env, TAR_GNAME, file_header->tar__gname); -#endif - dec2env(tar_env, TAR_SIZE, file_header->size); - dec2env(tar_env, TAR_UID, file_header->uid); - dec2env(tar_env, TAR_GID, file_header->gid); - close(p[1]); - xdup2(p[0], STDIN_FILENO); - signal(SIGPIPE, SIG_DFL); - execl(DEFAULT_SHELL, DEFAULT_SHELL_SHORT_NAME, "-c", archive_handle->tar__to_command, NULL); - bb_perror_msg_and_die("can't execute '%s'", DEFAULT_SHELL); - } - close(p[0]); - /* Our caller is expected to do signal(SIGPIPE, SIG_IGN) - * so that we don't die if child don't read all the input: */ - bb_copyfd_exact_size(archive_handle->src_fd, p[1], -file_header->size); - close(p[1]); - - if (safe_waitpid(pid, &status, 0) == -1) - bb_perror_msg_and_die("waitpid"); - if (WIFEXITED(status) && WEXITSTATUS(status)) - bb_error_msg_and_die("'%s' returned status %d", - archive_handle->tar__to_command, WEXITSTATUS(status)); - if (WIFSIGNALED(status)) - bb_error_msg_and_die("'%s' terminated on signal %d", - archive_handle->tar__to_command, WTERMSIG(status)); - - if (!BB_MMU) { - int i; - for (i = 0; i < TAR_MAX; i++) { - if (tar_env[i]) - bb_unsetenv_and_free(tar_env[i]); - } - } - } - -#if 0 /* ENABLE_FEATURE_TAR_SELINUX */ - if (sctx) - /* reset the context after creating an entry */ - setfscreatecon(NULL); -#endif -} diff --git a/archival/libunarchive/data_extract_to_stdout.c b/archival/libunarchive/data_extract_to_stdout.c deleted file mode 100644 index ce0713ac4..000000000 --- a/archival/libunarchive/data_extract_to_stdout.c +++ /dev/null @@ -1,14 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Licensed under GPLv2 or later, see file LICENSE in this source tree. - */ - -#include "libbb.h" -#include "unarchive.h" - -void FAST_FUNC data_extract_to_stdout(archive_handle_t *archive_handle) -{ - bb_copyfd_exact_size(archive_handle->src_fd, - STDOUT_FILENO, - archive_handle->file_header->size); -} diff --git a/archival/libunarchive/data_skip.c b/archival/libunarchive/data_skip.c deleted file mode 100644 index 06b74399d..000000000 --- a/archival/libunarchive/data_skip.c +++ /dev/null @@ -1,12 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Licensed under GPLv2 or later, see file LICENSE in this source tree. - */ - -#include "libbb.h" -#include "unarchive.h" - -void FAST_FUNC data_skip(archive_handle_t *archive_handle) -{ - archive_handle->seek(archive_handle->src_fd, archive_handle->file_header->size); -} diff --git a/archival/libunarchive/decompress_bunzip2.c b/archival/libunarchive/decompress_bunzip2.c deleted file mode 100644 index 15f08a60e..000000000 --- a/archival/libunarchive/decompress_bunzip2.c +++ /dev/null @@ -1,822 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* Small bzip2 deflate implementation, by Rob Landley (rob@landley.net). - - Based on bzip2 decompression code by Julian R Seward (jseward@acm.org), - which also acknowledges contributions by Mike Burrows, David Wheeler, - Peter Fenwick, Alistair Moffat, Radford Neal, Ian H. Witten, - Robert Sedgewick, and Jon L. Bentley. - - Licensed under GPLv2 or later, see file LICENSE in this source tree. -*/ - -/* - Size and speed optimizations by Manuel Novoa III (mjn3@codepoet.org). - - More efficient reading of Huffman codes, a streamlined read_bunzip() - function, and various other tweaks. In (limited) tests, approximately - 20% faster than bzcat on x86 and about 10% faster on arm. - - Note that about 2/3 of the time is spent in read_bunzip() reversing - the Burrows-Wheeler transformation. Much of that time is delay - resulting from cache misses. - - (2010 update by vda: profiled "bzcat <84mbyte.bz2 >/dev/null" - on x86-64 CPU with L2 > 1M: get_next_block is hotter than read_bunzip: - %time seconds calls function - 71.01 12.69 444 get_next_block - 28.65 5.12 93065 read_bunzip - 00.22 0.04 7736490 get_bits - 00.11 0.02 47 dealloc_bunzip - 00.00 0.00 93018 full_write - ...) - - - I would ask that anyone benefiting from this work, especially those - using it in commercial products, consider making a donation to my local - non-profit hospice organization (www.hospiceacadiana.com) in the name of - the woman I loved, Toni W. Hagan, who passed away Feb. 12, 2003. - - Manuel - */ - -#include "libbb.h" -#include "unarchive.h" - -/* Constants for Huffman coding */ -#define MAX_GROUPS 6 -#define GROUP_SIZE 50 /* 64 would have been more efficient */ -#define MAX_HUFCODE_BITS 20 /* Longest Huffman code allowed */ -#define MAX_SYMBOLS 258 /* 256 literals + RUNA + RUNB */ -#define SYMBOL_RUNA 0 -#define SYMBOL_RUNB 1 - -/* Status return values */ -#define RETVAL_OK 0 -#define RETVAL_LAST_BLOCK (-1) -#define RETVAL_NOT_BZIP_DATA (-2) -#define RETVAL_UNEXPECTED_INPUT_EOF (-3) -#define RETVAL_SHORT_WRITE (-4) -#define RETVAL_DATA_ERROR (-5) -#define RETVAL_OUT_OF_MEMORY (-6) -#define RETVAL_OBSOLETE_INPUT (-7) - -/* Other housekeeping constants */ -#define IOBUF_SIZE 4096 - -/* This is what we know about each Huffman coding group */ -struct group_data { - /* We have an extra slot at the end of limit[] for a sentinel value. */ - int limit[MAX_HUFCODE_BITS+1], base[MAX_HUFCODE_BITS], permute[MAX_SYMBOLS]; - int minLen, maxLen; -}; - -/* Structure holding all the housekeeping data, including IO buffers and - * memory that persists between calls to bunzip - * Found the most used member: - * cat this_file.c | sed -e 's/"/ /g' -e "s/'/ /g" | xargs -n1 \ - * | grep 'bd->' | sed 's/^.*bd->/bd->/' | sort | $PAGER - * and moved it (inbufBitCount) to offset 0. - */ -struct bunzip_data { - /* I/O tracking data (file handles, buffers, positions, etc.) */ - unsigned inbufBitCount, inbufBits; - int in_fd, out_fd, inbufCount, inbufPos /*, outbufPos*/; - uint8_t *inbuf /*,*outbuf*/; - - /* State for interrupting output loop */ - int writeCopies, writePos, writeRunCountdown, writeCount; - int writeCurrent; /* actually a uint8_t */ - - /* The CRC values stored in the block header and calculated from the data */ - uint32_t headerCRC, totalCRC, writeCRC; - - /* Intermediate buffer and its size (in bytes) */ - uint32_t *dbuf; - unsigned dbufSize; - - /* For I/O error handling */ - jmp_buf jmpbuf; - - /* Big things go last (register-relative addressing can be larger for big offsets) */ - uint32_t crc32Table[256]; - 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 */ - - -/* Return the next nnn bits of input. All reads from the compressed input - are done through this function. All reads are big endian */ -static unsigned get_bits(bunzip_data *bd, int bits_wanted) -{ - unsigned bits = 0; - /* Cache bd->inbufBitCount in a CPU register (hopefully): */ - int bit_count = bd->inbufBitCount; - - /* If we need to get more data from the byte buffer, do so. (Loop getting - one byte at a time to enforce endianness and avoid unaligned access.) */ - while (bit_count < bits_wanted) { - - /* If we need to read more data from file into byte buffer, do so */ - if (bd->inbufPos == bd->inbufCount) { - /* if "no input fd" case: in_fd == -1, read fails, we jump */ - bd->inbufCount = read(bd->in_fd, bd->inbuf, IOBUF_SIZE); - if (bd->inbufCount <= 0) - longjmp(bd->jmpbuf, RETVAL_UNEXPECTED_INPUT_EOF); - bd->inbufPos = 0; - } - - /* Avoid 32-bit overflow (dump bit buffer to top of output) */ - if (bit_count >= 24) { - bits = bd->inbufBits & ((1 << bit_count) - 1); - bits_wanted -= bit_count; - bits <<= bits_wanted; - bit_count = 0; - } - - /* Grab next 8 bits of input from buffer. */ - bd->inbufBits = (bd->inbufBits << 8) | bd->inbuf[bd->inbufPos++]; - bit_count += 8; - } - - /* Calculate result */ - bit_count -= bits_wanted; - bd->inbufBitCount = bit_count; - bits |= (bd->inbufBits >> bit_count) & ((1 << bits_wanted) - 1); - - return bits; -} - -/* Unpacks the next block and sets up for the inverse Burrows-Wheeler step. */ -static int get_next_block(bunzip_data *bd) -{ - struct group_data *hufGroup; - int dbufCount, dbufSize, groupCount, *base, *limit, selector, - i, j, t, runPos, symCount, symTotal, nSelectors, byteCount[256]; - int runCnt = runCnt; /* for compiler */ - uint8_t uc, symToByte[256], mtfSymbol[256], *selectors; - uint32_t *dbuf; - unsigned origPtr; - - dbuf = bd->dbuf; - dbufSize = bd->dbufSize; - selectors = bd->selectors; - -/* In bbox, we are ok with aborting through setjmp which is set up in start_bunzip */ -#if 0 - /* Reset longjmp I/O error handling */ - i = setjmp(bd->jmpbuf); - if (i) return i; -#endif - - /* Read in header signature and CRC, then validate signature. - (last block signature means CRC is for whole file, return now) */ - i = get_bits(bd, 24); - j = get_bits(bd, 24); - bd->headerCRC = get_bits(bd, 32); - if ((i == 0x177245) && (j == 0x385090)) return RETVAL_LAST_BLOCK; - if ((i != 0x314159) || (j != 0x265359)) return RETVAL_NOT_BZIP_DATA; - - /* We can add support for blockRandomised if anybody complains. There was - some code for this in busybox 1.0.0-pre3, but nobody ever noticed that - it didn't actually work. */ - if (get_bits(bd, 1)) return RETVAL_OBSOLETE_INPUT; - origPtr = get_bits(bd, 24); - if ((int)origPtr > dbufSize) return RETVAL_DATA_ERROR; - - /* mapping table: if some byte values are never used (encoding things - like ascii text), the compression code removes the gaps to have fewer - symbols to deal with, and writes a sparse bitfield indicating which - values were present. We make a translation table to convert the symbols - back to the corresponding bytes. */ - symTotal = 0; - i = 0; - t = get_bits(bd, 16); - do { - if (t & (1 << 15)) { - unsigned inner_map = get_bits(bd, 16); - do { - if (inner_map & (1 << 15)) - symToByte[symTotal++] = i; - inner_map <<= 1; - i++; - } while (i & 15); - i -= 16; - } - t <<= 1; - i += 16; - } while (i < 256); - - /* How many different Huffman coding groups does this block use? */ - groupCount = get_bits(bd, 3); - if (groupCount < 2 || groupCount > MAX_GROUPS) - return RETVAL_DATA_ERROR; - - /* nSelectors: Every GROUP_SIZE many symbols we select a new Huffman coding - group. Read in the group selector list, which is stored as MTF encoded - bit runs. (MTF=Move To Front, as each value is used it's moved to the - start of the list.) */ - for (i = 0; i < groupCount; i++) - mtfSymbol[i] = i; - nSelectors = get_bits(bd, 15); - if (!nSelectors) - return RETVAL_DATA_ERROR; - for (i = 0; i < nSelectors; i++) { - uint8_t tmp_byte; - /* Get next value */ - int n = 0; - while (get_bits(bd, 1)) { - if (n >= groupCount) return RETVAL_DATA_ERROR; - n++; - } - /* Decode MTF to get the next selector */ - tmp_byte = mtfSymbol[n]; - while (--n >= 0) - mtfSymbol[n + 1] = mtfSymbol[n]; - mtfSymbol[0] = selectors[i] = tmp_byte; - } - - /* Read the Huffman coding tables for each group, which code for symTotal - literal symbols, plus two run symbols (RUNA, RUNB) */ - symCount = symTotal + 2; - for (j = 0; j < groupCount; j++) { - uint8_t length[MAX_SYMBOLS]; - /* 8 bits is ALMOST enough for temp[], see below */ - unsigned temp[MAX_HUFCODE_BITS+1]; - int minLen, maxLen, pp, len_m1; - - /* Read Huffman code lengths for each symbol. They're stored in - a way similar to mtf; record a starting value for the first symbol, - and an offset from the previous value for every symbol after that. - (Subtracting 1 before the loop and then adding it back at the end is - an optimization that makes the test inside the loop simpler: symbol - length 0 becomes negative, so an unsigned inequality catches it.) */ - len_m1 = get_bits(bd, 5) - 1; - for (i = 0; i < symCount; i++) { - for (;;) { - int two_bits; - if ((unsigned)len_m1 > (MAX_HUFCODE_BITS-1)) - return RETVAL_DATA_ERROR; - - /* If first bit is 0, stop. Else second bit indicates whether - to increment or decrement the value. Optimization: grab 2 - bits and unget the second if the first was 0. */ - two_bits = get_bits(bd, 2); - if (two_bits < 2) { - bd->inbufBitCount++; - break; - } - - /* Add one if second bit 1, else subtract 1. Avoids if/else */ - len_m1 += (((two_bits+1) & 2) - 1); - } - - /* Correct for the initial -1, to get the final symbol length */ - length[i] = len_m1 + 1; - } - - /* Find largest and smallest lengths in this group */ - minLen = maxLen = length[0]; - for (i = 1; i < symCount; i++) { - if (length[i] > maxLen) maxLen = length[i]; - else if (length[i] < minLen) minLen = length[i]; - } - - /* Calculate permute[], base[], and limit[] tables from length[]. - * - * permute[] is the lookup table for converting Huffman coded symbols - * into decoded symbols. base[] is the amount to subtract from the - * value of a Huffman symbol of a given length when using permute[]. - * - * limit[] indicates the largest numerical value a symbol with a given - * number of bits can have. This is how the Huffman codes can vary in - * length: each code with a value>limit[length] needs another bit. - */ - hufGroup = bd->groups + j; - hufGroup->minLen = minLen; - hufGroup->maxLen = maxLen; - - /* Note that minLen can't be smaller than 1, so we adjust the base - and limit array pointers so we're not always wasting the first - entry. We do this again when using them (during symbol decoding). */ - base = hufGroup->base - 1; - limit = hufGroup->limit - 1; - - /* Calculate permute[]. Concurently, initialize temp[] and limit[]. */ - pp = 0; - for (i = minLen; i <= maxLen; i++) { - int k; - temp[i] = limit[i] = 0; - for (k = 0; k < symCount; k++) - if (length[k] == i) - hufGroup->permute[pp++] = k; - } - - /* Count symbols coded for at each bit length */ - /* NB: in pathological cases, temp[8] can end ip being 256. - * That's why uint8_t is too small for temp[]. */ - for (i = 0; i < symCount; i++) temp[length[i]]++; - - /* Calculate limit[] (the largest symbol-coding value at each bit - * length, which is (previous limit<<1)+symbols at this level), and - * base[] (number of symbols to ignore at each bit length, which is - * limit minus the cumulative count of symbols coded for already). */ - pp = t = 0; - for (i = minLen; i < maxLen;) { - unsigned temp_i = temp[i]; - - pp += temp_i; - - /* We read the largest possible symbol size and then unget bits - after determining how many we need, and those extra bits could - be set to anything. (They're noise from future symbols.) At - each level we're really only interested in the first few bits, - so here we set all the trailing to-be-ignored bits to 1 so they - don't affect the value>limit[length] comparison. */ - limit[i] = (pp << (maxLen - i)) - 1; - pp <<= 1; - t += temp_i; - base[++i] = pp - t; - } - limit[maxLen] = pp + temp[maxLen] - 1; - limit[maxLen+1] = INT_MAX; /* Sentinel value for reading next sym. */ - base[minLen] = 0; - } - - /* We've finished reading and digesting the block header. Now read this - block's Huffman coded symbols from the file and undo the Huffman coding - and run length encoding, saving the result into dbuf[dbufCount++] = uc */ - - /* Initialize symbol occurrence counters and symbol Move To Front table */ - /*memset(byteCount, 0, sizeof(byteCount)); - smaller, but slower */ - for (i = 0; i < 256; i++) { - byteCount[i] = 0; - mtfSymbol[i] = (uint8_t)i; - } - - /* Loop through compressed symbols. */ - - runPos = dbufCount = selector = 0; - for (;;) { - int nextSym; - - /* Fetch next Huffman coding group from list. */ - symCount = GROUP_SIZE - 1; - if (selector >= nSelectors) return RETVAL_DATA_ERROR; - hufGroup = bd->groups + selectors[selector++]; - base = hufGroup->base - 1; - limit = hufGroup->limit - 1; - - continue_this_group: - /* Read next Huffman-coded symbol. */ - - /* Note: It is far cheaper to read maxLen bits and back up than it is - to read minLen bits and then add additional bit at a time, testing - as we go. Because there is a trailing last block (with file CRC), - there is no danger of the overread causing an unexpected EOF for a - valid compressed file. - */ - if (1) { - /* As a further optimization, we do the read inline - (falling back to a call to get_bits if the buffer runs dry). - */ - int new_cnt; - while ((new_cnt = bd->inbufBitCount - hufGroup->maxLen) < 0) { - /* bd->inbufBitCount < hufGroup->maxLen */ - if (bd->inbufPos == bd->inbufCount) { - nextSym = get_bits(bd, hufGroup->maxLen); - goto got_huff_bits; - } - bd->inbufBits = (bd->inbufBits << 8) | bd->inbuf[bd->inbufPos++]; - bd->inbufBitCount += 8; - }; - bd->inbufBitCount = new_cnt; /* "bd->inbufBitCount -= hufGroup->maxLen;" */ - nextSym = (bd->inbufBits >> new_cnt) & ((1 << hufGroup->maxLen) - 1); - got_huff_bits: ; - } else { /* unoptimized equivalent */ - nextSym = get_bits(bd, hufGroup->maxLen); - } - /* Figure how many bits are in next symbol and unget extras */ - i = hufGroup->minLen; - while (nextSym > limit[i]) ++i; - j = hufGroup->maxLen - i; - if (j < 0) - return RETVAL_DATA_ERROR; - bd->inbufBitCount += j; - - /* Huffman decode value to get nextSym (with bounds checking) */ - nextSym = (nextSym >> j) - base[i]; - if ((unsigned)nextSym >= MAX_SYMBOLS) - return RETVAL_DATA_ERROR; - nextSym = hufGroup->permute[nextSym]; - - /* We have now decoded the symbol, which indicates either a new literal - byte, or a repeated run of the most recent literal byte. First, - check if nextSym indicates a repeated run, and if so loop collecting - how many times to repeat the last literal. */ - if ((unsigned)nextSym <= SYMBOL_RUNB) { /* RUNA or RUNB */ - - /* If this is the start of a new run, zero out counter */ - if (runPos == 0) { - runPos = 1; - runCnt = 0; - } - - /* Neat trick that saves 1 symbol: instead of or-ing 0 or 1 at - each bit position, add 1 or 2 instead. For example, - 1011 is 1<<0 + 1<<1 + 2<<2. 1010 is 2<<0 + 2<<1 + 1<<2. - You can make any bit pattern that way using 1 less symbol than - the basic or 0/1 method (except all bits 0, which would use no - symbols, but a run of length 0 doesn't mean anything in this - context). Thus space is saved. */ - runCnt += (runPos << nextSym); /* +runPos if RUNA; +2*runPos if RUNB */ - if (runPos < dbufSize) runPos <<= 1; - goto end_of_huffman_loop; - } - - /* When we hit the first non-run symbol after a run, we now know - how many times to repeat the last literal, so append that many - copies to our buffer of decoded symbols (dbuf) now. (The last - literal used is the one at the head of the mtfSymbol array.) */ - if (runPos != 0) { - uint8_t tmp_byte; - if (dbufCount + runCnt >= dbufSize) return RETVAL_DATA_ERROR; - tmp_byte = symToByte[mtfSymbol[0]]; - byteCount[tmp_byte] += runCnt; - while (--runCnt >= 0) dbuf[dbufCount++] = (uint32_t)tmp_byte; - runPos = 0; - } - - /* Is this the terminating symbol? */ - if (nextSym > symTotal) break; - - /* At this point, nextSym indicates a new literal character. Subtract - one to get the position in the MTF array at which this literal is - currently to be found. (Note that the result can't be -1 or 0, - because 0 and 1 are RUNA and RUNB. But another instance of the - first symbol in the mtf array, position 0, would have been handled - as part of a run above. Therefore 1 unused mtf position minus - 2 non-literal nextSym values equals -1.) */ - if (dbufCount >= dbufSize) return RETVAL_DATA_ERROR; - i = nextSym - 1; - uc = mtfSymbol[i]; - - /* Adjust the MTF array. Since we typically expect to move only a - * small number of symbols, and are bound by 256 in any case, using - * memmove here would typically be bigger and slower due to function - * call overhead and other assorted setup costs. */ - do { - mtfSymbol[i] = mtfSymbol[i-1]; - } while (--i); - mtfSymbol[0] = uc; - uc = symToByte[uc]; - - /* We have our literal byte. Save it into dbuf. */ - byteCount[uc]++; - dbuf[dbufCount++] = (uint32_t)uc; - - /* Skip group initialization if we're not done with this group. Done - * this way to avoid compiler warning. */ - end_of_huffman_loop: - if (--symCount >= 0) goto continue_this_group; - } - - /* At this point, we've read all the Huffman-coded symbols (and repeated - runs) for this block from the input stream, and decoded them into the - intermediate buffer. There are dbufCount many decoded bytes in dbuf[]. - Now undo the Burrows-Wheeler transform on dbuf. - See http://dogma.net/markn/articles/bwt/bwt.htm - */ - - /* Turn byteCount into cumulative occurrence counts of 0 to n-1. */ - j = 0; - for (i = 0; i < 256; i++) { - int tmp_count = j + byteCount[i]; - byteCount[i] = j; - j = tmp_count; - } - - /* Figure out what order dbuf would be in if we sorted it. */ - for (i = 0; i < dbufCount; i++) { - uint8_t tmp_byte = (uint8_t)dbuf[i]; - int tmp_count = byteCount[tmp_byte]; - dbuf[tmp_count] |= (i << 8); - byteCount[tmp_byte] = tmp_count + 1; - } - - /* Decode first byte by hand to initialize "previous" byte. Note that it - doesn't get output, and if the first three characters are identical - it doesn't qualify as a run (hence writeRunCountdown=5). */ - if (dbufCount) { - uint32_t tmp; - if ((int)origPtr >= dbufCount) return RETVAL_DATA_ERROR; - tmp = dbuf[origPtr]; - bd->writeCurrent = (uint8_t)tmp; - bd->writePos = (tmp >> 8); - bd->writeRunCountdown = 5; - } - bd->writeCount = dbufCount; - - return RETVAL_OK; -} - -/* Undo Burrows-Wheeler transform on intermediate buffer to produce output. - If start_bunzip was initialized with out_fd=-1, then up to len bytes of - data are written to outbuf. Return value is number of bytes written or - error (all errors are negative numbers). If out_fd!=-1, outbuf and len - are ignored, data is written to out_fd and return is RETVAL_OK or error. - - 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. - (Why? This allows to get rid of one local variable) -*/ -int FAST_FUNC read_bunzip(bunzip_data *bd, char *outbuf, int len) -{ - const uint32_t *dbuf; - int pos, current, previous; - uint32_t CRC; - - /* If we already have error/end indicator, return it */ - if (bd->writeCount < 0) - return bd->writeCount; - - dbuf = bd->dbuf; - - /* Register-cached state (hopefully): */ - pos = bd->writePos; - current = bd->writeCurrent; - CRC = bd->writeCRC; /* small loss on x86-32 (not enough regs), win on x86-64 */ - - /* We will always have pending decoded data to write into the output - buffer unless this is the very first call (in which case we haven't - Huffman-decoded a block into the intermediate buffer yet). */ - if (bd->writeCopies) { - - dec_writeCopies: - /* Inside the loop, writeCopies means extra copies (beyond 1) */ - --bd->writeCopies; - - /* Loop outputting bytes */ - for (;;) { - - /* If the output buffer is full, save cached state and return */ - if (--len < 0) { - /* Unlikely branch. - * Use of "goto" instead of keeping code here - * helps compiler to realize this. */ - goto outbuf_full; - } - - /* Write next byte into output buffer, updating CRC */ - *outbuf++ = current; - CRC = (CRC << 8) ^ bd->crc32Table[(CRC >> 24) ^ current]; - - /* Loop now if we're outputting multiple copies of this byte */ - if (bd->writeCopies) { - /* Unlikely branch */ - /*--bd->writeCopies;*/ - /*continue;*/ - /* Same, but (ab)using other existing --writeCopies operation - * (and this if() compiles into just test+branch pair): */ - goto dec_writeCopies; - } - decode_next_byte: - if (--bd->writeCount < 0) - break; /* input block is fully consumed, need next one */ - - /* Follow sequence vector to undo Burrows-Wheeler transform */ - previous = current; - pos = dbuf[pos]; - current = (uint8_t)pos; - pos >>= 8; - - /* After 3 consecutive copies of the same byte, the 4th - * is a repeat count. We count down from 4 instead - * of counting up because testing for non-zero is faster */ - if (--bd->writeRunCountdown != 0) { - if (current != previous) - bd->writeRunCountdown = 4; - } else { - /* Unlikely branch */ - /* We have a repeated run, this byte indicates the count */ - bd->writeCopies = current; - current = previous; - bd->writeRunCountdown = 5; - - /* Sometimes there are just 3 bytes (run length 0) */ - if (!bd->writeCopies) goto decode_next_byte; - - /* Subtract the 1 copy we'd output anyway to get extras */ - --bd->writeCopies; - } - } /* for(;;) */ - - /* Decompression of this input block completed successfully */ - bd->writeCRC = CRC = ~CRC; - bd->totalCRC = ((bd->totalCRC << 1) | (bd->totalCRC >> 31)) ^ CRC; - - /* If this block had a CRC error, force file level CRC error */ - if (CRC != bd->headerCRC) { - bd->totalCRC = bd->headerCRC + 1; - return RETVAL_LAST_BLOCK; - } - } - - /* Refill the intermediate buffer by Huffman-decoding next block of input */ - { - int r = get_next_block(bd); - if (r) { /* error/end */ - bd->writeCount = r; - return (r != RETVAL_LAST_BLOCK) ? r : len; - } - } - - CRC = ~0; - pos = bd->writePos; - current = bd->writeCurrent; - goto decode_next_byte; - - outbuf_full: - /* Output buffer is full, save cached state and return */ - bd->writePos = pos; - bd->writeCurrent = current; - bd->writeCRC = CRC; - - bd->writeCopies++; - - return 0; -} - -/* Allocate the structure, read file header. If in_fd==-1, inbuf must contain - a complete bunzip file (len bytes long). If in_fd!=-1, inbuf and len are - ignored, and data is read from file handle into temporary buffer. */ - -/* 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(bunzip_data **bdp, int in_fd, - const void *inbuf, int len) -{ - bunzip_data *bd; - unsigned i; - enum { - BZh0 = ('B' << 24) + ('Z' << 16) + ('h' << 8) + '0', - h0 = ('h' << 8) + '0', - }; - - /* Figure out how much data to allocate */ - i = sizeof(bunzip_data); - if (in_fd != -1) i += IOBUF_SIZE; - - /* Allocate bunzip_data. Most fields initialize to zero. */ - bd = *bdp = xzalloc(i); - - /* Setup input buffer */ - bd->in_fd = in_fd; - if (-1 == in_fd) { - /* in this case, bd->inbuf is read-only */ - bd->inbuf = (void*)inbuf; /* cast away const-ness */ - } else { - bd->inbuf = (uint8_t*)(bd + 1); - memcpy(bd->inbuf, inbuf, len); - } - bd->inbufCount = len; - - /* Init the CRC32 table (big endian) */ - crc32_filltable(bd->crc32Table, 1); - - /* Setup for I/O error handling via longjmp */ - i = setjmp(bd->jmpbuf); - if (i) return i; - - /* Ensure that file starts with "BZh['1'-'9']." */ - /* Update: now caller verifies 1st two bytes, makes .gz/.bz2 - * integration easier */ - /* was: */ - /* i = get_bits(bd, 32); */ - /* if ((unsigned)(i - BZh0 - 1) >= 9) return RETVAL_NOT_BZIP_DATA; */ - i = get_bits(bd, 16); - if ((unsigned)(i - h0 - 1) >= 9) return RETVAL_NOT_BZIP_DATA; - - /* Fourth byte (ascii '1'-'9') indicates block size in units of 100k of - uncompressed data. Allocate intermediate buffer for block. */ - /* bd->dbufSize = 100000 * (i - BZh0); */ - bd->dbufSize = 100000 * (i - h0); - - /* Cannot use xmalloc - may leak bd in NOFORK case! */ - bd->dbuf = malloc_or_warn(bd->dbufSize * sizeof(bd->dbuf[0])); - if (!bd->dbuf) { - free(bd); - xfunc_die(); - } - return RETVAL_OK; -} - -void FAST_FUNC dealloc_bunzip(bunzip_data *bd) -{ - free(bd->dbuf); - free(bd); -} - - -/* Decompress src_fd to dst_fd. Stops at end of bzip data, not end of file. */ -IF_DESKTOP(long long) int FAST_FUNC -unpack_bz2_stream(int src_fd, int dst_fd) -{ - IF_DESKTOP(long long total_written = 0;) - bunzip_data *bd; - char *outbuf; - int i; - unsigned len; - - outbuf = xmalloc(IOBUF_SIZE); - len = 0; - while (1) { /* "Process one BZ... stream" loop */ - - i = start_bunzip(&bd, src_fd, outbuf + 2, len); - - if (i == 0) { - while (1) { /* "Produce some output bytes" loop */ - i = read_bunzip(bd, outbuf, IOBUF_SIZE); - if (i < 0) /* error? */ - break; - i = IOBUF_SIZE - i; /* number of bytes produced */ - if (i == 0) /* EOF? */ - break; - if (i != full_write(dst_fd, outbuf, i)) { - bb_error_msg("short write"); - i = RETVAL_SHORT_WRITE; - goto release_mem; - } - IF_DESKTOP(total_written += i;) - } - } - - if (i != RETVAL_LAST_BLOCK) { - bb_error_msg("bunzip error %d", i); - break; - } - if (bd->headerCRC != bd->totalCRC) { - bb_error_msg("CRC error"); - break; - } - - /* Successfully unpacked one BZ stream */ - i = RETVAL_OK; - - /* Do we have "BZ..." after last processed byte? - * pbzip2 (parallelized bzip2) produces such files. - */ - len = bd->inbufCount - bd->inbufPos; - memcpy(outbuf, &bd->inbuf[bd->inbufPos], len); - if (len < 2) { - if (safe_read(src_fd, outbuf + len, 2 - len) != 2 - len) - break; - len = 2; - } - if (*(uint16_t*)outbuf != BZIP2_MAGIC) /* "BZ"? */ - break; - dealloc_bunzip(bd); - len -= 2; - } - - release_mem: - dealloc_bunzip(bd); - free(outbuf); - - return i ? i : IF_DESKTOP(total_written) + 0; -} - -IF_DESKTOP(long long) int FAST_FUNC -unpack_bz2_stream_prime(int src_fd, int dst_fd) -{ - uint16_t magic2; - xread(src_fd, &magic2, 2); - if (magic2 != BZIP2_MAGIC) { - bb_error_msg_and_die("invalid magic"); - } - return unpack_bz2_stream(src_fd, dst_fd); -} - -#ifdef TESTING - -static char *const bunzip_errors[] = { - NULL, "Bad file checksum", "Not bzip data", - "Unexpected input EOF", "Unexpected output EOF", "Data error", - "Out of memory", "Obsolete (pre 0.9.5) bzip format not supported" -}; - -/* Dumb little test thing, decompress stdin to stdout */ -int main(int argc, char **argv) -{ - int i; - char c; - - int i = unpack_bz2_stream_prime(0, 1); - if (i < 0) - fprintf(stderr, "%s\n", bunzip_errors[-i]); - else if (read(STDIN_FILENO, &c, 1)) - fprintf(stderr, "Trailing garbage ignored\n"); - return -i; -} -#endif diff --git a/archival/libunarchive/decompress_uncompress.c b/archival/libunarchive/decompress_uncompress.c deleted file mode 100644 index 285b4efeb..000000000 --- a/archival/libunarchive/decompress_uncompress.c +++ /dev/null @@ -1,307 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* uncompress for busybox -- (c) 2002 Robert Griebl - * - * based on the original compress42.c source - * (see disclaimer below) - */ - -/* (N)compress42.c - File compression ala IEEE Computer, Mar 1992. - * - * Authors: - * Spencer W. Thomas (decvax!harpo!utah-cs!utah-gr!thomas) - * Jim McKie (decvax!mcvax!jim) - * Steve Davies (decvax!vax135!petsd!peora!srd) - * Ken Turkowski (decvax!decwrl!turtlevax!ken) - * James A. Woods (decvax!ihnp4!ames!jaw) - * Joe Orost (decvax!vax135!petsd!joe) - * Dave Mack (csu@alembic.acs.com) - * Peter Jannesen, Network Communication Systems - * (peter@ncs.nl) - * - * marc@suse.de : a small security fix for a buffer overflow - * - * [... History snipped ...] - * - */ - -#include "libbb.h" -#include "unarchive.h" - - -/* Default input buffer size */ -#define IBUFSIZ 2048 - -/* Default output buffer size */ -#define OBUFSIZ 2048 - -/* Defines for third byte of header */ -#define BIT_MASK 0x1f /* Mask for 'number of compresssion bits' */ - /* Masks 0x20 and 0x40 are free. */ - /* I think 0x20 should mean that there is */ - /* a fourth header byte (for expansion). */ -#define BLOCK_MODE 0x80 /* Block compression if table is full and */ - /* compression rate is dropping flush tables */ - /* the next two codes should not be changed lightly, as they must not */ - /* lie within the contiguous general code space. */ -#define FIRST 257 /* first free entry */ -#define CLEAR 256 /* table clear output code */ - -#define INIT_BITS 9 /* initial number of bits/code */ - - -/* machine variants which require cc -Dmachine: pdp11, z8000, DOS */ -#define HBITS 17 /* 50% occupancy */ -#define HSIZE (1< BITS) { - bb_error_msg("compressed with %d bits, can only handle " - BITS_STR" bits", maxbits); - goto err; - } - - n_bits = INIT_BITS; - maxcode = MAXCODE(INIT_BITS) - 1; - bitmask = (1 << INIT_BITS) - 1; - oldcode = -1; - finchar = 0; - outpos = 0; - posbits = 0 << 3; - - free_ent = ((block_mode) ? FIRST : 256); - - /* As above, initialize the first 256 entries in the table. */ - /*clear_tab_prefixof(); - done by xzalloc */ - - for (code = 255; code >= 0; --code) { - tab_suffixof(code) = (unsigned char) code; - } - - do { - resetbuf: - { - int i; - int e; - int o; - - o = posbits >> 3; - e = insize - o; - - for (i = 0; i < e; ++i) - inbuf[i] = inbuf[i + o]; - - insize = e; - posbits = 0; - } - - if (insize < (int) (IBUFSIZ + 64) - IBUFSIZ) { - rsize = safe_read(fd_in, inbuf + insize, IBUFSIZ); -//error check?? - insize += rsize; - } - - inbits = ((rsize > 0) ? (insize - insize % n_bits) << 3 : - (insize << 3) - (n_bits - 1)); - - while (inbits > posbits) { - if (free_ent > maxcode) { - posbits = - ((posbits - 1) + - ((n_bits << 3) - - (posbits - 1 + (n_bits << 3)) % (n_bits << 3))); - ++n_bits; - if (n_bits == maxbits) { - maxcode = maxmaxcode; - } else { - maxcode = MAXCODE(n_bits) - 1; - } - bitmask = (1 << n_bits) - 1; - goto resetbuf; - } - { - unsigned char *p = &inbuf[posbits >> 3]; - - code = ((((long) (p[0])) | ((long) (p[1]) << 8) | - ((long) (p[2]) << 16)) >> (posbits & 0x7)) & bitmask; - } - posbits += n_bits; - - - if (oldcode == -1) { - oldcode = code; - finchar = (int) oldcode; - outbuf[outpos++] = (unsigned char) finchar; - continue; - } - - if (code == CLEAR && block_mode) { - clear_tab_prefixof(); - free_ent = FIRST - 1; - posbits = - ((posbits - 1) + - ((n_bits << 3) - - (posbits - 1 + (n_bits << 3)) % (n_bits << 3))); - n_bits = INIT_BITS; - maxcode = MAXCODE(INIT_BITS) - 1; - bitmask = (1 << INIT_BITS) - 1; - goto resetbuf; - } - - incode = code; - stackp = de_stack; - - /* Special case for KwKwK string. */ - if (code >= free_ent) { - if (code > free_ent) { - unsigned char *p; - - posbits -= n_bits; - p = &inbuf[posbits >> 3]; - - bb_error_msg - ("insize:%d posbits:%d inbuf:%02X %02X %02X %02X %02X (%d)", - insize, posbits, p[-1], p[0], p[1], p[2], p[3], - (posbits & 07)); - bb_error_msg("corrupted data"); - goto err; - } - - *--stackp = (unsigned char) finchar; - code = oldcode; - } - - /* Generate output characters in reverse order */ - while ((long) code >= (long) 256) { - *--stackp = tab_suffixof(code); - code = tab_prefixof(code); - } - - finchar = tab_suffixof(code); - *--stackp = (unsigned char) finchar; - - /* And put them out in forward order */ - { - int i; - - i = de_stack - stackp; - if (outpos + i >= OBUFSIZ) { - do { - if (i > OBUFSIZ - outpos) { - i = OBUFSIZ - outpos; - } - - if (i > 0) { - memcpy(outbuf + outpos, stackp, i); - outpos += i; - } - - if (outpos >= OBUFSIZ) { - full_write(fd_out, outbuf, outpos); -//error check?? - IF_DESKTOP(total_written += outpos;) - outpos = 0; - } - stackp += i; - i = de_stack - stackp; - } while (i > 0); - } else { - memcpy(outbuf + outpos, stackp, i); - outpos += i; - } - } - - /* Generate the new entry. */ - code = free_ent; - if (code < maxmaxcode) { - tab_prefixof(code) = (unsigned short) oldcode; - tab_suffixof(code) = (unsigned char) finchar; - free_ent = code + 1; - } - - /* Remember previous code. */ - oldcode = incode; - } - - } while (rsize > 0); - - if (outpos > 0) { - full_write(fd_out, outbuf, outpos); -//error check?? - IF_DESKTOP(total_written += outpos;) - } - - retval = IF_DESKTOP(total_written) + 0; - err: - free(inbuf); - free(outbuf); - free(htab); - free(codetab); - return retval; -} diff --git a/archival/libunarchive/decompress_unlzma.c b/archival/libunarchive/decompress_unlzma.c deleted file mode 100644 index 1a3a8f86b..000000000 --- a/archival/libunarchive/decompress_unlzma.c +++ /dev/null @@ -1,465 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Small lzma deflate implementation. - * Copyright (C) 2006 Aurelien Jacobs - * - * Based on LzmaDecode.c from the LZMA SDK 4.22 (http://www.7-zip.org/) - * Copyright (C) 1999-2005 Igor Pavlov - * - * Licensed under GPLv2 or later, see file LICENSE in this source tree. - */ -#include "libbb.h" -#include "unarchive.h" - -#if ENABLE_FEATURE_LZMA_FAST -# define speed_inline ALWAYS_INLINE -# define size_inline -#else -# define speed_inline -# define size_inline ALWAYS_INLINE -#endif - - -typedef struct { - int fd; - uint8_t *ptr; - -/* Was keeping rc on stack in unlzma and separately allocating buffer, - * but with "buffer 'attached to' allocated rc" code is smaller: */ - /* uint8_t *buffer; */ -#define RC_BUFFER ((uint8_t*)(rc+1)) - - uint8_t *buffer_end; - -/* Had provisions for variable buffer, but we don't need it here */ - /* int buffer_size; */ -#define RC_BUFFER_SIZE 0x10000 - - uint32_t code; - uint32_t range; - uint32_t bound; -} rc_t; - -#define RC_TOP_BITS 24 -#define RC_MOVE_BITS 5 -#define RC_MODEL_TOTAL_BITS 11 - - -/* Called twice: once at startup (LZMA_FAST only) and once in rc_normalize() */ -static size_inline void rc_read(rc_t *rc) -{ - int buffer_size = safe_read(rc->fd, RC_BUFFER, RC_BUFFER_SIZE); -//TODO: return -1 instead -//This will make unlzma delete broken unpacked file on unpack errors - if (buffer_size <= 0) - bb_error_msg_and_die("unexpected EOF"); - rc->ptr = RC_BUFFER; - rc->buffer_end = RC_BUFFER + buffer_size; -} - -/* Called twice, but one callsite is in speed_inline'd rc_is_bit_1() */ -static void rc_do_normalize(rc_t *rc) -{ - if (rc->ptr >= rc->buffer_end) - rc_read(rc); - rc->range <<= 8; - rc->code = (rc->code << 8) | *rc->ptr++; -} - -/* Called once */ -static ALWAYS_INLINE rc_t* rc_init(int fd) /*, int buffer_size) */ -{ - int i; - rc_t *rc; - - rc = xzalloc(sizeof(*rc) + RC_BUFFER_SIZE); - - rc->fd = fd; - /* rc->ptr = rc->buffer_end; */ - - for (i = 0; i < 5; i++) { -#if ENABLE_FEATURE_LZMA_FAST - if (rc->ptr >= rc->buffer_end) - rc_read(rc); - rc->code = (rc->code << 8) | *rc->ptr++; -#else - rc_do_normalize(rc); -#endif - } - rc->range = 0xFFFFFFFF; - return rc; -} - -/* Called once */ -static ALWAYS_INLINE void rc_free(rc_t *rc) -{ - free(rc); -} - -static ALWAYS_INLINE void rc_normalize(rc_t *rc) -{ - if (rc->range < (1 << RC_TOP_BITS)) { - rc_do_normalize(rc); - } -} - -/* rc_is_bit_1 is called 9 times */ -static speed_inline int rc_is_bit_1(rc_t *rc, uint16_t *p) -{ - rc_normalize(rc); - rc->bound = *p * (rc->range >> RC_MODEL_TOTAL_BITS); - if (rc->code < rc->bound) { - rc->range = rc->bound; - *p += ((1 << RC_MODEL_TOTAL_BITS) - *p) >> RC_MOVE_BITS; - return 0; - } - rc->range -= rc->bound; - rc->code -= rc->bound; - *p -= *p >> RC_MOVE_BITS; - return 1; -} - -/* Called 4 times in unlzma loop */ -static speed_inline int rc_get_bit(rc_t *rc, uint16_t *p, int *symbol) -{ - int ret = rc_is_bit_1(rc, p); - *symbol = *symbol * 2 + ret; - return ret; -} - -/* Called once */ -static ALWAYS_INLINE int rc_direct_bit(rc_t *rc) -{ - rc_normalize(rc); - rc->range >>= 1; - if (rc->code >= rc->range) { - rc->code -= rc->range; - return 1; - } - return 0; -} - -/* Called twice */ -static speed_inline void -rc_bit_tree_decode(rc_t *rc, uint16_t *p, int num_levels, int *symbol) -{ - int i = num_levels; - - *symbol = 1; - while (i--) - rc_get_bit(rc, p + *symbol, symbol); - *symbol -= 1 << num_levels; -} - - -typedef struct { - uint8_t pos; - uint32_t dict_size; - uint64_t dst_size; -} PACKED lzma_header_t; - - -/* #defines will force compiler to compute/optimize each one with each usage. - * Have heart and use enum instead. */ -enum { - LZMA_BASE_SIZE = 1846, - LZMA_LIT_SIZE = 768, - - LZMA_NUM_POS_BITS_MAX = 4, - - LZMA_LEN_NUM_LOW_BITS = 3, - LZMA_LEN_NUM_MID_BITS = 3, - LZMA_LEN_NUM_HIGH_BITS = 8, - - LZMA_LEN_CHOICE = 0, - LZMA_LEN_CHOICE_2 = (LZMA_LEN_CHOICE + 1), - LZMA_LEN_LOW = (LZMA_LEN_CHOICE_2 + 1), - LZMA_LEN_MID = (LZMA_LEN_LOW \ - + (1 << (LZMA_NUM_POS_BITS_MAX + LZMA_LEN_NUM_LOW_BITS))), - LZMA_LEN_HIGH = (LZMA_LEN_MID \ - + (1 << (LZMA_NUM_POS_BITS_MAX + LZMA_LEN_NUM_MID_BITS))), - LZMA_NUM_LEN_PROBS = (LZMA_LEN_HIGH + (1 << LZMA_LEN_NUM_HIGH_BITS)), - - LZMA_NUM_STATES = 12, - LZMA_NUM_LIT_STATES = 7, - - LZMA_START_POS_MODEL_INDEX = 4, - LZMA_END_POS_MODEL_INDEX = 14, - LZMA_NUM_FULL_DISTANCES = (1 << (LZMA_END_POS_MODEL_INDEX >> 1)), - - LZMA_NUM_POS_SLOT_BITS = 6, - LZMA_NUM_LEN_TO_POS_STATES = 4, - - LZMA_NUM_ALIGN_BITS = 4, - - LZMA_MATCH_MIN_LEN = 2, - - LZMA_IS_MATCH = 0, - LZMA_IS_REP = (LZMA_IS_MATCH + (LZMA_NUM_STATES << LZMA_NUM_POS_BITS_MAX)), - LZMA_IS_REP_G0 = (LZMA_IS_REP + LZMA_NUM_STATES), - LZMA_IS_REP_G1 = (LZMA_IS_REP_G0 + LZMA_NUM_STATES), - LZMA_IS_REP_G2 = (LZMA_IS_REP_G1 + LZMA_NUM_STATES), - LZMA_IS_REP_0_LONG = (LZMA_IS_REP_G2 + LZMA_NUM_STATES), - LZMA_POS_SLOT = (LZMA_IS_REP_0_LONG \ - + (LZMA_NUM_STATES << LZMA_NUM_POS_BITS_MAX)), - LZMA_SPEC_POS = (LZMA_POS_SLOT \ - + (LZMA_NUM_LEN_TO_POS_STATES << LZMA_NUM_POS_SLOT_BITS)), - LZMA_ALIGN = (LZMA_SPEC_POS \ - + LZMA_NUM_FULL_DISTANCES - LZMA_END_POS_MODEL_INDEX), - LZMA_LEN_CODER = (LZMA_ALIGN + (1 << LZMA_NUM_ALIGN_BITS)), - LZMA_REP_LEN_CODER = (LZMA_LEN_CODER + LZMA_NUM_LEN_PROBS), - LZMA_LITERAL = (LZMA_REP_LEN_CODER + LZMA_NUM_LEN_PROBS), -}; - - -IF_DESKTOP(long long) int FAST_FUNC -unpack_lzma_stream(int src_fd, int dst_fd) -{ - IF_DESKTOP(long long total_written = 0;) - lzma_header_t header; - int lc, pb, lp; - uint32_t pos_state_mask; - uint32_t literal_pos_mask; - uint16_t *p; - int num_bits; - int num_probs; - rc_t *rc; - int i; - uint8_t *buffer; - uint8_t previous_byte = 0; - size_t buffer_pos = 0, global_pos = 0; - int len = 0; - int state = 0; - uint32_t rep0 = 1, rep1 = 1, rep2 = 1, rep3 = 1; - - if (full_read(src_fd, &header, sizeof(header)) != sizeof(header) - || header.pos >= (9 * 5 * 5) - ) { - bb_error_msg("bad lzma header"); - return -1; - } - - i = header.pos / 9; - lc = header.pos % 9; - pb = i / 5; - lp = i % 5; - pos_state_mask = (1 << pb) - 1; - literal_pos_mask = (1 << lp) - 1; - - header.dict_size = SWAP_LE32(header.dict_size); - header.dst_size = SWAP_LE64(header.dst_size); - - if (header.dict_size == 0) - header.dict_size++; - - buffer = xmalloc(MIN(header.dst_size, header.dict_size)); - - num_probs = LZMA_BASE_SIZE + (LZMA_LIT_SIZE << (lc + lp)); - p = xmalloc(num_probs * sizeof(*p)); - num_probs += LZMA_LITERAL - LZMA_BASE_SIZE; - for (i = 0; i < num_probs; i++) - p[i] = (1 << RC_MODEL_TOTAL_BITS) >> 1; - - rc = rc_init(src_fd); /*, RC_BUFFER_SIZE); */ - - while (global_pos + buffer_pos < header.dst_size) { - int pos_state = (buffer_pos + global_pos) & pos_state_mask; - uint16_t *prob = p + LZMA_IS_MATCH + (state << LZMA_NUM_POS_BITS_MAX) + pos_state; - - if (!rc_is_bit_1(rc, prob)) { - static const char next_state[LZMA_NUM_STATES] = - { 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 4, 5 }; - int mi = 1; - - prob = (p + LZMA_LITERAL - + (LZMA_LIT_SIZE * ((((buffer_pos + global_pos) & literal_pos_mask) << lc) - + (previous_byte >> (8 - lc)) - ) - ) - ); - - if (state >= LZMA_NUM_LIT_STATES) { - int match_byte; - uint32_t pos = buffer_pos - rep0; - - while (pos >= header.dict_size) - pos += header.dict_size; - match_byte = buffer[pos]; - do { - int bit; - - match_byte <<= 1; - bit = match_byte & 0x100; - bit ^= (rc_get_bit(rc, prob + 0x100 + bit + mi, &mi) << 8); /* 0x100 or 0 */ - if (bit) - break; - } while (mi < 0x100); - } - while (mi < 0x100) { - rc_get_bit(rc, prob + mi, &mi); - } - - state = next_state[state]; - - previous_byte = (uint8_t) mi; -#if ENABLE_FEATURE_LZMA_FAST - one_byte1: - buffer[buffer_pos++] = previous_byte; - if (buffer_pos == header.dict_size) { - buffer_pos = 0; - global_pos += header.dict_size; - if (full_write(dst_fd, buffer, header.dict_size) != (ssize_t)header.dict_size) - goto bad; - IF_DESKTOP(total_written += header.dict_size;) - } -#else - len = 1; - goto one_byte2; -#endif - } else { - int offset; - uint16_t *prob2; -#define prob_len prob2 - - prob2 = p + LZMA_IS_REP + state; - if (!rc_is_bit_1(rc, prob2)) { - rep3 = rep2; - rep2 = rep1; - rep1 = rep0; - state = state < LZMA_NUM_LIT_STATES ? 0 : 3; - prob2 = p + LZMA_LEN_CODER; - } else { - prob2 += LZMA_IS_REP_G0 - LZMA_IS_REP; - if (!rc_is_bit_1(rc, prob2)) { - prob2 = (p + LZMA_IS_REP_0_LONG - + (state << LZMA_NUM_POS_BITS_MAX) - + pos_state - ); - if (!rc_is_bit_1(rc, prob2)) { -#if ENABLE_FEATURE_LZMA_FAST - uint32_t pos = buffer_pos - rep0; - state = state < LZMA_NUM_LIT_STATES ? 9 : 11; - while (pos >= header.dict_size) - pos += header.dict_size; - previous_byte = buffer[pos]; - goto one_byte1; -#else - state = state < LZMA_NUM_LIT_STATES ? 9 : 11; - len = 1; - goto string; -#endif - } - } else { - uint32_t distance; - - prob2 += LZMA_IS_REP_G1 - LZMA_IS_REP_G0; - distance = rep1; - if (rc_is_bit_1(rc, prob2)) { - prob2 += LZMA_IS_REP_G2 - LZMA_IS_REP_G1; - distance = rep2; - if (rc_is_bit_1(rc, prob2)) { - distance = rep3; - rep3 = rep2; - } - rep2 = rep1; - } - rep1 = rep0; - rep0 = distance; - } - state = state < LZMA_NUM_LIT_STATES ? 8 : 11; - prob2 = p + LZMA_REP_LEN_CODER; - } - - prob_len = prob2 + LZMA_LEN_CHOICE; - num_bits = LZMA_LEN_NUM_LOW_BITS; - if (!rc_is_bit_1(rc, prob_len)) { - prob_len += LZMA_LEN_LOW - LZMA_LEN_CHOICE - + (pos_state << LZMA_LEN_NUM_LOW_BITS); - offset = 0; - } else { - prob_len += LZMA_LEN_CHOICE_2 - LZMA_LEN_CHOICE; - if (!rc_is_bit_1(rc, prob_len)) { - prob_len += LZMA_LEN_MID - LZMA_LEN_CHOICE_2 - + (pos_state << LZMA_LEN_NUM_MID_BITS); - offset = 1 << LZMA_LEN_NUM_LOW_BITS; - num_bits += LZMA_LEN_NUM_MID_BITS - LZMA_LEN_NUM_LOW_BITS; - } else { - prob_len += LZMA_LEN_HIGH - LZMA_LEN_CHOICE_2; - offset = ((1 << LZMA_LEN_NUM_LOW_BITS) - + (1 << LZMA_LEN_NUM_MID_BITS)); - num_bits += LZMA_LEN_NUM_HIGH_BITS - LZMA_LEN_NUM_LOW_BITS; - } - } - rc_bit_tree_decode(rc, prob_len, num_bits, &len); - len += offset; - - if (state < 4) { - int pos_slot; - uint16_t *prob3; - - state += LZMA_NUM_LIT_STATES; - prob3 = p + LZMA_POS_SLOT + - ((len < LZMA_NUM_LEN_TO_POS_STATES ? len : - LZMA_NUM_LEN_TO_POS_STATES - 1) - << LZMA_NUM_POS_SLOT_BITS); - rc_bit_tree_decode(rc, prob3, - LZMA_NUM_POS_SLOT_BITS, &pos_slot); - rep0 = pos_slot; - if (pos_slot >= LZMA_START_POS_MODEL_INDEX) { - int i2, mi2, num_bits2 = (pos_slot >> 1) - 1; - rep0 = 2 | (pos_slot & 1); - if (pos_slot < LZMA_END_POS_MODEL_INDEX) { - rep0 <<= num_bits2; - prob3 = p + LZMA_SPEC_POS + rep0 - pos_slot - 1; - } else { - for (; num_bits2 != LZMA_NUM_ALIGN_BITS; num_bits2--) - rep0 = (rep0 << 1) | rc_direct_bit(rc); - rep0 <<= LZMA_NUM_ALIGN_BITS; - prob3 = p + LZMA_ALIGN; - } - i2 = 1; - mi2 = 1; - while (num_bits2--) { - if (rc_get_bit(rc, prob3 + mi2, &mi2)) - rep0 |= i2; - i2 <<= 1; - } - } - if (++rep0 == 0) - break; - } - - len += LZMA_MATCH_MIN_LEN; - IF_NOT_FEATURE_LZMA_FAST(string:) - do { - uint32_t pos = buffer_pos - rep0; - while (pos >= header.dict_size) - pos += header.dict_size; - previous_byte = buffer[pos]; - IF_NOT_FEATURE_LZMA_FAST(one_byte2:) - buffer[buffer_pos++] = previous_byte; - if (buffer_pos == header.dict_size) { - buffer_pos = 0; - global_pos += header.dict_size; - if (full_write(dst_fd, buffer, header.dict_size) != (ssize_t)header.dict_size) - goto bad; - IF_DESKTOP(total_written += header.dict_size;) - } - len--; - } while (len != 0 && buffer_pos < header.dst_size); - } - } - - { - IF_NOT_DESKTOP(int total_written = 0; /* success */) - IF_DESKTOP(total_written += buffer_pos;) - if (full_write(dst_fd, buffer, buffer_pos) != (ssize_t)buffer_pos) { - bad: - total_written = -1; /* failure */ - } - rc_free(rc); - free(p); - free(buffer); - return total_written; - } -} diff --git a/archival/libunarchive/decompress_unxz.c b/archival/libunarchive/decompress_unxz.c deleted file mode 100644 index ca427231e..000000000 --- a/archival/libunarchive/decompress_unxz.c +++ /dev/null @@ -1,98 +0,0 @@ -/* - * This file uses XZ Embedded library code which is written - * by Lasse Collin - * and Igor Pavlov - * - * See README file in unxz/ directory for more information. - * - * This file is: - * Copyright (C) 2010 Denys Vlasenko - * Licensed under GPLv2, see file LICENSE in this source tree. - */ -#include "libbb.h" -#include "unarchive.h" - -#define XZ_FUNC FAST_FUNC -#define XZ_EXTERN static - -#define XZ_DEC_DYNALLOC - -/* Skip check (rather than fail) of unsupported hash functions */ -#define XZ_DEC_ANY_CHECK 1 - -/* We use our own crc32 function */ -#define XZ_INTERNAL_CRC32 0 -static uint32_t xz_crc32(const uint8_t *buf, size_t size, uint32_t crc) -{ - return ~crc32_block_endian0(~crc, buf, size, global_crc32_table); -} - -/* We use arch-optimized unaligned accessors */ -#define get_unaligned_le32(buf) ({ uint32_t v; move_from_unaligned32(v, buf); SWAP_LE32(v); }) -#define get_unaligned_be32(buf) ({ uint32_t v; move_from_unaligned32(v, buf); SWAP_BE32(v); }) -#define put_unaligned_le32(val, buf) move_to_unaligned16(buf, SWAP_LE32(val)) -#define put_unaligned_be32(val, buf) move_to_unaligned16(buf, SWAP_BE32(val)) - -#include "unxz/xz_dec_bcj.c" -#include "unxz/xz_dec_lzma2.c" -#include "unxz/xz_dec_stream.c" - -IF_DESKTOP(long long) int FAST_FUNC -unpack_xz_stream(int src_fd, int dst_fd) -{ - struct xz_buf iobuf; - struct xz_dec *state; - unsigned char *membuf; - IF_DESKTOP(long long) int total = 0; - - if (!global_crc32_table) - global_crc32_table = crc32_filltable(NULL, /*endian:*/ 0); - - memset(&iobuf, 0, sizeof(iobuf)); - /* Preload XZ file signature */ - membuf = (void*) strcpy(xmalloc(2 * BUFSIZ), HEADER_MAGIC); - iobuf.in = membuf; - iobuf.in_size = HEADER_MAGIC_SIZE; - iobuf.out = membuf + BUFSIZ; - iobuf.out_size = BUFSIZ; - - /* Limit memory usage to about 64 MiB. */ - state = xz_dec_init(XZ_DYNALLOC, 64*1024*1024); - - while (1) { - enum xz_ret r; - - if (iobuf.in_pos == iobuf.in_size) { - int rd = safe_read(src_fd, membuf, BUFSIZ); - if (rd < 0) { - bb_error_msg(bb_msg_read_error); - total = -1; - break; - } - iobuf.in_size = rd; - iobuf.in_pos = 0; - } -// bb_error_msg(">in pos:%d size:%d out pos:%d size:%d", -// iobuf.in_pos, iobuf.in_size, iobuf.out_pos, iobuf.out_size); - r = xz_dec_run(state, &iobuf); -// bb_error_msg(" - * based on gzip sources - * - * Adjusted further by Erik Andersen to support - * files as well as stdin/stdout, and to generally behave itself wrt - * command line handling. - * - * General cleanup to better adhere to the style guide and make use of standard - * busybox functions by Glenn McGrath - * - * read_gz interface + associated hacking by Laurence Anderson - * - * Fixed huft_build() so decoding end-of-block code does not grab more bits - * than necessary (this is required by unzip applet), added inflate_cleanup() - * to free leaked bytebuffer memory (used in unzip.c), and some minor style - * guide cleanups by Ed Clark - * - * gzip (GNU zip) -- compress files with zip algorithm and 'compress' interface - * Copyright (C) 1992-1993 Jean-loup Gailly - * The unzip code was written and put in the public domain by Mark Adler. - * Portions of the lzw code are derived from the public domain 'compress' - * written by Spencer Thomas, Joe Orost, James Woods, Jim McKie, Steve Davies, - * Ken Turkowski, Dave Mack and Peter Jannesen. - * - * See the file algorithm.doc for the compression algorithms and file formats. - * - * Licensed under GPLv2 or later, see file LICENSE in this source tree. - */ - -#include -#include "libbb.h" -#include "unarchive.h" - -typedef struct huft_t { - unsigned char e; /* number of extra bits or operation */ - unsigned char b; /* number of bits in this code or subcode */ - union { - unsigned short n; /* literal, length base, or distance base */ - struct huft_t *t; /* pointer to next level of table */ - } v; -} huft_t; - -enum { - /* gunzip_window size--must be a power of two, and - * at least 32K for zip's deflate method */ - GUNZIP_WSIZE = 0x8000, - /* If BMAX needs to be larger than 16, then h and x[] should be ulg. */ - BMAX = 16, /* maximum bit length of any code (16 for explode) */ - N_MAX = 288, /* maximum number of codes in any set */ -}; - - -/* This is somewhat complex-looking arrangement, but it allows - * to place decompressor state either in bss or in - * malloc'ed space simply by changing #defines below. - * Sizes on i386: - * text data bss dec hex - * 5256 0 108 5364 14f4 - bss - * 4915 0 0 4915 1333 - malloc - */ -#define STATE_IN_BSS 0 -#define STATE_IN_MALLOC 1 - - -typedef struct state_t { - off_t gunzip_bytes_out; /* number of output bytes */ - uint32_t gunzip_crc; - - int gunzip_src_fd; - unsigned gunzip_outbuf_count; /* bytes in output buffer */ - - unsigned char *gunzip_window; - - uint32_t *gunzip_crc_table; - - /* bitbuffer */ - unsigned gunzip_bb; /* bit buffer */ - unsigned char gunzip_bk; /* bits in bit buffer */ - - /* input (compressed) data */ - unsigned char *bytebuffer; /* buffer itself */ - off_t to_read; /* compressed bytes to read (unzip only, -1 for gunzip) */ -// unsigned bytebuffer_max; /* buffer size */ - unsigned bytebuffer_offset; /* buffer position */ - unsigned bytebuffer_size; /* how much data is there (size <= max) */ - - /* private data of inflate_codes() */ - unsigned inflate_codes_ml; /* masks for bl and bd bits */ - unsigned inflate_codes_md; /* masks for bl and bd bits */ - unsigned inflate_codes_bb; /* bit buffer */ - unsigned inflate_codes_k; /* number of bits in bit buffer */ - unsigned inflate_codes_w; /* current gunzip_window position */ - huft_t *inflate_codes_tl; - huft_t *inflate_codes_td; - unsigned inflate_codes_bl; - unsigned inflate_codes_bd; - unsigned inflate_codes_nn; /* length and index for copy */ - unsigned inflate_codes_dd; - - smallint resume_copy; - - /* private data of inflate_get_next_window() */ - smallint method; /* method == -1 for stored, -2 for codes */ - smallint need_another_block; - smallint end_reached; - - /* private data of inflate_stored() */ - unsigned inflate_stored_n; - unsigned inflate_stored_b; - unsigned inflate_stored_k; - unsigned inflate_stored_w; - - const char *error_msg; - jmp_buf error_jmp; -} state_t; -#define gunzip_bytes_out (S()gunzip_bytes_out ) -#define gunzip_crc (S()gunzip_crc ) -#define gunzip_src_fd (S()gunzip_src_fd ) -#define gunzip_outbuf_count (S()gunzip_outbuf_count) -#define gunzip_window (S()gunzip_window ) -#define gunzip_crc_table (S()gunzip_crc_table ) -#define gunzip_bb (S()gunzip_bb ) -#define gunzip_bk (S()gunzip_bk ) -#define to_read (S()to_read ) -// #define bytebuffer_max (S()bytebuffer_max ) -// Both gunzip and unzip can use constant buffer size now (16k): -#define bytebuffer_max 0x4000 -#define bytebuffer (S()bytebuffer ) -#define bytebuffer_offset (S()bytebuffer_offset ) -#define bytebuffer_size (S()bytebuffer_size ) -#define inflate_codes_ml (S()inflate_codes_ml ) -#define inflate_codes_md (S()inflate_codes_md ) -#define inflate_codes_bb (S()inflate_codes_bb ) -#define inflate_codes_k (S()inflate_codes_k ) -#define inflate_codes_w (S()inflate_codes_w ) -#define inflate_codes_tl (S()inflate_codes_tl ) -#define inflate_codes_td (S()inflate_codes_td ) -#define inflate_codes_bl (S()inflate_codes_bl ) -#define inflate_codes_bd (S()inflate_codes_bd ) -#define inflate_codes_nn (S()inflate_codes_nn ) -#define inflate_codes_dd (S()inflate_codes_dd ) -#define resume_copy (S()resume_copy ) -#define method (S()method ) -#define need_another_block (S()need_another_block ) -#define end_reached (S()end_reached ) -#define inflate_stored_n (S()inflate_stored_n ) -#define inflate_stored_b (S()inflate_stored_b ) -#define inflate_stored_k (S()inflate_stored_k ) -#define inflate_stored_w (S()inflate_stored_w ) -#define error_msg (S()error_msg ) -#define error_jmp (S()error_jmp ) - -/* This is a generic part */ -#if STATE_IN_BSS /* Use global data segment */ -#define DECLARE_STATE /*nothing*/ -#define ALLOC_STATE /*nothing*/ -#define DEALLOC_STATE ((void)0) -#define S() state. -#define PASS_STATE /*nothing*/ -#define PASS_STATE_ONLY /*nothing*/ -#define STATE_PARAM /*nothing*/ -#define STATE_PARAM_ONLY void -static state_t state; -#endif - -#if STATE_IN_MALLOC /* Use malloc space */ -#define DECLARE_STATE state_t *state -#define ALLOC_STATE (state = xzalloc(sizeof(*state))) -#define DEALLOC_STATE free(state) -#define S() state-> -#define PASS_STATE state, -#define PASS_STATE_ONLY state -#define STATE_PARAM state_t *state, -#define STATE_PARAM_ONLY state_t *state -#endif - - -static const uint16_t mask_bits[] ALIGN2 = { - 0x0000, 0x0001, 0x0003, 0x0007, 0x000f, 0x001f, 0x003f, 0x007f, 0x00ff, - 0x01ff, 0x03ff, 0x07ff, 0x0fff, 0x1fff, 0x3fff, 0x7fff, 0xffff -}; - -/* Copy lengths for literal codes 257..285 */ -static const uint16_t cplens[] ALIGN2 = { - 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, 35, 43, 51, 59, - 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0 -}; - -/* note: see note #13 above about the 258 in this list. */ -/* Extra bits for literal codes 257..285 */ -static const uint8_t cplext[] ALIGN1 = { - 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, - 5, 5, 5, 0, 99, 99 -}; /* 99 == invalid */ - -/* Copy offsets for distance codes 0..29 */ -static const uint16_t cpdist[] ALIGN2 = { - 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, 257, 385, 513, - 769, 1025, 1537, 2049, 3073, 4097, 6145, 8193, 12289, 16385, 24577 -}; - -/* Extra bits for distance codes */ -static const uint8_t cpdext[] ALIGN1 = { - 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, - 11, 11, 12, 12, 13, 13 -}; - -/* Tables for deflate from PKZIP's appnote.txt. */ -/* Order of the bit length code lengths */ -static const uint8_t border[] ALIGN1 = { - 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 -}; - - -/* - * Free the malloc'ed tables built by huft_build(), which makes a linked - * list of the tables it made, with the links in a dummy first entry of - * each table. - * t: table to free - */ -static void huft_free(huft_t *p) -{ - huft_t *q; - - /* Go through linked list, freeing from the malloced (t[-1]) address. */ - while (p) { - q = (--p)->v.t; - free(p); - p = q; - } -} - -static void huft_free_all(STATE_PARAM_ONLY) -{ - huft_free(inflate_codes_tl); - huft_free(inflate_codes_td); - inflate_codes_tl = NULL; - inflate_codes_td = NULL; -} - -static void abort_unzip(STATE_PARAM_ONLY) NORETURN; -static void abort_unzip(STATE_PARAM_ONLY) -{ - huft_free_all(PASS_STATE_ONLY); - longjmp(error_jmp, 1); -} - -static unsigned fill_bitbuffer(STATE_PARAM unsigned bitbuffer, unsigned *current, const unsigned required) -{ - while (*current < required) { - if (bytebuffer_offset >= bytebuffer_size) { - unsigned sz = bytebuffer_max - 4; - if (to_read >= 0 && to_read < sz) /* unzip only */ - sz = to_read; - /* Leave the first 4 bytes empty so we can always unwind the bitbuffer - * to the front of the bytebuffer */ - bytebuffer_size = safe_read(gunzip_src_fd, &bytebuffer[4], sz); - if ((int)bytebuffer_size < 1) { - error_msg = "unexpected end of file"; - abort_unzip(PASS_STATE_ONLY); - } - if (to_read >= 0) /* unzip only */ - to_read -= bytebuffer_size; - bytebuffer_size += 4; - bytebuffer_offset = 4; - } - bitbuffer |= ((unsigned) bytebuffer[bytebuffer_offset]) << *current; - bytebuffer_offset++; - *current += 8; - } - return bitbuffer; -} - - -/* Given a list of code lengths and a maximum table size, make a set of - * tables to decode that set of codes. Return zero on success, one if - * the given code set is incomplete (the tables are still built in this - * case), two if the input is invalid (all zero length codes or an - * oversubscribed set of lengths) - in this case stores NULL in *t. - * - * b: code lengths in bits (all assumed <= BMAX) - * n: number of codes (assumed <= N_MAX) - * s: number of simple-valued codes (0..s-1) - * d: list of base values for non-simple codes - * e: list of extra bits for non-simple codes - * t: result: starting table - * m: maximum lookup bits, returns actual - */ -static int huft_build(const unsigned *b, const unsigned n, - const unsigned s, const unsigned short *d, - const unsigned char *e, huft_t **t, unsigned *m) -{ - unsigned a; /* counter for codes of length k */ - unsigned c[BMAX + 1]; /* bit length count table */ - unsigned eob_len; /* length of end-of-block code (value 256) */ - unsigned f; /* i repeats in table every f entries */ - int g; /* maximum code length */ - int htl; /* table level */ - unsigned i; /* counter, current code */ - unsigned j; /* counter */ - int k; /* number of bits in current code */ - unsigned *p; /* pointer into c[], b[], or v[] */ - huft_t *q; /* points to current table */ - huft_t r; /* table entry for structure assignment */ - huft_t *u[BMAX]; /* table stack */ - unsigned v[N_MAX]; /* values in order of bit length */ - int ws[BMAX + 1]; /* bits decoded stack */ - int w; /* bits decoded */ - unsigned x[BMAX + 1]; /* bit offsets, then code stack */ - unsigned *xp; /* pointer into x */ - int y; /* number of dummy codes added */ - unsigned z; /* number of entries in current table */ - - /* Length of EOB code, if any */ - eob_len = n > 256 ? b[256] : BMAX; - - *t = NULL; - - /* Generate counts for each bit length */ - memset(c, 0, sizeof(c)); - p = (unsigned *) b; /* cast allows us to reuse p for pointing to b */ - i = n; - do { - c[*p]++; /* assume all entries <= BMAX */ - p++; /* can't combine with above line (Solaris bug) */ - } while (--i); - if (c[0] == n) { /* null input - all zero length codes */ - *m = 0; - return 2; - } - - /* Find minimum and maximum length, bound *m by those */ - for (j = 1; (c[j] == 0) && (j <= BMAX); j++) - continue; - k = j; /* minimum code length */ - for (i = BMAX; (c[i] == 0) && i; i--) - continue; - g = i; /* maximum code length */ - *m = (*m < j) ? j : ((*m > i) ? i : *m); - - /* Adjust last length count to fill out codes, if needed */ - for (y = 1 << j; j < i; j++, y <<= 1) { - y -= c[j]; - if (y < 0) - return 2; /* bad input: more codes than bits */ - } - y -= c[i]; - if (y < 0) - return 2; - c[i] += y; - - /* Generate starting offsets into the value table for each length */ - x[1] = j = 0; - p = c + 1; - xp = x + 2; - while (--i) { /* note that i == g from above */ - j += *p++; - *xp++ = j; - } - - /* Make a table of values in order of bit lengths */ - p = (unsigned *) b; - i = 0; - do { - j = *p++; - if (j != 0) { - v[x[j]++] = i; - } - } while (++i < n); - - /* Generate the Huffman codes and for each, make the table entries */ - x[0] = i = 0; /* first Huffman code is zero */ - p = v; /* grab values in bit order */ - htl = -1; /* no tables yet--level -1 */ - w = ws[0] = 0; /* bits decoded */ - u[0] = NULL; /* just to keep compilers happy */ - q = NULL; /* ditto */ - z = 0; /* ditto */ - - /* go through the bit lengths (k already is bits in shortest code) */ - for (; k <= g; k++) { - a = c[k]; - while (a--) { - /* here i is the Huffman code of length k bits for value *p */ - /* make tables up to required level */ - while (k > ws[htl + 1]) { - w = ws[++htl]; - - /* compute minimum size table less than or equal to *m bits */ - z = g - w; - z = z > *m ? *m : z; /* upper limit on table size */ - j = k - w; - f = 1 << j; - if (f > a + 1) { /* try a k-w bit table */ - /* too few codes for k-w bit table */ - f -= a + 1; /* deduct codes from patterns left */ - xp = c + k; - while (++j < z) { /* try smaller tables up to z bits */ - f <<= 1; - if (f <= *++xp) { - break; /* enough codes to use up j bits */ - } - f -= *xp; /* else deduct codes from patterns */ - } - } - j = (w + j > eob_len && w < eob_len) ? eob_len - w : j; /* make EOB code end at table */ - z = 1 << j; /* table entries for j-bit table */ - ws[htl+1] = w + j; /* set bits decoded in stack */ - - /* allocate and link in new table */ - q = xzalloc((z + 1) * sizeof(huft_t)); - *t = q + 1; /* link to list for huft_free() */ - t = &(q->v.t); - u[htl] = ++q; /* table starts after link */ - - /* connect to last table, if there is one */ - if (htl) { - x[htl] = i; /* save pattern for backing up */ - r.b = (unsigned char) (w - ws[htl - 1]); /* bits to dump before this table */ - r.e = (unsigned char) (16 + j); /* bits in this table */ - r.v.t = q; /* pointer to this table */ - j = (i & ((1 << w) - 1)) >> ws[htl - 1]; - u[htl - 1][j] = r; /* connect to last table */ - } - } - - /* set up table entry in r */ - r.b = (unsigned char) (k - w); - if (p >= v + n) { - r.e = 99; /* out of values--invalid code */ - } else if (*p < s) { - r.e = (unsigned char) (*p < 256 ? 16 : 15); /* 256 is EOB code */ - r.v.n = (unsigned short) (*p++); /* simple code is just the value */ - } else { - r.e = (unsigned char) e[*p - s]; /* non-simple--look up in lists */ - r.v.n = d[*p++ - s]; - } - - /* fill code-like entries with r */ - f = 1 << (k - w); - for (j = i >> w; j < z; j += f) { - q[j] = r; - } - - /* backwards increment the k-bit code i */ - for (j = 1 << (k - 1); i & j; j >>= 1) { - i ^= j; - } - i ^= j; - - /* backup over finished tables */ - while ((i & ((1 << w) - 1)) != x[htl]) { - w = ws[--htl]; - } - } - } - - /* return actual size of base table */ - *m = ws[1]; - - /* Return 1 if we were given an incomplete table */ - return y != 0 && g != 1; -} - - -/* - * inflate (decompress) the codes in a deflated (compressed) block. - * Return an error code or zero if it all goes ok. - * - * tl, td: literal/length and distance decoder tables - * bl, bd: number of bits decoded by tl[] and td[] - */ -/* called once from inflate_block */ - -/* map formerly local static variables to globals */ -#define ml inflate_codes_ml -#define md inflate_codes_md -#define bb inflate_codes_bb -#define k inflate_codes_k -#define w inflate_codes_w -#define tl inflate_codes_tl -#define td inflate_codes_td -#define bl inflate_codes_bl -#define bd inflate_codes_bd -#define nn inflate_codes_nn -#define dd inflate_codes_dd -static void inflate_codes_setup(STATE_PARAM unsigned my_bl, unsigned my_bd) -{ - bl = my_bl; - bd = my_bd; - /* make local copies of globals */ - bb = gunzip_bb; /* initialize bit buffer */ - k = gunzip_bk; - w = gunzip_outbuf_count; /* initialize gunzip_window position */ - /* inflate the coded data */ - ml = mask_bits[bl]; /* precompute masks for speed */ - md = mask_bits[bd]; -} -/* called once from inflate_get_next_window */ -static NOINLINE int inflate_codes(STATE_PARAM_ONLY) -{ - unsigned e; /* table entry flag/number of extra bits */ - huft_t *t; /* pointer to table entry */ - - if (resume_copy) - goto do_copy; - - while (1) { /* do until end of block */ - bb = fill_bitbuffer(PASS_STATE bb, &k, bl); - t = tl + ((unsigned) bb & ml); - e = t->e; - if (e > 16) - do { - if (e == 99) - abort_unzip(PASS_STATE_ONLY);; - bb >>= t->b; - k -= t->b; - e -= 16; - bb = fill_bitbuffer(PASS_STATE bb, &k, e); - t = t->v.t + ((unsigned) bb & mask_bits[e]); - e = t->e; - } while (e > 16); - bb >>= t->b; - k -= t->b; - if (e == 16) { /* then it's a literal */ - gunzip_window[w++] = (unsigned char) t->v.n; - if (w == GUNZIP_WSIZE) { - gunzip_outbuf_count = w; - //flush_gunzip_window(); - w = 0; - return 1; // We have a block to read - } - } else { /* it's an EOB or a length */ - /* exit if end of block */ - if (e == 15) { - break; - } - - /* get length of block to copy */ - bb = fill_bitbuffer(PASS_STATE bb, &k, e); - nn = t->v.n + ((unsigned) bb & mask_bits[e]); - bb >>= e; - k -= e; - - /* decode distance of block to copy */ - bb = fill_bitbuffer(PASS_STATE bb, &k, bd); - t = td + ((unsigned) bb & md); - e = t->e; - if (e > 16) - do { - if (e == 99) - abort_unzip(PASS_STATE_ONLY); - bb >>= t->b; - k -= t->b; - e -= 16; - bb = fill_bitbuffer(PASS_STATE bb, &k, e); - t = t->v.t + ((unsigned) bb & mask_bits[e]); - e = t->e; - } while (e > 16); - bb >>= t->b; - k -= t->b; - bb = fill_bitbuffer(PASS_STATE bb, &k, e); - dd = w - t->v.n - ((unsigned) bb & mask_bits[e]); - bb >>= e; - k -= e; - - /* do the copy */ - do_copy: - do { - /* Was: nn -= (e = (e = GUNZIP_WSIZE - ((dd &= GUNZIP_WSIZE - 1) > w ? dd : w)) > nn ? nn : e); */ - /* Who wrote THAT?? rewritten as: */ - unsigned delta; - - dd &= GUNZIP_WSIZE - 1; - e = GUNZIP_WSIZE - (dd > w ? dd : w); - delta = w > dd ? w - dd : dd - w; - if (e > nn) e = nn; - nn -= e; - - /* copy to new buffer to prevent possible overwrite */ - if (delta >= e) { - memcpy(gunzip_window + w, gunzip_window + dd, e); - w += e; - dd += e; - } else { - /* do it slow to avoid memcpy() overlap */ - /* !NOMEMCPY */ - do { - gunzip_window[w++] = gunzip_window[dd++]; - } while (--e); - } - if (w == GUNZIP_WSIZE) { - gunzip_outbuf_count = w; - resume_copy = (nn != 0); - //flush_gunzip_window(); - w = 0; - return 1; - } - } while (nn); - resume_copy = 0; - } - } - - /* restore the globals from the locals */ - gunzip_outbuf_count = w; /* restore global gunzip_window pointer */ - gunzip_bb = bb; /* restore global bit buffer */ - gunzip_bk = k; - - /* normally just after call to inflate_codes, but save code by putting it here */ - /* free the decoding tables (tl and td), return */ - huft_free_all(PASS_STATE_ONLY); - - /* done */ - return 0; -} -#undef ml -#undef md -#undef bb -#undef k -#undef w -#undef tl -#undef td -#undef bl -#undef bd -#undef nn -#undef dd - - -/* called once from inflate_block */ -static void inflate_stored_setup(STATE_PARAM int my_n, int my_b, int my_k) -{ - inflate_stored_n = my_n; - inflate_stored_b = my_b; - inflate_stored_k = my_k; - /* initialize gunzip_window position */ - inflate_stored_w = gunzip_outbuf_count; -} -/* called once from inflate_get_next_window */ -static int inflate_stored(STATE_PARAM_ONLY) -{ - /* read and output the compressed data */ - while (inflate_stored_n--) { - inflate_stored_b = fill_bitbuffer(PASS_STATE inflate_stored_b, &inflate_stored_k, 8); - gunzip_window[inflate_stored_w++] = (unsigned char) inflate_stored_b; - if (inflate_stored_w == GUNZIP_WSIZE) { - gunzip_outbuf_count = inflate_stored_w; - //flush_gunzip_window(); - inflate_stored_w = 0; - inflate_stored_b >>= 8; - inflate_stored_k -= 8; - return 1; /* We have a block */ - } - inflate_stored_b >>= 8; - inflate_stored_k -= 8; - } - - /* restore the globals from the locals */ - gunzip_outbuf_count = inflate_stored_w; /* restore global gunzip_window pointer */ - gunzip_bb = inflate_stored_b; /* restore global bit buffer */ - gunzip_bk = inflate_stored_k; - return 0; /* Finished */ -} - - -/* - * decompress an inflated block - * e: last block flag - * - * GLOBAL VARIABLES: bb, kk, - */ -/* Return values: -1 = inflate_stored, -2 = inflate_codes */ -/* One callsite in inflate_get_next_window */ -static int inflate_block(STATE_PARAM smallint *e) -{ - unsigned ll[286 + 30]; /* literal/length and distance code lengths */ - unsigned t; /* block type */ - unsigned b; /* bit buffer */ - unsigned k; /* number of bits in bit buffer */ - - /* make local bit buffer */ - - b = gunzip_bb; - k = gunzip_bk; - - /* read in last block bit */ - b = fill_bitbuffer(PASS_STATE b, &k, 1); - *e = b & 1; - b >>= 1; - k -= 1; - - /* read in block type */ - b = fill_bitbuffer(PASS_STATE b, &k, 2); - t = (unsigned) b & 3; - b >>= 2; - k -= 2; - - /* restore the global bit buffer */ - gunzip_bb = b; - gunzip_bk = k; - - /* Do we see block type 1 often? Yes! - * TODO: fix performance problem (see below) */ - //bb_error_msg("blktype %d", t); - - /* inflate that block type */ - switch (t) { - case 0: /* Inflate stored */ - { - unsigned n; /* number of bytes in block */ - unsigned b_stored; /* bit buffer */ - unsigned k_stored; /* number of bits in bit buffer */ - - /* make local copies of globals */ - b_stored = gunzip_bb; /* initialize bit buffer */ - k_stored = gunzip_bk; - - /* go to byte boundary */ - n = k_stored & 7; - b_stored >>= n; - k_stored -= n; - - /* get the length and its complement */ - b_stored = fill_bitbuffer(PASS_STATE b_stored, &k_stored, 16); - n = ((unsigned) b_stored & 0xffff); - b_stored >>= 16; - k_stored -= 16; - - b_stored = fill_bitbuffer(PASS_STATE b_stored, &k_stored, 16); - if (n != (unsigned) ((~b_stored) & 0xffff)) { - abort_unzip(PASS_STATE_ONLY); /* error in compressed data */ - } - b_stored >>= 16; - k_stored -= 16; - - inflate_stored_setup(PASS_STATE n, b_stored, k_stored); - - return -1; - } - case 1: - /* Inflate fixed - * decompress an inflated type 1 (fixed Huffman codes) block. We should - * either replace this with a custom decoder, or at least precompute the - * Huffman tables. TODO */ - { - int i; /* temporary variable */ - unsigned bl; /* lookup bits for tl */ - unsigned bd; /* lookup bits for td */ - /* gcc 4.2.1 is too dumb to reuse stackspace. Moved up... */ - //unsigned ll[288]; /* length list for huft_build */ - - /* set up literal table */ - for (i = 0; i < 144; i++) - ll[i] = 8; - for (; i < 256; i++) - ll[i] = 9; - for (; i < 280; i++) - ll[i] = 7; - for (; i < 288; i++) /* make a complete, but wrong code set */ - ll[i] = 8; - bl = 7; - huft_build(ll, 288, 257, cplens, cplext, &inflate_codes_tl, &bl); - /* huft_build() never return nonzero - we use known data */ - - /* set up distance table */ - for (i = 0; i < 30; i++) /* make an incomplete code set */ - ll[i] = 5; - bd = 5; - huft_build(ll, 30, 0, cpdist, cpdext, &inflate_codes_td, &bd); - - /* set up data for inflate_codes() */ - inflate_codes_setup(PASS_STATE bl, bd); - - /* huft_free code moved into inflate_codes */ - - return -2; - } - case 2: /* Inflate dynamic */ - { - enum { dbits = 6 }; /* bits in base distance lookup table */ - enum { lbits = 9 }; /* bits in base literal/length lookup table */ - - huft_t *td; /* distance code table */ - unsigned i; /* temporary variables */ - unsigned j; - unsigned l; /* last length */ - unsigned m; /* mask for bit lengths table */ - unsigned n; /* number of lengths to get */ - unsigned bl; /* lookup bits for tl */ - unsigned bd; /* lookup bits for td */ - unsigned nb; /* number of bit length codes */ - unsigned nl; /* number of literal/length codes */ - unsigned nd; /* number of distance codes */ - - //unsigned ll[286 + 30];/* literal/length and distance code lengths */ - unsigned b_dynamic; /* bit buffer */ - unsigned k_dynamic; /* number of bits in bit buffer */ - - /* make local bit buffer */ - b_dynamic = gunzip_bb; - k_dynamic = gunzip_bk; - - /* read in table lengths */ - b_dynamic = fill_bitbuffer(PASS_STATE b_dynamic, &k_dynamic, 5); - nl = 257 + ((unsigned) b_dynamic & 0x1f); /* number of literal/length codes */ - - b_dynamic >>= 5; - k_dynamic -= 5; - b_dynamic = fill_bitbuffer(PASS_STATE b_dynamic, &k_dynamic, 5); - nd = 1 + ((unsigned) b_dynamic & 0x1f); /* number of distance codes */ - - b_dynamic >>= 5; - k_dynamic -= 5; - b_dynamic = fill_bitbuffer(PASS_STATE b_dynamic, &k_dynamic, 4); - nb = 4 + ((unsigned) b_dynamic & 0xf); /* number of bit length codes */ - - b_dynamic >>= 4; - k_dynamic -= 4; - if (nl > 286 || nd > 30) - abort_unzip(PASS_STATE_ONLY); /* bad lengths */ - - /* read in bit-length-code lengths */ - for (j = 0; j < nb; j++) { - b_dynamic = fill_bitbuffer(PASS_STATE b_dynamic, &k_dynamic, 3); - ll[border[j]] = (unsigned) b_dynamic & 7; - b_dynamic >>= 3; - k_dynamic -= 3; - } - for (; j < 19; j++) - ll[border[j]] = 0; - - /* build decoding table for trees - single level, 7 bit lookup */ - bl = 7; - i = huft_build(ll, 19, 19, NULL, NULL, &inflate_codes_tl, &bl); - if (i != 0) { - abort_unzip(PASS_STATE_ONLY); //return i; /* incomplete code set */ - } - - /* read in literal and distance code lengths */ - n = nl + nd; - m = mask_bits[bl]; - i = l = 0; - while ((unsigned) i < n) { - b_dynamic = fill_bitbuffer(PASS_STATE b_dynamic, &k_dynamic, (unsigned)bl); - td = inflate_codes_tl + ((unsigned) b_dynamic & m); - j = td->b; - b_dynamic >>= j; - k_dynamic -= j; - j = td->v.n; - if (j < 16) { /* length of code in bits (0..15) */ - ll[i++] = l = j; /* save last length in l */ - } else if (j == 16) { /* repeat last length 3 to 6 times */ - b_dynamic = fill_bitbuffer(PASS_STATE b_dynamic, &k_dynamic, 2); - j = 3 + ((unsigned) b_dynamic & 3); - b_dynamic >>= 2; - k_dynamic -= 2; - if ((unsigned) i + j > n) { - abort_unzip(PASS_STATE_ONLY); //return 1; - } - while (j--) { - ll[i++] = l; - } - } else if (j == 17) { /* 3 to 10 zero length codes */ - b_dynamic = fill_bitbuffer(PASS_STATE b_dynamic, &k_dynamic, 3); - j = 3 + ((unsigned) b_dynamic & 7); - b_dynamic >>= 3; - k_dynamic -= 3; - if ((unsigned) i + j > n) { - abort_unzip(PASS_STATE_ONLY); //return 1; - } - while (j--) { - ll[i++] = 0; - } - l = 0; - } else { /* j == 18: 11 to 138 zero length codes */ - b_dynamic = fill_bitbuffer(PASS_STATE b_dynamic, &k_dynamic, 7); - j = 11 + ((unsigned) b_dynamic & 0x7f); - b_dynamic >>= 7; - k_dynamic -= 7; - if ((unsigned) i + j > n) { - abort_unzip(PASS_STATE_ONLY); //return 1; - } - while (j--) { - ll[i++] = 0; - } - l = 0; - } - } - - /* free decoding table for trees */ - huft_free(inflate_codes_tl); - - /* restore the global bit buffer */ - gunzip_bb = b_dynamic; - gunzip_bk = k_dynamic; - - /* build the decoding tables for literal/length and distance codes */ - bl = lbits; - - i = huft_build(ll, nl, 257, cplens, cplext, &inflate_codes_tl, &bl); - if (i != 0) - abort_unzip(PASS_STATE_ONLY); - bd = dbits; - i = huft_build(ll + nl, nd, 0, cpdist, cpdext, &inflate_codes_td, &bd); - if (i != 0) - abort_unzip(PASS_STATE_ONLY); - - /* set up data for inflate_codes() */ - inflate_codes_setup(PASS_STATE bl, bd); - - /* huft_free code moved into inflate_codes */ - - return -2; - } - default: - abort_unzip(PASS_STATE_ONLY); - } -} - -/* Two callsites, both in inflate_get_next_window */ -static void calculate_gunzip_crc(STATE_PARAM_ONLY) -{ - gunzip_crc = crc32_block_endian0(gunzip_crc, gunzip_window, gunzip_outbuf_count, gunzip_crc_table); - gunzip_bytes_out += gunzip_outbuf_count; -} - -/* One callsite in inflate_unzip_internal */ -static int inflate_get_next_window(STATE_PARAM_ONLY) -{ - gunzip_outbuf_count = 0; - - while (1) { - int ret; - - if (need_another_block) { - if (end_reached) { - calculate_gunzip_crc(PASS_STATE_ONLY); - end_reached = 0; - /* NB: need_another_block is still set */ - return 0; /* Last block */ - } - method = inflate_block(PASS_STATE &end_reached); - need_another_block = 0; - } - - switch (method) { - case -1: - ret = inflate_stored(PASS_STATE_ONLY); - break; - case -2: - ret = inflate_codes(PASS_STATE_ONLY); - break; - default: /* cannot happen */ - abort_unzip(PASS_STATE_ONLY); - } - - if (ret == 1) { - calculate_gunzip_crc(PASS_STATE_ONLY); - return 1; /* more data left */ - } - need_another_block = 1; /* end of that block */ - } - /* Doesnt get here */ -} - - -/* Called from unpack_gz_stream() and inflate_unzip() */ -static IF_DESKTOP(long long) int -inflate_unzip_internal(STATE_PARAM int in, int out) -{ - IF_DESKTOP(long long) int n = 0; - ssize_t nwrote; - - /* Allocate all global buffers (for DYN_ALLOC option) */ - gunzip_window = xmalloc(GUNZIP_WSIZE); - gunzip_outbuf_count = 0; - gunzip_bytes_out = 0; - gunzip_src_fd = in; - - /* (re) initialize state */ - method = -1; - need_another_block = 1; - resume_copy = 0; - gunzip_bk = 0; - gunzip_bb = 0; - - /* Create the crc table */ - gunzip_crc_table = crc32_filltable(NULL, 0); - gunzip_crc = ~0; - - error_msg = "corrupted data"; - if (setjmp(error_jmp)) { - /* Error from deep inside zip machinery */ - n = -1; - goto ret; - } - - while (1) { - int r = inflate_get_next_window(PASS_STATE_ONLY); - nwrote = full_write(out, gunzip_window, gunzip_outbuf_count); - if (nwrote != (ssize_t)gunzip_outbuf_count) { - bb_perror_msg("write"); - n = -1; - goto ret; - } - IF_DESKTOP(n += nwrote;) - if (r == 0) break; - } - - /* Store unused bytes in a global buffer so calling applets can access it */ - if (gunzip_bk >= 8) { - /* Undo too much lookahead. The next read will be byte aligned - * so we can discard unused bits in the last meaningful byte. */ - bytebuffer_offset--; - bytebuffer[bytebuffer_offset] = gunzip_bb & 0xff; - gunzip_bb >>= 8; - gunzip_bk -= 8; - } - ret: - /* Cleanup */ - free(gunzip_window); - free(gunzip_crc_table); - return n; -} - - -/* External entry points */ - -/* For unzip */ - -IF_DESKTOP(long long) int FAST_FUNC -inflate_unzip(inflate_unzip_result *res, off_t compr_size, int in, int out) -{ - IF_DESKTOP(long long) int n; - DECLARE_STATE; - - ALLOC_STATE; - - to_read = compr_size; -// bytebuffer_max = 0x8000; - bytebuffer_offset = 4; - bytebuffer = xmalloc(bytebuffer_max); - n = inflate_unzip_internal(PASS_STATE in, out); - free(bytebuffer); - - res->crc = gunzip_crc; - res->bytes_out = gunzip_bytes_out; - DEALLOC_STATE; - return n; -} - - -/* For gunzip */ - -/* helpers first */ - -/* Top up the input buffer with at least n bytes. */ -static int top_up(STATE_PARAM unsigned n) -{ - int count = bytebuffer_size - bytebuffer_offset; - - if (count < (int)n) { - memmove(bytebuffer, &bytebuffer[bytebuffer_offset], count); - bytebuffer_offset = 0; - bytebuffer_size = full_read(gunzip_src_fd, &bytebuffer[count], bytebuffer_max - count); - if ((int)bytebuffer_size < 0) { - bb_error_msg(bb_msg_read_error); - return 0; - } - bytebuffer_size += count; - if (bytebuffer_size < n) - return 0; - } - return 1; -} - -static uint16_t buffer_read_le_u16(STATE_PARAM_ONLY) -{ - uint16_t res; -#if BB_LITTLE_ENDIAN - move_from_unaligned16(res, &bytebuffer[bytebuffer_offset]); -#else - res = bytebuffer[bytebuffer_offset]; - res |= bytebuffer[bytebuffer_offset + 1] << 8; -#endif - bytebuffer_offset += 2; - return res; -} - -static uint32_t buffer_read_le_u32(STATE_PARAM_ONLY) -{ - uint32_t res; -#if BB_LITTLE_ENDIAN - move_from_unaligned32(res, &bytebuffer[bytebuffer_offset]); -#else - res = bytebuffer[bytebuffer_offset]; - res |= bytebuffer[bytebuffer_offset + 1] << 8; - res |= bytebuffer[bytebuffer_offset + 2] << 16; - res |= bytebuffer[bytebuffer_offset + 3] << 24; -#endif - bytebuffer_offset += 4; - return res; -} - -static int check_header_gzip(STATE_PARAM unpack_info_t *info) -{ - union { - unsigned char raw[8]; - struct { - uint8_t gz_method; - uint8_t flags; - uint32_t mtime; - uint8_t xtra_flags_UNUSED; - uint8_t os_flags_UNUSED; - } PACKED formatted; - } header; - struct BUG_header { - char BUG_header[sizeof(header) == 8 ? 1 : -1]; - }; - - /* - * Rewind bytebuffer. We use the beginning because the header has 8 - * bytes, leaving enough for unwinding afterwards. - */ - bytebuffer_size -= bytebuffer_offset; - memmove(bytebuffer, &bytebuffer[bytebuffer_offset], bytebuffer_size); - bytebuffer_offset = 0; - - if (!top_up(PASS_STATE 8)) - return 0; - memcpy(header.raw, &bytebuffer[bytebuffer_offset], 8); - bytebuffer_offset += 8; - - /* Check the compression method */ - if (header.formatted.gz_method != 8) { - return 0; - } - - if (header.formatted.flags & 0x04) { - /* bit 2 set: extra field present */ - unsigned extra_short; - - if (!top_up(PASS_STATE 2)) - return 0; - extra_short = buffer_read_le_u16(PASS_STATE_ONLY); - if (!top_up(PASS_STATE extra_short)) - return 0; - /* Ignore extra field */ - bytebuffer_offset += extra_short; - } - - /* Discard original name and file comment if any */ - /* bit 3 set: original file name present */ - /* bit 4 set: file comment present */ - if (header.formatted.flags & 0x18) { - while (1) { - do { - if (!top_up(PASS_STATE 1)) - return 0; - } while (bytebuffer[bytebuffer_offset++] != 0); - if ((header.formatted.flags & 0x18) != 0x18) - break; - header.formatted.flags &= ~0x18; - } - } - - if (info) - info->mtime = SWAP_LE32(header.formatted.mtime); - - /* Read the header checksum */ - if (header.formatted.flags & 0x02) { - if (!top_up(PASS_STATE 2)) - return 0; - bytebuffer_offset += 2; - } - return 1; -} - -IF_DESKTOP(long long) int FAST_FUNC -unpack_gz_stream_with_info(int in, int out, unpack_info_t *info) -{ - uint32_t v32; - IF_DESKTOP(long long) int n; - DECLARE_STATE; - - n = 0; - - ALLOC_STATE; - to_read = -1; -// bytebuffer_max = 0x8000; - bytebuffer = xmalloc(bytebuffer_max); - gunzip_src_fd = in; - - again: - if (!check_header_gzip(PASS_STATE info)) { - bb_error_msg("corrupted data"); - n = -1; - goto ret; - } - n += inflate_unzip_internal(PASS_STATE in, out); - if (n < 0) - goto ret; - - if (!top_up(PASS_STATE 8)) { - bb_error_msg("corrupted data"); - n = -1; - goto ret; - } - - /* Validate decompression - crc */ - v32 = buffer_read_le_u32(PASS_STATE_ONLY); - if ((~gunzip_crc) != v32) { - bb_error_msg("crc error"); - n = -1; - goto ret; - } - - /* Validate decompression - size */ - v32 = buffer_read_le_u32(PASS_STATE_ONLY); - if ((uint32_t)gunzip_bytes_out != v32) { - bb_error_msg("incorrect length"); - n = -1; - } - - if (!top_up(PASS_STATE 2)) - goto ret; /* EOF */ - - if (bytebuffer[bytebuffer_offset] == 0x1f - && bytebuffer[bytebuffer_offset + 1] == 0x8b - ) { - bytebuffer_offset += 2; - goto again; - } - /* GNU gzip says: */ - /*bb_error_msg("decompression OK, trailing garbage ignored");*/ - - ret: - free(bytebuffer); - DEALLOC_STATE; - return n; -} - -IF_DESKTOP(long long) int FAST_FUNC -unpack_gz_stream(int in, int out) -{ - return unpack_gz_stream_with_info(in, out, NULL); -} diff --git a/archival/libunarchive/filter_accept_all.c b/archival/libunarchive/filter_accept_all.c deleted file mode 100644 index cb1f506c8..000000000 --- a/archival/libunarchive/filter_accept_all.c +++ /dev/null @@ -1,17 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Copyright (C) 2002 by Glenn McGrath - * - * Licensed under GPLv2 or later, see file LICENSE in this source tree. - */ - -#include "libbb.h" -#include "unarchive.h" - -/* Accept any non-null name, its not really a filter at all */ -char FAST_FUNC filter_accept_all(archive_handle_t *archive_handle) -{ - if (archive_handle->file_header->name) - return EXIT_SUCCESS; - return EXIT_FAILURE; -} diff --git a/archival/libunarchive/filter_accept_list.c b/archival/libunarchive/filter_accept_list.c deleted file mode 100644 index fe4414c85..000000000 --- a/archival/libunarchive/filter_accept_list.c +++ /dev/null @@ -1,19 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Copyright (C) 2002 by Glenn McGrath - * - * Licensed under GPLv2 or later, see file LICENSE in this source tree. - */ - -#include "libbb.h" -#include "unarchive.h" - -/* - * Accept names that are in the accept list, ignoring reject list. - */ -char FAST_FUNC filter_accept_list(archive_handle_t *archive_handle) -{ - if (find_list_entry(archive_handle->accept, archive_handle->file_header->name)) - return EXIT_SUCCESS; - return EXIT_FAILURE; -} diff --git a/archival/libunarchive/filter_accept_list_reassign.c b/archival/libunarchive/filter_accept_list_reassign.c deleted file mode 100644 index 891f58390..000000000 --- a/archival/libunarchive/filter_accept_list_reassign.c +++ /dev/null @@ -1,51 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Copyright (C) 2002 by Glenn McGrath - * - * Licensed under GPLv2 or later, see file LICENSE in this source tree. - */ - -#include "libbb.h" -#include "unarchive.h" - -/* Built and used only if ENABLE_DPKG || ENABLE_DPKG_DEB */ - -/* - * Reassign the subarchive metadata parser based on the filename extension - * e.g. if its a .tar.gz modify archive_handle->sub_archive to process a .tar.gz - * or if its a .tar.bz2 make archive_handle->sub_archive handle that - */ -char FAST_FUNC filter_accept_list_reassign(archive_handle_t *archive_handle) -{ - /* Check the file entry is in the accept list */ - if (find_list_entry(archive_handle->accept, archive_handle->file_header->name)) { - const char *name_ptr; - - /* Find extension */ - name_ptr = strrchr(archive_handle->file_header->name, '.'); - if (!name_ptr) - return EXIT_FAILURE; - name_ptr++; - - /* Modify the subarchive handler based on the extension */ - if (ENABLE_FEATURE_SEAMLESS_GZ - && strcmp(name_ptr, "gz") == 0 - ) { - archive_handle->dpkg__action_data_subarchive = get_header_tar_gz; - return EXIT_SUCCESS; - } - if (ENABLE_FEATURE_SEAMLESS_BZ2 - && strcmp(name_ptr, "bz2") == 0 - ) { - archive_handle->dpkg__action_data_subarchive = get_header_tar_bz2; - return EXIT_SUCCESS; - } - if (ENABLE_FEATURE_SEAMLESS_LZMA - && strcmp(name_ptr, "lzma") == 0 - ) { - archive_handle->dpkg__action_data_subarchive = get_header_tar_lzma; - return EXIT_SUCCESS; - } - } - return EXIT_FAILURE; -} diff --git a/archival/libunarchive/filter_accept_reject_list.c b/archival/libunarchive/filter_accept_reject_list.c deleted file mode 100644 index 89a5502d5..000000000 --- a/archival/libunarchive/filter_accept_reject_list.c +++ /dev/null @@ -1,36 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Copyright (C) 2002 by Glenn McGrath - * - * Licensed under GPLv2 or later, see file LICENSE in this source tree. - */ - -#include "libbb.h" -#include "unarchive.h" - -/* - * Accept names that are in the accept list and not in the reject list - */ -char FAST_FUNC filter_accept_reject_list(archive_handle_t *archive_handle) -{ - const char *key; - const llist_t *reject_entry; - const llist_t *accept_entry; - - key = archive_handle->file_header->name; - - /* If the key is in a reject list fail */ - reject_entry = find_list_entry2(archive_handle->reject, key); - if (reject_entry) { - return EXIT_FAILURE; - } - accept_entry = find_list_entry2(archive_handle->accept, key); - - /* Fail if an accept list was specified and the key wasnt in there */ - if ((accept_entry == NULL) && archive_handle->accept) { - return EXIT_FAILURE; - } - - /* Accepted */ - return EXIT_SUCCESS; -} diff --git a/archival/libunarchive/find_list_entry.c b/archival/libunarchive/find_list_entry.c deleted file mode 100644 index 5c0c85f09..000000000 --- a/archival/libunarchive/find_list_entry.c +++ /dev/null @@ -1,54 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Copyright (C) 2002 by Glenn McGrath - * - * Licensed under GPLv2 or later, see file LICENSE in this source tree. - */ - -#include -#include "libbb.h" -#include "unarchive.h" - -/* Find a string in a shell pattern list */ -const llist_t* FAST_FUNC find_list_entry(const llist_t *list, const char *filename) -{ - while (list) { - if (fnmatch(list->data, filename, 0) == 0) { - return list; - } - list = list->link; - } - return NULL; -} - -/* Same, but compares only path components present in pattern - * (extra trailing path components in filename are assumed to match) - */ -const llist_t* FAST_FUNC find_list_entry2(const llist_t *list, const char *filename) -{ - char buf[PATH_MAX]; - int pattern_slash_cnt; - const char *c; - char *d; - - while (list) { - c = list->data; - pattern_slash_cnt = 0; - while (*c) - if (*c++ == '/') pattern_slash_cnt++; - c = filename; - d = buf; - /* paranoia is better than buffer overflows */ - while (*c && d != buf + sizeof(buf)-1) { - if (*c == '/' && --pattern_slash_cnt < 0) - break; - *d++ = *c++; - } - *d = '\0'; - if (fnmatch(list->data, buf, 0) == 0) { - return list; - } - list = list->link; - } - return NULL; -} diff --git a/archival/libunarchive/get_header_ar.c b/archival/libunarchive/get_header_ar.c deleted file mode 100644 index 6bfc6bc27..000000000 --- a/archival/libunarchive/get_header_ar.c +++ /dev/null @@ -1,133 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* Copyright 2001 Glenn McGrath. - * - * Licensed under GPLv2 or later, see file LICENSE in this source tree. - */ - -#include "libbb.h" -#include "unarchive.h" -#include "ar.h" - -static unsigned read_num(const char *str, int base) -{ - /* This code works because - * on misformatted numbers bb_strtou returns all-ones */ - int err = bb_strtou(str, NULL, base); - if (err == -1) - bb_error_msg_and_die("invalid ar header"); - return err; -} - -char FAST_FUNC get_header_ar(archive_handle_t *archive_handle) -{ - file_header_t *typed = archive_handle->file_header; - unsigned size; - union { - char raw[60]; - struct ar_header formatted; - } ar; -#if ENABLE_FEATURE_AR_LONG_FILENAMES - static char *ar_long_names; - static unsigned ar_long_name_size; -#endif - - /* dont use xread as we want to handle the error ourself */ - if (read(archive_handle->src_fd, ar.raw, 60) != 60) { - /* End Of File */ - return EXIT_FAILURE; - } - - /* ar header starts on an even byte (2 byte aligned) - * '\n' is used for padding - */ - if (ar.raw[0] == '\n') { - /* fix up the header, we started reading 1 byte too early */ - memmove(ar.raw, &ar.raw[1], 59); - ar.raw[59] = xread_char(archive_handle->src_fd); - archive_handle->offset++; - } - archive_handle->offset += 60; - - if (ar.formatted.magic[0] != '`' || ar.formatted.magic[1] != '\n') - bb_error_msg_and_die("invalid ar header"); - - /* FIXME: more thorough routine would be in order here - * (we have something like that in tar) - * but for now we are lax. */ - ar.formatted.magic[0] = '\0'; /* else 4G-2 file will have size="4294967294`\n..." */ - typed->size = size = read_num(ar.formatted.size, 10); - - /* special filenames have '/' as the first character */ - if (ar.formatted.name[0] == '/') { - if (ar.formatted.name[1] == ' ') { - /* This is the index of symbols in the file for compilers */ - data_skip(archive_handle); - archive_handle->offset += size; - return get_header_ar(archive_handle); /* Return next header */ - } -#if ENABLE_FEATURE_AR_LONG_FILENAMES - if (ar.formatted.name[1] == '/') { - /* If the second char is a '/' then this entries data section - * stores long filename for multiple entries, they are stored - * in static variable long_names for use in future entries - */ - ar_long_name_size = size; - free(ar_long_names); - ar_long_names = xmalloc(size); - xread(archive_handle->src_fd, ar_long_names, size); - archive_handle->offset += size; - /* Return next header */ - return get_header_ar(archive_handle); - } -#else - bb_error_msg_and_die("long filenames not supported"); -#endif - } - /* Only size is always present, the rest may be missing in - * long filename pseudo file. Thus we decode the rest - * after dealing with long filename pseudo file. - */ - typed->mode = read_num(ar.formatted.mode, 8); - typed->mtime = read_num(ar.formatted.date, 10); - typed->uid = read_num(ar.formatted.uid, 10); - typed->gid = read_num(ar.formatted.gid, 10); - -#if ENABLE_FEATURE_AR_LONG_FILENAMES - if (ar.formatted.name[0] == '/') { - unsigned long_offset; - - /* The number after the '/' indicates the offset in the ar data section - * (saved in ar_long_names) that conatains the real filename */ - long_offset = read_num(&ar.formatted.name[1], 10); - if (long_offset >= ar_long_name_size) { - bb_error_msg_and_die("can't resolve long filename"); - } - typed->name = xstrdup(ar_long_names + long_offset); - } else -#endif - { - /* short filenames */ - typed->name = xstrndup(ar.formatted.name, 16); - } - - typed->name[strcspn(typed->name, " /")] = '\0'; - - if (archive_handle->filter(archive_handle) == EXIT_SUCCESS) { - archive_handle->action_header(typed); -#if ENABLE_DPKG || ENABLE_DPKG_DEB - if (archive_handle->dpkg__sub_archive) { - while (archive_handle->dpkg__action_data_subarchive(archive_handle->dpkg__sub_archive) == EXIT_SUCCESS) - continue; - } else -#endif - archive_handle->action_data(archive_handle); - } else { - data_skip(archive_handle); - } - - archive_handle->offset += typed->size; - /* Set the file pointer to the correct spot, we may have been reading a compressed file */ - lseek(archive_handle->src_fd, archive_handle->offset, SEEK_SET); - - return EXIT_SUCCESS; -} diff --git a/archival/libunarchive/get_header_cpio.c b/archival/libunarchive/get_header_cpio.c deleted file mode 100644 index 8cd1096ba..000000000 --- a/archival/libunarchive/get_header_cpio.c +++ /dev/null @@ -1,186 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* Copyright 2002 Laurence Anderson - * - * Licensed under GPLv2 or later, see file LICENSE in this source tree. - */ - -#include "libbb.h" -#include "unarchive.h" - -typedef struct hardlinks_t { - struct hardlinks_t *next; - int inode; /* TODO: must match maj/min too! */ - int mode ; - int mtime; /* These three are useful only in corner case */ - int uid ; /* of hardlinks with zero size body */ - int gid ; - char name[1]; -} hardlinks_t; - -char FAST_FUNC get_header_cpio(archive_handle_t *archive_handle) -{ - file_header_t *file_header = archive_handle->file_header; - char cpio_header[110]; - int namesize; - int major, minor, nlink, mode, inode; - unsigned size, uid, gid, mtime; - - /* There can be padding before archive header */ - data_align(archive_handle, 4); - - size = full_read(archive_handle->src_fd, cpio_header, 110); - if (size == 0) { - goto create_hardlinks; - } - if (size != 110) { - bb_error_msg_and_die("short read"); - } - archive_handle->offset += 110; - - if (strncmp(&cpio_header[0], "07070", 5) != 0 - || (cpio_header[5] != '1' && cpio_header[5] != '2') - ) { - bb_error_msg_and_die("unsupported cpio format, use newc or crc"); - } - - if (sscanf(cpio_header + 6, - "%8x" "%8x" "%8x" "%8x" - "%8x" "%8x" "%8x" /*maj,min:*/ "%*16c" - /*rmaj,rmin:*/"%8x" "%8x" "%8x" /*chksum: "%*8c"*/, - &inode, &mode, &uid, &gid, - &nlink, &mtime, &size, - &major, &minor, &namesize) != 10) - bb_error_msg_and_die("damaged cpio file"); - file_header->mode = mode; - file_header->uid = uid; - file_header->gid = gid; - file_header->mtime = mtime; - file_header->size = size; - - namesize &= 0x1fff; /* paranoia: limit names to 8k chars */ - file_header->name = xzalloc(namesize + 1); - /* Read in filename */ - xread(archive_handle->src_fd, file_header->name, namesize); - if (file_header->name[0] == '/') { - /* Testcase: echo /etc/hosts | cpio -pvd /tmp - * Without this code, it tries to unpack /etc/hosts - * into "/etc/hosts", not "etc/hosts". - */ - char *p = file_header->name; - do p++; while (*p == '/'); - overlapping_strcpy(file_header->name, p); - } - archive_handle->offset += namesize; - - /* Update offset amount and skip padding before file contents */ - data_align(archive_handle, 4); - - if (strcmp(file_header->name, "TRAILER!!!") == 0) { - /* Always round up. ">> 9" divides by 512 */ - archive_handle->cpio__blocks = (uoff_t)(archive_handle->offset + 511) >> 9; - goto create_hardlinks; - } - - file_header->link_target = NULL; - if (S_ISLNK(file_header->mode)) { - file_header->size &= 0x1fff; /* paranoia: limit names to 8k chars */ - file_header->link_target = xzalloc(file_header->size + 1); - xread(archive_handle->src_fd, file_header->link_target, file_header->size); - archive_handle->offset += file_header->size; - file_header->size = 0; /* Stop possible seeks in future */ - } - -// TODO: data_extract_all can't deal with hardlinks to non-files... -// when fixed, change S_ISREG to !S_ISDIR here - - if (nlink > 1 && S_ISREG(file_header->mode)) { - hardlinks_t *new = xmalloc(sizeof(*new) + namesize); - new->inode = inode; - new->mode = mode ; - new->mtime = mtime; - new->uid = uid ; - new->gid = gid ; - strcpy(new->name, file_header->name); - /* Put file on a linked list for later */ - if (size == 0) { - new->next = archive_handle->cpio__hardlinks_to_create; - archive_handle->cpio__hardlinks_to_create = new; - return EXIT_SUCCESS; /* Skip this one */ - /* TODO: this breaks cpio -t (it does not show hardlinks) */ - } - new->next = archive_handle->cpio__created_hardlinks; - archive_handle->cpio__created_hardlinks = new; - } - file_header->device = makedev(major, minor); - - if (archive_handle->filter(archive_handle) == EXIT_SUCCESS) { - archive_handle->action_data(archive_handle); -//TODO: run "echo /etc/hosts | cpio -pv /tmp" twice. On 2nd run: -//cpio: etc/hosts not created: newer or same age file exists -//etc/hosts <-- should NOT show it -//2 blocks <-- should say "0 blocks" - archive_handle->action_header(file_header); - } else { - data_skip(archive_handle); - } - - archive_handle->offset += file_header->size; - - free(file_header->link_target); - free(file_header->name); - file_header->link_target = NULL; - file_header->name = NULL; - - return EXIT_SUCCESS; - - create_hardlinks: - free(file_header->link_target); - free(file_header->name); - - while (archive_handle->cpio__hardlinks_to_create) { - hardlinks_t *cur; - hardlinks_t *make_me = archive_handle->cpio__hardlinks_to_create; - - archive_handle->cpio__hardlinks_to_create = make_me->next; - - memset(file_header, 0, sizeof(*file_header)); - file_header->mtime = make_me->mtime; - file_header->name = make_me->name; - file_header->mode = make_me->mode; - file_header->uid = make_me->uid; - file_header->gid = make_me->gid; - /*file_header->size = 0;*/ - /*file_header->link_target = NULL;*/ - - /* Try to find a file we are hardlinked to */ - cur = archive_handle->cpio__created_hardlinks; - while (cur) { - /* TODO: must match maj/min too! */ - if (cur->inode == make_me->inode) { - file_header->link_target = cur->name; - /* link_target != NULL, size = 0: "I am a hardlink" */ - if (archive_handle->filter(archive_handle) == EXIT_SUCCESS) - archive_handle->action_data(archive_handle); - free(make_me); - goto next_link; - } - cur = cur->next; - } - /* Oops... no file with such inode was created... do it now - * (happens when hardlinked files are empty (zero length)) */ - if (archive_handle->filter(archive_handle) == EXIT_SUCCESS) - archive_handle->action_data(archive_handle); - /* Move to the list of created hardlinked files */ - make_me->next = archive_handle->cpio__created_hardlinks; - archive_handle->cpio__created_hardlinks = make_me; - next_link: ; - } - - while (archive_handle->cpio__created_hardlinks) { - hardlinks_t *p = archive_handle->cpio__created_hardlinks; - archive_handle->cpio__created_hardlinks = p->next; - free(p); - } - - return EXIT_FAILURE; /* "No more files to process" */ -} diff --git a/archival/libunarchive/get_header_tar.c b/archival/libunarchive/get_header_tar.c deleted file mode 100644 index cf6487207..000000000 --- a/archival/libunarchive/get_header_tar.c +++ /dev/null @@ -1,461 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* Licensed under GPLv2 or later, see file LICENSE in this source tree. - * - * FIXME: - * In privileged mode if uname and gname map to a uid and gid then use the - * mapped value instead of the uid/gid values in tar header - * - * References: - * GNU tar and star man pages, - * Opengroup's ustar interchange format, - * http://www.opengroup.org/onlinepubs/007904975/utilities/pax.html - */ - -#include "libbb.h" -#include "unarchive.h" - -typedef uint32_t aliased_uint32_t FIX_ALIASING; -typedef off_t aliased_off_t FIX_ALIASING; - - -/* NB: _DESTROYS_ str[len] character! */ -static unsigned long long getOctal(char *str, int len) -{ - unsigned long long v; - char *end; - /* NB: leading spaces are allowed. Using strtoull to handle that. - * The downside is that we accept e.g. "-123" too :( - */ - str[len] = '\0'; - v = strtoull(str, &end, 8); - /* std: "Each numeric field is terminated by one or more - * or NUL characters". We must support ' '! */ - if (*end != '\0' && *end != ' ') { - int8_t first = str[0]; - if (!(first & 0x80)) - bb_error_msg_and_die("corrupted octal value in tar header"); - /* - * GNU tar uses "base-256 encoding" for very large numbers. - * Encoding is binary, with highest bit always set as a marker - * and sign in next-highest bit: - * 80 00 .. 00 - zero - * bf ff .. ff - largest positive number - * ff ff .. ff - minus 1 - * c0 00 .. 00 - smallest negative number - * - * Example of tar file with 8914993153 (0x213600001) byte file. - * Field starts at offset 7c: - * 00070 30 30 30 00 30 30 30 30 30 30 30 00 80 00 00 00 |000.0000000.....| - * 00080 00 00 00 02 13 60 00 01 31 31 31 32 30 33 33 36 |.....`..11120336| - * - * NB: tarballs with NEGATIVE unix times encoded that way were seen! - */ - v = first; - /* Sign-extend using 6th bit: */ - v <<= sizeof(unsigned long long)*8 - 7; - v = (long long)v >> (sizeof(unsigned long long)*8 - 7); - while (--len != 0) - v = (v << 8) + (unsigned char) *str++; - } - return v; -} -#define GET_OCTAL(a) getOctal((a), sizeof(a)) - -#if ENABLE_FEATURE_TAR_SELINUX -/* Scan a PAX header for SELinux contexts, via "RHT.security.selinux" keyword. - * This is what Red Hat's patched version of tar uses. - */ -# define SELINUX_CONTEXT_KEYWORD "RHT.security.selinux" -static char *get_selinux_sctx_from_pax_hdr(archive_handle_t *archive_handle, unsigned sz) -{ - char *buf, *p; - char *result; - - p = buf = xmalloc(sz + 1); - /* prevent bb_strtou from running off the buffer */ - buf[sz] = '\0'; - xread(archive_handle->src_fd, buf, sz); - archive_handle->offset += sz; - - result = NULL; - while (sz != 0) { - char *end, *value; - unsigned len; - - /* Every record has this format: "LEN NAME=VALUE\n" */ - len = bb_strtou(p, &end, 10); - /* expect errno to be EINVAL, because the character - * following the digits should be a space - */ - p += len; - sz -= len; - if ((int)sz < 0 - || len == 0 - || errno != EINVAL - || *end != ' ' - ) { - bb_error_msg("malformed extended header, skipped"); - // More verbose version: - //bb_error_msg("malformed extended header at %"OFF_FMT"d, skipped", - // archive_handle->offset - (sz + len)); - break; - } - /* overwrite the terminating newline with NUL - * (we do not bother to check that it *was* a newline) - */ - p[-1] = '\0'; - /* Is it selinux security context? */ - value = end + 1; - if (strncmp(value, SELINUX_CONTEXT_KEYWORD"=", sizeof(SELINUX_CONTEXT_KEYWORD"=") - 1) == 0) { - value += sizeof(SELINUX_CONTEXT_KEYWORD"=") - 1; - result = xstrdup(value); - break; - } - } - - free(buf); - return result; -} -#endif - -char FAST_FUNC get_header_tar(archive_handle_t *archive_handle) -{ - file_header_t *file_header = archive_handle->file_header; - struct tar_header_t tar; - char *cp; - int i, sum_u, sum; -#if ENABLE_FEATURE_TAR_OLDSUN_COMPATIBILITY - int sum_s; -#endif - int parse_names; - - /* Our "private data" */ -#if ENABLE_FEATURE_TAR_GNU_EXTENSIONS -# define p_longname (archive_handle->tar__longname) -# define p_linkname (archive_handle->tar__linkname) -#else -# define p_longname 0 -# define p_linkname 0 -#endif - -#if ENABLE_FEATURE_TAR_GNU_EXTENSIONS || ENABLE_FEATURE_TAR_SELINUX - again: -#endif - /* Align header */ - data_align(archive_handle, 512); - - again_after_align: - -#if ENABLE_DESKTOP || ENABLE_FEATURE_TAR_AUTODETECT - /* to prevent misdetection of bz2 sig */ - *(aliased_uint32_t*)&tar = 0; - i = full_read(archive_handle->src_fd, &tar, 512); - /* If GNU tar sees EOF in above read, it says: - * "tar: A lone zero block at N", where N = kilobyte - * where EOF was met (not EOF block, actual EOF!), - * and exits with EXIT_SUCCESS. - * We will mimic exit(EXIT_SUCCESS), although we will not mimic - * the message and we don't check whether we indeed - * saw zero block directly before this. */ - if (i == 0) { - xfunc_error_retval = 0; - short_read: - bb_error_msg_and_die("short read"); - } - if (i != 512) { - IF_FEATURE_TAR_AUTODETECT(goto autodetect;) - goto short_read; - } - -#else - i = 512; - xread(archive_handle->src_fd, &tar, i); -#endif - archive_handle->offset += i; - - /* If there is no filename its an empty header */ - if (tar.name[0] == 0 && tar.prefix[0] == 0) { - if (archive_handle->tar__end) { - /* Second consecutive empty header - end of archive. - * Read until the end to empty the pipe from gz or bz2 - */ - while (full_read(archive_handle->src_fd, &tar, 512) == 512) - continue; - return EXIT_FAILURE; - } - archive_handle->tar__end = 1; - return EXIT_SUCCESS; - } - archive_handle->tar__end = 0; - - /* Check header has valid magic, "ustar" is for the proper tar, - * five NULs are for the old tar format */ - if (strncmp(tar.magic, "ustar", 5) != 0 - && (!ENABLE_FEATURE_TAR_OLDGNU_COMPATIBILITY - || memcmp(tar.magic, "\0\0\0\0", 5) != 0) - ) { -#if ENABLE_FEATURE_TAR_AUTODETECT - char FAST_FUNC (*get_header_ptr)(archive_handle_t *); - uint16_t magic2; - - autodetect: - magic2 = *(uint16_t*)tar.name; - /* tar gz/bz autodetect: check for gz/bz2 magic. - * If we see the magic, and it is the very first block, - * we can switch to get_header_tar_gz/bz2/lzma(). - * Needs seekable fd. I wish recv(MSG_PEEK) works - * on any fd... */ -# if ENABLE_FEATURE_SEAMLESS_GZ - if (magic2 == GZIP_MAGIC) { - get_header_ptr = get_header_tar_gz; - } else -# endif -# if ENABLE_FEATURE_SEAMLESS_BZ2 - if (magic2 == BZIP2_MAGIC - && tar.name[2] == 'h' && isdigit(tar.name[3]) - ) { /* bzip2 */ - get_header_ptr = get_header_tar_bz2; - } else -# endif -# if ENABLE_FEATURE_SEAMLESS_XZ - //TODO: if (magic2 == XZ_MAGIC1)... - //else -# endif - goto err; - /* Two different causes for lseek() != 0: - * unseekable fd (would like to support that too, but...), - * or not first block (false positive, it's not .gz/.bz2!) */ - if (lseek(archive_handle->src_fd, -i, SEEK_CUR) != 0) - goto err; - while (get_header_ptr(archive_handle) == EXIT_SUCCESS) - continue; - return EXIT_FAILURE; - err: -#endif /* FEATURE_TAR_AUTODETECT */ - bb_error_msg_and_die("invalid tar magic"); - } - - /* Do checksum on headers. - * POSIX says that checksum is done on unsigned bytes, but - * Sun and HP-UX gets it wrong... more details in - * GNU tar source. */ -#if ENABLE_FEATURE_TAR_OLDSUN_COMPATIBILITY - sum_s = ' ' * sizeof(tar.chksum); -#endif - sum_u = ' ' * sizeof(tar.chksum); - for (i = 0; i < 148; i++) { - sum_u += ((unsigned char*)&tar)[i]; -#if ENABLE_FEATURE_TAR_OLDSUN_COMPATIBILITY - sum_s += ((signed char*)&tar)[i]; -#endif - } - for (i = 156; i < 512; i++) { - sum_u += ((unsigned char*)&tar)[i]; -#if ENABLE_FEATURE_TAR_OLDSUN_COMPATIBILITY - sum_s += ((signed char*)&tar)[i]; -#endif - } - /* This field does not need special treatment (getOctal) */ - { - char *endp; /* gcc likes temp var for &endp */ - sum = strtoul(tar.chksum, &endp, 8); - if ((*endp != '\0' && *endp != ' ') - || (sum_u != sum IF_FEATURE_TAR_OLDSUN_COMPATIBILITY(&& sum_s != sum)) - ) { - bb_error_msg_and_die("invalid tar header checksum"); - } - } - /* don't use xstrtoul, tar.chksum may have leading spaces */ - sum = strtoul(tar.chksum, NULL, 8); - if (sum_u != sum IF_FEATURE_TAR_OLDSUN_COMPATIBILITY(&& sum_s != sum)) { - bb_error_msg_and_die("invalid tar header checksum"); - } - - /* 0 is reserved for high perf file, treat as normal file */ - if (!tar.typeflag) tar.typeflag = '0'; - parse_names = (tar.typeflag >= '0' && tar.typeflag <= '7'); - - /* getOctal trashes subsequent field, therefore we call it - * on fields in reverse order */ - if (tar.devmajor[0]) { - char t = tar.prefix[0]; - /* we trash prefix[0] here, but we DO need it later! */ - unsigned minor = GET_OCTAL(tar.devminor); - unsigned major = GET_OCTAL(tar.devmajor); - file_header->device = makedev(major, minor); - tar.prefix[0] = t; - } - file_header->link_target = NULL; - if (!p_linkname && parse_names && tar.linkname[0]) { - file_header->link_target = xstrndup(tar.linkname, sizeof(tar.linkname)); - /* FIXME: what if we have non-link object with link_target? */ - /* Will link_target be free()ed? */ - } -#if ENABLE_FEATURE_TAR_UNAME_GNAME - file_header->tar__uname = tar.uname[0] ? xstrndup(tar.uname, sizeof(tar.uname)) : NULL; - file_header->tar__gname = tar.gname[0] ? xstrndup(tar.gname, sizeof(tar.gname)) : NULL; -#endif - file_header->mtime = GET_OCTAL(tar.mtime); - file_header->size = GET_OCTAL(tar.size); - file_header->gid = GET_OCTAL(tar.gid); - file_header->uid = GET_OCTAL(tar.uid); - /* Set bits 0-11 of the files mode */ - file_header->mode = 07777 & GET_OCTAL(tar.mode); - - file_header->name = NULL; - if (!p_longname && parse_names) { - /* we trash mode[0] here, it's ok */ - //tar.name[sizeof(tar.name)] = '\0'; - gcc 4.3.0 would complain - tar.mode[0] = '\0'; - if (tar.prefix[0]) { - /* and padding[0] */ - //tar.prefix[sizeof(tar.prefix)] = '\0'; - gcc 4.3.0 would complain - tar.padding[0] = '\0'; - file_header->name = concat_path_file(tar.prefix, tar.name); - } else - file_header->name = xstrdup(tar.name); - } - - /* Set bits 12-15 of the files mode */ - /* (typeflag was not trashed because chksum does not use getOctal) */ - switch (tar.typeflag) { - /* busybox identifies hard links as being regular files with 0 size and a link name */ - case '1': - file_header->mode |= S_IFREG; - break; - case '7': - /* case 0: */ - case '0': -#if ENABLE_FEATURE_TAR_OLDGNU_COMPATIBILITY - if (last_char_is(file_header->name, '/')) { - goto set_dir; - } -#endif - file_header->mode |= S_IFREG; - break; - case '2': - file_header->mode |= S_IFLNK; - /* have seen tarballs with size field containing - * the size of the link target's name */ - size0: - file_header->size = 0; - break; - case '3': - file_header->mode |= S_IFCHR; - goto size0; /* paranoia */ - case '4': - file_header->mode |= S_IFBLK; - goto size0; - case '5': - IF_FEATURE_TAR_OLDGNU_COMPATIBILITY(set_dir:) - file_header->mode |= S_IFDIR; - goto size0; - case '6': - file_header->mode |= S_IFIFO; - goto size0; -#if ENABLE_FEATURE_TAR_GNU_EXTENSIONS - case 'L': - /* free: paranoia: tar with several consecutive longnames */ - free(p_longname); - /* For paranoia reasons we allocate extra NUL char */ - p_longname = xzalloc(file_header->size + 1); - /* We read ASCIZ string, including NUL */ - xread(archive_handle->src_fd, p_longname, file_header->size); - archive_handle->offset += file_header->size; - /* return get_header_tar(archive_handle); */ - /* gcc 4.1.1 didn't optimize it into jump */ - /* so we will do it ourself, this also saves stack */ - goto again; - case 'K': - free(p_linkname); - p_linkname = xzalloc(file_header->size + 1); - xread(archive_handle->src_fd, p_linkname, file_header->size); - archive_handle->offset += file_header->size; - /* return get_header_tar(archive_handle); */ - goto again; - case 'D': /* GNU dump dir */ - case 'M': /* Continuation of multi volume archive */ - case 'N': /* Old GNU for names > 100 characters */ - case 'S': /* Sparse file */ - case 'V': /* Volume header */ -#endif -#if !ENABLE_FEATURE_TAR_SELINUX - case 'g': /* pax global header */ - case 'x': /* pax extended header */ -#else - skip_ext_hdr: -#endif - { - off_t sz; - bb_error_msg("warning: skipping header '%c'", tar.typeflag); - sz = (file_header->size + 511) & ~(off_t)511; - archive_handle->offset += sz; - sz >>= 9; /* sz /= 512 but w/o contortions for signed div */ - while (sz--) - xread(archive_handle->src_fd, &tar, 512); - /* return get_header_tar(archive_handle); */ - goto again_after_align; - } -#if ENABLE_FEATURE_TAR_SELINUX - case 'g': /* pax global header */ - case 'x': { /* pax extended header */ - char **pp; - if ((uoff_t)file_header->size > 0xfffff) /* paranoia */ - goto skip_ext_hdr; - pp = (tar.typeflag == 'g') ? &archive_handle->tar__global_sctx : &archive_handle->tar__next_file_sctx; - free(*pp); - *pp = get_selinux_sctx_from_pax_hdr(archive_handle, file_header->size); - goto again; - } -#endif - default: - bb_error_msg_and_die("unknown typeflag: 0x%x", tar.typeflag); - } - -#if ENABLE_FEATURE_TAR_GNU_EXTENSIONS - if (p_longname) { - file_header->name = p_longname; - p_longname = NULL; - } - if (p_linkname) { - file_header->link_target = p_linkname; - p_linkname = NULL; - } -#endif - if (strncmp(file_header->name, "/../"+1, 3) == 0 - || strstr(file_header->name, "/../") - ) { - bb_error_msg_and_die("name with '..' encountered: '%s'", - file_header->name); - } - - /* Strip trailing '/' in directories */ - /* Must be done after mode is set as '/' is used to check if it's a directory */ - cp = last_char_is(file_header->name, '/'); - - if (archive_handle->filter(archive_handle) == EXIT_SUCCESS) { - archive_handle->action_header(/*archive_handle->*/ file_header); - /* Note that we kill the '/' only after action_header() */ - /* (like GNU tar 1.15.1: verbose mode outputs "dir/dir/") */ - if (cp) - *cp = '\0'; - archive_handle->action_data(archive_handle); - if (archive_handle->accept || archive_handle->reject) - llist_add_to(&archive_handle->passed, file_header->name); - else /* Caller isn't interested in list of unpacked files */ - free(file_header->name); - } else { - data_skip(archive_handle); - free(file_header->name); - } - archive_handle->offset += file_header->size; - - free(file_header->link_target); - /* Do not free(file_header->name)! - * It might be inserted in archive_handle->passed - see above */ -#if ENABLE_FEATURE_TAR_UNAME_GNAME - free(file_header->tar__uname); - free(file_header->tar__gname); -#endif - return EXIT_SUCCESS; -} diff --git a/archival/libunarchive/get_header_tar_bz2.c b/archival/libunarchive/get_header_tar_bz2.c deleted file mode 100644 index 4ffc17086..000000000 --- a/archival/libunarchive/get_header_tar_bz2.c +++ /dev/null @@ -1,21 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Licensed under GPLv2 or later, see file LICENSE in this source tree. - */ - -#include "libbb.h" -#include "unarchive.h" - -char FAST_FUNC get_header_tar_bz2(archive_handle_t *archive_handle) -{ - /* Can't lseek over pipes */ - archive_handle->seek = seek_by_read; - - open_transformer(archive_handle->src_fd, unpack_bz2_stream_prime, "bunzip2"); - archive_handle->offset = 0; - while (get_header_tar(archive_handle) == EXIT_SUCCESS) - continue; - - /* Can only do one file at a time */ - return EXIT_FAILURE; -} diff --git a/archival/libunarchive/get_header_tar_gz.c b/archival/libunarchive/get_header_tar_gz.c deleted file mode 100644 index a9af22e0e..000000000 --- a/archival/libunarchive/get_header_tar_gz.c +++ /dev/null @@ -1,36 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Licensed under GPLv2 or later, see file LICENSE in this source tree. - */ - -#include "libbb.h" -#include "unarchive.h" - -char FAST_FUNC get_header_tar_gz(archive_handle_t *archive_handle) -{ -#if BB_MMU - unsigned char magic[2]; -#endif - - /* Can't lseek over pipes */ - archive_handle->seek = seek_by_read; - - /* Check gzip magic only if open_transformer will invoke unpack_gz_stream (MMU case). - * Otherwise, it will invoke an external helper "gunzip -cf" (NOMMU case) which will - * need the header. */ -#if BB_MMU - xread(archive_handle->src_fd, &magic, 2); - /* Can skip this check, but error message will be less clear */ - if ((magic[0] != 0x1f) || (magic[1] != 0x8b)) { - bb_error_msg_and_die("invalid gzip magic"); - } -#endif - - open_transformer(archive_handle->src_fd, unpack_gz_stream, "gunzip"); - archive_handle->offset = 0; - while (get_header_tar(archive_handle) == EXIT_SUCCESS) - continue; - - /* Can only do one file at a time */ - return EXIT_FAILURE; -} diff --git a/archival/libunarchive/get_header_tar_lzma.c b/archival/libunarchive/get_header_tar_lzma.c deleted file mode 100644 index 9876b3827..000000000 --- a/archival/libunarchive/get_header_tar_lzma.c +++ /dev/null @@ -1,24 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Small lzma deflate implementation. - * Copyright (C) 2006 Aurelien Jacobs - * - * Licensed under GPLv2, see file LICENSE in this source tree. - */ - -#include "libbb.h" -#include "unarchive.h" - -char FAST_FUNC get_header_tar_lzma(archive_handle_t *archive_handle) -{ - /* Can't lseek over pipes */ - archive_handle->seek = seek_by_read; - - open_transformer(archive_handle->src_fd, unpack_lzma_stream, "unlzma"); - archive_handle->offset = 0; - while (get_header_tar(archive_handle) == EXIT_SUCCESS) - continue; - - /* Can only do one file at a time */ - return EXIT_FAILURE; -} diff --git a/archival/libunarchive/header_list.c b/archival/libunarchive/header_list.c deleted file mode 100644 index 902d6ebe0..000000000 --- a/archival/libunarchive/header_list.c +++ /dev/null @@ -1,12 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Licensed under GPLv2 or later, see file LICENSE in this source tree. - */ -#include "libbb.h" -#include "unarchive.h" - -void FAST_FUNC header_list(const file_header_t *file_header) -{ -//TODO: cpio -vp DIR should output "DIR/NAME", not just "NAME" */ - puts(file_header->name); -} diff --git a/archival/libunarchive/header_skip.c b/archival/libunarchive/header_skip.c deleted file mode 100644 index 2af36ac9c..000000000 --- a/archival/libunarchive/header_skip.c +++ /dev/null @@ -1,10 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Licensed under GPLv2 or later, see file LICENSE in this source tree. - */ -#include "libbb.h" -#include "unarchive.h" - -void FAST_FUNC header_skip(const file_header_t *file_header UNUSED_PARAM) -{ -} diff --git a/archival/libunarchive/header_verbose_list.c b/archival/libunarchive/header_verbose_list.c deleted file mode 100644 index d863e6a29..000000000 --- a/archival/libunarchive/header_verbose_list.c +++ /dev/null @@ -1,69 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Licensed under GPLv2 or later, see file LICENSE in this source tree. - */ - -#include "libbb.h" -#include "unarchive.h" - -void FAST_FUNC header_verbose_list(const file_header_t *file_header) -{ - struct tm tm_time; - struct tm *ptm = &tm_time; //localtime(&file_header->mtime); - -#if ENABLE_FEATURE_TAR_UNAME_GNAME - char uid[sizeof(int)*3 + 2]; - /*char gid[sizeof(int)*3 + 2];*/ - char *user; - char *group; - - localtime_r(&file_header->mtime, ptm); - - user = file_header->tar__uname; - if (user == NULL) { - sprintf(uid, "%u", (unsigned)file_header->uid); - user = uid; - } - group = file_header->tar__gname; - if (group == NULL) { - /*sprintf(gid, "%u", (unsigned)file_header->gid);*/ - group = utoa(file_header->gid); - } - printf("%s %s/%s %9"OFF_FMT"u %4u-%02u-%02u %02u:%02u:%02u %s", - bb_mode_string(file_header->mode), - user, - group, - file_header->size, - 1900 + ptm->tm_year, - 1 + ptm->tm_mon, - ptm->tm_mday, - ptm->tm_hour, - ptm->tm_min, - ptm->tm_sec, - file_header->name); - -#else /* !FEATURE_TAR_UNAME_GNAME */ - - localtime_r(&file_header->mtime, ptm); - - printf("%s %u/%u %9"OFF_FMT"u %4u-%02u-%02u %02u:%02u:%02u %s", - bb_mode_string(file_header->mode), - (unsigned)file_header->uid, - (unsigned)file_header->gid, - file_header->size, - 1900 + ptm->tm_year, - 1 + ptm->tm_mon, - ptm->tm_mday, - ptm->tm_hour, - ptm->tm_min, - ptm->tm_sec, - file_header->name); - -#endif /* FEATURE_TAR_UNAME_GNAME */ - - /* NB: GNU tar shows "->" for symlinks and "link to" for hardlinks */ - if (file_header->link_target) { - printf(" -> %s", file_header->link_target); - } - bb_putchar('\n'); -} diff --git a/archival/libunarchive/init_handle.c b/archival/libunarchive/init_handle.c deleted file mode 100644 index de7021f78..000000000 --- a/archival/libunarchive/init_handle.c +++ /dev/null @@ -1,22 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Licensed under GPLv2 or later, see file LICENSE in this source tree. - */ - -#include "libbb.h" -#include "unarchive.h" - -archive_handle_t* FAST_FUNC init_handle(void) -{ - archive_handle_t *archive_handle; - - /* Initialize default values */ - archive_handle = xzalloc(sizeof(archive_handle_t)); - archive_handle->file_header = xzalloc(sizeof(file_header_t)); - archive_handle->action_header = header_skip; - archive_handle->action_data = data_skip; - archive_handle->filter = filter_accept_all; - archive_handle->seek = seek_by_jump; - - return archive_handle; -} diff --git a/archival/libunarchive/liblzo.h b/archival/libunarchive/liblzo.h deleted file mode 100644 index 843997cb9..000000000 --- a/archival/libunarchive/liblzo.h +++ /dev/null @@ -1,93 +0,0 @@ -/* - This file is part of the LZO real-time data compression library. - - Copyright (C) 1996..2008 Markus Franz Xaver Johannes Oberhumer - All Rights Reserved. - - Markus F.X.J. Oberhumer - http://www.oberhumer.com/opensource/lzo/ - - The LZO library is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License as - published by the Free Software Foundation; either version 2 of - the License, or (at your option) any later version. - - The LZO library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with the LZO library; see the file COPYING. - If not, write to the Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -#include "liblzo_interface.h" - -/* lzo-2.03/src/config1x.h */ -#define M2_MIN_LEN 3 -#define M2_MAX_LEN 8 -#define M3_MAX_LEN 33 -#define M4_MAX_LEN 9 -#define M1_MAX_OFFSET 0x0400 -#define M2_MAX_OFFSET 0x0800 -#define M3_MAX_OFFSET 0x4000 -#define M4_MAX_OFFSET 0xbfff -#define M1_MARKER 0 -#define M3_MARKER 32 -#define M4_MARKER 16 - -#define MX_MAX_OFFSET (M1_MAX_OFFSET + M2_MAX_OFFSET) -#define MIN_LOOKAHEAD (M2_MAX_LEN + 1) - -#define LZO_EOF_CODE - -/* lzo-2.03/src/lzo_dict.h */ -#define GINDEX(m_pos,m_off,dict,dindex,in) m_pos = dict[dindex] -#define DX2(p,s1,s2) \ - (((((unsigned)((p)[2]) << (s2)) ^ (p)[1]) << (s1)) ^ (p)[0]) -//#define DA3(p,s1,s2,s3) ((DA2((p)+1,s2,s3) << (s1)) + (p)[0]) -//#define DS3(p,s1,s2,s3) ((DS2((p)+1,s2,s3) << (s1)) - (p)[0]) -#define DX3(p,s1,s2,s3) ((DX2((p)+1,s2,s3) << (s1)) ^ (p)[0]) - -#define D_SIZE (1U << D_BITS) -#define D_MASK ((1U << D_BITS) - 1) -#define D_HIGH ((D_MASK >> 1) + 1) - -#define LZO_CHECK_MPOS_NON_DET(m_pos,m_off,in,ip,max_offset) \ - ( \ - m_pos = ip - (unsigned)(ip - m_pos), \ - ((uintptr_t)m_pos < (uintptr_t)in \ - || (m_off = (unsigned)(ip - m_pos)) <= 0 \ - || m_off > max_offset) \ - ) - -#define DENTRY(p,in) (p) -#define UPDATE_I(dict,drun,index,p,in) dict[index] = DENTRY(p,in) - -#define DMS(v,s) ((unsigned) (((v) & (D_MASK >> (s))) << (s))) -#define DM(v) ((unsigned) ((v) & D_MASK)) -#define DMUL(a,b) ((unsigned) ((a) * (b))) - -/* lzo-2.03/src/lzo_ptr.h */ -#define pd(a,b) ((unsigned)((a)-(b))) - -# define TEST_IP (ip < ip_end) -# define NEED_IP(x) \ - if ((unsigned)(ip_end - ip) < (unsigned)(x)) goto input_overrun - -# undef TEST_OP /* don't need both of the tests here */ -# define TEST_OP 1 -# define NEED_OP(x) \ - if ((unsigned)(op_end - op) < (unsigned)(x)) goto output_overrun - -#define HAVE_ANY_OP 1 - -//#if defined(LZO_TEST_OVERRUN_LOOKBEHIND) -# define TEST_LB(m_pos) if (m_pos < out || m_pos >= op) goto lookbehind_overrun -//# define TEST_LBO(m_pos,o) if (m_pos < out || m_pos >= op - (o)) goto lookbehind_overrun -//#else -//# define TEST_LB(m_pos) ((void) 0) -//# define TEST_LBO(m_pos,o) ((void) 0) -//#endif diff --git a/archival/libunarchive/lzo1x_1.c b/archival/libunarchive/lzo1x_1.c deleted file mode 100644 index a88839846..000000000 --- a/archival/libunarchive/lzo1x_1.c +++ /dev/null @@ -1,35 +0,0 @@ -/* LZO1X-1 compression - - This file is part of the LZO real-time data compression library. - - Copyright (C) 1996..2008 Markus Franz Xaver Johannes Oberhumer - All Rights Reserved. - - Markus F.X.J. Oberhumer - http://www.oberhumer.com/opensource/lzo/ - - The LZO library is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License as - published by the Free Software Foundation; either version 2 of - the License, or (at your option) any later version. - - The LZO library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with the LZO library; see the file COPYING. - If not, write to the Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -#include "libbb.h" -#include "liblzo.h" - -#define D_BITS 14 -#define D_INDEX1(d,p) d = DM(DMUL(0x21,DX3(p,5,5,6)) >> 5) -#define D_INDEX2(d,p) d = (d & (D_MASK & 0x7ff)) ^ (D_HIGH | 0x1f) - -#define DO_COMPRESS lzo1x_1_compress - -#include "lzo1x_c.c" diff --git a/archival/libunarchive/lzo1x_1o.c b/archival/libunarchive/lzo1x_1o.c deleted file mode 100644 index 3c61253e0..000000000 --- a/archival/libunarchive/lzo1x_1o.c +++ /dev/null @@ -1,35 +0,0 @@ -/* LZO1X-1(15) compression - - This file is part of the LZO real-time data compression library. - - Copyright (C) 1996..2008 Markus Franz Xaver Johannes Oberhumer - All Rights Reserved. - - Markus F.X.J. Oberhumer - http://www.oberhumer.com/opensource/lzo/ - - The LZO library is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License as - published by the Free Software Foundation; either version 2 of - the License, or (at your option) any later version. - - The LZO library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with the LZO library; see the file COPYING. - If not, write to the Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -#include "libbb.h" -#include "liblzo.h" - -#define D_BITS 15 -#define D_INDEX1(d,p) d = DM(DMUL(0x21,DX3(p,5,5,6)) >> 5) -#define D_INDEX2(d,p) d = (d & (D_MASK & 0x7ff)) ^ (D_HIGH | 0x1f) - -#define DO_COMPRESS lzo1x_1_15_compress - -#include "lzo1x_c.c" diff --git a/archival/libunarchive/lzo1x_9x.c b/archival/libunarchive/lzo1x_9x.c deleted file mode 100644 index 483205155..000000000 --- a/archival/libunarchive/lzo1x_9x.c +++ /dev/null @@ -1,921 +0,0 @@ -/* lzo1x_9x.c -- implementation of the LZO1X-999 compression algorithm - - This file is part of the LZO real-time data compression library. - - Copyright (C) 2008 Markus Franz Xaver Johannes Oberhumer - Copyright (C) 2007 Markus Franz Xaver Johannes Oberhumer - Copyright (C) 2006 Markus Franz Xaver Johannes Oberhumer - Copyright (C) 2005 Markus Franz Xaver Johannes Oberhumer - Copyright (C) 2004 Markus Franz Xaver Johannes Oberhumer - Copyright (C) 2003 Markus Franz Xaver Johannes Oberhumer - Copyright (C) 2002 Markus Franz Xaver Johannes Oberhumer - Copyright (C) 2001 Markus Franz Xaver Johannes Oberhumer - Copyright (C) 2000 Markus Franz Xaver Johannes Oberhumer - Copyright (C) 1999 Markus Franz Xaver Johannes Oberhumer - Copyright (C) 1998 Markus Franz Xaver Johannes Oberhumer - Copyright (C) 1997 Markus Franz Xaver Johannes Oberhumer - Copyright (C) 1996 Markus Franz Xaver Johannes Oberhumer - All Rights Reserved. - - The LZO library is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License as - published by the Free Software Foundation; either version 2 of - the License, or (at your option) any later version. - - The LZO library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with the LZO library; see the file COPYING. - If not, write to the Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - - Markus F.X.J. Oberhumer - - http://www.oberhumer.com/opensource/lzo/ -*/ -#include "libbb.h" - -/* The following is probably only safe on Intel-compatible processors ... */ -#define LZO_UNALIGNED_OK_2 -#define LZO_UNALIGNED_OK_4 - -#include "liblzo.h" - -#define LZO_MAX(a,b) ((a) >= (b) ? (a) : (b)) -#define LZO_MIN(a,b) ((a) <= (b) ? (a) : (b)) -#define LZO_MAX3(a,b,c) ((a) >= (b) ? LZO_MAX(a,c) : LZO_MAX(b,c)) - -/*********************************************************************** -// -************************************************************************/ -#define SWD_N M4_MAX_OFFSET /* size of ring buffer */ -#define SWD_F 2048 /* upper limit for match length */ - -#define SWD_BEST_OFF (LZO_MAX3(M2_MAX_LEN, M3_MAX_LEN, M4_MAX_LEN) + 1) - -typedef struct { - int init; - - unsigned look; /* bytes in lookahead buffer */ - - unsigned m_len; - unsigned m_off; - - const uint8_t *bp; - const uint8_t *ip; - const uint8_t *in; - const uint8_t *in_end; - uint8_t *out; - - unsigned r1_lit; - -} lzo1x_999_t; - -#define getbyte(c) ((c).ip < (c).in_end ? *((c).ip)++ : (-1)) - -/* lzo_swd.c -- sliding window dictionary */ - -/*********************************************************************** -// -************************************************************************/ -#define SWD_UINT_MAX USHRT_MAX - -#ifndef SWD_HSIZE -# define SWD_HSIZE 16384 -#endif -#ifndef SWD_MAX_CHAIN -# define SWD_MAX_CHAIN 2048 -#endif - -#define HEAD3(b, p) \ - ( ((0x9f5f * ((((b[p]<<5)^b[p+1])<<5) ^ b[p+2])) >> 5) & (SWD_HSIZE-1) ) - -#if defined(LZO_UNALIGNED_OK_2) -# define HEAD2(b,p) (* (uint16_t *) &(b[p])) -#else -# define HEAD2(b,p) (b[p] ^ ((unsigned)b[p+1]<<8)) -#endif -#define NIL2 SWD_UINT_MAX - -typedef struct lzo_swd { - /* public - "built-in" */ - - /* public - configuration */ - unsigned max_chain; - int use_best_off; - - /* public - output */ - unsigned m_len; - unsigned m_off; - unsigned look; - int b_char; -#if defined(SWD_BEST_OFF) - unsigned best_off[SWD_BEST_OFF]; -#endif - - /* semi public */ - lzo1x_999_t *c; - unsigned m_pos; -#if defined(SWD_BEST_OFF) - unsigned best_pos[SWD_BEST_OFF]; -#endif - - /* private */ - unsigned ip; /* input pointer (lookahead) */ - unsigned bp; /* buffer pointer */ - unsigned rp; /* remove pointer */ - - unsigned node_count; - unsigned first_rp; - - uint8_t b[SWD_N + SWD_F]; - uint8_t b_wrap[SWD_F]; /* must follow b */ - uint16_t head3[SWD_HSIZE]; - uint16_t succ3[SWD_N + SWD_F]; - uint16_t best3[SWD_N + SWD_F]; - uint16_t llen3[SWD_HSIZE]; -#ifdef HEAD2 - uint16_t head2[65536L]; -#endif -} lzo_swd_t, *lzo_swd_p; - -#define SIZEOF_LZO_SWD_T (sizeof(lzo_swd_t)) - - -/* Access macro for head3. - * head3[key] may be uninitialized, but then its value will never be used. - */ -#define s_get_head3(s,key) s->head3[key] - - -/*********************************************************************** -// -************************************************************************/ -#define B_SIZE (SWD_N + SWD_F) - -static int swd_init(lzo_swd_p s) -{ - /* defaults */ - s->node_count = SWD_N; - - memset(s->llen3, 0, sizeof(s->llen3[0]) * (unsigned)SWD_HSIZE); -#ifdef HEAD2 - memset(s->head2, 0xff, sizeof(s->head2[0]) * 65536L); - assert(s->head2[0] == NIL2); -#endif - - s->ip = 0; - s->bp = s->ip; - s->first_rp = s->ip; - - assert(s->ip + SWD_F <= B_SIZE); - s->look = (unsigned) (s->c->in_end - s->c->ip); - if (s->look > 0) { - if (s->look > SWD_F) - s->look = SWD_F; - memcpy(&s->b[s->ip], s->c->ip, s->look); - s->c->ip += s->look; - s->ip += s->look; - } - if (s->ip == B_SIZE) - s->ip = 0; - - s->rp = s->first_rp; - if (s->rp >= s->node_count) - s->rp -= s->node_count; - else - s->rp += B_SIZE - s->node_count; - - return LZO_E_OK; -} - -#define swd_pos2off(s,pos) \ - (s->bp > (pos) ? s->bp - (pos) : B_SIZE - ((pos) - s->bp)) - - -/*********************************************************************** -// -************************************************************************/ -static void swd_getbyte(lzo_swd_p s) -{ - int c; - - if ((c = getbyte(*(s->c))) < 0) { - if (s->look > 0) - --s->look; - } else { - s->b[s->ip] = c; - if (s->ip < SWD_F) - s->b_wrap[s->ip] = c; - } - if (++s->ip == B_SIZE) - s->ip = 0; - if (++s->bp == B_SIZE) - s->bp = 0; - if (++s->rp == B_SIZE) - s->rp = 0; -} - - -/*********************************************************************** -// remove node from lists -************************************************************************/ -static void swd_remove_node(lzo_swd_p s, unsigned node) -{ - if (s->node_count == 0) { - unsigned key; - - key = HEAD3(s->b,node); - assert(s->llen3[key] > 0); - --s->llen3[key]; - -#ifdef HEAD2 - key = HEAD2(s->b,node); - assert(s->head2[key] != NIL2); - if ((unsigned) s->head2[key] == node) - s->head2[key] = NIL2; -#endif - } else - --s->node_count; -} - - -/*********************************************************************** -// -************************************************************************/ -static void swd_accept(lzo_swd_p s, unsigned n) -{ - assert(n <= s->look); - - while (n--) { - unsigned key; - - swd_remove_node(s,s->rp); - - /* add bp into HEAD3 */ - key = HEAD3(s->b, s->bp); - s->succ3[s->bp] = s_get_head3(s, key); - s->head3[key] = s->bp; - s->best3[s->bp] = SWD_F + 1; - s->llen3[key]++; - assert(s->llen3[key] <= SWD_N); - -#ifdef HEAD2 - /* add bp into HEAD2 */ - key = HEAD2(s->b, s->bp); - s->head2[key] = s->bp; -#endif - - swd_getbyte(s); - } -} - - -/*********************************************************************** -// -************************************************************************/ -static void swd_search(lzo_swd_p s, unsigned node, unsigned cnt) -{ - const uint8_t *p1; - const uint8_t *p2; - const uint8_t *px; - unsigned m_len = s->m_len; - const uint8_t *b = s->b; - const uint8_t *bp = s->b + s->bp; - const uint8_t *bx = s->b + s->bp + s->look; - unsigned char scan_end1; - - assert(s->m_len > 0); - - scan_end1 = bp[m_len - 1]; - for ( ; cnt-- > 0; node = s->succ3[node]) { - p1 = bp; - p2 = b + node; - px = bx; - - assert(m_len < s->look); - - if (p2[m_len - 1] == scan_end1 - && p2[m_len] == p1[m_len] - && p2[0] == p1[0] - && p2[1] == p1[1] - ) { - unsigned i; - assert(lzo_memcmp(bp, &b[node], 3) == 0); - - p1 += 2; p2 += 2; - do {} while (++p1 < px && *p1 == *++p2); - i = p1-bp; - - assert(lzo_memcmp(bp, &b[node], i) == 0); - -#if defined(SWD_BEST_OFF) - if (i < SWD_BEST_OFF) { - if (s->best_pos[i] == 0) - s->best_pos[i] = node + 1; - } -#endif - if (i > m_len) { - s->m_len = m_len = i; - s->m_pos = node; - if (m_len == s->look) - return; - if (m_len >= SWD_F) - return; - if (m_len > (unsigned) s->best3[node]) - return; - scan_end1 = bp[m_len - 1]; - } - } - } -} - - -/*********************************************************************** -// -************************************************************************/ -#ifdef HEAD2 - -static int swd_search2(lzo_swd_p s) -{ - unsigned key; - - assert(s->look >= 2); - assert(s->m_len > 0); - - key = s->head2[HEAD2(s->b, s->bp)]; - if (key == NIL2) - return 0; - assert(lzo_memcmp(&s->b[s->bp], &s->b[key], 2) == 0); -#if defined(SWD_BEST_OFF) - if (s->best_pos[2] == 0) - s->best_pos[2] = key + 1; -#endif - - if (s->m_len < 2) { - s->m_len = 2; - s->m_pos = key; - } - return 1; -} - -#endif - - -/*********************************************************************** -// -************************************************************************/ -static void swd_findbest(lzo_swd_p s) -{ - unsigned key; - unsigned cnt, node; - unsigned len; - - assert(s->m_len > 0); - - /* get current head, add bp into HEAD3 */ - key = HEAD3(s->b,s->bp); - node = s->succ3[s->bp] = s_get_head3(s, key); - cnt = s->llen3[key]++; - assert(s->llen3[key] <= SWD_N + SWD_F); - if (cnt > s->max_chain) - cnt = s->max_chain; - s->head3[key] = s->bp; - - s->b_char = s->b[s->bp]; - len = s->m_len; - if (s->m_len >= s->look) { - if (s->look == 0) - s->b_char = -1; - s->m_off = 0; - s->best3[s->bp] = SWD_F + 1; - } else { -#ifdef HEAD2 - if (swd_search2(s)) -#endif - if (s->look >= 3) - swd_search(s, node, cnt); - if (s->m_len > len) - s->m_off = swd_pos2off(s,s->m_pos); - s->best3[s->bp] = s->m_len; - -#if defined(SWD_BEST_OFF) - if (s->use_best_off) { - int i; - for (i = 2; i < SWD_BEST_OFF; i++) { - if (s->best_pos[i] > 0) - s->best_off[i] = swd_pos2off(s, s->best_pos[i]-1); - else - s->best_off[i] = 0; - } - } -#endif - } - - swd_remove_node(s,s->rp); - -#ifdef HEAD2 - /* add bp into HEAD2 */ - key = HEAD2(s->b, s->bp); - s->head2[key] = s->bp; -#endif -} - -#undef HEAD3 -#undef HEAD2 -#undef s_get_head3 - - -/*********************************************************************** -// -************************************************************************/ -static int init_match(lzo1x_999_t *c, lzo_swd_p s, uint32_t use_best_off) -{ - int r; - - assert(!c->init); - c->init = 1; - - s->c = c; - - r = swd_init(s); - if (r != 0) - return r; - - s->use_best_off = use_best_off; - return r; -} - - -/*********************************************************************** -// -************************************************************************/ -static int find_match(lzo1x_999_t *c, lzo_swd_p s, - unsigned this_len, unsigned skip) -{ - assert(c->init); - - if (skip > 0) { - assert(this_len >= skip); - swd_accept(s, this_len - skip); - } else { - assert(this_len <= 1); - } - - s->m_len = 1; - s->m_len = 1; -#ifdef SWD_BEST_OFF - if (s->use_best_off) - memset(s->best_pos, 0, sizeof(s->best_pos)); -#endif - swd_findbest(s); - c->m_len = s->m_len; - c->m_off = s->m_off; - - swd_getbyte(s); - - if (s->b_char < 0) { - c->look = 0; - c->m_len = 0; - } else { - c->look = s->look + 1; - } - c->bp = c->ip - c->look; - - return LZO_E_OK; -} - -/* this is a public functions, but there is no prototype in a header file */ -static int lzo1x_999_compress_internal(const uint8_t *in , unsigned in_len, - uint8_t *out, unsigned *out_len, - void *wrkmem, - unsigned good_length, - unsigned max_lazy, - unsigned max_chain, - uint32_t use_best_off); - - -/*********************************************************************** -// -************************************************************************/ -static uint8_t *code_match(lzo1x_999_t *c, - uint8_t *op, unsigned m_len, unsigned m_off) -{ - assert(op > c->out); - if (m_len == 2) { - assert(m_off <= M1_MAX_OFFSET); - assert(c->r1_lit > 0); - assert(c->r1_lit < 4); - m_off -= 1; - *op++ = M1_MARKER | ((m_off & 3) << 2); - *op++ = m_off >> 2; - } else if (m_len <= M2_MAX_LEN && m_off <= M2_MAX_OFFSET) { - assert(m_len >= 3); - m_off -= 1; - *op++ = ((m_len - 1) << 5) | ((m_off & 7) << 2); - *op++ = m_off >> 3; - assert(op[-2] >= M2_MARKER); - } else if (m_len == M2_MIN_LEN && m_off <= MX_MAX_OFFSET && c->r1_lit >= 4) { - assert(m_len == 3); - assert(m_off > M2_MAX_OFFSET); - m_off -= 1 + M2_MAX_OFFSET; - *op++ = M1_MARKER | ((m_off & 3) << 2); - *op++ = m_off >> 2; - } else if (m_off <= M3_MAX_OFFSET) { - assert(m_len >= 3); - m_off -= 1; - if (m_len <= M3_MAX_LEN) - *op++ = M3_MARKER | (m_len - 2); - else { - m_len -= M3_MAX_LEN; - *op++ = M3_MARKER | 0; - while (m_len > 255) { - m_len -= 255; - *op++ = 0; - } - assert(m_len > 0); - *op++ = m_len; - } - *op++ = m_off << 2; - *op++ = m_off >> 6; - } else { - unsigned k; - - assert(m_len >= 3); - assert(m_off > 0x4000); - assert(m_off <= 0xbfff); - m_off -= 0x4000; - k = (m_off & 0x4000) >> 11; - if (m_len <= M4_MAX_LEN) - *op++ = M4_MARKER | k | (m_len - 2); - else { - m_len -= M4_MAX_LEN; - *op++ = M4_MARKER | k | 0; - while (m_len > 255) { - m_len -= 255; - *op++ = 0; - } - assert(m_len > 0); - *op++ = m_len; - } - *op++ = m_off << 2; - *op++ = m_off >> 6; - } - - return op; -} - - -static uint8_t *STORE_RUN(lzo1x_999_t *c, uint8_t *op, - const uint8_t *ii, unsigned t) -{ - if (op == c->out && t <= 238) { - *op++ = 17 + t; - } else if (t <= 3) { - op[-2] |= t; - } else if (t <= 18) { - *op++ = t - 3; - } else { - unsigned tt = t - 18; - - *op++ = 0; - while (tt > 255) { - tt -= 255; - *op++ = 0; - } - assert(tt > 0); - *op++ = tt; - } - do *op++ = *ii++; while (--t > 0); - - return op; -} - - -static uint8_t *code_run(lzo1x_999_t *c, uint8_t *op, const uint8_t *ii, - unsigned lit) -{ - if (lit > 0) { - assert(m_len >= 2); - op = STORE_RUN(c, op, ii, lit); - } else { - assert(m_len >= 3); - } - c->r1_lit = lit; - - return op; -} - - -/*********************************************************************** -// -************************************************************************/ -static int len_of_coded_match(unsigned m_len, unsigned m_off, unsigned lit) -{ - int n = 4; - - if (m_len < 2) - return -1; - if (m_len == 2) - return (m_off <= M1_MAX_OFFSET && lit > 0 && lit < 4) ? 2 : -1; - if (m_len <= M2_MAX_LEN && m_off <= M2_MAX_OFFSET) - return 2; - if (m_len == M2_MIN_LEN && m_off <= MX_MAX_OFFSET && lit >= 4) - return 2; - if (m_off <= M3_MAX_OFFSET) { - if (m_len <= M3_MAX_LEN) - return 3; - m_len -= M3_MAX_LEN; - } else if (m_off <= M4_MAX_OFFSET) { - if (m_len <= M4_MAX_LEN) - return 3; - m_len -= M4_MAX_LEN; - } else - return -1; - while (m_len > 255) { - m_len -= 255; - n++; - } - return n; -} - - -static int min_gain(unsigned ahead, unsigned lit1, - unsigned lit2, int l1, int l2, int l3) -{ - int lazy_match_min_gain = 0; - - assert (ahead >= 1); - lazy_match_min_gain += ahead; - - if (lit1 <= 3) - lazy_match_min_gain += (lit2 <= 3) ? 0 : 2; - else if (lit1 <= 18) - lazy_match_min_gain += (lit2 <= 18) ? 0 : 1; - - lazy_match_min_gain += (l2 - l1) * 2; - if (l3 > 0) - lazy_match_min_gain -= (ahead - l3) * 2; - - if (lazy_match_min_gain < 0) - lazy_match_min_gain = 0; - - return lazy_match_min_gain; -} - - -/*********************************************************************** -// -************************************************************************/ -#if defined(SWD_BEST_OFF) - -static void better_match(const lzo_swd_p swd, - unsigned *m_len, unsigned *m_off) -{ - if (*m_len <= M2_MIN_LEN) - return; - - if (*m_off <= M2_MAX_OFFSET) - return; - - /* M3/M4 -> M2 */ - if (*m_off > M2_MAX_OFFSET - && *m_len >= M2_MIN_LEN + 1 && *m_len <= M2_MAX_LEN + 1 - && swd->best_off[*m_len-1] && swd->best_off[*m_len-1] <= M2_MAX_OFFSET - ) { - *m_len = *m_len - 1; - *m_off = swd->best_off[*m_len]; - return; - } - - /* M4 -> M2 */ - if (*m_off > M3_MAX_OFFSET - && *m_len >= M4_MAX_LEN + 1 && *m_len <= M2_MAX_LEN + 2 - && swd->best_off[*m_len-2] && swd->best_off[*m_len-2] <= M2_MAX_OFFSET - ) { - *m_len = *m_len - 2; - *m_off = swd->best_off[*m_len]; - return; - } - /* M4 -> M3 */ - if (*m_off > M3_MAX_OFFSET - && *m_len >= M4_MAX_LEN + 1 && *m_len <= M3_MAX_LEN + 1 - && swd->best_off[*m_len-1] && swd->best_off[*m_len-1] <= M3_MAX_OFFSET - ) { - *m_len = *m_len - 1; - *m_off = swd->best_off[*m_len]; - } -} - -#endif - - -/*********************************************************************** -// -************************************************************************/ -static int lzo1x_999_compress_internal(const uint8_t *in, unsigned in_len, - uint8_t *out, unsigned *out_len, - void *wrkmem, - unsigned good_length, - unsigned max_lazy, - unsigned max_chain, - uint32_t use_best_off) -{ - uint8_t *op; - const uint8_t *ii; - unsigned lit; - unsigned m_len, m_off; - lzo1x_999_t cc; - lzo1x_999_t *const c = &cc; - const lzo_swd_p swd = (lzo_swd_p) wrkmem; - int r; - - c->init = 0; - c->ip = c->in = in; - c->in_end = in + in_len; - c->out = out; - - op = out; - ii = c->ip; /* point to start of literal run */ - lit = 0; - c->r1_lit = 0; - - r = init_match(c, swd, use_best_off); - if (r != 0) - return r; - swd->max_chain = max_chain; - - r = find_match(c, swd, 0, 0); - if (r != 0) - return r; - - while (c->look > 0) { - unsigned ahead; - unsigned max_ahead; - int l1, l2, l3; - - m_len = c->m_len; - m_off = c->m_off; - - assert(c->bp == c->ip - c->look); - assert(c->bp >= in); - if (lit == 0) - ii = c->bp; - assert(ii + lit == c->bp); - assert(swd->b_char == *(c->bp)); - - if (m_len < 2 - || (m_len == 2 && (m_off > M1_MAX_OFFSET || lit == 0 || lit >= 4)) - /* Do not accept this match for compressed-data compatibility - * with LZO v1.01 and before - * [ might be a problem for decompress() and optimize() ] - */ - || (m_len == 2 && op == out) - || (op == out && lit == 0) - ) { - /* a literal */ - m_len = 0; - } - else if (m_len == M2_MIN_LEN) { - /* compression ratio improves if we code a literal in some cases */ - if (m_off > MX_MAX_OFFSET && lit >= 4) - m_len = 0; - } - - if (m_len == 0) { - /* a literal */ - lit++; - swd->max_chain = max_chain; - r = find_match(c, swd, 1, 0); - assert(r == 0); - continue; - } - - /* a match */ -#if defined(SWD_BEST_OFF) - if (swd->use_best_off) - better_match(swd, &m_len, &m_off); -#endif - - /* shall we try a lazy match ? */ - ahead = 0; - if (m_len >= max_lazy) { - /* no */ - l1 = 0; - max_ahead = 0; - } else { - /* yes, try a lazy match */ - l1 = len_of_coded_match(m_len, m_off, lit); - assert(l1 > 0); - max_ahead = LZO_MIN(2, (unsigned)l1 - 1); - } - - - while (ahead < max_ahead && c->look > m_len) { - int lazy_match_min_gain; - - if (m_len >= good_length) - swd->max_chain = max_chain >> 2; - else - swd->max_chain = max_chain; - r = find_match(c, swd, 1, 0); - ahead++; - - assert(r == 0); - assert(c->look > 0); - assert(ii + lit + ahead == c->bp); - - if (c->m_len < m_len) - continue; - if (c->m_len == m_len && c->m_off >= m_off) - continue; -#if defined(SWD_BEST_OFF) - if (swd->use_best_off) - better_match(swd, &c->m_len, &c->m_off); -#endif - l2 = len_of_coded_match(c->m_len, c->m_off, lit+ahead); - if (l2 < 0) - continue; - - /* compressed-data compatibility [see above] */ - l3 = (op == out) ? -1 : len_of_coded_match(ahead, m_off, lit); - - lazy_match_min_gain = min_gain(ahead, lit, lit+ahead, l1, l2, l3); - if (c->m_len >= m_len + lazy_match_min_gain) { - if (l3 > 0) { - /* code previous run */ - op = code_run(c, op, ii, lit); - lit = 0; - /* code shortened match */ - op = code_match(c, op, ahead, m_off); - } else { - lit += ahead; - assert(ii + lit == c->bp); - } - goto lazy_match_done; - } - } - - assert(ii + lit + ahead == c->bp); - - /* 1 - code run */ - op = code_run(c, op, ii, lit); - lit = 0; - - /* 2 - code match */ - op = code_match(c, op, m_len, m_off); - swd->max_chain = max_chain; - r = find_match(c, swd, m_len, 1+ahead); - assert(r == 0); - - lazy_match_done: ; - } - - /* store final run */ - if (lit > 0) - op = STORE_RUN(c, op, ii, lit); - -#if defined(LZO_EOF_CODE) - *op++ = M4_MARKER | 1; - *op++ = 0; - *op++ = 0; -#endif - - *out_len = op - out; - - return LZO_E_OK; -} - - -/*********************************************************************** -// -************************************************************************/ -int lzo1x_999_compress_level(const uint8_t *in, unsigned in_len, - uint8_t *out, unsigned *out_len, - void *wrkmem, - int compression_level) -{ - static const struct { - uint16_t good_length; - uint16_t max_lazy; - uint16_t max_chain; - uint16_t use_best_off; - } c[3] = { - { 8, 32, 256, 0 }, - { 32, 128, 2048, 1 }, - { SWD_F, SWD_F, 4096, 1 } /* max. compression */ - }; - - if (compression_level < 7 || compression_level > 9) - return LZO_E_ERROR; - - compression_level -= 7; - return lzo1x_999_compress_internal(in, in_len, out, out_len, wrkmem, - c[compression_level].good_length, - c[compression_level].max_lazy, - c[compression_level].max_chain, - c[compression_level].use_best_off); -} diff --git a/archival/libunarchive/lzo1x_c.c b/archival/libunarchive/lzo1x_c.c deleted file mode 100644 index cc86f74b1..000000000 --- a/archival/libunarchive/lzo1x_c.c +++ /dev/null @@ -1,296 +0,0 @@ -/* implementation of the LZO1[XY]-1 compression algorithm - - This file is part of the LZO real-time data compression library. - - Copyright (C) 1996..2008 Markus Franz Xaver Johannes Oberhumer - All Rights Reserved. - - Markus F.X.J. Oberhumer - http://www.oberhumer.com/opensource/lzo/ - - The LZO library is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License as - published by the Free Software Foundation; either version 2 of - the License, or (at your option) any later version. - - The LZO library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with the LZO library; see the file COPYING. - If not, write to the Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -/*********************************************************************** -// compress a block of data. -************************************************************************/ -static NOINLINE unsigned -do_compress(const uint8_t* in, unsigned in_len, - uint8_t* out, unsigned* out_len, - void* wrkmem) -{ - register const uint8_t* ip; - uint8_t* op; - const uint8_t* const in_end = in + in_len; - const uint8_t* const ip_end = in + in_len - M2_MAX_LEN - 5; - const uint8_t* ii; - const void* *const dict = (const void**) wrkmem; - - op = out; - ip = in; - ii = ip; - - ip += 4; - for (;;) { - register const uint8_t* m_pos; - unsigned m_off; - unsigned m_len; - unsigned dindex; - - D_INDEX1(dindex,ip); - GINDEX(m_pos,m_off,dict,dindex,in); - if (LZO_CHECK_MPOS_NON_DET(m_pos,m_off,in,ip,M4_MAX_OFFSET)) - goto literal; -#if 1 - if (m_off <= M2_MAX_OFFSET || m_pos[3] == ip[3]) - goto try_match; - D_INDEX2(dindex,ip); -#endif - GINDEX(m_pos,m_off,dict,dindex,in); - if (LZO_CHECK_MPOS_NON_DET(m_pos,m_off,in,ip,M4_MAX_OFFSET)) - goto literal; - if (m_off <= M2_MAX_OFFSET || m_pos[3] == ip[3]) - goto try_match; - goto literal; - - try_match: -#if 1 && defined(LZO_UNALIGNED_OK_2) - if (* (const lzo_ushortp) m_pos != * (const lzo_ushortp) ip) -#else - if (m_pos[0] != ip[0] || m_pos[1] != ip[1]) -#endif - { - } else { - if (m_pos[2] == ip[2]) { -#if 0 - if (m_off <= M2_MAX_OFFSET) - goto match; - if (lit <= 3) - goto match; - if (lit == 3) { /* better compression, but slower */ - assert(op - 2 > out); op[-2] |= (uint8_t)(3); - *op++ = *ii++; *op++ = *ii++; *op++ = *ii++; - goto code_match; - } - if (m_pos[3] == ip[3]) -#endif - goto match; - } - else { - /* still need a better way for finding M1 matches */ -#if 0 - /* a M1 match */ -#if 0 - if (m_off <= M1_MAX_OFFSET && lit > 0 && lit <= 3) -#else - if (m_off <= M1_MAX_OFFSET && lit == 3) -#endif - { - register unsigned t; - - t = lit; - assert(op - 2 > out); op[-2] |= (uint8_t)(t); - do *op++ = *ii++; while (--t > 0); - assert(ii == ip); - m_off -= 1; - *op++ = (uint8_t)(M1_MARKER | ((m_off & 3) << 2)); - *op++ = (uint8_t)(m_off >> 2); - ip += 2; - goto match_done; - } -#endif - } - } - - /* a literal */ - literal: - UPDATE_I(dict, 0, dindex, ip, in); - ++ip; - if (ip >= ip_end) - break; - continue; - - /* a match */ -match: - UPDATE_I(dict, 0, dindex, ip, in); - /* store current literal run */ - if (pd(ip, ii) > 0) { - register unsigned t = pd(ip, ii); - - if (t <= 3) { - assert(op - 2 > out); - op[-2] |= (uint8_t)(t); - } - else if (t <= 18) - *op++ = (uint8_t)(t - 3); - else { - register unsigned tt = t - 18; - - *op++ = 0; - while (tt > 255) { - tt -= 255; - *op++ = 0; - } - assert(tt > 0); - *op++ = (uint8_t)(tt); - } - do *op++ = *ii++; while (--t > 0); - } - - /* code the match */ - assert(ii == ip); - ip += 3; - if (m_pos[3] != *ip++ || m_pos[4] != *ip++ || m_pos[5] != *ip++ - || m_pos[6] != *ip++ || m_pos[7] != *ip++ || m_pos[8] != *ip++ -#ifdef LZO1Y - || m_pos[ 9] != *ip++ || m_pos[10] != *ip++ || m_pos[11] != *ip++ - || m_pos[12] != *ip++ || m_pos[13] != *ip++ || m_pos[14] != *ip++ -#endif - ) { - --ip; - m_len = pd(ip, ii); - assert(m_len >= 3); - assert(m_len <= M2_MAX_LEN); - - if (m_off <= M2_MAX_OFFSET) { - m_off -= 1; -#if defined(LZO1X) - *op++ = (uint8_t)(((m_len - 1) << 5) | ((m_off & 7) << 2)); - *op++ = (uint8_t)(m_off >> 3); -#elif defined(LZO1Y) - *op++ = (uint8_t)(((m_len + 1) << 4) | ((m_off & 3) << 2)); - *op++ = (uint8_t)(m_off >> 2); -#endif - } - else if (m_off <= M3_MAX_OFFSET) { - m_off -= 1; - *op++ = (uint8_t)(M3_MARKER | (m_len - 2)); - goto m3_m4_offset; - } else { -#if defined(LZO1X) - m_off -= 0x4000; - assert(m_off > 0); - assert(m_off <= 0x7fff); - *op++ = (uint8_t)(M4_MARKER | ((m_off & 0x4000) >> 11) | (m_len - 2)); - goto m3_m4_offset; -#elif defined(LZO1Y) - goto m4_match; -#endif - } - } - else { - { - const uint8_t* end = in_end; - const uint8_t* m = m_pos + M2_MAX_LEN + 1; - while (ip < end && *m == *ip) - m++, ip++; - m_len = pd(ip, ii); - } - assert(m_len > M2_MAX_LEN); - - if (m_off <= M3_MAX_OFFSET) { - m_off -= 1; - if (m_len <= 33) - *op++ = (uint8_t)(M3_MARKER | (m_len - 2)); - else { - m_len -= 33; - *op++ = M3_MARKER | 0; - goto m3_m4_len; - } - } else { -#if defined(LZO1Y) - m4_match: -#endif - m_off -= 0x4000; - assert(m_off > 0); - assert(m_off <= 0x7fff); - if (m_len <= M4_MAX_LEN) - *op++ = (uint8_t)(M4_MARKER | ((m_off & 0x4000) >> 11) | (m_len - 2)); - else { - m_len -= M4_MAX_LEN; - *op++ = (uint8_t)(M4_MARKER | ((m_off & 0x4000) >> 11)); - m3_m4_len: - while (m_len > 255) { - m_len -= 255; - *op++ = 0; - } - assert(m_len > 0); - *op++ = (uint8_t)(m_len); - } - } - m3_m4_offset: - *op++ = (uint8_t)((m_off & 63) << 2); - *op++ = (uint8_t)(m_off >> 6); - } -#if 0 - match_done: -#endif - ii = ip; - if (ip >= ip_end) - break; - } - - *out_len = pd(op, out); - return pd(in_end, ii); -} - -/*********************************************************************** -// public entry point -************************************************************************/ -int DO_COMPRESS(const uint8_t* in, unsigned in_len, - uint8_t* out, unsigned* out_len, - void* wrkmem) -{ - uint8_t* op = out; - unsigned t; - - if (in_len <= M2_MAX_LEN + 5) - t = in_len; - else { - t = do_compress(in,in_len,op,out_len,wrkmem); - op += *out_len; - } - - if (t > 0) { - const uint8_t* ii = in + in_len - t; - - if (op == out && t <= 238) - *op++ = (uint8_t)(17 + t); - else if (t <= 3) - op[-2] |= (uint8_t)(t); - else if (t <= 18) - *op++ = (uint8_t)(t - 3); - else { - unsigned tt = t - 18; - - *op++ = 0; - while (tt > 255) { - tt -= 255; - *op++ = 0; - } - assert(tt > 0); - *op++ = (uint8_t)(tt); - } - do *op++ = *ii++; while (--t > 0); - } - - *op++ = M4_MARKER | 1; - *op++ = 0; - *op++ = 0; - - *out_len = pd(op, out); - return 0; /*LZO_E_OK*/ -} diff --git a/archival/libunarchive/lzo1x_d.c b/archival/libunarchive/lzo1x_d.c deleted file mode 100644 index 348a85510..000000000 --- a/archival/libunarchive/lzo1x_d.c +++ /dev/null @@ -1,420 +0,0 @@ -/* implementation of the LZO1X decompression algorithm - - This file is part of the LZO real-time data compression library. - - Copyright (C) 1996..2008 Markus Franz Xaver Johannes Oberhumer - All Rights Reserved. - - Markus F.X.J. Oberhumer - http://www.oberhumer.com/opensource/lzo/ - - The LZO library is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License as - published by the Free Software Foundation; either version 2 of - the License, or (at your option) any later version. - - The LZO library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with the LZO library; see the file COPYING. - If not, write to the Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -#include "libbb.h" -#include "liblzo.h" - -/*********************************************************************** -// decompress a block of data. -************************************************************************/ -/* safe decompression with overrun testing */ -int lzo1x_decompress_safe(const uint8_t* in, unsigned in_len, - uint8_t* out, unsigned* out_len, - void* wrkmem UNUSED_PARAM) -{ - register uint8_t* op; - register const uint8_t* ip; - register unsigned t; -#if defined(COPY_DICT) - unsigned m_off; - const uint8_t* dict_end; -#else - register const uint8_t* m_pos = NULL; /* possibly not needed */ -#endif - const uint8_t* const ip_end = in + in_len; -#if defined(HAVE_ANY_OP) - uint8_t* const op_end = out + *out_len; -#endif -#if defined(LZO1Z) - unsigned last_m_off = 0; -#endif - -// LZO_UNUSED(wrkmem); - -#if defined(COPY_DICT) - if (dict) { - if (dict_len > M4_MAX_OFFSET) { - dict += dict_len - M4_MAX_OFFSET; - dict_len = M4_MAX_OFFSET; - } - dict_end = dict + dict_len; - } else { - dict_len = 0; - dict_end = NULL; - } -#endif /* COPY_DICT */ - - *out_len = 0; - - op = out; - ip = in; - - if (*ip > 17) { - t = *ip++ - 17; - if (t < 4) - goto match_next; - assert(t > 0); NEED_OP(t); NEED_IP(t+1); - do *op++ = *ip++; while (--t > 0); - goto first_literal_run; - } - - while (TEST_IP && TEST_OP) { - t = *ip++; - if (t >= 16) - goto match; - /* a literal run */ - if (t == 0) { - NEED_IP(1); - while (*ip == 0) { - t += 255; - ip++; - NEED_IP(1); - } - t += 15 + *ip++; - } - /* copy literals */ - assert(t > 0); - NEED_OP(t+3); - NEED_IP(t+4); -#if defined(LZO_UNALIGNED_OK_4) || defined(LZO_ALIGNED_OK_4) -# if !defined(LZO_UNALIGNED_OK_4) - if (PTR_ALIGNED2_4(op, ip)) -# endif - { - COPY4(op, ip); - op += 4; - ip += 4; - if (--t > 0) { - if (t >= 4) { - do { - COPY4(op, ip); - op += 4; - ip += 4; - t -= 4; - } while (t >= 4); - if (t > 0) - do *op++ = *ip++; while (--t > 0); - } else { - do *op++ = *ip++; while (--t > 0); - } - } - } -# if !defined(LZO_UNALIGNED_OK_4) - else -# endif -#endif -#if !defined(LZO_UNALIGNED_OK_4) - { - *op++ = *ip++; - *op++ = *ip++; - *op++ = *ip++; - do *op++ = *ip++; while (--t > 0); - } -#endif - - first_literal_run: - t = *ip++; - if (t >= 16) - goto match; -#if defined(COPY_DICT) -#if defined(LZO1Z) - m_off = (1 + M2_MAX_OFFSET) + (t << 6) + (*ip++ >> 2); - last_m_off = m_off; -#else - m_off = (1 + M2_MAX_OFFSET) + (t >> 2) + (*ip++ << 2); -#endif - NEED_OP(3); - t = 3; COPY_DICT(t,m_off) -#else /* !COPY_DICT */ -#if defined(LZO1Z) - t = (1 + M2_MAX_OFFSET) + (t << 6) + (*ip++ >> 2); - m_pos = op - t; - last_m_off = t; -#else - m_pos = op - (1 + M2_MAX_OFFSET); - m_pos -= t >> 2; - m_pos -= *ip++ << 2; -#endif - TEST_LB(m_pos); NEED_OP(3); - *op++ = *m_pos++; - *op++ = *m_pos++; - *op++ = *m_pos; -#endif /* COPY_DICT */ - goto match_done; - - /* handle matches */ - do { - match: - if (t >= 64) { /* a M2 match */ -#if defined(COPY_DICT) -#if defined(LZO1X) - m_off = 1 + ((t >> 2) & 7) + (*ip++ << 3); - t = (t >> 5) - 1; -#elif defined(LZO1Y) - m_off = 1 + ((t >> 2) & 3) + (*ip++ << 2); - t = (t >> 4) - 3; -#elif defined(LZO1Z) - m_off = t & 0x1f; - if (m_off >= 0x1c) - m_off = last_m_off; - else { - m_off = 1 + (m_off << 6) + (*ip++ >> 2); - last_m_off = m_off; - } - t = (t >> 5) - 1; -#endif -#else /* !COPY_DICT */ -#if defined(LZO1X) - m_pos = op - 1; - m_pos -= (t >> 2) & 7; - m_pos -= *ip++ << 3; - t = (t >> 5) - 1; -#elif defined(LZO1Y) - m_pos = op - 1; - m_pos -= (t >> 2) & 3; - m_pos -= *ip++ << 2; - t = (t >> 4) - 3; -#elif defined(LZO1Z) - { - unsigned off = t & 0x1f; - m_pos = op; - if (off >= 0x1c) { - assert(last_m_off > 0); - m_pos -= last_m_off; - } else { - off = 1 + (off << 6) + (*ip++ >> 2); - m_pos -= off; - last_m_off = off; - } - } - t = (t >> 5) - 1; -#endif - TEST_LB(m_pos); assert(t > 0); NEED_OP(t+3-1); - goto copy_match; -#endif /* COPY_DICT */ - } - else if (t >= 32) { /* a M3 match */ - t &= 31; - if (t == 0) { - NEED_IP(1); - while (*ip == 0) { - t += 255; - ip++; - NEED_IP(1); - } - t += 31 + *ip++; - } -#if defined(COPY_DICT) -#if defined(LZO1Z) - m_off = 1 + (ip[0] << 6) + (ip[1] >> 2); - last_m_off = m_off; -#else - m_off = 1 + (ip[0] >> 2) + (ip[1] << 6); -#endif -#else /* !COPY_DICT */ -#if defined(LZO1Z) - { - unsigned off = 1 + (ip[0] << 6) + (ip[1] >> 2); - m_pos = op - off; - last_m_off = off; - } -#elif defined(LZO_UNALIGNED_OK_2) && defined(LZO_ABI_LITTLE_ENDIAN) - m_pos = op - 1; - m_pos -= (* (const lzo_ushortp) ip) >> 2; -#else - m_pos = op - 1; - m_pos -= (ip[0] >> 2) + (ip[1] << 6); -#endif -#endif /* COPY_DICT */ - ip += 2; - } - else if (t >= 16) { /* a M4 match */ -#if defined(COPY_DICT) - m_off = (t & 8) << 11; -#else /* !COPY_DICT */ - m_pos = op; - m_pos -= (t & 8) << 11; -#endif /* COPY_DICT */ - t &= 7; - if (t == 0) { - NEED_IP(1); - while (*ip == 0) { - t += 255; - ip++; - NEED_IP(1); - } - t += 7 + *ip++; - } -#if defined(COPY_DICT) -#if defined(LZO1Z) - m_off += (ip[0] << 6) + (ip[1] >> 2); -#else - m_off += (ip[0] >> 2) + (ip[1] << 6); -#endif - ip += 2; - if (m_off == 0) - goto eof_found; - m_off += 0x4000; -#if defined(LZO1Z) - last_m_off = m_off; -#endif -#else /* !COPY_DICT */ -#if defined(LZO1Z) - m_pos -= (ip[0] << 6) + (ip[1] >> 2); -#elif defined(LZO_UNALIGNED_OK_2) && defined(LZO_ABI_LITTLE_ENDIAN) - m_pos -= (* (const lzo_ushortp) ip) >> 2; -#else - m_pos -= (ip[0] >> 2) + (ip[1] << 6); -#endif - ip += 2; - if (m_pos == op) - goto eof_found; - m_pos -= 0x4000; -#if defined(LZO1Z) - last_m_off = pd((const uint8_t*)op, m_pos); -#endif -#endif /* COPY_DICT */ - } - else { /* a M1 match */ -#if defined(COPY_DICT) -#if defined(LZO1Z) - m_off = 1 + (t << 6) + (*ip++ >> 2); - last_m_off = m_off; -#else - m_off = 1 + (t >> 2) + (*ip++ << 2); -#endif - NEED_OP(2); - t = 2; COPY_DICT(t,m_off) -#else /* !COPY_DICT */ -#if defined(LZO1Z) - t = 1 + (t << 6) + (*ip++ >> 2); - m_pos = op - t; - last_m_off = t; -#else - m_pos = op - 1; - m_pos -= t >> 2; - m_pos -= *ip++ << 2; -#endif - TEST_LB(m_pos); NEED_OP(2); - *op++ = *m_pos++; - *op++ = *m_pos; -#endif /* COPY_DICT */ - goto match_done; - } - - /* copy match */ -#if defined(COPY_DICT) - - NEED_OP(t+3-1); - t += 3-1; COPY_DICT(t,m_off) - -#else /* !COPY_DICT */ - - TEST_LB(m_pos); assert(t > 0); NEED_OP(t+3-1); -#if defined(LZO_UNALIGNED_OK_4) || defined(LZO_ALIGNED_OK_4) -# if !defined(LZO_UNALIGNED_OK_4) - if (t >= 2 * 4 - (3 - 1) && PTR_ALIGNED2_4(op,m_pos)) { - assert((op - m_pos) >= 4); /* both pointers are aligned */ -# else - if (t >= 2 * 4 - (3 - 1) && (op - m_pos) >= 4) { -# endif - COPY4(op,m_pos); - op += 4; m_pos += 4; t -= 4 - (3 - 1); - do { - COPY4(op,m_pos); - op += 4; m_pos += 4; t -= 4; - } while (t >= 4); - if (t > 0) - do *op++ = *m_pos++; while (--t > 0); - } - else -#endif - { - copy_match: - *op++ = *m_pos++; *op++ = *m_pos++; - do *op++ = *m_pos++; while (--t > 0); - } - -#endif /* COPY_DICT */ - - match_done: -#if defined(LZO1Z) - t = ip[-1] & 3; -#else - t = ip[-2] & 3; -#endif - if (t == 0) - break; - - /* copy literals */ - match_next: - assert(t > 0); - assert(t < 4); - NEED_OP(t); - NEED_IP(t+1); -#if 0 - do *op++ = *ip++; while (--t > 0); -#else - *op++ = *ip++; - if (t > 1) { - *op++ = *ip++; - if (t > 2) - *op++ = *ip++; - } -#endif - t = *ip++; - } while (TEST_IP && TEST_OP); - } - -//#if defined(HAVE_TEST_IP) || defined(HAVE_TEST_OP) - /* no EOF code was found */ - *out_len = pd(op, out); - return LZO_E_EOF_NOT_FOUND; -//#endif - - eof_found: - assert(t == 1); - *out_len = pd(op, out); - return (ip == ip_end ? LZO_E_OK : - (ip < ip_end ? LZO_E_INPUT_NOT_CONSUMED : LZO_E_INPUT_OVERRUN)); - -//#if defined(HAVE_NEED_IP) - input_overrun: - *out_len = pd(op, out); - return LZO_E_INPUT_OVERRUN; -//#endif - -//#if defined(HAVE_NEED_OP) - output_overrun: - *out_len = pd(op, out); - return LZO_E_OUTPUT_OVERRUN; -//#endif - -//#if defined(LZO_TEST_OVERRUN_LOOKBEHIND) - lookbehind_overrun: - *out_len = pd(op, out); - return LZO_E_LOOKBEHIND_OVERRUN; -//#endif -} diff --git a/archival/libunarchive/open_transformer.c b/archival/libunarchive/open_transformer.c deleted file mode 100644 index ed6a556bb..000000000 --- a/archival/libunarchive/open_transformer.c +++ /dev/null @@ -1,54 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Licensed under GPLv2 or later, see file LICENSE in this source tree. - */ - -#include "libbb.h" -#include "unarchive.h" - -/* transformer(), more than meets the eye */ -/* - * On MMU machine, the transform_prog is removed by macro magic - * in include/unarchive.h. On NOMMU, transformer is removed. - */ -void FAST_FUNC open_transformer(int fd, - IF_DESKTOP(long long) int FAST_FUNC (*transformer)(int src_fd, int dst_fd), - const char *transform_prog) -{ - struct fd_pair fd_pipe; - int pid; - - xpiped_pair(fd_pipe); - pid = BB_MMU ? xfork() : xvfork(); - if (pid == 0) { - /* Child */ - close(fd_pipe.rd); /* we don't want to read from the parent */ - // FIXME: error check? -#if BB_MMU - transformer(fd, fd_pipe.wr); - if (ENABLE_FEATURE_CLEAN_UP) { - close(fd_pipe.wr); /* send EOF */ - close(fd); - } - /* must be _exit! bug was actually seen here */ - _exit(EXIT_SUCCESS); -#else - { - char *argv[4]; - xmove_fd(fd, 0); - xmove_fd(fd_pipe.wr, 1); - argv[0] = (char*)transform_prog; - argv[1] = (char*)"-cf"; - argv[2] = (char*)"-"; - argv[3] = NULL; - BB_EXECVP(transform_prog, argv); - bb_perror_msg_and_die("can't execute '%s'", transform_prog); - } -#endif - /* notreached */ - } - - /* parent process */ - close(fd_pipe.wr); /* don't want to write to the child */ - xmove_fd(fd_pipe.rd, fd); -} diff --git a/archival/libunarchive/seek_by_jump.c b/archival/libunarchive/seek_by_jump.c deleted file mode 100644 index bda55e1b1..000000000 --- a/archival/libunarchive/seek_by_jump.c +++ /dev/null @@ -1,19 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Licensed under GPLv2 or later, see file LICENSE in this source tree. - */ - -#include "libbb.h" -#include "unarchive.h" - -void FAST_FUNC seek_by_jump(int fd, off_t amount) -{ - if (amount - && lseek(fd, amount, SEEK_CUR) == (off_t) -1 - ) { - if (errno == ESPIPE) - seek_by_read(fd, amount); - else - bb_perror_msg_and_die("seek failure"); - } -} diff --git a/archival/libunarchive/seek_by_read.c b/archival/libunarchive/seek_by_read.c deleted file mode 100644 index 25b31365d..000000000 --- a/archival/libunarchive/seek_by_read.c +++ /dev/null @@ -1,16 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Licensed under GPLv2 or later, see file LICENSE in this source tree. - */ - -#include "libbb.h" -#include "unarchive.h" - -/* If we are reading through a pipe, or from stdin then we can't lseek, - * we must read and discard the data to skip over it. - */ -void FAST_FUNC seek_by_read(int fd, off_t amount) -{ - if (amount) - bb_copyfd_exact_size(fd, -1, amount); -} diff --git a/archival/libunarchive/unpack_ar_archive.c b/archival/libunarchive/unpack_ar_archive.c deleted file mode 100644 index 4f68ba3d8..000000000 --- a/archival/libunarchive/unpack_ar_archive.c +++ /dev/null @@ -1,22 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Licensed under GPLv2 or later, see file LICENSE in this source tree. - */ - -#include "libbb.h" -#include "unarchive.h" -#include "ar.h" - -void FAST_FUNC unpack_ar_archive(archive_handle_t *ar_archive) -{ - char magic[7]; - - xread(ar_archive->src_fd, magic, AR_MAGIC_LEN); - if (strncmp(magic, AR_MAGIC, AR_MAGIC_LEN) != 0) { - bb_error_msg_and_die("invalid ar magic"); - } - ar_archive->offset += AR_MAGIC_LEN; - - while (get_header_ar(ar_archive) == EXIT_SUCCESS) - continue; -} diff --git a/archival/libunarchive/unxz/README b/archival/libunarchive/unxz/README deleted file mode 100644 index c5972f6b8..000000000 --- a/archival/libunarchive/unxz/README +++ /dev/null @@ -1,135 +0,0 @@ - -XZ Embedded -=========== - - XZ Embedded is a relatively small, limited implementation of the .xz - file format. Currently only decoding is implemented. - - XZ Embedded was written for use in the Linux kernel, but the code can - be easily used in other environments too, including regular userspace - applications. - - This README contains information that is useful only when the copy - of XZ Embedded isn't part of the Linux kernel tree. You should also - read linux/Documentation/xz.txt even if you aren't using XZ Embedded - as part of Linux; information in that file is not repeated in this - README. - -Compiling the Linux kernel module - - The xz_dec module depends on crc32 module, so make sure that you have - it enabled (CONFIG_CRC32). - - Building the xz_dec and xz_dec_test modules without support for BCJ - filters: - - cd linux/lib/xz - make -C /path/to/kernel/source \ - KCPPFLAGS=-I"$(pwd)/../../include" M="$(pwd)" \ - CONFIG_XZ_DEC=m CONFIG_XZ_DEC_TEST=m - - Building the xz_dec and xz_dec_test modules with support for BCJ - filters: - - cd linux/lib/xz - make -C /path/to/kernel/source \ - KCPPFLAGS=-I"$(pwd)/../../include" M="$(pwd)" \ - CONFIG_XZ_DEC=m CONFIG_XZ_DEC_TEST=m CONFIG_XZ_DEC_BCJ=y \ - CONFIG_XZ_DEC_X86=y CONFIG_XZ_DEC_POWERPC=y \ - CONFIG_XZ_DEC_IA64=y CONFIG_XZ_DEC_ARM=y \ - CONFIG_XZ_DEC_ARMTHUMB=y CONFIG_XZ_DEC_SPARC=y - - If you want only one or a few of the BCJ filters, omit the appropriate - variables. CONFIG_XZ_DEC_BCJ=y is always required to build the support - code shared between all BCJ filters. - - Most people don't need the xz_dec_test module. You can skip building - it by omitting CONFIG_XZ_DEC_TEST=m from the make command line. - -Compiler requirements - - XZ Embedded should compile as either GNU-C89 (used in the Linux - kernel) or with any C99 compiler. Getting the code to compile with - non-GNU C89 compiler or a C++ compiler should be quite easy as - long as there is a data type for unsigned 64-bit integer (or the - code is modified not to support large files, which needs some more - care than just using 32-bit integer instead of 64-bit). - - If you use GCC, try to use a recent version. For example, on x86, - xz_dec_lzma2.c compiled with GCC 3.3.6 is 15-25 % slower than when - compiled with GCC 4.3.3. - -Embedding into userspace applications - - To embed the XZ decoder, copy the following files into a single - directory in your source code tree: - - linux/include/linux/xz.h - linux/lib/xz/xz_crc32.c - linux/lib/xz/xz_dec_lzma2.c - linux/lib/xz/xz_dec_stream.c - linux/lib/xz/xz_lzma2.h - linux/lib/xz/xz_private.h - linux/lib/xz/xz_stream.h - userspace/xz_config.h - - Alternatively, xz.h may be placed into a different directory but then - that directory must be in the compiler include path when compiling - the .c files. - - Your code should use only the functions declared in xz.h. The rest of - the .h files are meant only for internal use in XZ Embedded. - - You may want to modify xz_config.h to be more suitable for your build - environment. Probably you should at least skim through it even if the - default file works as is. - -BCJ filter support - - If you want support for one or more BCJ filters, you need to copy also - linux/lib/xz/xz_dec_bcj.c into your application, and use appropriate - #defines in xz_config.h or in compiler flags. You don't need these - #defines in the code that just uses XZ Embedded via xz.h, but having - them always #defined doesn't hurt either. - - #define Instruction set BCJ filter endianness - XZ_DEC_X86 x86 or x86-64 Little endian only - XZ_DEC_POWERPC PowerPC Big endian only - XZ_DEC_IA64 Itanium (IA-64) Big or little endian - XZ_DEC_ARM ARM Little endian only - XZ_DEC_ARMTHUMB ARM-Thumb Little endian only - XZ_DEC_SPARC SPARC Big or little endian - - While some architectures are (partially) bi-endian, the endianness - setting doesn't change the endianness of the instructions on all - architectures. That's why Itanium and SPARC filters work for both big - and little endian executables (Itanium has little endian instructions - and SPARC has big endian instructions). - - There currently is no filter for little endian PowerPC or big endian - ARM or ARM-Thumb. Implementing filters for them can be considered if - there is a need for such filters in real-world applications. - -Notes about shared libraries - - If you are including XZ Embedded into a shared library, you very - probably should rename the xz_* functions to prevent symbol - conflicts in case your library is linked against some other library - or application that also has XZ Embedded in it (which may even be - a different version of XZ Embedded). TODO: Provide an easy way - to do this. - - Please don't create a shared library of XZ Embedded itself unless - it is fine to rebuild everything depending on that shared library - everytime you upgrade to a newer version of XZ Embedded. There are - no API or ABI stability guarantees between different versions of - XZ Embedded. - -Specifying the calling convention - - XZ_FUNC macro was included to support declaring functions with __init - in Linux. Outside Linux, it can be used to specify the calling - convention on systems that support multiple calling conventions. - For example, on Windows, you may make all functions use the stdcall - calling convention by defining XZ_FUNC=__stdcall when building and - using the functions from XZ Embedded. diff --git a/archival/libunarchive/unxz/xz.h b/archival/libunarchive/unxz/xz.h deleted file mode 100644 index c6c071c4a..000000000 --- a/archival/libunarchive/unxz/xz.h +++ /dev/null @@ -1,271 +0,0 @@ -/* - * XZ decompressor - * - * Authors: Lasse Collin - * Igor Pavlov - * - * This file has been put into the public domain. - * You can do whatever you want with this file. - */ - -#ifndef XZ_H -#define XZ_H - -#ifdef __KERNEL__ -# include -# include -#else -# include -# include -#endif - -/* In Linux, this is used to make extern functions static when needed. */ -#ifndef XZ_EXTERN -# define XZ_EXTERN extern -#endif - -/* In Linux, this is used to mark the functions with __init when needed. */ -#ifndef XZ_FUNC -# define XZ_FUNC -#endif - -/** - * enum xz_mode - Operation mode - * - * @XZ_SINGLE: Single-call mode. This uses less RAM than - * than multi-call modes, because the LZMA2 - * dictionary doesn't need to be allocated as - * part of the decoder state. All required data - * structures are allocated at initialization, - * so xz_dec_run() cannot return XZ_MEM_ERROR. - * @XZ_PREALLOC: Multi-call mode with preallocated LZMA2 - * dictionary buffer. All data structures are - * allocated at initialization, so xz_dec_run() - * cannot return XZ_MEM_ERROR. - * @XZ_DYNALLOC: Multi-call mode. The LZMA2 dictionary is - * allocated once the required size has been - * parsed from the stream headers. If the - * allocation fails, xz_dec_run() will return - * XZ_MEM_ERROR. - * - * It is possible to enable support only for a subset of the above - * modes at compile time by defining XZ_DEC_SINGLE, XZ_DEC_PREALLOC, - * or XZ_DEC_DYNALLOC. The xz_dec kernel module is always compiled - * with support for all operation modes, but the preboot code may - * be built with fewer features to minimize code size. - */ -enum xz_mode { - XZ_SINGLE, - XZ_PREALLOC, - XZ_DYNALLOC -}; - -/** - * enum xz_ret - Return codes - * @XZ_OK: Everything is OK so far. More input or more - * output space is required to continue. This - * return code is possible only in multi-call mode - * (XZ_PREALLOC or XZ_DYNALLOC). - * @XZ_STREAM_END: Operation finished successfully. - * @XZ_UNSUPPORTED_CHECK: Integrity check type is not supported. Decoding - * is still possible in multi-call mode by simply - * calling xz_dec_run() again. - * NOTE: This return value is used only if - * XZ_DEC_ANY_CHECK was defined at build time, - * which is not used in the kernel. Unsupported - * check types return XZ_OPTIONS_ERROR if - * XZ_DEC_ANY_CHECK was not defined at build time. - * @XZ_MEM_ERROR: Allocating memory failed. This return code is - * possible only if the decoder was initialized - * with XZ_DYNALLOC. The amount of memory that was - * tried to be allocated was no more than the - * dict_max argument given to xz_dec_init(). - * @XZ_MEMLIMIT_ERROR: A bigger LZMA2 dictionary would be needed than - * allowed by the dict_max argument given to - * xz_dec_init(). This return value is possible - * only in multi-call mode (XZ_PREALLOC or - * XZ_DYNALLOC); the single-call mode (XZ_SINGLE) - * ignores the dict_max argument. - * @XZ_FORMAT_ERROR: File format was not recognized (wrong magic - * bytes). - * @XZ_OPTIONS_ERROR: This implementation doesn't support the requested - * compression options. In the decoder this means - * that the header CRC32 matches, but the header - * itself specifies something that we don't support. - * @XZ_DATA_ERROR: Compressed data is corrupt. - * @XZ_BUF_ERROR: Cannot make any progress. Details are slightly - * different between multi-call and single-call - * mode; more information below. - * - * In multi-call mode, XZ_BUF_ERROR is returned when two consecutive calls - * to XZ code cannot consume any input and cannot produce any new output. - * This happens when there is no new input available, or the output buffer - * is full while at least one output byte is still pending. Assuming your - * code is not buggy, you can get this error only when decoding a compressed - * stream that is truncated or otherwise corrupt. - * - * In single-call mode, XZ_BUF_ERROR is returned only when the output buffer - * is too small, or the compressed input is corrupt in a way that makes the - * decoder produce more output than the caller expected. When it is - * (relatively) clear that the compressed input is truncated, XZ_DATA_ERROR - * is used instead of XZ_BUF_ERROR. - */ -enum xz_ret { - XZ_OK, - XZ_STREAM_END, - XZ_UNSUPPORTED_CHECK, - XZ_MEM_ERROR, - XZ_MEMLIMIT_ERROR, - XZ_FORMAT_ERROR, - XZ_OPTIONS_ERROR, - XZ_DATA_ERROR, - XZ_BUF_ERROR -}; - -/** - * struct xz_buf - Passing input and output buffers to XZ code - * @in: Beginning of the input buffer. This may be NULL if and only - * if in_pos is equal to in_size. - * @in_pos: Current position in the input buffer. This must not exceed - * in_size. - * @in_size: Size of the input buffer - * @out: Beginning of the output buffer. This may be NULL if and only - * if out_pos is equal to out_size. - * @out_pos: Current position in the output buffer. This must not exceed - * out_size. - * @out_size: Size of the output buffer - * - * Only the contents of the output buffer from out[out_pos] onward, and - * the variables in_pos and out_pos are modified by the XZ code. - */ -struct xz_buf { - const uint8_t *in; - size_t in_pos; - size_t in_size; - - uint8_t *out; - size_t out_pos; - size_t out_size; -}; - -/** - * struct xz_dec - Opaque type to hold the XZ decoder state - */ -struct xz_dec; - -/** - * xz_dec_init() - Allocate and initialize a XZ decoder state - * @mode: Operation mode - * @dict_max: Maximum size of the LZMA2 dictionary (history buffer) for - * multi-call decoding. This is ignored in single-call mode - * (mode == XZ_SINGLE). LZMA2 dictionary is always 2^n bytes - * or 2^n + 2^(n-1) bytes (the latter sizes are less common - * in practice), so other values for dict_max don't make sense. - * In the kernel, dictionary sizes of 64 KiB, 128 KiB, 256 KiB, - * 512 KiB, and 1 MiB are probably the only reasonable values, - * except for kernel and initramfs images where a bigger - * dictionary can be fine and useful. - * - * Single-call mode (XZ_SINGLE): xz_dec_run() decodes the whole stream at - * once. The caller must provide enough output space or the decoding will - * fail. The output space is used as the dictionary buffer, which is why - * there is no need to allocate the dictionary as part of the decoder's - * internal state. - * - * Because the output buffer is used as the workspace, streams encoded using - * a big dictionary are not a problem in single-call mode. It is enough that - * the output buffer is big enough to hold the actual uncompressed data; it - * can be smaller than the dictionary size stored in the stream headers. - * - * Multi-call mode with preallocated dictionary (XZ_PREALLOC): dict_max bytes - * of memory is preallocated for the LZMA2 dictionary. This way there is no - * risk that xz_dec_run() could run out of memory, since xz_dec_run() will - * never allocate any memory. Instead, if the preallocated dictionary is too - * small for decoding the given input stream, xz_dec_run() will return - * XZ_MEMLIMIT_ERROR. Thus, it is important to know what kind of data will be - * decoded to avoid allocating excessive amount of memory for the dictionary. - * - * Multi-call mode with dynamically allocated dictionary (XZ_DYNALLOC): - * dict_max specifies the maximum allowed dictionary size that xz_dec_run() - * may allocate once it has parsed the dictionary size from the stream - * headers. This way excessive allocations can be avoided while still - * limiting the maximum memory usage to a sane value to prevent running the - * system out of memory when decompressing streams from untrusted sources. - * - * On success, xz_dec_init() returns a pointer to struct xz_dec, which is - * ready to be used with xz_dec_run(). If memory allocation fails, - * xz_dec_init() returns NULL. - */ -XZ_EXTERN struct xz_dec * XZ_FUNC xz_dec_init( - enum xz_mode mode, uint32_t dict_max); - -/** - * xz_dec_run() - Run the XZ decoder - * @s: Decoder state allocated using xz_dec_init() - * @b: Input and output buffers - * - * The possible return values depend on build options and operation mode. - * See enum xz_ret for details. - * - * NOTE: If an error occurs in single-call mode (return value is not - * XZ_STREAM_END), b->in_pos and b->out_pos are not modified, and the - * contents of the output buffer from b->out[b->out_pos] onward are - * undefined. This is true even after XZ_BUF_ERROR, because with some filter - * chains, there may be a second pass over the output buffer, and this pass - * cannot be properly done if the output buffer is truncated. Thus, you - * cannot give the single-call decoder a too small buffer and then expect to - * get that amount valid data from the beginning of the stream. You must use - * the multi-call decoder if you don't want to uncompress the whole stream. - */ -XZ_EXTERN enum xz_ret XZ_FUNC xz_dec_run(struct xz_dec *s, struct xz_buf *b); - -/** - * xz_dec_reset() - Reset an already allocated decoder state - * @s: Decoder state allocated using xz_dec_init() - * - * This function can be used to reset the multi-call decoder state without - * freeing and reallocating memory with xz_dec_end() and xz_dec_init(). - * - * In single-call mode, xz_dec_reset() is always called in the beginning of - * xz_dec_run(). Thus, explicit call to xz_dec_reset() is useful only in - * multi-call mode. - */ -XZ_EXTERN void XZ_FUNC xz_dec_reset(struct xz_dec *s); - -/** - * xz_dec_end() - Free the memory allocated for the decoder state - * @s: Decoder state allocated using xz_dec_init(). If s is NULL, - * this function does nothing. - */ -XZ_EXTERN void XZ_FUNC xz_dec_end(struct xz_dec *s); - -/* - * Standalone build (userspace build or in-kernel build for boot time use) - * needs a CRC32 implementation. For normal in-kernel use, kernel's own - * CRC32 module is used instead, and users of this module don't need to - * care about the functions below. - */ -#ifndef XZ_INTERNAL_CRC32 -# ifdef __KERNEL__ -# define XZ_INTERNAL_CRC32 0 -# else -# define XZ_INTERNAL_CRC32 1 -# endif -#endif - -#if XZ_INTERNAL_CRC32 -/* - * This must be called before any other xz_* function to initialize - * the CRC32 lookup table. - */ -XZ_EXTERN void XZ_FUNC xz_crc32_init(void); - -/* - * Update CRC32 value using the polynomial from IEEE-802.3. To start a new - * calculation, the third argument must be zero. To continue the calculation, - * the previously returned value is passed as the third argument. - */ -XZ_EXTERN uint32_t XZ_FUNC xz_crc32( - const uint8_t *buf, size_t size, uint32_t crc); -#endif -#endif diff --git a/archival/libunarchive/unxz/xz_config.h b/archival/libunarchive/unxz/xz_config.h deleted file mode 100644 index 187e1cbed..000000000 --- a/archival/libunarchive/unxz/xz_config.h +++ /dev/null @@ -1,123 +0,0 @@ -/* - * Private includes and definitions for userspace use of XZ Embedded - * - * Author: Lasse Collin - * - * This file has been put into the public domain. - * You can do whatever you want with this file. - */ - -#ifndef XZ_CONFIG_H -#define XZ_CONFIG_H - -/* Uncomment as needed to enable BCJ filter decoders. */ -/* #define XZ_DEC_X86 */ -/* #define XZ_DEC_POWERPC */ -/* #define XZ_DEC_IA64 */ -/* #define XZ_DEC_ARM */ -/* #define XZ_DEC_ARMTHUMB */ -/* #define XZ_DEC_SPARC */ - -#include -#include -#include - -#include "xz.h" - -#define kmalloc(size, flags) malloc(size) -#define kfree(ptr) free(ptr) -#define vmalloc(size) malloc(size) -#define vfree(ptr) free(ptr) - -#define memeq(a, b, size) (memcmp(a, b, size) == 0) -#define memzero(buf, size) memset(buf, 0, size) - -#undef min -#undef min_t -#define min(x, y) ((x) < (y) ? (x) : (y)) -#define min_t(type, x, y) min(x, y) - -/* - * Some functions have been marked with __always_inline to keep the - * performance reasonable even when the compiler is optimizing for - * small code size. You may be able to save a few bytes by #defining - * __always_inline to plain inline, but don't complain if the code - * becomes slow. - * - * NOTE: System headers on GNU/Linux may #define this macro already, - * so if you want to change it, you need to #undef it first. - */ -#ifndef __always_inline -# ifdef __GNUC__ -# define __always_inline \ - inline __attribute__((__always_inline__)) -# else -# define __always_inline inline -# endif -#endif - -/* - * Some functions are marked to never be inlined to reduce stack usage. - * If you don't care about stack usage, you may want to modify this so - * that noinline_for_stack is #defined to be empty even when using GCC. - * Doing so may save a few bytes in binary size. - */ -#ifndef noinline_for_stack -# ifdef __GNUC__ -# define noinline_for_stack __attribute__((__noinline__)) -# else -# define noinline_for_stack -# endif -#endif - -/* Inline functions to access unaligned unsigned 32-bit integers */ -#ifndef get_unaligned_le32 -static inline uint32_t XZ_FUNC get_unaligned_le32(const uint8_t *buf) -{ - return (uint32_t)buf[0] - | ((uint32_t)buf[1] << 8) - | ((uint32_t)buf[2] << 16) - | ((uint32_t)buf[3] << 24); -} -#endif - -#ifndef get_unaligned_be32 -static inline uint32_t XZ_FUNC get_unaligned_be32(const uint8_t *buf) -{ - return (uint32_t)(buf[0] << 24) - | ((uint32_t)buf[1] << 16) - | ((uint32_t)buf[2] << 8) - | (uint32_t)buf[3]; -} -#endif - -#ifndef put_unaligned_le32 -static inline void XZ_FUNC put_unaligned_le32(uint32_t val, uint8_t *buf) -{ - buf[0] = (uint8_t)val; - buf[1] = (uint8_t)(val >> 8); - buf[2] = (uint8_t)(val >> 16); - buf[3] = (uint8_t)(val >> 24); -} -#endif - -#ifndef put_unaligned_be32 -static inline void XZ_FUNC put_unaligned_be32(uint32_t val, uint8_t *buf) -{ - buf[0] = (uint8_t)(val >> 24); - buf[1] = (uint8_t)(val >> 16); - buf[2] = (uint8_t)(val >> 8); - buf[3] = (uint8_t)val; -} -#endif - -/* - * Use get_unaligned_le32() also for aligned access for simplicity. On - * little endian systems, #define get_le32(ptr) (*(const uint32_t *)(ptr)) - * could save a few bytes in code size. - */ -#ifndef get_le32 -# define get_le32 get_unaligned_le32 -#endif - -#endif diff --git a/archival/libunarchive/unxz/xz_dec_bcj.c b/archival/libunarchive/unxz/xz_dec_bcj.c deleted file mode 100644 index 09162b51f..000000000 --- a/archival/libunarchive/unxz/xz_dec_bcj.c +++ /dev/null @@ -1,564 +0,0 @@ -/* - * Branch/Call/Jump (BCJ) filter decoders - * - * Authors: Lasse Collin - * Igor Pavlov - * - * This file has been put into the public domain. - * You can do whatever you want with this file. - */ - -#include "xz_private.h" - -/* - * The rest of the file is inside this ifdef. It makes things a little more - * convenient when building without support for any BCJ filters. - */ -#ifdef XZ_DEC_BCJ - -struct xz_dec_bcj { - /* Type of the BCJ filter being used */ - enum { - BCJ_X86 = 4, /* x86 or x86-64 */ - BCJ_POWERPC = 5, /* Big endian only */ - BCJ_IA64 = 6, /* Big or little endian */ - BCJ_ARM = 7, /* Little endian only */ - BCJ_ARMTHUMB = 8, /* Little endian only */ - BCJ_SPARC = 9 /* Big or little endian */ - } type; - - /* - * Return value of the next filter in the chain. We need to preserve - * this information across calls, because we must not call the next - * filter anymore once it has returned XZ_STREAM_END. - */ - enum xz_ret ret; - - /* True if we are operating in single-call mode. */ - bool single_call; - - /* - * Absolute position relative to the beginning of the uncompressed - * data (in a single .xz Block). We care only about the lowest 32 - * bits so this doesn't need to be uint64_t even with big files. - */ - uint32_t pos; - - /* x86 filter state */ - uint32_t x86_prev_mask; - - /* Temporary space to hold the variables from struct xz_buf */ - uint8_t *out; - size_t out_pos; - size_t out_size; - - struct { - /* Amount of already filtered data in the beginning of buf */ - size_t filtered; - - /* Total amount of data currently stored in buf */ - size_t size; - - /* - * Buffer to hold a mix of filtered and unfiltered data. This - * needs to be big enough to hold Alignment + 2 * Look-ahead: - * - * Type Alignment Look-ahead - * x86 1 4 - * PowerPC 4 0 - * IA-64 16 0 - * ARM 4 0 - * ARM-Thumb 2 2 - * SPARC 4 0 - */ - uint8_t buf[16]; - } temp; -}; - -#ifdef XZ_DEC_X86 -/* - * This is macro used to test the most significant byte of a memory address - * in an x86 instruction. - */ -#define bcj_x86_test_msbyte(b) ((b) == 0x00 || (b) == 0xFF) - -static noinline_for_stack size_t XZ_FUNC bcj_x86( - struct xz_dec_bcj *s, uint8_t *buf, size_t size) -{ - static const bool mask_to_allowed_status[8] - = { true, true, true, false, true, false, false, false }; - - static const uint8_t mask_to_bit_num[8] = { 0, 1, 2, 2, 3, 3, 3, 3 }; - - size_t i; - size_t prev_pos = (size_t)-1; - uint32_t prev_mask = s->x86_prev_mask; - uint32_t src; - uint32_t dest; - uint32_t j; - uint8_t b; - - if (size <= 4) - return 0; - - size -= 4; - for (i = 0; i < size; ++i) { - if ((buf[i] & 0xFE) != 0xE8) - continue; - - prev_pos = i - prev_pos; - if (prev_pos > 3) { - prev_mask = 0; - } else { - prev_mask = (prev_mask << (prev_pos - 1)) & 7; - if (prev_mask != 0) { - b = buf[i + 4 - mask_to_bit_num[prev_mask]]; - if (!mask_to_allowed_status[prev_mask] - || bcj_x86_test_msbyte(b)) { - prev_pos = i; - prev_mask = (prev_mask << 1) | 1; - continue; - } - } - } - - prev_pos = i; - - if (bcj_x86_test_msbyte(buf[i + 4])) { - src = get_unaligned_le32(buf + i + 1); - while (true) { - dest = src - (s->pos + (uint32_t)i + 5); - if (prev_mask == 0) - break; - - j = mask_to_bit_num[prev_mask] * 8; - b = (uint8_t)(dest >> (24 - j)); - if (!bcj_x86_test_msbyte(b)) - break; - - src = dest ^ (((uint32_t)1 << (32 - j)) - 1); - } - - dest &= 0x01FFFFFF; - dest |= (uint32_t)0 - (dest & 0x01000000); - put_unaligned_le32(dest, buf + i + 1); - i += 4; - } else { - prev_mask = (prev_mask << 1) | 1; - } - } - - prev_pos = i - prev_pos; - s->x86_prev_mask = prev_pos > 3 ? 0 : prev_mask << (prev_pos - 1); - return i; -} -#endif - -#ifdef XZ_DEC_POWERPC -static noinline_for_stack size_t XZ_FUNC bcj_powerpc( - struct xz_dec_bcj *s, uint8_t *buf, size_t size) -{ - size_t i; - uint32_t instr; - - for (i = 0; i + 4 <= size; i += 4) { - instr = get_unaligned_be32(buf + i); - if ((instr & 0xFC000003) == 0x48000001) { - instr &= 0x03FFFFFC; - instr -= s->pos + (uint32_t)i; - instr &= 0x03FFFFFC; - instr |= 0x48000001; - put_unaligned_be32(instr, buf + i); - } - } - - return i; -} -#endif - -#ifdef XZ_DEC_IA64 -static noinline_for_stack size_t XZ_FUNC bcj_ia64( - struct xz_dec_bcj *s, uint8_t *buf, size_t size) -{ - static const uint8_t branch_table[32] = { - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 4, 4, 6, 6, 0, 0, 7, 7, - 4, 4, 0, 0, 4, 4, 0, 0 - }; - - /* - * The local variables take a little bit stack space, but it's less - * than what LZMA2 decoder takes, so it doesn't make sense to reduce - * stack usage here without doing that for the LZMA2 decoder too. - */ - - /* Loop counters */ - size_t i; - size_t j; - - /* Instruction slot (0, 1, or 2) in the 128-bit instruction word */ - uint32_t slot; - - /* Bitwise offset of the instruction indicated by slot */ - uint32_t bit_pos; - - /* bit_pos split into byte and bit parts */ - uint32_t byte_pos; - uint32_t bit_res; - - /* Address part of an instruction */ - uint32_t addr; - - /* Mask used to detect which instructions to convert */ - uint32_t mask; - - /* 41-bit instruction stored somewhere in the lowest 48 bits */ - uint64_t instr; - - /* Instruction normalized with bit_res for easier manipulation */ - uint64_t norm; - - for (i = 0; i + 16 <= size; i += 16) { - mask = branch_table[buf[i] & 0x1F]; - for (slot = 0, bit_pos = 5; slot < 3; ++slot, bit_pos += 41) { - if (((mask >> slot) & 1) == 0) - continue; - - byte_pos = bit_pos >> 3; - bit_res = bit_pos & 7; - instr = 0; - for (j = 0; j < 6; ++j) - instr |= (uint64_t)(buf[i + j + byte_pos]) - << (8 * j); - - norm = instr >> bit_res; - - if (((norm >> 37) & 0x0F) == 0x05 - && ((norm >> 9) & 0x07) == 0) { - addr = (norm >> 13) & 0x0FFFFF; - addr |= ((uint32_t)(norm >> 36) & 1) << 20; - addr <<= 4; - addr -= s->pos + (uint32_t)i; - addr >>= 4; - - norm &= ~((uint64_t)0x8FFFFF << 13); - norm |= (uint64_t)(addr & 0x0FFFFF) << 13; - norm |= (uint64_t)(addr & 0x100000) - << (36 - 20); - - instr &= (1 << bit_res) - 1; - instr |= norm << bit_res; - - for (j = 0; j < 6; j++) - buf[i + j + byte_pos] - = (uint8_t)(instr >> (8 * j)); - } - } - } - - return i; -} -#endif - -#ifdef XZ_DEC_ARM -static noinline_for_stack size_t XZ_FUNC bcj_arm( - struct xz_dec_bcj *s, uint8_t *buf, size_t size) -{ - size_t i; - uint32_t addr; - - for (i = 0; i + 4 <= size; i += 4) { - if (buf[i + 3] == 0xEB) { - addr = (uint32_t)buf[i] | ((uint32_t)buf[i + 1] << 8) - | ((uint32_t)buf[i + 2] << 16); - addr <<= 2; - addr -= s->pos + (uint32_t)i + 8; - addr >>= 2; - buf[i] = (uint8_t)addr; - buf[i + 1] = (uint8_t)(addr >> 8); - buf[i + 2] = (uint8_t)(addr >> 16); - } - } - - return i; -} -#endif - -#ifdef XZ_DEC_ARMTHUMB -static noinline_for_stack size_t XZ_FUNC bcj_armthumb( - struct xz_dec_bcj *s, uint8_t *buf, size_t size) -{ - size_t i; - uint32_t addr; - - for (i = 0; i + 4 <= size; i += 2) { - if ((buf[i + 1] & 0xF8) == 0xF0 - && (buf[i + 3] & 0xF8) == 0xF8) { - addr = (((uint32_t)buf[i + 1] & 0x07) << 19) - | ((uint32_t)buf[i] << 11) - | (((uint32_t)buf[i + 3] & 0x07) << 8) - | (uint32_t)buf[i + 2]; - addr <<= 1; - addr -= s->pos + (uint32_t)i + 4; - addr >>= 1; - buf[i + 1] = (uint8_t)(0xF0 | ((addr >> 19) & 0x07)); - buf[i] = (uint8_t)(addr >> 11); - buf[i + 3] = (uint8_t)(0xF8 | ((addr >> 8) & 0x07)); - buf[i + 2] = (uint8_t)addr; - i += 2; - } - } - - return i; -} -#endif - -#ifdef XZ_DEC_SPARC -static noinline_for_stack size_t XZ_FUNC bcj_sparc( - struct xz_dec_bcj *s, uint8_t *buf, size_t size) -{ - size_t i; - uint32_t instr; - - for (i = 0; i + 4 <= size; i += 4) { - instr = get_unaligned_be32(buf + i); - if ((instr >> 22) == 0x100 || (instr >> 22) == 0x1FF) { - instr <<= 2; - instr -= s->pos + (uint32_t)i; - instr >>= 2; - instr = ((uint32_t)0x40000000 - (instr & 0x400000)) - | 0x40000000 | (instr & 0x3FFFFF); - put_unaligned_be32(instr, buf + i); - } - } - - return i; -} -#endif - -/* - * Apply the selected BCJ filter. Update *pos and s->pos to match the amount - * of data that got filtered. - * - * NOTE: This is implemented as a switch statement to avoid using function - * pointers, which could be problematic in the kernel boot code, which must - * avoid pointers to static data (at least on x86). - */ -static void XZ_FUNC bcj_apply(struct xz_dec_bcj *s, - uint8_t *buf, size_t *pos, size_t size) -{ - size_t filtered; - - buf += *pos; - size -= *pos; - - switch (s->type) { -#ifdef XZ_DEC_X86 - case BCJ_X86: - filtered = bcj_x86(s, buf, size); - break; -#endif -#ifdef XZ_DEC_POWERPC - case BCJ_POWERPC: - filtered = bcj_powerpc(s, buf, size); - break; -#endif -#ifdef XZ_DEC_IA64 - case BCJ_IA64: - filtered = bcj_ia64(s, buf, size); - break; -#endif -#ifdef XZ_DEC_ARM - case BCJ_ARM: - filtered = bcj_arm(s, buf, size); - break; -#endif -#ifdef XZ_DEC_ARMTHUMB - case BCJ_ARMTHUMB: - filtered = bcj_armthumb(s, buf, size); - break; -#endif -#ifdef XZ_DEC_SPARC - case BCJ_SPARC: - filtered = bcj_sparc(s, buf, size); - break; -#endif - default: - /* Never reached but silence compiler warnings. */ - filtered = 0; - break; - } - - *pos += filtered; - s->pos += filtered; -} - -/* - * Flush pending filtered data from temp to the output buffer. - * Move the remaining mixture of possibly filtered and unfiltered - * data to the beginning of temp. - */ -static void XZ_FUNC bcj_flush(struct xz_dec_bcj *s, struct xz_buf *b) -{ - size_t copy_size; - - copy_size = min_t(size_t, s->temp.filtered, b->out_size - b->out_pos); - memcpy(b->out + b->out_pos, s->temp.buf, copy_size); - b->out_pos += copy_size; - - s->temp.filtered -= copy_size; - s->temp.size -= copy_size; - memmove(s->temp.buf, s->temp.buf + copy_size, s->temp.size); -} - -/* - * The BCJ filter functions are primitive in sense that they process the - * data in chunks of 1-16 bytes. To hide this issue, this function does - * some buffering. - */ -XZ_EXTERN enum xz_ret XZ_FUNC xz_dec_bcj_run(struct xz_dec_bcj *s, - struct xz_dec_lzma2 *lzma2, struct xz_buf *b) -{ - size_t out_start; - - /* - * Flush pending already filtered data to the output buffer. Return - * immediatelly if we couldn't flush everything, or if the next - * filter in the chain had already returned XZ_STREAM_END. - */ - if (s->temp.filtered > 0) { - bcj_flush(s, b); - if (s->temp.filtered > 0) - return XZ_OK; - - if (s->ret == XZ_STREAM_END) - return XZ_STREAM_END; - } - - /* - * If we have more output space than what is currently pending in - * temp, copy the unfiltered data from temp to the output buffer - * and try to fill the output buffer by decoding more data from the - * next filter in the chain. Apply the BCJ filter on the new data - * in the output buffer. If everything cannot be filtered, copy it - * to temp and rewind the output buffer position accordingly. - */ - if (s->temp.size < b->out_size - b->out_pos) { - out_start = b->out_pos; - memcpy(b->out + b->out_pos, s->temp.buf, s->temp.size); - b->out_pos += s->temp.size; - - s->ret = xz_dec_lzma2_run(lzma2, b); - if (s->ret != XZ_STREAM_END - && (s->ret != XZ_OK || s->single_call)) - return s->ret; - - bcj_apply(s, b->out, &out_start, b->out_pos); - - /* - * As an exception, if the next filter returned XZ_STREAM_END, - * we can do that too, since the last few bytes that remain - * unfiltered are meant to remain unfiltered. - */ - if (s->ret == XZ_STREAM_END) - return XZ_STREAM_END; - - s->temp.size = b->out_pos - out_start; - b->out_pos -= s->temp.size; - memcpy(s->temp.buf, b->out + b->out_pos, s->temp.size); - } - - /* - * If we have unfiltered data in temp, try to fill by decoding more - * data from the next filter. Apply the BCJ filter on temp. Then we - * hopefully can fill the actual output buffer by copying filtered - * data from temp. A mix of filtered and unfiltered data may be left - * in temp; it will be taken care on the next call to this function. - */ - if (s->temp.size > 0) { - /* Make b->out{,_pos,_size} temporarily point to s->temp. */ - s->out = b->out; - s->out_pos = b->out_pos; - s->out_size = b->out_size; - b->out = s->temp.buf; - b->out_pos = s->temp.size; - b->out_size = sizeof(s->temp.buf); - - s->ret = xz_dec_lzma2_run(lzma2, b); - - s->temp.size = b->out_pos; - b->out = s->out; - b->out_pos = s->out_pos; - b->out_size = s->out_size; - - if (s->ret != XZ_OK && s->ret != XZ_STREAM_END) - return s->ret; - - bcj_apply(s, s->temp.buf, &s->temp.filtered, s->temp.size); - - /* - * If the next filter returned XZ_STREAM_END, we mark that - * everything is filtered, since the last unfiltered bytes - * of the stream are meant to be left as is. - */ - if (s->ret == XZ_STREAM_END) - s->temp.filtered = s->temp.size; - - bcj_flush(s, b); - if (s->temp.filtered > 0) - return XZ_OK; - } - - return s->ret; -} - -XZ_EXTERN struct xz_dec_bcj * XZ_FUNC xz_dec_bcj_create(bool single_call) -{ - struct xz_dec_bcj *s = kmalloc(sizeof(*s), GFP_KERNEL); - if (s != NULL) - s->single_call = single_call; - - return s; -} - -XZ_EXTERN enum xz_ret XZ_FUNC xz_dec_bcj_reset( - struct xz_dec_bcj *s, uint8_t id) -{ - switch (id) { -#ifdef XZ_DEC_X86 - case BCJ_X86: -#endif -#ifdef XZ_DEC_POWERPC - case BCJ_POWERPC: -#endif -#ifdef XZ_DEC_IA64 - case BCJ_IA64: -#endif -#ifdef XZ_DEC_ARM - case BCJ_ARM: -#endif -#ifdef XZ_DEC_ARMTHUMB - case BCJ_ARMTHUMB: -#endif -#ifdef XZ_DEC_SPARC - case BCJ_SPARC: -#endif - break; - - default: - /* Unsupported Filter ID */ - return XZ_OPTIONS_ERROR; - } - - s->type = id; - s->ret = XZ_OK; - s->pos = 0; - s->x86_prev_mask = 0; - s->temp.filtered = 0; - s->temp.size = 0; - - return XZ_OK; -} - -#endif diff --git a/archival/libunarchive/unxz/xz_dec_lzma2.c b/archival/libunarchive/unxz/xz_dec_lzma2.c deleted file mode 100644 index da71cb4d4..000000000 --- a/archival/libunarchive/unxz/xz_dec_lzma2.c +++ /dev/null @@ -1,1175 +0,0 @@ -/* - * LZMA2 decoder - * - * Authors: Lasse Collin - * Igor Pavlov - * - * This file has been put into the public domain. - * You can do whatever you want with this file. - */ - -#include "xz_private.h" -#include "xz_lzma2.h" - -/* - * Range decoder initialization eats the first five bytes of each LZMA chunk. - */ -#define RC_INIT_BYTES 5 - -/* - * Minimum number of usable input buffer to safely decode one LZMA symbol. - * The worst case is that we decode 22 bits using probabilities and 26 - * direct bits. This may decode at maximum of 20 bytes of input. However, - * lzma_main() does an extra normalization before returning, thus we - * need to put 21 here. - */ -#define LZMA_IN_REQUIRED 21 - -/* - * Dictionary (history buffer) - * - * These are always true: - * start <= pos <= full <= end - * pos <= limit <= end - * - * In multi-call mode, also these are true: - * end == size - * size <= size_max - * allocated <= size - * - * Most of these variables are size_t to support single-call mode, - * in which the dictionary variables address the actual output - * buffer directly. - */ -struct dictionary { - /* Beginning of the history buffer */ - uint8_t *buf; - - /* Old position in buf (before decoding more data) */ - size_t start; - - /* Position in buf */ - size_t pos; - - /* - * How full dictionary is. This is used to detect corrupt input that - * would read beyond the beginning of the uncompressed stream. - */ - size_t full; - - /* Write limit; we don't write to buf[limit] or later bytes. */ - size_t limit; - - /* - * End of the dictionary buffer. In multi-call mode, this is - * the same as the dictionary size. In single-call mode, this - * indicates the size of the output buffer. - */ - size_t end; - - /* - * Size of the dictionary as specified in Block Header. This is used - * together with "full" to detect corrupt input that would make us - * read beyond the beginning of the uncompressed stream. - */ - uint32_t size; - - /* - * Maximum allowed dictionary size in multi-call mode. - * This is ignored in single-call mode. - */ - uint32_t size_max; - - /* - * Amount of memory currently allocated for the dictionary. - * This is used only with XZ_DYNALLOC. (With XZ_PREALLOC, - * size_max is always the same as the allocated size.) - */ - uint32_t allocated; - - /* Operation mode */ - enum xz_mode mode; -}; - -/* Range decoder */ -struct rc_dec { - uint32_t range; - uint32_t code; - - /* - * Number of initializing bytes remaining to be read - * by rc_read_init(). - */ - uint32_t init_bytes_left; - - /* - * Buffer from which we read our input. It can be either - * temp.buf or the caller-provided input buffer. - */ - const uint8_t *in; - size_t in_pos; - size_t in_limit; -}; - -/* Probabilities for a length decoder. */ -struct lzma_len_dec { - /* Probability of match length being at least 10 */ - uint16_t choice; - - /* Probability of match length being at least 18 */ - uint16_t choice2; - - /* Probabilities for match lengths 2-9 */ - uint16_t low[POS_STATES_MAX][LEN_LOW_SYMBOLS]; - - /* Probabilities for match lengths 10-17 */ - uint16_t mid[POS_STATES_MAX][LEN_MID_SYMBOLS]; - - /* Probabilities for match lengths 18-273 */ - uint16_t high[LEN_HIGH_SYMBOLS]; -}; - -struct lzma_dec { - /* Distances of latest four matches */ - uint32_t rep0; - uint32_t rep1; - uint32_t rep2; - uint32_t rep3; - - /* Types of the most recently seen LZMA symbols */ - enum lzma_state state; - - /* - * Length of a match. This is updated so that dict_repeat can - * be called again to finish repeating the whole match. - */ - uint32_t len; - - /* - * LZMA properties or related bit masks (number of literal - * context bits, a mask dervied from the number of literal - * position bits, and a mask dervied from the number - * position bits) - */ - uint32_t lc; - uint32_t literal_pos_mask; /* (1 << lp) - 1 */ - uint32_t pos_mask; /* (1 << pb) - 1 */ - - /* If 1, it's a match. Otherwise it's a single 8-bit literal. */ - uint16_t is_match[STATES][POS_STATES_MAX]; - - /* If 1, it's a repeated match. The distance is one of rep0 .. rep3. */ - uint16_t is_rep[STATES]; - - /* - * If 0, distance of a repeated match is rep0. - * Otherwise check is_rep1. - */ - uint16_t is_rep0[STATES]; - - /* - * If 0, distance of a repeated match is rep1. - * Otherwise check is_rep2. - */ - uint16_t is_rep1[STATES]; - - /* If 0, distance of a repeated match is rep2. Otherwise it is rep3. */ - uint16_t is_rep2[STATES]; - - /* - * If 1, the repeated match has length of one byte. Otherwise - * the length is decoded from rep_len_decoder. - */ - uint16_t is_rep0_long[STATES][POS_STATES_MAX]; - - /* - * Probability tree for the highest two bits of the match - * distance. There is a separate probability tree for match - * lengths of 2 (i.e. MATCH_LEN_MIN), 3, 4, and [5, 273]. - */ - uint16_t dist_slot[DIST_STATES][DIST_SLOTS]; - - /* - * Probility trees for additional bits for match distance - * when the distance is in the range [4, 127]. - */ - uint16_t dist_special[FULL_DISTANCES - DIST_MODEL_END]; - - /* - * Probability tree for the lowest four bits of a match - * distance that is equal to or greater than 128. - */ - uint16_t dist_align[ALIGN_SIZE]; - - /* Length of a normal match */ - struct lzma_len_dec match_len_dec; - - /* Length of a repeated match */ - struct lzma_len_dec rep_len_dec; - - /* Probabilities of literals */ - uint16_t literal[LITERAL_CODERS_MAX][LITERAL_CODER_SIZE]; -}; - -struct lzma2_dec { - /* Position in xz_dec_lzma2_run(). */ - enum lzma2_seq { - SEQ_CONTROL, - SEQ_UNCOMPRESSED_1, - SEQ_UNCOMPRESSED_2, - SEQ_COMPRESSED_0, - SEQ_COMPRESSED_1, - SEQ_PROPERTIES, - SEQ_LZMA_PREPARE, - SEQ_LZMA_RUN, - SEQ_COPY - } sequence; - - /* Next position after decoding the compressed size of the chunk. */ - enum lzma2_seq next_sequence; - - /* Uncompressed size of LZMA chunk (2 MiB at maximum) */ - uint32_t uncompressed; - - /* - * Compressed size of LZMA chunk or compressed/uncompressed - * size of uncompressed chunk (64 KiB at maximum) - */ - uint32_t compressed; - - /* - * True if dictionary reset is needed. This is false before - * the first chunk (LZMA or uncompressed). - */ - bool need_dict_reset; - - /* - * True if new LZMA properties are needed. This is false - * before the first LZMA chunk. - */ - bool need_props; -}; - -struct xz_dec_lzma2 { - /* - * The order below is important on x86 to reduce code size and - * it shouldn't hurt on other platforms. Everything up to and - * including lzma.pos_mask are in the first 128 bytes on x86-32, - * which allows using smaller instructions to access those - * variables. On x86-64, fewer variables fit into the first 128 - * bytes, but this is still the best order without sacrificing - * the readability by splitting the structures. - */ - struct rc_dec rc; - struct dictionary dict; - struct lzma2_dec lzma2; - struct lzma_dec lzma; - - /* - * Temporary buffer which holds small number of input bytes between - * decoder calls. See lzma2_lzma() for details. - */ - struct { - uint32_t size; - uint8_t buf[3 * LZMA_IN_REQUIRED]; - } temp; -}; - -/************** - * Dictionary * - **************/ - -/* - * Reset the dictionary state. When in single-call mode, set up the beginning - * of the dictionary to point to the actual output buffer. - */ -static void XZ_FUNC dict_reset(struct dictionary *dict, struct xz_buf *b) -{ - if (DEC_IS_SINGLE(dict->mode)) { - dict->buf = b->out + b->out_pos; - dict->end = b->out_size - b->out_pos; - } - - dict->start = 0; - dict->pos = 0; - dict->limit = 0; - dict->full = 0; -} - -/* Set dictionary write limit */ -static void XZ_FUNC dict_limit(struct dictionary *dict, size_t out_max) -{ - if (dict->end - dict->pos <= out_max) - dict->limit = dict->end; - else - dict->limit = dict->pos + out_max; -} - -/* Return true if at least one byte can be written into the dictionary. */ -static __always_inline bool XZ_FUNC dict_has_space(const struct dictionary *dict) -{ - return dict->pos < dict->limit; -} - -/* - * Get a byte from the dictionary at the given distance. The distance is - * assumed to valid, or as a special case, zero when the dictionary is - * still empty. This special case is needed for single-call decoding to - * avoid writing a '\0' to the end of the destination buffer. - */ -static __always_inline uint32_t XZ_FUNC dict_get( - const struct dictionary *dict, uint32_t dist) -{ - size_t offset = dict->pos - dist - 1; - - if (dist >= dict->pos) - offset += dict->end; - - return dict->full > 0 ? dict->buf[offset] : 0; -} - -/* - * Put one byte into the dictionary. It is assumed that there is space for it. - */ -static inline void XZ_FUNC dict_put(struct dictionary *dict, uint8_t byte) -{ - dict->buf[dict->pos++] = byte; - - if (dict->full < dict->pos) - dict->full = dict->pos; -} - -/* - * Repeat given number of bytes from the given distance. If the distance is - * invalid, false is returned. On success, true is returned and *len is - * updated to indicate how many bytes were left to be repeated. - */ -static bool XZ_FUNC dict_repeat( - struct dictionary *dict, uint32_t *len, uint32_t dist) -{ - size_t back; - uint32_t left; - - if (dist >= dict->full || dist >= dict->size) - return false; - - left = min_t(size_t, dict->limit - dict->pos, *len); - *len -= left; - - back = dict->pos - dist - 1; - if (dist >= dict->pos) - back += dict->end; - - do { - dict->buf[dict->pos++] = dict->buf[back++]; - if (back == dict->end) - back = 0; - } while (--left > 0); - - if (dict->full < dict->pos) - dict->full = dict->pos; - - return true; -} - -/* Copy uncompressed data as is from input to dictionary and output buffers. */ -static void XZ_FUNC dict_uncompressed( - struct dictionary *dict, struct xz_buf *b, uint32_t *left) -{ - size_t copy_size; - - while (*left > 0 && b->in_pos < b->in_size - && b->out_pos < b->out_size) { - copy_size = min(b->in_size - b->in_pos, - b->out_size - b->out_pos); - if (copy_size > dict->end - dict->pos) - copy_size = dict->end - dict->pos; - if (copy_size > *left) - copy_size = *left; - - *left -= copy_size; - - memcpy(dict->buf + dict->pos, b->in + b->in_pos, copy_size); - dict->pos += copy_size; - - if (dict->full < dict->pos) - dict->full = dict->pos; - - if (DEC_IS_MULTI(dict->mode)) { - if (dict->pos == dict->end) - dict->pos = 0; - - memcpy(b->out + b->out_pos, b->in + b->in_pos, - copy_size); - } - - dict->start = dict->pos; - - b->out_pos += copy_size; - b->in_pos += copy_size; - - } -} - -/* - * Flush pending data from dictionary to b->out. It is assumed that there is - * enough space in b->out. This is guaranteed because caller uses dict_limit() - * before decoding data into the dictionary. - */ -static uint32_t XZ_FUNC dict_flush(struct dictionary *dict, struct xz_buf *b) -{ - size_t copy_size = dict->pos - dict->start; - - if (DEC_IS_MULTI(dict->mode)) { - if (dict->pos == dict->end) - dict->pos = 0; - - memcpy(b->out + b->out_pos, dict->buf + dict->start, - copy_size); - } - - dict->start = dict->pos; - b->out_pos += copy_size; - return copy_size; -} - -/***************** - * Range decoder * - *****************/ - -/* Reset the range decoder. */ -static void XZ_FUNC rc_reset(struct rc_dec *rc) -{ - rc->range = (uint32_t)-1; - rc->code = 0; - rc->init_bytes_left = RC_INIT_BYTES; -} - -/* - * Read the first five initial bytes into rc->code if they haven't been - * read already. (Yes, the first byte gets completely ignored.) - */ -static bool XZ_FUNC rc_read_init(struct rc_dec *rc, struct xz_buf *b) -{ - while (rc->init_bytes_left > 0) { - if (b->in_pos == b->in_size) - return false; - - rc->code = (rc->code << 8) + b->in[b->in_pos++]; - --rc->init_bytes_left; - } - - return true; -} - -/* Return true if there may not be enough input for the next decoding loop. */ -static inline bool XZ_FUNC rc_limit_exceeded(const struct rc_dec *rc) -{ - return rc->in_pos > rc->in_limit; -} - -/* - * Return true if it is possible (from point of view of range decoder) that - * we have reached the end of the LZMA chunk. - */ -static inline bool XZ_FUNC rc_is_finished(const struct rc_dec *rc) -{ - return rc->code == 0; -} - -/* Read the next input byte if needed. */ -static __always_inline void XZ_FUNC rc_normalize(struct rc_dec *rc) -{ - if (rc->range < RC_TOP_VALUE) { - rc->range <<= RC_SHIFT_BITS; - rc->code = (rc->code << RC_SHIFT_BITS) + rc->in[rc->in_pos++]; - } -} - -/* - * Decode one bit. In some versions, this function has been splitted in three - * functions so that the compiler is supposed to be able to more easily avoid - * an extra branch. In this particular version of the LZMA decoder, this - * doesn't seem to be a good idea (tested with GCC 3.3.6, 3.4.6, and 4.3.3 - * on x86). Using a non-splitted version results in nicer looking code too. - * - * NOTE: This must return an int. Do not make it return a bool or the speed - * of the code generated by GCC 3.x decreases 10-15 %. (GCC 4.3 doesn't care, - * and it generates 10-20 % faster code than GCC 3.x from this file anyway.) - */ -static __always_inline int XZ_FUNC rc_bit(struct rc_dec *rc, uint16_t *prob) -{ - uint32_t bound; - int bit; - - rc_normalize(rc); - bound = (rc->range >> RC_BIT_MODEL_TOTAL_BITS) * *prob; - if (rc->code < bound) { - rc->range = bound; - *prob += (RC_BIT_MODEL_TOTAL - *prob) >> RC_MOVE_BITS; - bit = 0; - } else { - rc->range -= bound; - rc->code -= bound; - *prob -= *prob >> RC_MOVE_BITS; - bit = 1; - } - - return bit; -} - -/* Decode a bittree starting from the most significant bit. */ -static __always_inline uint32_t XZ_FUNC rc_bittree( - struct rc_dec *rc, uint16_t *probs, uint32_t limit) -{ - uint32_t symbol = 1; - - do { - if (rc_bit(rc, &probs[symbol])) - symbol = (symbol << 1) + 1; - else - symbol <<= 1; - } while (symbol < limit); - - return symbol; -} - -/* Decode a bittree starting from the least significant bit. */ -static __always_inline void XZ_FUNC rc_bittree_reverse(struct rc_dec *rc, - uint16_t *probs, uint32_t *dest, uint32_t limit) -{ - uint32_t symbol = 1; - uint32_t i = 0; - - do { - if (rc_bit(rc, &probs[symbol])) { - symbol = (symbol << 1) + 1; - *dest += 1 << i; - } else { - symbol <<= 1; - } - } while (++i < limit); -} - -/* Decode direct bits (fixed fifty-fifty probability) */ -static inline void XZ_FUNC rc_direct( - struct rc_dec *rc, uint32_t *dest, uint32_t limit) -{ - uint32_t mask; - - do { - rc_normalize(rc); - rc->range >>= 1; - rc->code -= rc->range; - mask = (uint32_t)0 - (rc->code >> 31); - rc->code += rc->range & mask; - *dest = (*dest << 1) + (mask + 1); - } while (--limit > 0); -} - -/******** - * LZMA * - ********/ - -/* Get pointer to literal coder probability array. */ -static uint16_t * XZ_FUNC lzma_literal_probs(struct xz_dec_lzma2 *s) -{ - uint32_t prev_byte = dict_get(&s->dict, 0); - uint32_t low = prev_byte >> (8 - s->lzma.lc); - uint32_t high = (s->dict.pos & s->lzma.literal_pos_mask) << s->lzma.lc; - return s->lzma.literal[low + high]; -} - -/* Decode a literal (one 8-bit byte) */ -static void XZ_FUNC lzma_literal(struct xz_dec_lzma2 *s) -{ - uint16_t *probs; - uint32_t symbol; - uint32_t match_byte; - uint32_t match_bit; - uint32_t offset; - uint32_t i; - - probs = lzma_literal_probs(s); - - if (lzma_state_is_literal(s->lzma.state)) { - symbol = rc_bittree(&s->rc, probs, 0x100); - } else { - symbol = 1; - match_byte = dict_get(&s->dict, s->lzma.rep0) << 1; - offset = 0x100; - - do { - match_bit = match_byte & offset; - match_byte <<= 1; - i = offset + match_bit + symbol; - - if (rc_bit(&s->rc, &probs[i])) { - symbol = (symbol << 1) + 1; - offset &= match_bit; - } else { - symbol <<= 1; - offset &= ~match_bit; - } - } while (symbol < 0x100); - } - - dict_put(&s->dict, (uint8_t)symbol); - lzma_state_literal(&s->lzma.state); -} - -/* Decode the length of the match into s->lzma.len. */ -static void XZ_FUNC lzma_len(struct xz_dec_lzma2 *s, struct lzma_len_dec *l, - uint32_t pos_state) -{ - uint16_t *probs; - uint32_t limit; - - if (!rc_bit(&s->rc, &l->choice)) { - probs = l->low[pos_state]; - limit = LEN_LOW_SYMBOLS; - s->lzma.len = MATCH_LEN_MIN; - } else { - if (!rc_bit(&s->rc, &l->choice2)) { - probs = l->mid[pos_state]; - limit = LEN_MID_SYMBOLS; - s->lzma.len = MATCH_LEN_MIN + LEN_LOW_SYMBOLS; - } else { - probs = l->high; - limit = LEN_HIGH_SYMBOLS; - s->lzma.len = MATCH_LEN_MIN + LEN_LOW_SYMBOLS - + LEN_MID_SYMBOLS; - } - } - - s->lzma.len += rc_bittree(&s->rc, probs, limit) - limit; -} - -/* Decode a match. The distance will be stored in s->lzma.rep0. */ -static void XZ_FUNC lzma_match(struct xz_dec_lzma2 *s, uint32_t pos_state) -{ - uint16_t *probs; - uint32_t dist_slot; - uint32_t limit; - - lzma_state_match(&s->lzma.state); - - s->lzma.rep3 = s->lzma.rep2; - s->lzma.rep2 = s->lzma.rep1; - s->lzma.rep1 = s->lzma.rep0; - - lzma_len(s, &s->lzma.match_len_dec, pos_state); - - probs = s->lzma.dist_slot[lzma_get_dist_state(s->lzma.len)]; - dist_slot = rc_bittree(&s->rc, probs, DIST_SLOTS) - DIST_SLOTS; - - if (dist_slot < DIST_MODEL_START) { - s->lzma.rep0 = dist_slot; - } else { - limit = (dist_slot >> 1) - 1; - s->lzma.rep0 = 2 + (dist_slot & 1); - - if (dist_slot < DIST_MODEL_END) { - s->lzma.rep0 <<= limit; - probs = s->lzma.dist_special + s->lzma.rep0 - - dist_slot - 1; - rc_bittree_reverse(&s->rc, probs, - &s->lzma.rep0, limit); - } else { - rc_direct(&s->rc, &s->lzma.rep0, limit - ALIGN_BITS); - s->lzma.rep0 <<= ALIGN_BITS; - rc_bittree_reverse(&s->rc, s->lzma.dist_align, - &s->lzma.rep0, ALIGN_BITS); - } - } -} - -/* - * Decode a repeated match. The distance is one of the four most recently - * seen matches. The distance will be stored in s->lzma.rep0. - */ -static void XZ_FUNC lzma_rep_match(struct xz_dec_lzma2 *s, uint32_t pos_state) -{ - uint32_t tmp; - - if (!rc_bit(&s->rc, &s->lzma.is_rep0[s->lzma.state])) { - if (!rc_bit(&s->rc, &s->lzma.is_rep0_long[ - s->lzma.state][pos_state])) { - lzma_state_short_rep(&s->lzma.state); - s->lzma.len = 1; - return; - } - } else { - if (!rc_bit(&s->rc, &s->lzma.is_rep1[s->lzma.state])) { - tmp = s->lzma.rep1; - } else { - if (!rc_bit(&s->rc, &s->lzma.is_rep2[s->lzma.state])) { - tmp = s->lzma.rep2; - } else { - tmp = s->lzma.rep3; - s->lzma.rep3 = s->lzma.rep2; - } - - s->lzma.rep2 = s->lzma.rep1; - } - - s->lzma.rep1 = s->lzma.rep0; - s->lzma.rep0 = tmp; - } - - lzma_state_long_rep(&s->lzma.state); - lzma_len(s, &s->lzma.rep_len_dec, pos_state); -} - -/* LZMA decoder core */ -static bool XZ_FUNC lzma_main(struct xz_dec_lzma2 *s) -{ - uint32_t pos_state; - - /* - * If the dictionary was reached during the previous call, try to - * finish the possibly pending repeat in the dictionary. - */ - if (dict_has_space(&s->dict) && s->lzma.len > 0) - dict_repeat(&s->dict, &s->lzma.len, s->lzma.rep0); - - /* - * Decode more LZMA symbols. One iteration may consume up to - * LZMA_IN_REQUIRED - 1 bytes. - */ - while (dict_has_space(&s->dict) && !rc_limit_exceeded(&s->rc)) { - pos_state = s->dict.pos & s->lzma.pos_mask; - - if (!rc_bit(&s->rc, &s->lzma.is_match[ - s->lzma.state][pos_state])) { - lzma_literal(s); - } else { - if (rc_bit(&s->rc, &s->lzma.is_rep[s->lzma.state])) - lzma_rep_match(s, pos_state); - else - lzma_match(s, pos_state); - - if (!dict_repeat(&s->dict, &s->lzma.len, s->lzma.rep0)) - return false; - } - } - - /* - * Having the range decoder always normalized when we are outside - * this function makes it easier to correctly handle end of the chunk. - */ - rc_normalize(&s->rc); - - return true; -} - -/* - * Reset the LZMA decoder and range decoder state. Dictionary is nore reset - * here, because LZMA state may be reset without resetting the dictionary. - */ -static void XZ_FUNC lzma_reset(struct xz_dec_lzma2 *s) -{ - uint16_t *probs; - size_t i; - - s->lzma.state = STATE_LIT_LIT; - s->lzma.rep0 = 0; - s->lzma.rep1 = 0; - s->lzma.rep2 = 0; - s->lzma.rep3 = 0; - - /* - * All probabilities are initialized to the same value. This hack - * makes the code smaller by avoiding a separate loop for each - * probability array. - * - * This could be optimized so that only that part of literal - * probabilities that are actually required. In the common case - * we would write 12 KiB less. - */ - probs = s->lzma.is_match[0]; - for (i = 0; i < PROBS_TOTAL; ++i) - probs[i] = RC_BIT_MODEL_TOTAL / 2; - - rc_reset(&s->rc); -} - -/* - * Decode and validate LZMA properties (lc/lp/pb) and calculate the bit masks - * from the decoded lp and pb values. On success, the LZMA decoder state is - * reset and true is returned. - */ -static bool XZ_FUNC lzma_props(struct xz_dec_lzma2 *s, uint8_t props) -{ - if (props > (4 * 5 + 4) * 9 + 8) - return false; - - s->lzma.pos_mask = 0; - while (props >= 9 * 5) { - props -= 9 * 5; - ++s->lzma.pos_mask; - } - - s->lzma.pos_mask = (1 << s->lzma.pos_mask) - 1; - - s->lzma.literal_pos_mask = 0; - while (props >= 9) { - props -= 9; - ++s->lzma.literal_pos_mask; - } - - s->lzma.lc = props; - - if (s->lzma.lc + s->lzma.literal_pos_mask > 4) - return false; - - s->lzma.literal_pos_mask = (1 << s->lzma.literal_pos_mask) - 1; - - lzma_reset(s); - - return true; -} - -/********* - * LZMA2 * - *********/ - -/* - * The LZMA decoder assumes that if the input limit (s->rc.in_limit) hasn't - * been exceeded, it is safe to read up to LZMA_IN_REQUIRED bytes. This - * wrapper function takes care of making the LZMA decoder's assumption safe. - * - * As long as there is plenty of input left to be decoded in the current LZMA - * chunk, we decode directly from the caller-supplied input buffer until - * there's LZMA_IN_REQUIRED bytes left. Those remaining bytes are copied into - * s->temp.buf, which (hopefully) gets filled on the next call to this - * function. We decode a few bytes from the temporary buffer so that we can - * continue decoding from the caller-supplied input buffer again. - */ -static bool XZ_FUNC lzma2_lzma(struct xz_dec_lzma2 *s, struct xz_buf *b) -{ - size_t in_avail; - uint32_t tmp; - - in_avail = b->in_size - b->in_pos; - if (s->temp.size > 0 || s->lzma2.compressed == 0) { - tmp = 2 * LZMA_IN_REQUIRED - s->temp.size; - if (tmp > s->lzma2.compressed - s->temp.size) - tmp = s->lzma2.compressed - s->temp.size; - if (tmp > in_avail) - tmp = in_avail; - - memcpy(s->temp.buf + s->temp.size, b->in + b->in_pos, tmp); - - if (s->temp.size + tmp == s->lzma2.compressed) { - memzero(s->temp.buf + s->temp.size + tmp, - sizeof(s->temp.buf) - - s->temp.size - tmp); - s->rc.in_limit = s->temp.size + tmp; - } else if (s->temp.size + tmp < LZMA_IN_REQUIRED) { - s->temp.size += tmp; - b->in_pos += tmp; - return true; - } else { - s->rc.in_limit = s->temp.size + tmp - LZMA_IN_REQUIRED; - } - - s->rc.in = s->temp.buf; - s->rc.in_pos = 0; - - if (!lzma_main(s) || s->rc.in_pos > s->temp.size + tmp) - return false; - - s->lzma2.compressed -= s->rc.in_pos; - - if (s->rc.in_pos < s->temp.size) { - s->temp.size -= s->rc.in_pos; - memmove(s->temp.buf, s->temp.buf + s->rc.in_pos, - s->temp.size); - return true; - } - - b->in_pos += s->rc.in_pos - s->temp.size; - s->temp.size = 0; - } - - in_avail = b->in_size - b->in_pos; - if (in_avail >= LZMA_IN_REQUIRED) { - s->rc.in = b->in; - s->rc.in_pos = b->in_pos; - - if (in_avail >= s->lzma2.compressed + LZMA_IN_REQUIRED) - s->rc.in_limit = b->in_pos + s->lzma2.compressed; - else - s->rc.in_limit = b->in_size - LZMA_IN_REQUIRED; - - if (!lzma_main(s)) - return false; - - in_avail = s->rc.in_pos - b->in_pos; - if (in_avail > s->lzma2.compressed) - return false; - - s->lzma2.compressed -= in_avail; - b->in_pos = s->rc.in_pos; - } - - in_avail = b->in_size - b->in_pos; - if (in_avail < LZMA_IN_REQUIRED) { - if (in_avail > s->lzma2.compressed) - in_avail = s->lzma2.compressed; - - memcpy(s->temp.buf, b->in + b->in_pos, in_avail); - s->temp.size = in_avail; - b->in_pos += in_avail; - } - - return true; -} - -/* - * Take care of the LZMA2 control layer, and forward the job of actual LZMA - * decoding or copying of uncompressed chunks to other functions. - */ -XZ_EXTERN NOINLINE enum xz_ret XZ_FUNC xz_dec_lzma2_run( - struct xz_dec_lzma2 *s, struct xz_buf *b) -{ - uint32_t tmp; - - while (b->in_pos < b->in_size || s->lzma2.sequence == SEQ_LZMA_RUN) { - switch (s->lzma2.sequence) { - case SEQ_CONTROL: - /* - * LZMA2 control byte - * - * Exact values: - * 0x00 End marker - * 0x01 Dictionary reset followed by - * an uncompressed chunk - * 0x02 Uncompressed chunk (no dictionary reset) - * - * Highest three bits (s->control & 0xE0): - * 0xE0 Dictionary reset, new properties and state - * reset, followed by LZMA compressed chunk - * 0xC0 New properties and state reset, followed - * by LZMA compressed chunk (no dictionary - * reset) - * 0xA0 State reset using old properties, - * followed by LZMA compressed chunk (no - * dictionary reset) - * 0x80 LZMA chunk (no dictionary or state reset) - * - * For LZMA compressed chunks, the lowest five bits - * (s->control & 1F) are the highest bits of the - * uncompressed size (bits 16-20). - * - * A new LZMA2 stream must begin with a dictionary - * reset. The first LZMA chunk must set new - * properties and reset the LZMA state. - * - * Values that don't match anything described above - * are invalid and we return XZ_DATA_ERROR. - */ - tmp = b->in[b->in_pos++]; - - if (tmp >= 0xE0 || tmp == 0x01) { - s->lzma2.need_props = true; - s->lzma2.need_dict_reset = false; - dict_reset(&s->dict, b); - } else if (s->lzma2.need_dict_reset) { - return XZ_DATA_ERROR; - } - - if (tmp >= 0x80) { - s->lzma2.uncompressed = (tmp & 0x1F) << 16; - s->lzma2.sequence = SEQ_UNCOMPRESSED_1; - - if (tmp >= 0xC0) { - /* - * When there are new properties, - * state reset is done at - * SEQ_PROPERTIES. - */ - s->lzma2.need_props = false; - s->lzma2.next_sequence - = SEQ_PROPERTIES; - - } else if (s->lzma2.need_props) { - return XZ_DATA_ERROR; - - } else { - s->lzma2.next_sequence - = SEQ_LZMA_PREPARE; - if (tmp >= 0xA0) - lzma_reset(s); - } - } else { - if (tmp == 0x00) - return XZ_STREAM_END; - - if (tmp > 0x02) - return XZ_DATA_ERROR; - - s->lzma2.sequence = SEQ_COMPRESSED_0; - s->lzma2.next_sequence = SEQ_COPY; - } - - break; - - case SEQ_UNCOMPRESSED_1: - s->lzma2.uncompressed - += (uint32_t)b->in[b->in_pos++] << 8; - s->lzma2.sequence = SEQ_UNCOMPRESSED_2; - break; - - case SEQ_UNCOMPRESSED_2: - s->lzma2.uncompressed - += (uint32_t)b->in[b->in_pos++] + 1; - s->lzma2.sequence = SEQ_COMPRESSED_0; - break; - - case SEQ_COMPRESSED_0: - s->lzma2.compressed - = (uint32_t)b->in[b->in_pos++] << 8; - s->lzma2.sequence = SEQ_COMPRESSED_1; - break; - - case SEQ_COMPRESSED_1: - s->lzma2.compressed - += (uint32_t)b->in[b->in_pos++] + 1; - s->lzma2.sequence = s->lzma2.next_sequence; - break; - - case SEQ_PROPERTIES: - if (!lzma_props(s, b->in[b->in_pos++])) - return XZ_DATA_ERROR; - - s->lzma2.sequence = SEQ_LZMA_PREPARE; - - case SEQ_LZMA_PREPARE: - if (s->lzma2.compressed < RC_INIT_BYTES) - return XZ_DATA_ERROR; - - if (!rc_read_init(&s->rc, b)) - return XZ_OK; - - s->lzma2.compressed -= RC_INIT_BYTES; - s->lzma2.sequence = SEQ_LZMA_RUN; - - case SEQ_LZMA_RUN: - /* - * Set dictionary limit to indicate how much we want - * to be encoded at maximum. Decode new data into the - * dictionary. Flush the new data from dictionary to - * b->out. Check if we finished decoding this chunk. - * In case the dictionary got full but we didn't fill - * the output buffer yet, we may run this loop - * multiple times without changing s->lzma2.sequence. - */ - dict_limit(&s->dict, min_t(size_t, - b->out_size - b->out_pos, - s->lzma2.uncompressed)); - if (!lzma2_lzma(s, b)) - return XZ_DATA_ERROR; - - s->lzma2.uncompressed -= dict_flush(&s->dict, b); - - if (s->lzma2.uncompressed == 0) { - if (s->lzma2.compressed > 0 || s->lzma.len > 0 - || !rc_is_finished(&s->rc)) - return XZ_DATA_ERROR; - - rc_reset(&s->rc); - s->lzma2.sequence = SEQ_CONTROL; - - } else if (b->out_pos == b->out_size - || (b->in_pos == b->in_size - && s->temp.size - < s->lzma2.compressed)) { - return XZ_OK; - } - - break; - - case SEQ_COPY: - dict_uncompressed(&s->dict, b, &s->lzma2.compressed); - if (s->lzma2.compressed > 0) - return XZ_OK; - - s->lzma2.sequence = SEQ_CONTROL; - break; - } - } - - return XZ_OK; -} - -XZ_EXTERN struct xz_dec_lzma2 * XZ_FUNC xz_dec_lzma2_create( - enum xz_mode mode, uint32_t dict_max) -{ - struct xz_dec_lzma2 *s = kmalloc(sizeof(*s), GFP_KERNEL); - if (s == NULL) - return NULL; - - s->dict.mode = mode; - s->dict.size_max = dict_max; - - if (DEC_IS_PREALLOC(mode)) { - s->dict.buf = vmalloc(dict_max); - if (s->dict.buf == NULL) { - kfree(s); - return NULL; - } - } else if (DEC_IS_DYNALLOC(mode)) { - s->dict.buf = NULL; - s->dict.allocated = 0; - } - - return s; -} - -XZ_EXTERN enum xz_ret XZ_FUNC xz_dec_lzma2_reset( - struct xz_dec_lzma2 *s, uint8_t props) -{ - /* This limits dictionary size to 3 GiB to keep parsing simpler. */ - if (props > 39) - return XZ_OPTIONS_ERROR; - - s->dict.size = 2 + (props & 1); - s->dict.size <<= (props >> 1) + 11; - - if (DEC_IS_MULTI(s->dict.mode)) { - if (s->dict.size > s->dict.size_max) - return XZ_MEMLIMIT_ERROR; - - s->dict.end = s->dict.size; - - if (DEC_IS_DYNALLOC(s->dict.mode)) { - if (s->dict.allocated < s->dict.size) { - vfree(s->dict.buf); - s->dict.buf = vmalloc(s->dict.size); - if (s->dict.buf == NULL) { - s->dict.allocated = 0; - return XZ_MEM_ERROR; - } - } - } - } - - s->lzma.len = 0; - - s->lzma2.sequence = SEQ_CONTROL; - s->lzma2.need_dict_reset = true; - - s->temp.size = 0; - - return XZ_OK; -} - -XZ_EXTERN void XZ_FUNC xz_dec_lzma2_end(struct xz_dec_lzma2 *s) -{ - if (DEC_IS_MULTI(s->dict.mode)) - vfree(s->dict.buf); - - kfree(s); -} diff --git a/archival/libunarchive/unxz/xz_dec_stream.c b/archival/libunarchive/unxz/xz_dec_stream.c deleted file mode 100644 index bdcbf1ba3..000000000 --- a/archival/libunarchive/unxz/xz_dec_stream.c +++ /dev/null @@ -1,822 +0,0 @@ -/* - * .xz Stream decoder - * - * Author: Lasse Collin - * - * This file has been put into the public domain. - * You can do whatever you want with this file. - */ - -#include "xz_private.h" -#include "xz_stream.h" - -/* Hash used to validate the Index field */ -struct xz_dec_hash { - vli_type unpadded; - vli_type uncompressed; - uint32_t crc32; -}; - -struct xz_dec { - /* Position in dec_main() */ - enum { - SEQ_STREAM_HEADER, - SEQ_BLOCK_START, - SEQ_BLOCK_HEADER, - SEQ_BLOCK_UNCOMPRESS, - SEQ_BLOCK_PADDING, - SEQ_BLOCK_CHECK, - SEQ_INDEX, - SEQ_INDEX_PADDING, - SEQ_INDEX_CRC32, - SEQ_STREAM_FOOTER - } sequence; - - /* Position in variable-length integers and Check fields */ - uint32_t pos; - - /* Variable-length integer decoded by dec_vli() */ - vli_type vli; - - /* Saved in_pos and out_pos */ - size_t in_start; - size_t out_start; - - /* CRC32 value in Block or Index */ - uint32_t crc32; - - /* Type of the integrity check calculated from uncompressed data */ - enum xz_check check_type; - - /* Operation mode */ - enum xz_mode mode; - - /* - * True if the next call to xz_dec_run() is allowed to return - * XZ_BUF_ERROR. - */ - bool allow_buf_error; - - /* Information stored in Block Header */ - struct { - /* - * Value stored in the Compressed Size field, or - * VLI_UNKNOWN if Compressed Size is not present. - */ - vli_type compressed; - - /* - * Value stored in the Uncompressed Size field, or - * VLI_UNKNOWN if Uncompressed Size is not present. - */ - vli_type uncompressed; - - /* Size of the Block Header field */ - uint32_t size; - } block_header; - - /* Information collected when decoding Blocks */ - struct { - /* Observed compressed size of the current Block */ - vli_type compressed; - - /* Observed uncompressed size of the current Block */ - vli_type uncompressed; - - /* Number of Blocks decoded so far */ - vli_type count; - - /* - * Hash calculated from the Block sizes. This is used to - * validate the Index field. - */ - struct xz_dec_hash hash; - } block; - - /* Variables needed when verifying the Index field */ - struct { - /* Position in dec_index() */ - enum { - SEQ_INDEX_COUNT, - SEQ_INDEX_UNPADDED, - SEQ_INDEX_UNCOMPRESSED - } sequence; - - /* Size of the Index in bytes */ - vli_type size; - - /* Number of Records (matches block.count in valid files) */ - vli_type count; - - /* - * Hash calculated from the Records (matches block.hash in - * valid files). - */ - struct xz_dec_hash hash; - } index; - - /* - * Temporary buffer needed to hold Stream Header, Block Header, - * and Stream Footer. The Block Header is the biggest (1 KiB) - * so we reserve space according to that. buf[] has to be aligned - * to a multiple of four bytes; the size_t variables before it - * should guarantee this. - */ - struct { - size_t pos; - size_t size; - uint8_t buf[1024]; - } temp; - - struct xz_dec_lzma2 *lzma2; - -#ifdef XZ_DEC_BCJ - struct xz_dec_bcj *bcj; - bool bcj_active; -#endif -}; - -#ifdef XZ_DEC_ANY_CHECK -/* Sizes of the Check field with different Check IDs */ -static const uint8_t check_sizes[16] = { - 0, - 4, 4, 4, - 8, 8, 8, - 16, 16, 16, - 32, 32, 32, - 64, 64, 64 -}; -#endif - -/* - * Fill s->temp by copying data starting from b->in[b->in_pos]. Caller - * must have set s->temp.pos to indicate how much data we are supposed - * to copy into s->temp.buf. Return true once s->temp.pos has reached - * s->temp.size. - */ -static bool XZ_FUNC fill_temp(struct xz_dec *s, struct xz_buf *b) -{ - size_t copy_size = min_t(size_t, - b->in_size - b->in_pos, s->temp.size - s->temp.pos); - - memcpy(s->temp.buf + s->temp.pos, b->in + b->in_pos, copy_size); - b->in_pos += copy_size; - s->temp.pos += copy_size; - - if (s->temp.pos == s->temp.size) { - s->temp.pos = 0; - return true; - } - - return false; -} - -/* Decode a variable-length integer (little-endian base-128 encoding) */ -static enum xz_ret XZ_FUNC dec_vli(struct xz_dec *s, - const uint8_t *in, size_t *in_pos, size_t in_size) -{ - uint8_t byte; - - if (s->pos == 0) - s->vli = 0; - - while (*in_pos < in_size) { - byte = in[*in_pos]; - ++*in_pos; - - s->vli |= (vli_type)(byte & 0x7F) << s->pos; - - if ((byte & 0x80) == 0) { - /* Don't allow non-minimal encodings. */ - if (byte == 0 && s->pos != 0) - return XZ_DATA_ERROR; - - s->pos = 0; - return XZ_STREAM_END; - } - - s->pos += 7; - if (s->pos == 7 * VLI_BYTES_MAX) - return XZ_DATA_ERROR; - } - - return XZ_OK; -} - -/* - * Decode the Compressed Data field from a Block. Update and validate - * the observed compressed and uncompressed sizes of the Block so that - * they don't exceed the values possibly stored in the Block Header - * (validation assumes that no integer overflow occurs, since vli_type - * is normally uint64_t). Update the CRC32 if presence of the CRC32 - * field was indicated in Stream Header. - * - * Once the decoding is finished, validate that the observed sizes match - * the sizes possibly stored in the Block Header. Update the hash and - * Block count, which are later used to validate the Index field. - */ -static enum xz_ret XZ_FUNC dec_block(struct xz_dec *s, struct xz_buf *b) -{ - enum xz_ret ret; - - s->in_start = b->in_pos; - s->out_start = b->out_pos; - -#ifdef XZ_DEC_BCJ - if (s->bcj_active) - ret = xz_dec_bcj_run(s->bcj, s->lzma2, b); - else -#endif - ret = xz_dec_lzma2_run(s->lzma2, b); - - s->block.compressed += b->in_pos - s->in_start; - s->block.uncompressed += b->out_pos - s->out_start; - - /* - * There is no need to separately check for VLI_UNKNOWN, since - * the observed sizes are always smaller than VLI_UNKNOWN. - */ - if (s->block.compressed > s->block_header.compressed - || s->block.uncompressed - > s->block_header.uncompressed) - return XZ_DATA_ERROR; - - if (s->check_type == XZ_CHECK_CRC32) - s->crc32 = xz_crc32(b->out + s->out_start, - b->out_pos - s->out_start, s->crc32); - - if (ret == XZ_STREAM_END) { - if (s->block_header.compressed != VLI_UNKNOWN - && s->block_header.compressed - != s->block.compressed) - return XZ_DATA_ERROR; - - if (s->block_header.uncompressed != VLI_UNKNOWN - && s->block_header.uncompressed - != s->block.uncompressed) - return XZ_DATA_ERROR; - - s->block.hash.unpadded += s->block_header.size - + s->block.compressed; - -#ifdef XZ_DEC_ANY_CHECK - s->block.hash.unpadded += check_sizes[s->check_type]; -#else - if (s->check_type == XZ_CHECK_CRC32) - s->block.hash.unpadded += 4; -#endif - - s->block.hash.uncompressed += s->block.uncompressed; - s->block.hash.crc32 = xz_crc32( - (const uint8_t *)&s->block.hash, - sizeof(s->block.hash), s->block.hash.crc32); - - ++s->block.count; - } - - return ret; -} - -/* Update the Index size and the CRC32 value. */ -static void XZ_FUNC index_update(struct xz_dec *s, const struct xz_buf *b) -{ - size_t in_used = b->in_pos - s->in_start; - s->index.size += in_used; - s->crc32 = xz_crc32(b->in + s->in_start, in_used, s->crc32); -} - -/* - * Decode the Number of Records, Unpadded Size, and Uncompressed Size - * fields from the Index field. That is, Index Padding and CRC32 are not - * decoded by this function. - * - * This can return XZ_OK (more input needed), XZ_STREAM_END (everything - * successfully decoded), or XZ_DATA_ERROR (input is corrupt). - */ -static enum xz_ret XZ_FUNC dec_index(struct xz_dec *s, struct xz_buf *b) -{ - enum xz_ret ret; - - do { - ret = dec_vli(s, b->in, &b->in_pos, b->in_size); - if (ret != XZ_STREAM_END) { - index_update(s, b); - return ret; - } - - switch (s->index.sequence) { - case SEQ_INDEX_COUNT: - s->index.count = s->vli; - - /* - * Validate that the Number of Records field - * indicates the same number of Records as - * there were Blocks in the Stream. - */ - if (s->index.count != s->block.count) - return XZ_DATA_ERROR; - - s->index.sequence = SEQ_INDEX_UNPADDED; - break; - - case SEQ_INDEX_UNPADDED: - s->index.hash.unpadded += s->vli; - s->index.sequence = SEQ_INDEX_UNCOMPRESSED; - break; - - case SEQ_INDEX_UNCOMPRESSED: - s->index.hash.uncompressed += s->vli; - s->index.hash.crc32 = xz_crc32( - (const uint8_t *)&s->index.hash, - sizeof(s->index.hash), - s->index.hash.crc32); - --s->index.count; - s->index.sequence = SEQ_INDEX_UNPADDED; - break; - } - } while (s->index.count > 0); - - return XZ_STREAM_END; -} - -/* - * Validate that the next four input bytes match the value of s->crc32. - * s->pos must be zero when starting to validate the first byte. - */ -static enum xz_ret XZ_FUNC crc32_validate(struct xz_dec *s, struct xz_buf *b) -{ - do { - if (b->in_pos == b->in_size) - return XZ_OK; - - if (((s->crc32 >> s->pos) & 0xFF) != b->in[b->in_pos++]) - return XZ_DATA_ERROR; - - s->pos += 8; - - } while (s->pos < 32); - - s->crc32 = 0; - s->pos = 0; - - return XZ_STREAM_END; -} - -#ifdef XZ_DEC_ANY_CHECK -/* - * Skip over the Check field when the Check ID is not supported. - * Returns true once the whole Check field has been skipped over. - */ -static bool XZ_FUNC check_skip(struct xz_dec *s, struct xz_buf *b) -{ - while (s->pos < check_sizes[s->check_type]) { - if (b->in_pos == b->in_size) - return false; - - ++b->in_pos; - ++s->pos; - } - - s->pos = 0; - - return true; -} -#endif - -/* Decode the Stream Header field (the first 12 bytes of the .xz Stream). */ -static enum xz_ret XZ_FUNC dec_stream_header(struct xz_dec *s) -{ - if (!memeq(s->temp.buf, HEADER_MAGIC, HEADER_MAGIC_SIZE)) - return XZ_FORMAT_ERROR; - - if (xz_crc32(s->temp.buf + HEADER_MAGIC_SIZE, 2, 0) - != get_le32(s->temp.buf + HEADER_MAGIC_SIZE + 2)) - return XZ_DATA_ERROR; - - if (s->temp.buf[HEADER_MAGIC_SIZE] != 0) - return XZ_OPTIONS_ERROR; - - /* - * Of integrity checks, we support only none (Check ID = 0) and - * CRC32 (Check ID = 1). However, if XZ_DEC_ANY_CHECK is defined, - * we will accept other check types too, but then the check won't - * be verified and a warning (XZ_UNSUPPORTED_CHECK) will be given. - */ - s->check_type = s->temp.buf[HEADER_MAGIC_SIZE + 1]; - -#ifdef XZ_DEC_ANY_CHECK - if (s->check_type > XZ_CHECK_MAX) - return XZ_OPTIONS_ERROR; - - if (s->check_type > XZ_CHECK_CRC32) - return XZ_UNSUPPORTED_CHECK; -#else - if (s->check_type > XZ_CHECK_CRC32) - return XZ_OPTIONS_ERROR; -#endif - - return XZ_OK; -} - -/* Decode the Stream Footer field (the last 12 bytes of the .xz Stream) */ -static enum xz_ret XZ_FUNC dec_stream_footer(struct xz_dec *s) -{ - if (!memeq(s->temp.buf + 10, FOOTER_MAGIC, FOOTER_MAGIC_SIZE)) - return XZ_DATA_ERROR; - - if (xz_crc32(s->temp.buf + 4, 6, 0) != get_le32(s->temp.buf)) - return XZ_DATA_ERROR; - - /* - * Validate Backward Size. Note that we never added the size of the - * Index CRC32 field to s->index.size, thus we use s->index.size / 4 - * instead of s->index.size / 4 - 1. - */ - if ((s->index.size >> 2) != get_le32(s->temp.buf + 4)) - return XZ_DATA_ERROR; - - if (s->temp.buf[8] != 0 || s->temp.buf[9] != s->check_type) - return XZ_DATA_ERROR; - - /* - * Use XZ_STREAM_END instead of XZ_OK to be more convenient - * for the caller. - */ - return XZ_STREAM_END; -} - -/* Decode the Block Header and initialize the filter chain. */ -static enum xz_ret XZ_FUNC dec_block_header(struct xz_dec *s) -{ - enum xz_ret ret; - - /* - * Validate the CRC32. We know that the temp buffer is at least - * eight bytes so this is safe. - */ - s->temp.size -= 4; - if (xz_crc32(s->temp.buf, s->temp.size, 0) - != get_le32(s->temp.buf + s->temp.size)) - return XZ_DATA_ERROR; - - s->temp.pos = 2; - - /* - * Catch unsupported Block Flags. We support only one or two filters - * in the chain, so we catch that with the same test. - */ -#ifdef XZ_DEC_BCJ - if (s->temp.buf[1] & 0x3E) -#else - if (s->temp.buf[1] & 0x3F) -#endif - return XZ_OPTIONS_ERROR; - - /* Compressed Size */ - if (s->temp.buf[1] & 0x40) { - if (dec_vli(s, s->temp.buf, &s->temp.pos, s->temp.size) - != XZ_STREAM_END) - return XZ_DATA_ERROR; - - s->block_header.compressed = s->vli; - } else { - s->block_header.compressed = VLI_UNKNOWN; - } - - /* Uncompressed Size */ - if (s->temp.buf[1] & 0x80) { - if (dec_vli(s, s->temp.buf, &s->temp.pos, s->temp.size) - != XZ_STREAM_END) - return XZ_DATA_ERROR; - - s->block_header.uncompressed = s->vli; - } else { - s->block_header.uncompressed = VLI_UNKNOWN; - } - -#ifdef XZ_DEC_BCJ - /* If there are two filters, the first one must be a BCJ filter. */ - s->bcj_active = s->temp.buf[1] & 0x01; - if (s->bcj_active) { - if (s->temp.size - s->temp.pos < 2) - return XZ_OPTIONS_ERROR; - - ret = xz_dec_bcj_reset(s->bcj, s->temp.buf[s->temp.pos++]); - if (ret != XZ_OK) - return ret; - - /* - * We don't support custom start offset, - * so Size of Properties must be zero. - */ - if (s->temp.buf[s->temp.pos++] != 0x00) - return XZ_OPTIONS_ERROR; - } -#endif - - /* Valid Filter Flags always take at least two bytes. */ - if (s->temp.size - s->temp.pos < 2) - return XZ_DATA_ERROR; - - /* Filter ID = LZMA2 */ - if (s->temp.buf[s->temp.pos++] != 0x21) - return XZ_OPTIONS_ERROR; - - /* Size of Properties = 1-byte Filter Properties */ - if (s->temp.buf[s->temp.pos++] != 0x01) - return XZ_OPTIONS_ERROR; - - /* Filter Properties contains LZMA2 dictionary size. */ - if (s->temp.size - s->temp.pos < 1) - return XZ_DATA_ERROR; - - ret = xz_dec_lzma2_reset(s->lzma2, s->temp.buf[s->temp.pos++]); - if (ret != XZ_OK) - return ret; - - /* The rest must be Header Padding. */ - while (s->temp.pos < s->temp.size) - if (s->temp.buf[s->temp.pos++] != 0x00) - return XZ_OPTIONS_ERROR; - - s->temp.pos = 0; - s->block.compressed = 0; - s->block.uncompressed = 0; - - return XZ_OK; -} - -static enum xz_ret XZ_FUNC dec_main(struct xz_dec *s, struct xz_buf *b) -{ - enum xz_ret ret; - - /* - * Store the start position for the case when we are in the middle - * of the Index field. - */ - s->in_start = b->in_pos; - - while (true) { - switch (s->sequence) { - case SEQ_STREAM_HEADER: - /* - * Stream Header is copied to s->temp, and then - * decoded from there. This way if the caller - * gives us only little input at a time, we can - * still keep the Stream Header decoding code - * simple. Similar approach is used in many places - * in this file. - */ - if (!fill_temp(s, b)) - return XZ_OK; - - /* - * If dec_stream_header() returns - * XZ_UNSUPPORTED_CHECK, it is still possible - * to continue decoding if working in multi-call - * mode. Thus, update s->sequence before calling - * dec_stream_header(). - */ - s->sequence = SEQ_BLOCK_START; - - ret = dec_stream_header(s); - if (ret != XZ_OK) - return ret; - - case SEQ_BLOCK_START: - /* We need one byte of input to continue. */ - if (b->in_pos == b->in_size) - return XZ_OK; - - /* See if this is the beginning of the Index field. */ - if (b->in[b->in_pos] == 0) { - s->in_start = b->in_pos++; - s->sequence = SEQ_INDEX; - break; - } - - /* - * Calculate the size of the Block Header and - * prepare to decode it. - */ - s->block_header.size - = ((uint32_t)b->in[b->in_pos] + 1) * 4; - - s->temp.size = s->block_header.size; - s->temp.pos = 0; - s->sequence = SEQ_BLOCK_HEADER; - - case SEQ_BLOCK_HEADER: - if (!fill_temp(s, b)) - return XZ_OK; - - ret = dec_block_header(s); - if (ret != XZ_OK) - return ret; - - s->sequence = SEQ_BLOCK_UNCOMPRESS; - - case SEQ_BLOCK_UNCOMPRESS: - ret = dec_block(s, b); - if (ret != XZ_STREAM_END) - return ret; - - s->sequence = SEQ_BLOCK_PADDING; - - case SEQ_BLOCK_PADDING: - /* - * Size of Compressed Data + Block Padding - * must be a multiple of four. We don't need - * s->block.compressed for anything else - * anymore, so we use it here to test the size - * of the Block Padding field. - */ - while (s->block.compressed & 3) { - if (b->in_pos == b->in_size) - return XZ_OK; - - if (b->in[b->in_pos++] != 0) - return XZ_DATA_ERROR; - - ++s->block.compressed; - } - - s->sequence = SEQ_BLOCK_CHECK; - - case SEQ_BLOCK_CHECK: - if (s->check_type == XZ_CHECK_CRC32) { - ret = crc32_validate(s, b); - if (ret != XZ_STREAM_END) - return ret; - } -#ifdef XZ_DEC_ANY_CHECK - else if (!check_skip(s, b)) { - return XZ_OK; - } -#endif - - s->sequence = SEQ_BLOCK_START; - break; - - case SEQ_INDEX: - ret = dec_index(s, b); - if (ret != XZ_STREAM_END) - return ret; - - s->sequence = SEQ_INDEX_PADDING; - - case SEQ_INDEX_PADDING: - while ((s->index.size + (b->in_pos - s->in_start)) - & 3) { - if (b->in_pos == b->in_size) { - index_update(s, b); - return XZ_OK; - } - - if (b->in[b->in_pos++] != 0) - return XZ_DATA_ERROR; - } - - /* Finish the CRC32 value and Index size. */ - index_update(s, b); - - /* Compare the hashes to validate the Index field. */ - if (!memeq(&s->block.hash, &s->index.hash, - sizeof(s->block.hash))) - return XZ_DATA_ERROR; - - s->sequence = SEQ_INDEX_CRC32; - - case SEQ_INDEX_CRC32: - ret = crc32_validate(s, b); - if (ret != XZ_STREAM_END) - return ret; - - s->temp.size = STREAM_HEADER_SIZE; - s->sequence = SEQ_STREAM_FOOTER; - - case SEQ_STREAM_FOOTER: - if (!fill_temp(s, b)) - return XZ_OK; - - return dec_stream_footer(s); - } - } - - /* Never reached */ -} - -/* - * xz_dec_run() is a wrapper for dec_main() to handle some special cases in - * multi-call and single-call decoding. - * - * In multi-call mode, we must return XZ_BUF_ERROR when it seems clear that we - * are not going to make any progress anymore. This is to prevent the caller - * from calling us infinitely when the input file is truncated or otherwise - * corrupt. Since zlib-style API allows that the caller fills the input buffer - * only when the decoder doesn't produce any new output, we have to be careful - * to avoid returning XZ_BUF_ERROR too easily: XZ_BUF_ERROR is returned only - * after the second consecutive call to xz_dec_run() that makes no progress. - * - * In single-call mode, if we couldn't decode everything and no error - * occurred, either the input is truncated or the output buffer is too small. - * Since we know that the last input byte never produces any output, we know - * that if all the input was consumed and decoding wasn't finished, the file - * must be corrupt. Otherwise the output buffer has to be too small or the - * file is corrupt in a way that decoding it produces too big output. - * - * If single-call decoding fails, we reset b->in_pos and b->out_pos back to - * their original values. This is because with some filter chains there won't - * be any valid uncompressed data in the output buffer unless the decoding - * actually succeeds (that's the price to pay of using the output buffer as - * the workspace). - */ -XZ_EXTERN enum xz_ret XZ_FUNC xz_dec_run(struct xz_dec *s, struct xz_buf *b) -{ - size_t in_start; - size_t out_start; - enum xz_ret ret; - - if (DEC_IS_SINGLE(s->mode)) - xz_dec_reset(s); - - in_start = b->in_pos; - out_start = b->out_pos; - ret = dec_main(s, b); - - if (DEC_IS_SINGLE(s->mode)) { - if (ret == XZ_OK) - ret = b->in_pos == b->in_size - ? XZ_DATA_ERROR : XZ_BUF_ERROR; - - if (ret != XZ_STREAM_END) { - b->in_pos = in_start; - b->out_pos = out_start; - } - - } else if (ret == XZ_OK && in_start == b->in_pos - && out_start == b->out_pos) { - if (s->allow_buf_error) - ret = XZ_BUF_ERROR; - - s->allow_buf_error = true; - } else { - s->allow_buf_error = false; - } - - return ret; -} - -XZ_EXTERN struct xz_dec * XZ_FUNC xz_dec_init( - enum xz_mode mode, uint32_t dict_max) -{ - struct xz_dec *s = kmalloc(sizeof(*s), GFP_KERNEL); - if (s == NULL) - return NULL; - - s->mode = mode; - -#ifdef XZ_DEC_BCJ - s->bcj = xz_dec_bcj_create(DEC_IS_SINGLE(mode)); - if (s->bcj == NULL) - goto error_bcj; -#endif - - s->lzma2 = xz_dec_lzma2_create(mode, dict_max); - if (s->lzma2 == NULL) - goto error_lzma2; - - xz_dec_reset(s); - return s; - -error_lzma2: -#ifdef XZ_DEC_BCJ - xz_dec_bcj_end(s->bcj); -error_bcj: -#endif - kfree(s); - return NULL; -} - -XZ_EXTERN void XZ_FUNC xz_dec_reset(struct xz_dec *s) -{ - s->sequence = SEQ_STREAM_HEADER; - s->allow_buf_error = false; - s->pos = 0; - s->crc32 = 0; - memzero(&s->block, sizeof(s->block)); - memzero(&s->index, sizeof(s->index)); - s->temp.pos = 0; - s->temp.size = STREAM_HEADER_SIZE; -} - -XZ_EXTERN void XZ_FUNC xz_dec_end(struct xz_dec *s) -{ - if (s != NULL) { - xz_dec_lzma2_end(s->lzma2); -#ifdef XZ_DEC_BCJ - xz_dec_bcj_end(s->bcj); -#endif - kfree(s); - } -} diff --git a/archival/libunarchive/unxz/xz_lzma2.h b/archival/libunarchive/unxz/xz_lzma2.h deleted file mode 100644 index 47f21afbc..000000000 --- a/archival/libunarchive/unxz/xz_lzma2.h +++ /dev/null @@ -1,204 +0,0 @@ -/* - * LZMA2 definitions - * - * Authors: Lasse Collin - * Igor Pavlov - * - * This file has been put into the public domain. - * You can do whatever you want with this file. - */ - -#ifndef XZ_LZMA2_H -#define XZ_LZMA2_H - -/* Range coder constants */ -#define RC_SHIFT_BITS 8 -#define RC_TOP_BITS 24 -#define RC_TOP_VALUE (1 << RC_TOP_BITS) -#define RC_BIT_MODEL_TOTAL_BITS 11 -#define RC_BIT_MODEL_TOTAL (1 << RC_BIT_MODEL_TOTAL_BITS) -#define RC_MOVE_BITS 5 - -/* - * Maximum number of position states. A position state is the lowest pb - * number of bits of the current uncompressed offset. In some places there - * are different sets of probabilities for different position states. - */ -#define POS_STATES_MAX (1 << 4) - -/* - * This enum is used to track which LZMA symbols have occurred most recently - * and in which order. This information is used to predict the next symbol. - * - * Symbols: - * - Literal: One 8-bit byte - * - Match: Repeat a chunk of data at some distance - * - Long repeat: Multi-byte match at a recently seen distance - * - Short repeat: One-byte repeat at a recently seen distance - * - * The symbol names are in from STATE_oldest_older_previous. REP means - * either short or long repeated match, and NONLIT means any non-literal. - */ -enum lzma_state { - STATE_LIT_LIT, - STATE_MATCH_LIT_LIT, - STATE_REP_LIT_LIT, - STATE_SHORTREP_LIT_LIT, - STATE_MATCH_LIT, - STATE_REP_LIT, - STATE_SHORTREP_LIT, - STATE_LIT_MATCH, - STATE_LIT_LONGREP, - STATE_LIT_SHORTREP, - STATE_NONLIT_MATCH, - STATE_NONLIT_REP -}; - -/* Total number of states */ -#define STATES 12 - -/* The lowest 7 states indicate that the previous state was a literal. */ -#define LIT_STATES 7 - -/* Indicate that the latest symbol was a literal. */ -static inline void XZ_FUNC lzma_state_literal(enum lzma_state *state) -{ - if (*state <= STATE_SHORTREP_LIT_LIT) - *state = STATE_LIT_LIT; - else if (*state <= STATE_LIT_SHORTREP) - *state -= 3; - else - *state -= 6; -} - -/* Indicate that the latest symbol was a match. */ -static inline void XZ_FUNC lzma_state_match(enum lzma_state *state) -{ - *state = *state < LIT_STATES ? STATE_LIT_MATCH : STATE_NONLIT_MATCH; -} - -/* Indicate that the latest state was a long repeated match. */ -static inline void XZ_FUNC lzma_state_long_rep(enum lzma_state *state) -{ - *state = *state < LIT_STATES ? STATE_LIT_LONGREP : STATE_NONLIT_REP; -} - -/* Indicate that the latest symbol was a short match. */ -static inline void XZ_FUNC lzma_state_short_rep(enum lzma_state *state) -{ - *state = *state < LIT_STATES ? STATE_LIT_SHORTREP : STATE_NONLIT_REP; -} - -/* Test if the previous symbol was a literal. */ -static inline bool XZ_FUNC lzma_state_is_literal(enum lzma_state state) -{ - return state < LIT_STATES; -} - -/* Each literal coder is divided in three sections: - * - 0x001-0x0FF: Without match byte - * - 0x101-0x1FF: With match byte; match bit is 0 - * - 0x201-0x2FF: With match byte; match bit is 1 - * - * Match byte is used when the previous LZMA symbol was something else than - * a literal (that is, it was some kind of match). - */ -#define LITERAL_CODER_SIZE 0x300 - -/* Maximum number of literal coders */ -#define LITERAL_CODERS_MAX (1 << 4) - -/* Minimum length of a match is two bytes. */ -#define MATCH_LEN_MIN 2 - -/* Match length is encoded with 4, 5, or 10 bits. - * - * Length Bits - * 2-9 4 = Choice=0 + 3 bits - * 10-17 5 = Choice=1 + Choice2=0 + 3 bits - * 18-273 10 = Choice=1 + Choice2=1 + 8 bits - */ -#define LEN_LOW_BITS 3 -#define LEN_LOW_SYMBOLS (1 << LEN_LOW_BITS) -#define LEN_MID_BITS 3 -#define LEN_MID_SYMBOLS (1 << LEN_MID_BITS) -#define LEN_HIGH_BITS 8 -#define LEN_HIGH_SYMBOLS (1 << LEN_HIGH_BITS) -#define LEN_SYMBOLS (LEN_LOW_SYMBOLS + LEN_MID_SYMBOLS + LEN_HIGH_SYMBOLS) - -/* - * Maximum length of a match is 273 which is a result of the encoding - * described above. - */ -#define MATCH_LEN_MAX (MATCH_LEN_MIN + LEN_SYMBOLS - 1) - -/* - * Different sets of probabilities are used for match distances that have - * very short match length: Lengths of 2, 3, and 4 bytes have a separate - * set of probabilities for each length. The matches with longer length - * use a shared set of probabilities. - */ -#define DIST_STATES 4 - -/* - * Get the index of the appropriate probability array for decoding - * the distance slot. - */ -static inline uint32_t XZ_FUNC lzma_get_dist_state(uint32_t len) -{ - return len < DIST_STATES + MATCH_LEN_MIN - ? len - MATCH_LEN_MIN : DIST_STATES - 1; -} - -/* - * The highest two bits of a 32-bit match distance are encoded using six bits. - * This six-bit value is called a distance slot. This way encoding a 32-bit - * value takes 6-36 bits, larger values taking more bits. - */ -#define DIST_SLOT_BITS 6 -#define DIST_SLOTS (1 << DIST_SLOT_BITS) - -/* Match distances up to 127 are fully encoded using probabilities. Since - * the highest two bits (distance slot) are always encoded using six bits, - * the distances 0-3 don't need any additional bits to encode, since the - * distance slot itself is the same as the actual distance. DIST_MODEL_START - * indicates the first distance slot where at least one additional bit is - * needed. - */ -#define DIST_MODEL_START 4 - -/* - * Match distances greater than 127 are encoded in three pieces: - * - distance slot: the highest two bits - * - direct bits: 2-26 bits below the highest two bits - * - alignment bits: four lowest bits - * - * Direct bits don't use any probabilities. - * - * The distance slot value of 14 is for distances 128-191. - */ -#define DIST_MODEL_END 14 - -/* Distance slots that indicate a distance <= 127. */ -#define FULL_DISTANCES_BITS (DIST_MODEL_END / 2) -#define FULL_DISTANCES (1 << FULL_DISTANCES_BITS) - -/* - * For match distances greater than 127, only the highest two bits and the - * lowest four bits (alignment) is encoded using probabilities. - */ -#define ALIGN_BITS 4 -#define ALIGN_SIZE (1 << ALIGN_BITS) -#define ALIGN_MASK (ALIGN_SIZE - 1) - -/* Total number of all probability variables */ -#define PROBS_TOTAL (1846 + LITERAL_CODERS_MAX * LITERAL_CODER_SIZE) - -/* - * LZMA remembers the four most recent match distances. Reusing these - * distances tends to take less space than re-encoding the actual - * distance value. - */ -#define REPS 4 - -#endif diff --git a/archival/libunarchive/unxz/xz_private.h b/archival/libunarchive/unxz/xz_private.h deleted file mode 100644 index 145649a83..000000000 --- a/archival/libunarchive/unxz/xz_private.h +++ /dev/null @@ -1,159 +0,0 @@ -/* - * Private includes and definitions - * - * Author: Lasse Collin - * - * This file has been put into the public domain. - * You can do whatever you want with this file. - */ - -#ifndef XZ_PRIVATE_H -#define XZ_PRIVATE_H - -#ifdef __KERNEL__ - /* XZ_PREBOOT may be defined only via decompress_unxz.c. */ -# ifndef XZ_PREBOOT -# include -# include -# include -# define memeq(a, b, size) (memcmp(a, b, size) == 0) -# define memzero(buf, size) memset(buf, 0, size) -# endif -# include -# include -# define get_le32(p) le32_to_cpup((const uint32_t *)(p)) - /* XZ_IGNORE_KCONFIG may be defined only via decompress_unxz.c. */ -# ifndef XZ_IGNORE_KCONFIG -# ifdef CONFIG_XZ_DEC_X86 -# define XZ_DEC_X86 -# endif -# ifdef CONFIG_XZ_DEC_POWERPC -# define XZ_DEC_POWERPC -# endif -# ifdef CONFIG_XZ_DEC_IA64 -# define XZ_DEC_IA64 -# endif -# ifdef CONFIG_XZ_DEC_ARM -# define XZ_DEC_ARM -# endif -# ifdef CONFIG_XZ_DEC_ARMTHUMB -# define XZ_DEC_ARMTHUMB -# endif -# ifdef CONFIG_XZ_DEC_SPARC -# define XZ_DEC_SPARC -# endif -# endif -# include -#else - /* - * For userspace builds, use a separate header to define the required - * macros and functions. This makes it easier to adapt the code into - * different environments and avoids clutter in the Linux kernel tree. - */ -# include "xz_config.h" -#endif - -/* If no specific decoding mode is requested, enable support for all modes. */ -#if !defined(XZ_DEC_SINGLE) && !defined(XZ_DEC_PREALLOC) \ - && !defined(XZ_DEC_DYNALLOC) -# define XZ_DEC_SINGLE -# define XZ_DEC_PREALLOC -# define XZ_DEC_DYNALLOC -#endif - -/* - * The DEC_IS_foo(mode) macros are used in "if" statements. If only some - * of the supported modes are enabled, these macros will evaluate to true or - * false at compile time and thus allow the compiler to omit unneeded code. - */ -#ifdef XZ_DEC_SINGLE -# define DEC_IS_SINGLE(mode) ((mode) == XZ_SINGLE) -#else -# define DEC_IS_SINGLE(mode) (false) -#endif - -#ifdef XZ_DEC_PREALLOC -# define DEC_IS_PREALLOC(mode) ((mode) == XZ_PREALLOC) -#else -# define DEC_IS_PREALLOC(mode) (false) -#endif - -#ifdef XZ_DEC_DYNALLOC -# define DEC_IS_DYNALLOC(mode) ((mode) == XZ_DYNALLOC) -#else -# define DEC_IS_DYNALLOC(mode) (false) -#endif - -#if !defined(XZ_DEC_SINGLE) -# define DEC_IS_MULTI(mode) (true) -#elif defined(XZ_DEC_PREALLOC) || defined(XZ_DEC_DYNALLOC) -# define DEC_IS_MULTI(mode) ((mode) != XZ_SINGLE) -#else -# define DEC_IS_MULTI(mode) (false) -#endif - -/* - * If any of the BCJ filter decoders are wanted, define XZ_DEC_BCJ. - * XZ_DEC_BCJ is used to enable generic support for BCJ decoders. - */ -#ifndef XZ_DEC_BCJ -# if defined(XZ_DEC_X86) || defined(XZ_DEC_POWERPC) \ - || defined(XZ_DEC_IA64) || defined(XZ_DEC_ARM) \ - || defined(XZ_DEC_ARM) || defined(XZ_DEC_ARMTHUMB) \ - || defined(XZ_DEC_SPARC) -# define XZ_DEC_BCJ -# endif -#endif - -/* - * Allocate memory for LZMA2 decoder. xz_dec_lzma2_reset() must be used - * before calling xz_dec_lzma2_run(). - */ -XZ_EXTERN struct xz_dec_lzma2 * XZ_FUNC xz_dec_lzma2_create( - enum xz_mode mode, uint32_t dict_max); - -/* - * Decode the LZMA2 properties (one byte) and reset the decoder. Return - * XZ_OK on success, XZ_MEMLIMIT_ERROR if the preallocated dictionary is not - * big enough, and XZ_OPTIONS_ERROR if props indicates something that this - * decoder doesn't support. - */ -XZ_EXTERN enum xz_ret XZ_FUNC xz_dec_lzma2_reset( - struct xz_dec_lzma2 *s, uint8_t props); - -/* Decode raw LZMA2 stream from b->in to b->out. */ -XZ_EXTERN enum xz_ret XZ_FUNC xz_dec_lzma2_run( - struct xz_dec_lzma2 *s, struct xz_buf *b); - -/* Free the memory allocated for the LZMA2 decoder. */ -XZ_EXTERN void XZ_FUNC xz_dec_lzma2_end(struct xz_dec_lzma2 *s); - -#ifdef XZ_DEC_BCJ -/* - * Allocate memory for BCJ decoders. xz_dec_bcj_reset() must be used before - * calling xz_dec_bcj_run(). - */ -XZ_EXTERN struct xz_dec_bcj * XZ_FUNC xz_dec_bcj_create(bool single_call); - -/* - * Decode the Filter ID of a BCJ filter. This implementation doesn't - * support custom start offsets, so no decoding of Filter Properties - * is needed. Returns XZ_OK if the given Filter ID is supported. - * Otherwise XZ_OPTIONS_ERROR is returned. - */ -XZ_EXTERN enum xz_ret XZ_FUNC xz_dec_bcj_reset( - struct xz_dec_bcj *s, uint8_t id); - -/* - * Decode raw BCJ + LZMA2 stream. This must be used only if there actually is - * a BCJ filter in the chain. If the chain has only LZMA2, xz_dec_lzma2_run() - * must be called directly. - */ -XZ_EXTERN enum xz_ret XZ_FUNC xz_dec_bcj_run(struct xz_dec_bcj *s, - struct xz_dec_lzma2 *lzma2, struct xz_buf *b); - -/* Free the memory allocated for the BCJ filters. */ -#define xz_dec_bcj_end(s) kfree(s) -#endif - -#endif diff --git a/archival/libunarchive/unxz/xz_stream.h b/archival/libunarchive/unxz/xz_stream.h deleted file mode 100644 index 36f2a7cbf..000000000 --- a/archival/libunarchive/unxz/xz_stream.h +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Definitions for handling the .xz file format - * - * Author: Lasse Collin - * - * This file has been put into the public domain. - * You can do whatever you want with this file. - */ - -#ifndef XZ_STREAM_H -#define XZ_STREAM_H - -#if defined(__KERNEL__) && !XZ_INTERNAL_CRC32 -# include -# undef crc32 -# define xz_crc32(buf, size, crc) \ - (~crc32_le(~(uint32_t)(crc), buf, size)) -#endif - -/* - * See the .xz file format specification at - * http://tukaani.org/xz/xz-file-format.txt - * to understand the container format. - */ - -#define STREAM_HEADER_SIZE 12 - -#define HEADER_MAGIC "\3757zXZ\0" -#define HEADER_MAGIC_SIZE 6 - -#define FOOTER_MAGIC "YZ" -#define FOOTER_MAGIC_SIZE 2 - -/* - * Variable-length integer can hold a 63-bit unsigned integer, or a special - * value to indicate that the value is unknown. - */ -typedef uint64_t vli_type; - -#define VLI_MAX ((vli_type)-1 / 2) -#define VLI_UNKNOWN ((vli_type)-1) - -/* Maximum encoded size of a VLI */ -#define VLI_BYTES_MAX (sizeof(vli_type) * 8 / 7) - -/* Integrity Check types */ -enum xz_check { - XZ_CHECK_NONE = 0, - XZ_CHECK_CRC32 = 1, - XZ_CHECK_CRC64 = 4, - XZ_CHECK_SHA256 = 10 -}; - -/* Maximum possible Check ID */ -#define XZ_CHECK_MAX 15 - -#endif diff --git a/archival/lzop.c b/archival/lzop.c index acb34fe14..094e78cf9 100644 --- a/archival/lzop.c +++ b/archival/lzop.c @@ -26,7 +26,7 @@ */ #include "libbb.h" -#include "unarchive.h" +#include "archive.h" #include "liblzo_interface.h" /* lzo-2.03/src/lzo_ptr.h */ diff --git a/archival/rpm.c b/archival/rpm.c index 7b316a5b8..380226f9b 100644 --- a/archival/rpm.c +++ b/archival/rpm.c @@ -8,7 +8,7 @@ */ #include "libbb.h" -#include "unarchive.h" +#include "archive.h" #include "rpm.h" #define RPM_CHAR_TYPE 1 diff --git a/archival/rpm2cpio.c b/archival/rpm2cpio.c index 70021d539..ce8cd2c2c 100644 --- a/archival/rpm2cpio.c +++ b/archival/rpm2cpio.c @@ -7,7 +7,7 @@ * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ #include "libbb.h" -#include "unarchive.h" +#include "archive.h" #include "rpm.h" enum { rpm_fd = STDIN_FILENO }; diff --git a/archival/tar.c b/archival/tar.c index 2176ad2ac..82caec770 100644 --- a/archival/tar.c +++ b/archival/tar.c @@ -25,7 +25,7 @@ #include #include "libbb.h" -#include "unarchive.h" +#include "archive.h" /* FIXME: Stop using this non-standard feature */ #ifndef FNM_LEADING_DIR # define FNM_LEADING_DIR 0 diff --git a/archival/unzip.c b/archival/unzip.c index 204e34952..5d62c08cb 100644 --- a/archival/unzip.c +++ b/archival/unzip.c @@ -20,7 +20,7 @@ */ #include "libbb.h" -#include "unarchive.h" +#include "archive.h" enum { #if BB_BIG_ENDIAN diff --git a/docs/keep_data_small.txt b/docs/keep_data_small.txt index 01c0d3c7b..21d732674 100644 --- a/docs/keep_data_small.txt +++ b/docs/keep_data_small.txt @@ -59,7 +59,7 @@ wait Example 1 One example how to reduce global data usage is in -archival/libunarchive/decompress_unzip.c: +archival/libarchive/decompress_unzip.c: /* This is somewhat complex-looking arrangement, but it allows * to place decompressor state either in bss or in diff --git a/include/archive.h b/include/archive.h new file mode 100644 index 000000000..ba6d323e0 --- /dev/null +++ b/include/archive.h @@ -0,0 +1,238 @@ +/* vi: set sw=4 ts=4: */ +#ifndef UNARCHIVE_H +#define UNARCHIVE_H 1 + +PUSH_AND_SET_FUNCTION_VISIBILITY_TO_HIDDEN + +enum { +#if BB_BIG_ENDIAN + COMPRESS_MAGIC = 0x1f9d, + GZIP_MAGIC = 0x1f8b, + BZIP2_MAGIC = 'B' * 256 + 'Z', + /* .xz signature: 0xfd, '7', 'z', 'X', 'Z', 0x00 */ + /* More info at: http://tukaani.org/xz/xz-file-format.txt */ + XZ_MAGIC1 = 0xfd * 256 + '7', + XZ_MAGIC2 = (('z' * 256 + 'X') * 256 + 'Z') * 256 + 0, + /* Different form: 32 bits, then 16 bits: */ + XZ_MAGIC1a = ((0xfd * 256 + '7') * 256 + 'z') * 256 + 'X', + XZ_MAGIC2a = 'Z' * 256 + 0, +#else + COMPRESS_MAGIC = 0x9d1f, + GZIP_MAGIC = 0x8b1f, + BZIP2_MAGIC = 'Z' * 256 + 'B', + XZ_MAGIC1 = '7' * 256 + 0xfd, + XZ_MAGIC2 = ((0 * 256 + 'Z') * 256 + 'X') * 256 + 'z', + XZ_MAGIC1a = (('X' * 256 + 'z') * 256 + '7') * 256 + 0xfd, + XZ_MAGIC2a = 0 * 256 + 'Z', +#endif +}; + +typedef struct file_header_t { + char *name; + char *link_target; +#if ENABLE_FEATURE_TAR_UNAME_GNAME + char *tar__uname; + char *tar__gname; +#endif + off_t size; + uid_t uid; + gid_t gid; + mode_t mode; + time_t mtime; + dev_t device; +} file_header_t; + +struct hardlinks_t; + +typedef struct archive_handle_t { + /* Flags. 1st since it is most used member */ + unsigned ah_flags; + + /* The raw stream as read from disk or stdin */ + int src_fd; + + /* Define if the header and data component should be processed */ + char FAST_FUNC (*filter)(struct archive_handle_t *); + /* List of files that have been accepted */ + llist_t *accept; + /* List of files that have been rejected */ + llist_t *reject; + /* List of files that have successfully been worked on */ + llist_t *passed; + + /* Currently processed file's header */ + file_header_t *file_header; + + /* Process the header component, e.g. tar -t */ + void FAST_FUNC (*action_header)(const file_header_t *); + + /* Process the data component, e.g. extract to filesystem */ + void FAST_FUNC (*action_data)(struct archive_handle_t *); + + /* Function that skips data */ + void FAST_FUNC (*seek)(int fd, off_t amount); + + /* Count processed bytes */ + off_t offset; + + /* Archiver specific. Can make it a union if it ever gets big */ +#if ENABLE_TAR || ENABLE_DPKG || ENABLE_DPKG_DEB + smallint tar__end; +# if ENABLE_FEATURE_TAR_GNU_EXTENSIONS + char* tar__longname; + char* tar__linkname; +# endif +#if ENABLE_FEATURE_TAR_TO_COMMAND + char* tar__to_command; +#endif +# if ENABLE_FEATURE_TAR_SELINUX + char* tar__global_sctx; + char* tar__next_file_sctx; +# endif +#endif +#if ENABLE_CPIO || ENABLE_RPM2CPIO || ENABLE_RPM + uoff_t cpio__blocks; + struct hardlinks_t *cpio__hardlinks_to_create; + struct hardlinks_t *cpio__created_hardlinks; +#endif +#if ENABLE_DPKG || ENABLE_DPKG_DEB + /* Temporary storage */ + char *dpkg__buffer; + /* How to process any sub archive, e.g. get_header_tar_gz */ + char FAST_FUNC (*dpkg__action_data_subarchive)(struct archive_handle_t *); + /* Contains the handle to a sub archive */ + struct archive_handle_t *dpkg__sub_archive; +#endif +#if ENABLE_FEATURE_AR_CREATE + const char *ar__name; + struct archive_handle_t *ar__out; +#endif +} archive_handle_t; +/* bits in ah_flags */ +#define ARCHIVE_RESTORE_DATE (1 << 0) +#define ARCHIVE_CREATE_LEADING_DIRS (1 << 1) +#define ARCHIVE_UNLINK_OLD (1 << 2) +#define ARCHIVE_EXTRACT_QUIET (1 << 3) +#define ARCHIVE_EXTRACT_NEWER (1 << 4) +#define ARCHIVE_DONT_RESTORE_OWNER (1 << 5) +#define ARCHIVE_DONT_RESTORE_PERM (1 << 6) +#define ARCHIVE_NUMERIC_OWNER (1 << 7) +#define ARCHIVE_O_TRUNC (1 << 8) + + +/* POSIX tar Header Block, from POSIX 1003.1-1990 */ +#define TAR_BLOCK_SIZE 512 +#define NAME_SIZE 100 +#define NAME_SIZE_STR "100" +typedef struct tar_header_t { /* byte offset */ + char name[NAME_SIZE]; /* 0-99 */ + char mode[8]; /* 100-107 */ + char uid[8]; /* 108-115 */ + char gid[8]; /* 116-123 */ + char size[12]; /* 124-135 */ + char mtime[12]; /* 136-147 */ + char chksum[8]; /* 148-155 */ + char typeflag; /* 156-156 */ + char linkname[NAME_SIZE]; /* 157-256 */ + /* POSIX: "ustar" NUL "00" */ + /* GNU tar: "ustar " NUL */ + /* Normally it's defined as magic[6] followed by + * version[2], but we put them together to save code. + */ + char magic[8]; /* 257-264 */ + char uname[32]; /* 265-296 */ + char gname[32]; /* 297-328 */ + char devmajor[8]; /* 329-336 */ + char devminor[8]; /* 337-344 */ + char prefix[155]; /* 345-499 */ + char padding[12]; /* 500-512 (pad to exactly TAR_BLOCK_SIZE) */ +} tar_header_t; +struct BUG_tar_header { + char c[sizeof(tar_header_t) == TAR_BLOCK_SIZE ? 1 : -1]; +}; + + + +/* Info struct unpackers can fill out to inform users of thing like + * timestamps of unpacked files */ +typedef struct unpack_info_t { + time_t mtime; +} unpack_info_t; + +extern archive_handle_t *init_handle(void) FAST_FUNC; + +extern char filter_accept_all(archive_handle_t *archive_handle) FAST_FUNC; +extern char filter_accept_list(archive_handle_t *archive_handle) FAST_FUNC; +extern char filter_accept_list_reassign(archive_handle_t *archive_handle) FAST_FUNC; +extern char filter_accept_reject_list(archive_handle_t *archive_handle) FAST_FUNC; + +extern void unpack_ar_archive(archive_handle_t *ar_archive) FAST_FUNC; + +extern void data_skip(archive_handle_t *archive_handle) FAST_FUNC; +extern void data_extract_all(archive_handle_t *archive_handle) FAST_FUNC; +extern void data_extract_to_stdout(archive_handle_t *archive_handle) FAST_FUNC; +extern void data_extract_to_command(archive_handle_t *archive_handle) FAST_FUNC; + +extern void header_skip(const file_header_t *file_header) FAST_FUNC; +extern void header_list(const file_header_t *file_header) FAST_FUNC; +extern void header_verbose_list(const file_header_t *file_header) FAST_FUNC; + +extern char get_header_ar(archive_handle_t *archive_handle) FAST_FUNC; +extern char get_header_cpio(archive_handle_t *archive_handle) FAST_FUNC; +extern char get_header_tar(archive_handle_t *archive_handle) FAST_FUNC; +extern char get_header_tar_gz(archive_handle_t *archive_handle) FAST_FUNC; +extern char get_header_tar_bz2(archive_handle_t *archive_handle) FAST_FUNC; +extern char get_header_tar_lzma(archive_handle_t *archive_handle) FAST_FUNC; + +extern void seek_by_jump(int fd, off_t amount) FAST_FUNC; +extern void seek_by_read(int fd, off_t amount) FAST_FUNC; + +extern void data_align(archive_handle_t *archive_handle, unsigned boundary) FAST_FUNC; +extern const llist_t *find_list_entry(const llist_t *list, const char *filename) FAST_FUNC; +extern 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(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; + +typedef struct inflate_unzip_result { + off_t bytes_out; + uint32_t crc; +} inflate_unzip_result; + +IF_DESKTOP(long long) int inflate_unzip(inflate_unzip_result *res, off_t compr_size, int src_fd, int dst_fd) FAST_FUNC; +/* xz unpacker takes .xz stream from offset 6 */ +IF_DESKTOP(long long) int unpack_xz_stream(int src_fd, int dst_fd) FAST_FUNC; +/* lzma unpacker takes .lzma stream from offset 0 */ +IF_DESKTOP(long long) int unpack_lzma_stream(int src_fd, int dst_fd) FAST_FUNC; +/* the rest wants 2 first bytes already skipped by the caller */ +IF_DESKTOP(long long) int unpack_bz2_stream(int src_fd, int dst_fd) FAST_FUNC; +IF_DESKTOP(long long) int unpack_gz_stream(int src_fd, int dst_fd) FAST_FUNC; +IF_DESKTOP(long long) int unpack_gz_stream_with_info(int src_fd, int dst_fd, unpack_info_t *info) FAST_FUNC; +IF_DESKTOP(long long) int unpack_Z_stream(int src_fd, int dst_fd) FAST_FUNC; +/* wrapper which checks first two bytes to be "BZ" */ +IF_DESKTOP(long long) int unpack_bz2_stream_prime(int src_fd, int dst_fd) FAST_FUNC; + +char* append_ext(char *filename, const char *expected_ext) FAST_FUNC; +int bbunpack(char **argv, + IF_DESKTOP(long long) int FAST_FUNC (*unpacker)(unpack_info_t *info), + char* FAST_FUNC (*make_new_name)(char *filename, const char *expected_ext), + const char *expected_ext +) FAST_FUNC; + +#if BB_MMU +void open_transformer(int fd, + IF_DESKTOP(long long) int FAST_FUNC (*transformer)(int src_fd, int dst_fd)) FAST_FUNC; +#define open_transformer(fd, transformer, transform_prog) open_transformer(fd, transformer) +#else +void open_transformer(int src_fd, const char *transform_prog) FAST_FUNC; +#define open_transformer(fd, transformer, transform_prog) open_transformer(fd, transform_prog) +#endif + +POP_SAVED_FUNCTION_VISIBILITY + +#endif diff --git a/include/unarchive.h b/include/unarchive.h deleted file mode 100644 index ba6d323e0..000000000 --- a/include/unarchive.h +++ /dev/null @@ -1,238 +0,0 @@ -/* vi: set sw=4 ts=4: */ -#ifndef UNARCHIVE_H -#define UNARCHIVE_H 1 - -PUSH_AND_SET_FUNCTION_VISIBILITY_TO_HIDDEN - -enum { -#if BB_BIG_ENDIAN - COMPRESS_MAGIC = 0x1f9d, - GZIP_MAGIC = 0x1f8b, - BZIP2_MAGIC = 'B' * 256 + 'Z', - /* .xz signature: 0xfd, '7', 'z', 'X', 'Z', 0x00 */ - /* More info at: http://tukaani.org/xz/xz-file-format.txt */ - XZ_MAGIC1 = 0xfd * 256 + '7', - XZ_MAGIC2 = (('z' * 256 + 'X') * 256 + 'Z') * 256 + 0, - /* Different form: 32 bits, then 16 bits: */ - XZ_MAGIC1a = ((0xfd * 256 + '7') * 256 + 'z') * 256 + 'X', - XZ_MAGIC2a = 'Z' * 256 + 0, -#else - COMPRESS_MAGIC = 0x9d1f, - GZIP_MAGIC = 0x8b1f, - BZIP2_MAGIC = 'Z' * 256 + 'B', - XZ_MAGIC1 = '7' * 256 + 0xfd, - XZ_MAGIC2 = ((0 * 256 + 'Z') * 256 + 'X') * 256 + 'z', - XZ_MAGIC1a = (('X' * 256 + 'z') * 256 + '7') * 256 + 0xfd, - XZ_MAGIC2a = 0 * 256 + 'Z', -#endif -}; - -typedef struct file_header_t { - char *name; - char *link_target; -#if ENABLE_FEATURE_TAR_UNAME_GNAME - char *tar__uname; - char *tar__gname; -#endif - off_t size; - uid_t uid; - gid_t gid; - mode_t mode; - time_t mtime; - dev_t device; -} file_header_t; - -struct hardlinks_t; - -typedef struct archive_handle_t { - /* Flags. 1st since it is most used member */ - unsigned ah_flags; - - /* The raw stream as read from disk or stdin */ - int src_fd; - - /* Define if the header and data component should be processed */ - char FAST_FUNC (*filter)(struct archive_handle_t *); - /* List of files that have been accepted */ - llist_t *accept; - /* List of files that have been rejected */ - llist_t *reject; - /* List of files that have successfully been worked on */ - llist_t *passed; - - /* Currently processed file's header */ - file_header_t *file_header; - - /* Process the header component, e.g. tar -t */ - void FAST_FUNC (*action_header)(const file_header_t *); - - /* Process the data component, e.g. extract to filesystem */ - void FAST_FUNC (*action_data)(struct archive_handle_t *); - - /* Function that skips data */ - void FAST_FUNC (*seek)(int fd, off_t amount); - - /* Count processed bytes */ - off_t offset; - - /* Archiver specific. Can make it a union if it ever gets big */ -#if ENABLE_TAR || ENABLE_DPKG || ENABLE_DPKG_DEB - smallint tar__end; -# if ENABLE_FEATURE_TAR_GNU_EXTENSIONS - char* tar__longname; - char* tar__linkname; -# endif -#if ENABLE_FEATURE_TAR_TO_COMMAND - char* tar__to_command; -#endif -# if ENABLE_FEATURE_TAR_SELINUX - char* tar__global_sctx; - char* tar__next_file_sctx; -# endif -#endif -#if ENABLE_CPIO || ENABLE_RPM2CPIO || ENABLE_RPM - uoff_t cpio__blocks; - struct hardlinks_t *cpio__hardlinks_to_create; - struct hardlinks_t *cpio__created_hardlinks; -#endif -#if ENABLE_DPKG || ENABLE_DPKG_DEB - /* Temporary storage */ - char *dpkg__buffer; - /* How to process any sub archive, e.g. get_header_tar_gz */ - char FAST_FUNC (*dpkg__action_data_subarchive)(struct archive_handle_t *); - /* Contains the handle to a sub archive */ - struct archive_handle_t *dpkg__sub_archive; -#endif -#if ENABLE_FEATURE_AR_CREATE - const char *ar__name; - struct archive_handle_t *ar__out; -#endif -} archive_handle_t; -/* bits in ah_flags */ -#define ARCHIVE_RESTORE_DATE (1 << 0) -#define ARCHIVE_CREATE_LEADING_DIRS (1 << 1) -#define ARCHIVE_UNLINK_OLD (1 << 2) -#define ARCHIVE_EXTRACT_QUIET (1 << 3) -#define ARCHIVE_EXTRACT_NEWER (1 << 4) -#define ARCHIVE_DONT_RESTORE_OWNER (1 << 5) -#define ARCHIVE_DONT_RESTORE_PERM (1 << 6) -#define ARCHIVE_NUMERIC_OWNER (1 << 7) -#define ARCHIVE_O_TRUNC (1 << 8) - - -/* POSIX tar Header Block, from POSIX 1003.1-1990 */ -#define TAR_BLOCK_SIZE 512 -#define NAME_SIZE 100 -#define NAME_SIZE_STR "100" -typedef struct tar_header_t { /* byte offset */ - char name[NAME_SIZE]; /* 0-99 */ - char mode[8]; /* 100-107 */ - char uid[8]; /* 108-115 */ - char gid[8]; /* 116-123 */ - char size[12]; /* 124-135 */ - char mtime[12]; /* 136-147 */ - char chksum[8]; /* 148-155 */ - char typeflag; /* 156-156 */ - char linkname[NAME_SIZE]; /* 157-256 */ - /* POSIX: "ustar" NUL "00" */ - /* GNU tar: "ustar " NUL */ - /* Normally it's defined as magic[6] followed by - * version[2], but we put them together to save code. - */ - char magic[8]; /* 257-264 */ - char uname[32]; /* 265-296 */ - char gname[32]; /* 297-328 */ - char devmajor[8]; /* 329-336 */ - char devminor[8]; /* 337-344 */ - char prefix[155]; /* 345-499 */ - char padding[12]; /* 500-512 (pad to exactly TAR_BLOCK_SIZE) */ -} tar_header_t; -struct BUG_tar_header { - char c[sizeof(tar_header_t) == TAR_BLOCK_SIZE ? 1 : -1]; -}; - - - -/* Info struct unpackers can fill out to inform users of thing like - * timestamps of unpacked files */ -typedef struct unpack_info_t { - time_t mtime; -} unpack_info_t; - -extern archive_handle_t *init_handle(void) FAST_FUNC; - -extern char filter_accept_all(archive_handle_t *archive_handle) FAST_FUNC; -extern char filter_accept_list(archive_handle_t *archive_handle) FAST_FUNC; -extern char filter_accept_list_reassign(archive_handle_t *archive_handle) FAST_FUNC; -extern char filter_accept_reject_list(archive_handle_t *archive_handle) FAST_FUNC; - -extern void unpack_ar_archive(archive_handle_t *ar_archive) FAST_FUNC; - -extern void data_skip(archive_handle_t *archive_handle) FAST_FUNC; -extern void data_extract_all(archive_handle_t *archive_handle) FAST_FUNC; -extern void data_extract_to_stdout(archive_handle_t *archive_handle) FAST_FUNC; -extern void data_extract_to_command(archive_handle_t *archive_handle) FAST_FUNC; - -extern void header_skip(const file_header_t *file_header) FAST_FUNC; -extern void header_list(const file_header_t *file_header) FAST_FUNC; -extern void header_verbose_list(const file_header_t *file_header) FAST_FUNC; - -extern char get_header_ar(archive_handle_t *archive_handle) FAST_FUNC; -extern char get_header_cpio(archive_handle_t *archive_handle) FAST_FUNC; -extern char get_header_tar(archive_handle_t *archive_handle) FAST_FUNC; -extern char get_header_tar_gz(archive_handle_t *archive_handle) FAST_FUNC; -extern char get_header_tar_bz2(archive_handle_t *archive_handle) FAST_FUNC; -extern char get_header_tar_lzma(archive_handle_t *archive_handle) FAST_FUNC; - -extern void seek_by_jump(int fd, off_t amount) FAST_FUNC; -extern void seek_by_read(int fd, off_t amount) FAST_FUNC; - -extern void data_align(archive_handle_t *archive_handle, unsigned boundary) FAST_FUNC; -extern const llist_t *find_list_entry(const llist_t *list, const char *filename) FAST_FUNC; -extern 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(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; - -typedef struct inflate_unzip_result { - off_t bytes_out; - uint32_t crc; -} inflate_unzip_result; - -IF_DESKTOP(long long) int inflate_unzip(inflate_unzip_result *res, off_t compr_size, int src_fd, int dst_fd) FAST_FUNC; -/* xz unpacker takes .xz stream from offset 6 */ -IF_DESKTOP(long long) int unpack_xz_stream(int src_fd, int dst_fd) FAST_FUNC; -/* lzma unpacker takes .lzma stream from offset 0 */ -IF_DESKTOP(long long) int unpack_lzma_stream(int src_fd, int dst_fd) FAST_FUNC; -/* the rest wants 2 first bytes already skipped by the caller */ -IF_DESKTOP(long long) int unpack_bz2_stream(int src_fd, int dst_fd) FAST_FUNC; -IF_DESKTOP(long long) int unpack_gz_stream(int src_fd, int dst_fd) FAST_FUNC; -IF_DESKTOP(long long) int unpack_gz_stream_with_info(int src_fd, int dst_fd, unpack_info_t *info) FAST_FUNC; -IF_DESKTOP(long long) int unpack_Z_stream(int src_fd, int dst_fd) FAST_FUNC; -/* wrapper which checks first two bytes to be "BZ" */ -IF_DESKTOP(long long) int unpack_bz2_stream_prime(int src_fd, int dst_fd) FAST_FUNC; - -char* append_ext(char *filename, const char *expected_ext) FAST_FUNC; -int bbunpack(char **argv, - IF_DESKTOP(long long) int FAST_FUNC (*unpacker)(unpack_info_t *info), - char* FAST_FUNC (*make_new_name)(char *filename, const char *expected_ext), - const char *expected_ext -) FAST_FUNC; - -#if BB_MMU -void open_transformer(int fd, - IF_DESKTOP(long long) int FAST_FUNC (*transformer)(int src_fd, int dst_fd)) FAST_FUNC; -#define open_transformer(fd, transformer, transform_prog) open_transformer(fd, transformer) -#else -void open_transformer(int src_fd, const char *transform_prog) FAST_FUNC; -#define open_transformer(fd, transformer, transform_prog) open_transformer(fd, transform_prog) -#endif - -POP_SAVED_FUNCTION_VISIBILITY - -#endif diff --git a/libbb/appletlib.c b/libbb/appletlib.c index fab996ca0..d7c9288cb 100644 --- a/libbb/appletlib.c +++ b/libbb/appletlib.c @@ -66,7 +66,7 @@ static const char usage_messages[] ALIGN1 = UNPACKED_USAGE; #if ENABLE_FEATURE_COMPRESS_USAGE static const char packed_usage[] ALIGN1 = { PACKED_USAGE }; -# include "unarchive.h" +# include "archive.h" static const char *unpack_usage_messages(void) { char *outbuf = NULL; diff --git a/libbb/read_printf.c b/libbb/read_printf.c index 7ca3d68c3..8664bc625 100644 --- a/libbb/read_printf.c +++ b/libbb/read_printf.c @@ -15,7 +15,7 @@ ) #if ZIPPED -# include "unarchive.h" +# include "archive.h" #endif diff --git a/miscutils/bbconfig.c b/miscutils/bbconfig.c index 1cb42edeb..7c30669a3 100644 --- a/miscutils/bbconfig.c +++ b/miscutils/bbconfig.c @@ -4,7 +4,7 @@ #include "libbb.h" #include "bbconfigopts.h" #if ENABLE_FEATURE_COMPRESS_BBCONFIG -# include "unarchive.h" +# include "archive.h" # include "bbconfigopts_bz2.h" #endif diff --git a/procps/smemcap.c b/procps/smemcap.c index 196c91f54..200df6795 100644 --- a/procps/smemcap.c +++ b/procps/smemcap.c @@ -20,7 +20,7 @@ //config: a memory usage statistic tool. #include "libbb.h" -#include "unarchive.h" +#include "archive.h" struct fileblock { struct fileblock *next; diff --git a/scripts/Makefile.IMA b/scripts/Makefile.IMA index 11ae39eae..a62618ae0 100644 --- a/scripts/Makefile.IMA +++ b/scripts/Makefile.IMA @@ -85,8 +85,8 @@ lib-y:= include archival/Kbuild lib-all-y += $(patsubst %,archival/%,$(sort $(lib-y))) lib-y:= -include archival/libunarchive/Kbuild -lib-all-y += $(patsubst %,archival/libunarchive/%,$(sort $(lib-y))) +include archival/libarchive/Kbuild +lib-all-y += $(patsubst %,archival/libarchive/%,$(sort $(lib-y))) lib-y:= include applets/Kbuild lib-all-y += $(patsubst %,applets/%,$(sort $(lib-y))) -- cgit v1.2.3-55-g6feb From 854738d39d121378921f8c05f268ff513904a618 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Wed, 3 Nov 2010 02:48:43 +0100 Subject: type fix in comment Signed-off-by: Denys Vlasenko --- libbb/update_passwd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libbb/update_passwd.c b/libbb/update_passwd.c index dc5029223..a30af6f72 100644 --- a/libbb/update_passwd.c +++ b/libbb/update_passwd.c @@ -58,7 +58,7 @@ static void check_selinux_update_passwd(const char *username) 6) delete a user from a group: update_passwd(FILE, GROUP, NULL, MEMBER) only if CONFIG_FEATURE_DEL_USER_FROM_GROUP=y and member != NULL - 7) change user's passord: update_passwd(FILE, USER, NEW_PASSWD, NULL) + 7) change user's password: update_passwd(FILE, USER, NEW_PASSWD, NULL) only if CONFIG_PASSWD=y and applet_name[0] == 'p' like in passwd or if CONFIG_CHPASSWD=y and applet_name[0] == 'c' like in chpasswd -- cgit v1.2.3-55-g6feb From 6052c2b0be796bc92c870b8261f49bc1584877b9 Mon Sep 17 00:00:00 2001 From: Maksym Kryzhanovskyy Date: Thu, 4 Nov 2010 08:41:57 +0100 Subject: powertop: code shrink function old new delta read_cstate_counts 355 360 +5 print_intel_cstates 494 499 +5 process_timer_stats 554 480 -74 process_irq_counts 765 530 -235 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 2/2 up/down: 10/-309) Total: -299 bytes Signed-off-by: Maksym Kryzhanovskyy Signed-off-by: Denys Vlasenko --- procps/powertop.c | 92 +++++++++++++++++++++---------------------------------- 1 file changed, 35 insertions(+), 57 deletions(-) diff --git a/procps/powertop.c b/procps/powertop.c index 77b071ffb..4c3c3565e 100644 --- a/procps/powertop.c +++ b/procps/powertop.c @@ -169,7 +169,7 @@ static void read_cstate_counts(ullong *usage, ullong *duration) if (len < 3 || len > BIG_SYSNAME_LEN) continue; - sprintf(buf, "/proc/acpi/processor/%s/power", d->d_name); + sprintf(buf, "%s/%s/power", "/proc/acpi/processor", d->d_name); fp = fopen_for_read(buf); if (!fp) continue; @@ -321,28 +321,17 @@ static void process_irq_counts(void) /* 0: 143646045 153901007 IO-APIC-edge timer * ^ */ + *p = '\0'; /* Deal with non-maskable interrupts -- make up fake numbers */ - nr = -1; - if (buf[0] != ' ' && !isdigit(buf[0])) { -//TODO: optimize - if (strncmp(buf, "NMI:", 4) == 0) - nr = 20000; - if (strncmp(buf, "RES:", 4) == 0) - nr = 20001; - if (strncmp(buf, "CAL:", 4) == 0) - nr = 20002; - if (strncmp(buf, "TLB:", 4) == 0) - nr = 20003; - if (strncmp(buf, "TRM:", 4) == 0) - nr = 20004; - if (strncmp(buf, "THR:", 4) == 0) - nr = 20005; - if (strncmp(buf, "SPU:", 4) == 0) - nr = 20006; + nr = index_in_strings("NMI\0RES\nCAL\0TLB\0TRM\0THR\0SPU\0", buf); + if (nr != -1) { + nr += 20000; } else { /* bb_strtou doesn't eat leading spaces, using strtoul */ nr = strtoul(buf, NULL, 10); } + *p = ':'; + if (nr == -1) continue; @@ -430,33 +419,31 @@ static NOINLINE int process_timer_stats(void) while (fgets(buf, sizeof(buf), fp)) { const char *count, *process, *func; char *p; - int cnt; + int idx; count = skip_whitespace(buf); + if (strcmp(strchrnul(count, ' '), " total events") == 0) + break; p = strchr(count, ','); if (!p) continue; *p++ = '\0'; - if (strcmp(strchrnul(count, ' '), " total events") == 0) - break; - p = skip_whitespace(p); /* points to pid */ - -/* Find char ' ', then eat remaining spaces */ -#define ADVANCE(p) do { \ - (p) = strchr((p), ' '); \ - if (!(p)) \ - continue; \ - *(p) = '\0'; \ - (p)++; \ - (p) = skip_whitespace(p); \ -} while (0) - /* Get process name */ - ADVANCE(p); - process = p; - /* Get function */ - ADVANCE(p); + if (strchr(count, 'D')) + continue; /* deferred */ + p = skip_whitespace(p); /* points to pid now */ + process = NULL; + get_func_name: + p = strchr(p, ' '); + if (!p) + continue; + *p++ = '\0'; + p = skip_whitespace(p); + if (process == NULL) { + process = p; + goto get_func_name; + } func = p; -#undef ADVANCE + //if (strcmp(process, "swapper") == 0 // && strcmp(func, "hrtimer_start_range_ns (tick_sched_timer)\n") == 0 //) { @@ -471,38 +458,29 @@ static NOINLINE int process_timer_stats(void) //if (strcmp(process, "powertop") == 0) // continue; - if (strcmp(process, "insmod") == 0) - process = "[kernel module]"; - if (strcmp(process, "modprobe") == 0) - process = "[kernel module]"; - if (strcmp(process, "swapper") == 0) - process = ""; + idx = index_in_strings("insmod\0modprobe\0swapper\0", process); + if (idx != -1) { + process = idx < 2 ? "[kernel module]" : ""; + } strchrnul(p, '\n')[0] = '\0'; - { - char *tmp; - cnt = bb_strtoull(count, &tmp, 10); - p = tmp; - } - while (*p != '\0') { - if (*p++ == 'D') /* deferred */ - goto skip; - } + // 46D\01136\0kondemand/1\0do_dbs_timer (delayed_work_timer_fn) + // ^ ^ ^ + // count process func //if (strchr(process, '[')) sprintf(line, "%15.15s : %s", process, func); //else // sprintf(line, "%s", process); - save_line(line, cnt); - skip: ; + save_line(line, bb_strtoull(count, NULL, 10)); } fclose(fp); } n = 0; #if ENABLE_FEATURE_POWERTOP_PROCIRQ - if (strstr(buf, "total events")) { + if (strstr(buf, " total events")) { n = bb_strtoull(buf, NULL, 10) / G.total_cpus; if (n > 0 && n < G.interrupt_0) { sprintf(line, " : %s", "extra timer interrupt"); @@ -566,7 +544,7 @@ static NOINLINE void print_intel_cstates(void) if (!isdigit(d->d_name[3])) continue; - len = sprintf(fname, "/sys/devices/system/cpu/%s/cpuidle", d->d_name); + len = sprintf(fname, "%s/%s/cpuidle", "/sys/devices/system/cpu", d->d_name); dir = opendir(fname); if (!dir) continue; -- cgit v1.2.3-55-g6feb From 3bbfb58bec18990a2ee93f31ea1ee2fd19c4d9b2 Mon Sep 17 00:00:00 2001 From: Christian Hornung Date: Wed, 3 Nov 2010 14:08:00 +0100 Subject: ip: Fix command line option parsing of "ip route get ..." I found and fixed a bug in the command line options parsing of "ip route get": It was impossible to get any option other than the IP address recognized correctly, and e.g. the command "ip route get connected" just hung up infinitely in the options parsing loop instead of printing an error message. Signed-off-by: Christian Hornung Signed-off-by: Denys Vlasenko --- networking/libiproute/iproute.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/networking/libiproute/iproute.c b/networking/libiproute/iproute.c index f66774afe..f6071b463 100644 --- a/networking/libiproute/iproute.c +++ b/networking/libiproute/iproute.c @@ -788,8 +788,8 @@ static int iproute_get(char **argv) } req.r.rtm_dst_len = addr.bitlen; } - argv++; } + argv++; } if (req.r.rtm_dst_len == 0) { -- cgit v1.2.3-55-g6feb From dcb163aa8e7808b59aef3d3319c707e7d9ac4ce4 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Thu, 4 Nov 2010 23:22:40 +0100 Subject: powertop: replace erroneous \n with \0; make numberic conversion more robust Signed-off-by: Denys Vlasenko --- procps/powertop.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/procps/powertop.c b/procps/powertop.c index 4c3c3565e..87efbe892 100644 --- a/procps/powertop.c +++ b/procps/powertop.c @@ -323,18 +323,16 @@ static void process_irq_counts(void) */ *p = '\0'; /* Deal with non-maskable interrupts -- make up fake numbers */ - nr = index_in_strings("NMI\0RES\nCAL\0TLB\0TRM\0THR\0SPU\0", buf); - if (nr != -1) { + nr = index_in_strings("NMI\0RES\0CAL\0TLB\0TRM\0THR\0SPU\0", buf); + if (nr >= 0) { nr += 20000; } else { /* bb_strtou doesn't eat leading spaces, using strtoul */ + errno = 0; nr = strtoul(buf, NULL, 10); + if (errno) + continue; } - *p = ':'; - - if (nr == -1) - continue; - p++; /* 0: 143646045 153901007 IO-APIC-edge timer * ^ -- cgit v1.2.3-55-g6feb From dea28e1e558228d9c46cdb25c7f00986d9d52bcc Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Thu, 4 Nov 2010 23:30:11 +0100 Subject: powertop: fix last line detection in process_timer_stats() Signed-off-by: Denys Vlasenko --- procps/powertop.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/procps/powertop.c b/procps/powertop.c index 87efbe892..da7f05258 100644 --- a/procps/powertop.c +++ b/procps/powertop.c @@ -420,12 +420,12 @@ static NOINLINE int process_timer_stats(void) int idx; count = skip_whitespace(buf); - if (strcmp(strchrnul(count, ' '), " total events") == 0) - break; p = strchr(count, ','); if (!p) continue; *p++ = '\0'; + if (strcmp(skip_non_whitespace(count), " total events") == 0) + break; if (strchr(count, 'D')) continue; /* deferred */ p = skip_whitespace(p); /* points to pid now */ -- cgit v1.2.3-55-g6feb From 4909fec73eb3d4bbd2af17c2fb891b75291265e7 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sat, 6 Nov 2010 00:46:57 +0100 Subject: ls: fix -lg to show group (was showing user) Signed-off-by: Denys Vlasenko --- coreutils/ls.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/coreutils/ls.c b/coreutils/ls.c index e69f1afd9..72f58c253 100644 --- a/coreutils/ls.c +++ b/coreutils/ls.c @@ -182,7 +182,7 @@ static const unsigned opt_flags[] = { LIST_INO, /* i */ LIST_LONG | STYLE_LONG, /* l - remember LS_DISP_HR in mask! */ LIST_SHORT | STYLE_SINGLE, /* 1 */ - 0, /* g (don't show group) - handled via OPT_g */ + 0, /* g (don't show owner) - handled via OPT_g */ LIST_ID_NUMERIC, /* n */ LIST_BLOCKS, /* s */ DISP_ROWS, /* x */ @@ -620,7 +620,7 @@ static NOINLINE unsigned list_single(const struct dnode *dn) if (all_fmt & LIST_ID_NAME) { if (option_mask32 & OPT_g) { column += printf("%-8.8s ", - get_cached_username(dn->dstat.st_uid)); + get_cached_groupname(dn->dstat.st_gid)); } else { column += printf("%-8.8s %-8.8s ", get_cached_username(dn->dstat.st_uid), @@ -630,7 +630,7 @@ static NOINLINE unsigned list_single(const struct dnode *dn) #endif if (all_fmt & LIST_ID_NUMERIC) { if (option_mask32 & OPT_g) - column += printf("%-8u ", (int) dn->dstat.st_uid); + column += printf("%-8u ", (int) dn->dstat.st_gid); else column += printf("%-8u %-8u ", (int) dn->dstat.st_uid, -- cgit v1.2.3-55-g6feb From 0ebafcc5b14b8c22a4a10f13328b996f8d85c2a5 Mon Sep 17 00:00:00 2001 From: Maksym Kryzhanovskyy Date: Sat, 6 Nov 2010 01:56:19 +0100 Subject: powertop: code shrink function old new delta process_timer_stats 490 449 -41 Signed-off-by: Maksym Kryzhanovskyy Signed-off-by: Denys Vlasenko --- procps/powertop.c | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/procps/powertop.c b/procps/powertop.c index da7f05258..2f977a03b 100644 --- a/procps/powertop.c +++ b/procps/powertop.c @@ -399,6 +399,7 @@ static NOINLINE int process_timer_stats(void) buf[0] = '\0'; totalticks = 0; + n = 0; fp = NULL; if (!G.cant_enable_timer_stats) fp = fopen_for_read("/proc/timer_stats"); @@ -418,14 +419,24 @@ static NOINLINE int process_timer_stats(void) const char *count, *process, *func; char *p; int idx; + unsigned cnt; count = skip_whitespace(buf); p = strchr(count, ','); if (!p) continue; *p++ = '\0'; - if (strcmp(skip_non_whitespace(count), " total events") == 0) + cnt = bb_strtou(count, NULL, 10); + if (strcmp(skip_non_whitespace(count), " total events") == 0) { +#if ENABLE_FEATURE_POWERTOP_PROCIRQ + n = cnt / G.total_cpus; + if (n > 0 && n < G.interrupt_0) { + sprintf(line, " : %s", "extra timer interrupt"); + save_line(line, G.interrupt_0 - n); + } +#endif break; + } if (strchr(count, 'D')) continue; /* deferred */ p = skip_whitespace(p); /* points to pid now */ @@ -471,21 +482,11 @@ static NOINLINE int process_timer_stats(void) sprintf(line, "%15.15s : %s", process, func); //else // sprintf(line, "%s", process); - save_line(line, bb_strtoull(count, NULL, 10)); + save_line(line, cnt); } fclose(fp); } - n = 0; -#if ENABLE_FEATURE_POWERTOP_PROCIRQ - if (strstr(buf, " total events")) { - n = bb_strtoull(buf, NULL, 10) / G.total_cpus; - if (n > 0 && n < G.interrupt_0) { - sprintf(line, " : %s", "extra timer interrupt"); - save_line(line, G.interrupt_0 - n); - } - } -#endif return n; } -- cgit v1.2.3-55-g6feb From 1586c7a92c9fd69967706c13b68eb8eb8fba54ed Mon Sep 17 00:00:00 2001 From: Tito Ragusa Date: Sat, 6 Nov 2010 22:14:55 +0100 Subject: deluser: 2nd attempt at deluser/delgroup size reduction and improvements Signed-off-by: Tito Ragusa Signed-off-by: Denys Vlasenko --- loginutils/deluser.c | 99 +++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 70 insertions(+), 29 deletions(-) diff --git a/loginutils/deluser.c b/loginutils/deluser.c index 08ca266d0..5a159b205 100644 --- a/loginutils/deluser.c +++ b/loginutils/deluser.c @@ -14,41 +14,82 @@ int deluser_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int deluser_main(int argc, char **argv) { - if (argc != 2 - && (!ENABLE_FEATURE_DEL_USER_FROM_GROUP - || applet_name[3] != 'g' - || argc != 3) - ) { - bb_show_usage(); - } + /* User or group name */ + char *name; + /* Username (non-NULL only in "delgroup USER GROUP" case) */ + char *member; + /* Name of passwd or group file */ + const char *pfile; + /* Name of shadow or gshadow file */ + const char *sfile; + /* Are we deluser or delgroup? */ + bool do_deluser = (ENABLE_DELUSER && (!ENABLE_DELGROUP || applet_name[3] == 'u')); - if (geteuid()) + if (geteuid() != 0) bb_error_msg_and_die(bb_msg_perm_denied_are_you_root); - if (ENABLE_DELUSER && applet_name[3] == 'u') { - /* deluser USER */ - if (update_passwd(bb_path_passwd_file, argv[1], NULL, NULL) < 0) - return EXIT_FAILURE; - if (ENABLE_FEATURE_SHADOWPASSWDS) - if (update_passwd(bb_path_shadow_file, argv[1], NULL, NULL) < 0) - return EXIT_FAILURE; - } else if (ENABLE_DELGROUP) { - /* delgroup ... */ - if (!ENABLE_FEATURE_DEL_USER_FROM_GROUP || argc != 3) { - /* delgroup GROUP */ - if (update_passwd(bb_path_group_file, argv[1], NULL, NULL) < 0) - return EXIT_FAILURE; + name = argv[1]; + member = NULL; + + switch (argc) { + case 3: + if (!ENABLE_FEATURE_DEL_USER_FROM_GROUP || do_deluser) + break; + /* It's "delgroup USER GROUP" */ + member = name; + name = argv[2]; + /* Fallthrough */ + + case 2: + if (do_deluser) { + /* "deluser USER" */ + xgetpwnam(name); /* bail out if USER is wrong */ + pfile = bb_path_passwd_file; if (ENABLE_FEATURE_SHADOWPASSWDS) - if (update_passwd(bb_path_gshadow_file, argv[1], NULL, NULL) < 0) - return EXIT_FAILURE; + sfile = bb_path_shadow_file; } else { - /* delgroup USER GROUP */ - if (update_passwd(bb_path_group_file, argv[2], NULL, argv[1]) < 0) - return EXIT_FAILURE; + do_delgroup: + /* "delgroup GROUP" or "delgroup USER GROUP" */ + xgetgrnam(name); /* bail out if GROUP is wrong */ + if (!member) { + /* "delgroup GROUP". + * If user with tha same name exists, + * bail out. + */ +//BUG: check should be done by GID, not by matching name! +//1. find GROUP's GID +//2. check that /etc/passwd doesn't have lines of the form +// user:pwd:uid:GID:... +//3. bail out if at least one such line exists + if (getpwnam(name) != NULL) + bb_error_msg_and_die("'%s' still has '%s' as their primary group!", name, name); + } + pfile = bb_path_group_file; if (ENABLE_FEATURE_SHADOWPASSWDS) - if (update_passwd(bb_path_gshadow_file, argv[2], NULL, argv[1]) < 0) - return EXIT_FAILURE; + sfile = bb_path_gshadow_file; + } + + /* Modify pfile, then sfile */ + do { + if (update_passwd(pfile, name, NULL, member) == -1) + return EXIT_FAILURE; + if (ENABLE_FEATURE_SHADOWPASSWDS) { + pfile = sfile; + sfile = NULL; + } + } while (ENABLE_FEATURE_SHADOWPASSWDS && pfile); + + if (ENABLE_DELGROUP && do_deluser) { + /* "deluser USER" also should try to delete + * same-named group. IOW: do "delgroup USER" + */ +//TODO: check how it actually works in upstream. +//I suspect it is only done if group has no more members. + do_deluser = 0; + goto do_delgroup; } + return EXIT_SUCCESS; } - return EXIT_SUCCESS; + /* Reached only if number of command line args is wrong */ + bb_show_usage(); } -- cgit v1.2.3-55-g6feb From f595d8ed46d627af9808a3c881a0e9a7fb88e3cb Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sat, 6 Nov 2010 22:17:30 +0100 Subject: typo fix Signed-off-by: Denys Vlasenko --- loginutils/deluser.c | 2 +- scripts/cleanup_printf2puts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/loginutils/deluser.c b/loginutils/deluser.c index 5a159b205..12fbbc673 100644 --- a/loginutils/deluser.c +++ b/loginutils/deluser.c @@ -53,7 +53,7 @@ int deluser_main(int argc, char **argv) xgetgrnam(name); /* bail out if GROUP is wrong */ if (!member) { /* "delgroup GROUP". - * If user with tha same name exists, + * If user with the same name exists, * bail out. */ //BUG: check should be done by GID, not by matching name! diff --git a/scripts/cleanup_printf2puts b/scripts/cleanup_printf2puts index 446152e12..00193a842 100755 --- a/scripts/cleanup_printf2puts +++ b/scripts/cleanup_printf2puts @@ -3,7 +3,7 @@ # Processes current directory recursively: # printf("abc\n") -> puts("abc"). Beware of fprintf etc... -# BTW, gcc 4.1.2 already does tha same! Can't believe it... +# BTW, gcc 4.1.2 already does the same! Can't believe it... grep -lr 'printf\([^%%]*\\n"\)' . | grep '.[ch]$' | xargs -n1 \ sed -e 's/\([^A-Za-z0-9_]\)printf(\( *"[^%]*\)\\n")/\1puts(\2")/' -i -- cgit v1.2.3-55-g6feb From e057b0f94f679af834d5eb15e10c714c72c16740 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sun, 7 Nov 2010 17:51:58 +0100 Subject: delgroup: correct the check for users who still use the group Signed-off-by: Tito Signed-off-by: Denys Vlasenko --- loginutils/deluser.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/loginutils/deluser.c b/loginutils/deluser.c index 12fbbc673..8ee72ef6f 100644 --- a/loginutils/deluser.c +++ b/loginutils/deluser.c @@ -48,21 +48,21 @@ int deluser_main(int argc, char **argv) if (ENABLE_FEATURE_SHADOWPASSWDS) sfile = bb_path_shadow_file; } else { + struct group *gr; do_delgroup: /* "delgroup GROUP" or "delgroup USER GROUP" */ - xgetgrnam(name); /* bail out if GROUP is wrong */ + gr = xgetgrnam(name); /* bail out if GROUP is wrong */ if (!member) { - /* "delgroup GROUP". - * If user with the same name exists, - * bail out. - */ -//BUG: check should be done by GID, not by matching name! -//1. find GROUP's GID -//2. check that /etc/passwd doesn't have lines of the form -// user:pwd:uid:GID:... -//3. bail out if at least one such line exists - if (getpwnam(name) != NULL) - bb_error_msg_and_die("'%s' still has '%s' as their primary group!", name, name); + /* "delgroup GROUP" */ + struct passwd *pw; + struct passwd pwent; + /* Check if the group is in use */ +#define passwd_buf bb_common_bufsiz1 + while (!getpwent_r(&pwent, passwd_buf, sizeof(passwd_buf), &pw)) { + if (pwent.pw_gid == gr->gr_gid) + bb_error_msg_and_die("'%s' still has '%s' as their primary group!", pwent.pw_name, name); + } + //endpwent(); } pfile = bb_path_group_file; if (ENABLE_FEATURE_SHADOWPASSWDS) -- cgit v1.2.3-55-g6feb From a8dc97cb8204d2574de4d65889264427b0485f50 Mon Sep 17 00:00:00 2001 From: Tito Ragusa Date: Mon, 8 Nov 2010 05:44:11 +0100 Subject: deluser: do not warn spuriously when deleting group by deluser Signed-off-by: Tito Ragusa Signed-off-by: Denys Vlasenko --- loginutils/deluser.c | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/loginutils/deluser.c b/loginutils/deluser.c index 8ee72ef6f..47a10fe14 100644 --- a/loginutils/deluser.c +++ b/loginutils/deluser.c @@ -23,7 +23,7 @@ int deluser_main(int argc, char **argv) /* Name of shadow or gshadow file */ const char *sfile; /* Are we deluser or delgroup? */ - bool do_deluser = (ENABLE_DELUSER && (!ENABLE_DELGROUP || applet_name[3] == 'u')); + int do_deluser = (ENABLE_DELUSER && (!ENABLE_DELGROUP || applet_name[3] == 'u')); if (geteuid() != 0) bb_error_msg_and_die(bb_msg_perm_denied_are_you_root); @@ -51,7 +51,13 @@ int deluser_main(int argc, char **argv) struct group *gr; do_delgroup: /* "delgroup GROUP" or "delgroup USER GROUP" */ - gr = xgetgrnam(name); /* bail out if GROUP is wrong */ + if (do_deluser < 0) { /* delgroup after deluser? */ + gr = getgrnam(name); + if (!gr) + return EXIT_SUCCESS; + } else { + gr = xgetgrnam(name); /* bail out if GROUP is wrong */ + } if (!member) { /* "delgroup GROUP" */ struct passwd *pw; @@ -79,13 +85,15 @@ int deluser_main(int argc, char **argv) } } while (ENABLE_FEATURE_SHADOWPASSWDS && pfile); - if (ENABLE_DELGROUP && do_deluser) { + if (ENABLE_DELGROUP && do_deluser > 0) { /* "deluser USER" also should try to delete * same-named group. IOW: do "delgroup USER" */ -//TODO: check how it actually works in upstream. -//I suspect it is only done if group has no more members. - do_deluser = 0; +// On debian deluser is a perl script that calls userdel. +// From man userdel: +// If USERGROUPS_ENAB is defined to yes in /etc/login.defs, userdel will +// delete the group with the same name as the user. + do_deluser = -1; goto do_delgroup; } return EXIT_SUCCESS; -- cgit v1.2.3-55-g6feb From 2b662c5deceb43a10f815424de85c1416c379e2a Mon Sep 17 00:00:00 2001 From: Lauri Kasanen Date: Sat, 13 Nov 2010 23:16:05 +0100 Subject: libbb: remove unused variable Signed-off-by: Lauri Kasanen Signed-off-by: Denys Vlasenko --- libbb/appletlib.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/libbb/appletlib.c b/libbb/appletlib.c index d7c9288cb..c417a270d 100644 --- a/libbb/appletlib.c +++ b/libbb/appletlib.c @@ -103,14 +103,13 @@ void FAST_FUNC bb_show_usage(void) if (ENABLE_SHOW_USAGE) { #ifdef SINGLE_APPLET_STR /* Imagine that this applet is "true". Dont suck in printf! */ - const char *p; - const char *usage_string = p = unpack_usage_messages(); + const char *usage_string = unpack_usage_messages(); - if (*p == '\b') { + if (*usage_string == '\b') { full_write2_str("No help available.\n\n"); } else { full_write2_str("Usage: "SINGLE_APPLET_STR" "); - full_write2_str(p); + full_write2_str(usage_string); full_write2_str("\n\n"); } if (ENABLE_FEATURE_CLEAN_UP) -- cgit v1.2.3-55-g6feb From c08c3f5d262acab7082cca88d0b2a329184b133b Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sun, 14 Nov 2010 01:59:55 +0100 Subject: hush: preparatory patch for set -o pipefail support Signed-off-by: Denys Vlasenko --- shell/hush.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/shell/hush.c b/shell/hush.c index 9dd30c436..126aaf074 100644 --- a/shell/hush.c +++ b/shell/hush.c @@ -6309,7 +6309,8 @@ static int checkjobs(struct pipe *fg_pipe) #endif /* Were we asked to wait for fg pipe? */ if (fg_pipe) { - for (i = 0; i < fg_pipe->num_cmds; i++) { + i = fg_pipe->num_cmds; + while (--i >= 0) { debug_printf_jobs("check pid %d\n", fg_pipe->cmds[i].pid); if (fg_pipe->cmds[i].pid != childpid) continue; @@ -6338,19 +6339,19 @@ static int checkjobs(struct pipe *fg_pipe) } debug_printf_jobs("fg_pipe: alive_cmds %d stopped_cmds %d\n", fg_pipe->alive_cmds, fg_pipe->stopped_cmds); - if (fg_pipe->alive_cmds - fg_pipe->stopped_cmds <= 0) { + if (fg_pipe->alive_cmds == fg_pipe->stopped_cmds) { /* All processes in fg pipe have exited or stopped */ /* Note: *non-interactive* bash does not continue if all processes in fg pipe * are stopped. Testcase: "cat | cat" in a script (not on command line!) * and "killall -STOP cat" */ if (G_interactive_fd) { #if ENABLE_HUSH_JOB - if (fg_pipe->alive_cmds) + if (fg_pipe->alive_cmds != 0) insert_bg_job(fg_pipe); #endif return rcode; } - if (!fg_pipe->alive_cmds) + if (fg_pipe->alive_cmds == 0) return rcode; } /* There are still running processes in the fg pipe */ -- cgit v1.2.3-55-g6feb From 6696eac274b5dcf5932b211fe9ee748d8268a39c Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sun, 14 Nov 2010 02:01:50 +0100 Subject: hush: add support for "set -o pipefail" function old new delta checkjobs 467 517 +50 builtin_set 259 286 +27 o_opt_strings - 10 +10 hush_main 1011 1013 +2 ------------------------------------------------------------------------------ (add/remove: 1/0 grow/shrink: 3/0 up/down: 89/0) Total: 89 bytes Signed-off-by: Denys Vlasenko --- shell/hush.c | 124 +++++++++++++++++++++++++------ shell/hush_test/hush-misc/pipefail.right | 40 ++++++++++ shell/hush_test/hush-misc/pipefail.tests | 45 +++++++++++ 3 files changed, 186 insertions(+), 23 deletions(-) create mode 100644 shell/hush_test/hush-misc/pipefail.right create mode 100755 shell/hush_test/hush-misc/pipefail.tests diff --git a/shell/hush.c b/shell/hush.c index 126aaf074..50e9ce333 100644 --- a/shell/hush.c +++ b/shell/hush.c @@ -507,6 +507,7 @@ struct command { # define CMD_FUNCDEF 3 #endif + smalluint cmd_exitcode; /* if non-NULL, this "command" is { list }, ( list ), or a compound statement */ struct pipe *group; #if !BB_MMU @@ -637,6 +638,43 @@ struct function { #endif +/* set -/+o OPT support. (TODO: make it optional) + * bash supports the following opts: + * allexport off + * braceexpand on + * emacs on + * errexit off + * errtrace off + * functrace off + * hashall on + * histexpand off + * history on + * ignoreeof off + * interactive-comments on + * keyword off + * monitor on + * noclobber off + * noexec off + * noglob off + * nolog off + * notify off + * nounset off + * onecmd off + * physical off + * pipefail off + * posix off + * privileged off + * verbose off + * vi off + * xtrace off + */ +static const char o_opt_strings[] ALIGN1 = "pipefail\0"; +enum { + OPT_O_PIPEFAIL, + NUM_OPT_O +}; + + /* "Globals" within this file */ /* Sorted roughly by size (smaller offsets == smaller code) */ struct globals { @@ -675,6 +713,7 @@ struct globals { int last_jobid; pid_t saved_tty_pgrp; struct pipe *job_list; + char o_opt[NUM_OPT_O]; # define G_saved_tty_pgrp (G.saved_tty_pgrp) #else # define G_saved_tty_pgrp 0 @@ -6315,24 +6354,23 @@ static int checkjobs(struct pipe *fg_pipe) if (fg_pipe->cmds[i].pid != childpid) continue; if (dead) { + int ex; fg_pipe->cmds[i].pid = 0; fg_pipe->alive_cmds--; - if (i == fg_pipe->num_cmds - 1) { - /* last process gives overall exitstatus */ - rcode = WEXITSTATUS(status); - /* bash prints killer signal's name for *last* - * process in pipe (prints just newline for SIGINT). - * Mimic this. Example: "sleep 5" + (^\ or kill -QUIT) - */ - if (WIFSIGNALED(status)) { - int sig = WTERMSIG(status); + ex = WEXITSTATUS(status); + /* bash prints killer signal's name for *last* + * process in pipe (prints just newline for SIGINT). + * Mimic this. Example: "sleep 5" + (^\ or kill -QUIT) + */ + if (WIFSIGNALED(status)) { + int sig = WTERMSIG(status); + if (i == fg_pipe->num_cmds-1) printf("%s\n", sig == SIGINT ? "" : get_signame(sig)); - /* TODO: MIPS has 128 sigs (1..128), what if sig==128 here? - * Maybe we need to use sig | 128? */ - rcode = sig + 128; - } - IF_HAS_KEYWORDS(if (fg_pipe->pi_inverted) rcode = !rcode;) + /* TODO: MIPS has 128 sigs (1..128), what if sig==128 here? + * Maybe we need to use sig | 128? */ + ex = sig + 128; } + fg_pipe->cmds[i].cmd_exitcode = ex; } else { fg_pipe->cmds[i].is_stopped = 1; fg_pipe->stopped_cmds++; @@ -6341,6 +6379,15 @@ static int checkjobs(struct pipe *fg_pipe) fg_pipe->alive_cmds, fg_pipe->stopped_cmds); if (fg_pipe->alive_cmds == fg_pipe->stopped_cmds) { /* All processes in fg pipe have exited or stopped */ + i = fg_pipe->num_cmds; + while (--i >= 0) { + rcode = fg_pipe->cmds[i].cmd_exitcode; + /* usually last process gives overall exitstatus, + * but with "set -o pipefail", last *failed* process does */ + if (G.o_opt[OPT_O_PIPEFAIL] == 0 || rcode != 0) + break; + } + IF_HAS_KEYWORDS(if (fg_pipe->pi_inverted) rcode = !rcode;) /* Note: *non-interactive* bash does not continue if all processes in fg pipe * are stopped. Testcase: "cat | cat" in a script (not on command line!) * and "killall -STOP cat" */ @@ -7340,13 +7387,41 @@ static void set_fatal_handlers(void) } #endif -static int set_mode(const char cstate, const char mode) +static int set_mode(int state, char mode, const char *o_opt) { - int state = (cstate == '-' ? 1 : 0); + int idx; switch (mode) { - case 'n': G.n_mode = state; break; - case 'x': IF_HUSH_MODE_X(G_x_mode = state;) break; - default: return EXIT_FAILURE; + case 'n': + G.n_mode = state; + break; + case 'x': + IF_HUSH_MODE_X(G_x_mode = state;) + break; + case 'o': + if (!o_opt) { + /* "set -+o" without parameter. + * in bash, set -o produces this output: + * pipefail off + * and set +o: + * set +o pipefail + * We always use the second form. + */ + const char *p = o_opt_strings; + idx = 0; + while (*p) { + printf("set %co %s\n", (G.o_opt[idx] ? '-' : '+'), p); + idx++; + p += strlen(p) + 1; + } + break; + } + idx = index_in_strings(o_opt_strings, o_opt); + if (idx >= 0) { + G.o_opt[idx] = state; + break; + } + default: + return EXIT_FAILURE; } return EXIT_SUCCESS; } @@ -7586,7 +7661,7 @@ int hush_main(int argc, char **argv) #endif case 'n': case 'x': - if (set_mode('-', opt) == 0) /* no error */ + if (set_mode(1, opt, NULL) == 0) /* no error */ break; default: #ifndef BB_VER @@ -8376,15 +8451,18 @@ static int FAST_FUNC builtin_set(char **argv) } do { - if (!strcmp(arg, "--")) { + if (strcmp(arg, "--") == 0) { ++argv; goto set_argv; } if (arg[0] != '+' && arg[0] != '-') break; - for (n = 1; arg[n]; ++n) - if (set_mode(arg[0], arg[n])) + for (n = 1; arg[n]; ++n) { + if (set_mode((arg[0] == '-'), arg[n], argv[1])) goto error; + if (arg[n] == 'o' && argv[1]) + argv++; + } } while ((arg = *++argv) != NULL); /* Now argv[0] is 1st argument */ diff --git a/shell/hush_test/hush-misc/pipefail.right b/shell/hush_test/hush-misc/pipefail.right new file mode 100644 index 000000000..5845d8939 --- /dev/null +++ b/shell/hush_test/hush-misc/pipefail.right @@ -0,0 +1,40 @@ +Default: +true | true: +0 +1 +true | false: +1 +0 +false | true: +0 +1 +exit 2 | exit 3 | exit 4: +4 +0 +Pipefail on: +true | true: +0 +1 +true | false: +1 +0 +false | true: +1 +0 +exit 2 | exit 3 | exit 4: +4 +0 +Pipefail off: +true | true: +0 +1 +true | false: +1 +0 +false | true: +0 +1 +exit 2 | exit 3 | exit 4: +4 +0 +Done diff --git a/shell/hush_test/hush-misc/pipefail.tests b/shell/hush_test/hush-misc/pipefail.tests new file mode 100755 index 000000000..9df841861 --- /dev/null +++ b/shell/hush_test/hush-misc/pipefail.tests @@ -0,0 +1,45 @@ +echo Default: +echo "true | true:" + true | true; echo $? +! true | true; echo $? +echo "true | false:" + true | false; echo $? +! true | false; echo $? +echo "false | true:" + false | true; echo $? +! false | true; echo $? +echo "exit 2 | exit 3 | exit 4:" + exit 2 | exit 3 | exit 4; echo $? +! exit 2 | exit 3 | exit 4; echo $? + +echo Pipefail on: +set -o pipefail +echo "true | true:" + true | true; echo $? +! true | true; echo $? +echo "true | false:" + true | false; echo $? +! true | false; echo $? +echo "false | true:" + false | true; echo $? +! false | true; echo $? +echo "exit 2 | exit 3 | exit 4:" + exit 2 | exit 3 | exit 4; echo $? +! exit 2 | exit 3 | exit 4; echo $? + +echo Pipefail off: +set +o pipefail +echo "true | true:" + true | true; echo $? +! true | true; echo $? +echo "true | false:" + true | false; echo $? +! true | false; echo $? +echo "false | true:" + false | true; echo $? +! false | true; echo $? +echo "exit 2 | exit 3 | exit 4:" + exit 2 | exit 3 | exit 4; echo $? +! exit 2 | exit 3 | exit 4; echo $? + +echo Done -- cgit v1.2.3-55-g6feb From 2e9aeae4dbc7bd45640ac472ee6ecb7eaf89fe8d Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Mon, 15 Nov 2010 02:58:28 +0100 Subject: lineedit: create history files with mode 0600 Signed-off-by: Wolfram Sang Signed-off-by: Denys Vlasenko --- libbb/lineedit.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/libbb/lineedit.c b/libbb/lineedit.c index 68006ffba..d6c33541e 100644 --- a/libbb/lineedit.c +++ b/libbb/lineedit.c @@ -1336,7 +1336,7 @@ static void save_history(char *str) int fd; int len, len2; - fd = open(state->hist_file, O_WRONLY | O_CREAT | O_APPEND, 0666); + fd = open(state->hist_file, O_WRONLY | O_CREAT | O_APPEND, 0600); if (fd < 0) return; xlseek(fd, 0, SEEK_END); /* paranoia */ @@ -1351,10 +1351,8 @@ static void save_history(char *str) /* did we write so much that history file needs trimming? */ state->cnt_history_in_file++; if (state->cnt_history_in_file > MAX_HISTORY * 4) { - FILE *fp; char *new_name; line_input_t *st_temp; - int i; /* we may have concurrently written entries from others. * load them */ @@ -1364,8 +1362,12 @@ static void save_history(char *str) /* write out temp file and replace hist_file atomically */ new_name = xasprintf("%s.%u.new", state->hist_file, (int) getpid()); - fp = fopen_for_write(new_name); - if (fp) { + fd = open(state->hist_file, O_WRONLY | O_CREAT | O_TRUNC, 0600); + if (fd >= 0) { + FILE *fp; + int i; + + fp = xfdopen_for_write(fd); for (i = 0; i < st_temp->cnt_history; i++) fprintf(fp, "%s\n", st_temp->history[i]); fclose(fp); -- cgit v1.2.3-55-g6feb From 8ce1ad3097ca6b92293ca767f6e4ddd98ad0d90e Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Tue, 16 Nov 2010 07:15:00 -0500 Subject: depmod.pl: add recursive sanity check If modules contain circular dependencies, the depmod script will follow the circle forever. So add a simple sanity check to abort rather than chew up the CPU. Signed-off-by: Mike Frysinger --- examples/depmod.pl | 3 +++ 1 file changed, 3 insertions(+) diff --git a/examples/depmod.pl b/examples/depmod.pl index 8c6548d28..f324b121a 100755 --- a/examples/depmod.pl +++ b/examples/depmod.pl @@ -173,6 +173,9 @@ sub add_mod_deps $depth .= " "; warn "${depth}loading deps of module: $this_module\n" if $verbose; + if (length($depth) > 50) { + die "too much recursion (circular dependencies in modules?)"; + } foreach my $md (keys %{$mod->{$this_module}}) { add_mod_deps ($depth, $mod, $mod2, $module, $md); -- cgit v1.2.3-55-g6feb From b78d561ec79b6a7c29d14bf49c82b600815b2cc4 Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Tue, 16 Nov 2010 09:01:30 -0500 Subject: allow SKIP_STRIP to be set in the env Signed-off-by: Mike Frysinger --- Makefile.flags | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile.flags b/Makefile.flags index 60bb888d8..363300b52 100644 --- a/Makefile.flags +++ b/Makefile.flags @@ -4,7 +4,7 @@ BB_VER = $(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION) export BB_VER -SKIP_STRIP = n +SKIP_STRIP ?= n # -std=gnu99 needed for [U]LLONG_MAX on some systems CPPFLAGS += $(call cc-option,-std=gnu99,) -- cgit v1.2.3-55-g6feb From f718e3a0dbe47ed7ed0398fe4461d33c8f69c669 Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Tue, 16 Nov 2010 07:29:12 -0500 Subject: gen_build_files.sh: rewrite with sed The shell parsing of files is incredibly slow on many systems. With one report, the process was taking a minute or two which made people thing the build was hung. So rewrite the craziness with sed and proper shell functions. On an idle system, this cut the runtime by half. Signed-off-by: Mike Frysinger --- scripts/gen_build_files.sh | 100 +++++++++++++++++++++------------------------ 1 file changed, 47 insertions(+), 53 deletions(-) diff --git a/scripts/gen_build_files.sh b/scripts/gen_build_files.sh index 09a95b507..1c1edcc12 100755 --- a/scripts/gen_build_files.sh +++ b/scripts/gen_build_files.sh @@ -9,43 +9,54 @@ mkdir include 2>/dev/null srctree="$1" +status() { printf ' %-8s%s\n' "$1" "$2"; } +gen() { status "GEN" "$@"; } +chk() { status "CHK" "$@"; } + +generate() +{ + local src="$1" dst="$2" header="$3" insert="$4" + #chk "${dst}" + ( + echo "${header}" + if grep -qs '^INSERT$' "${src}"; then + sed -n '1,/^INSERT$/p' "${src}" + echo "${insert}" + sed -n '/^INSERT$/,$p' "${src}" + else + if [ -n "${insert}" ]; then + echo "ERROR: INSERT line missing in: ${src}" 1>&2 + fi + cat "${src}" + fi + ) | sed '/^INSERT$/d' > "${dst}.tmp" + if ! cmp -s "${dst}" "${dst}.tmp"; then + gen "${dst}" + mv "${dst}.tmp" "${dst}" + else + rm -f "${dst}.tmp" + fi +} + # (Re)generate include/applets.h -src="$srctree/include/applets.src.h" -dst="include/applets.h" s=`sed -n 's@^//applet:@@p' -- "$srctree"/*/*.c "$srctree"/*/*/*.c` -old=`cat "$dst" 2>/dev/null` -# Why "IFS='' read -r REPLY"?? -# This atrocity is needed to read lines without mangling. -# IFS='' prevents whitespace trimming, -# -r suppresses backslash handling. -new=`echo "/* DO NOT EDIT. This file is generated from applets.src.h */" -while IFS='' read -r REPLY; do - test x"$REPLY" = x"INSERT" && REPLY="$s" - printf "%s\n" "$REPLY" -done <"$src"` -if test x"$new" != x"$old"; then - echo " GEN $dst" - printf "%s\n" "$new" >"$dst" -fi +generate \ + "$srctree/include/applets.src.h" \ + "include/applets.h" \ + "/* DO NOT EDIT. This file is generated from applets.src.h */" \ + "${s}" # (Re)generate include/usage.h -src="$srctree/include/usage.src.h" -dst="include/usage.h" # We add line continuation backslash after each line, # and insert empty line before each line which doesn't start # with space or tab # (note: we need to use \\\\ because of ``) s=`sed -n -e 's@^//usage:\([ \t].*\)$@\1 \\\\@p' -e 's@^//usage:\([^ \t].*\)$@\n\1 \\\\@p' -- "$srctree"/*/*.c "$srctree"/*/*/*.c` -old=`cat "$dst" 2>/dev/null` -new=`echo "/* DO NOT EDIT. This file is generated from usage.src.h */" -while IFS='' read -r REPLY; do - test x"$REPLY" = x"INSERT" && REPLY="$s" - printf "%s\n" "$REPLY" -done <"$src"` -if test x"$new" != x"$old"; then - echo " GEN $dst" - printf "%s\n" "$new" >"$dst" -fi +generate \ + "$srctree/include/usage.src.h" \ + "include/usage.h" \ + "/* DO NOT EDIT. This file is generated from usage.src.h */" \ + "${s}" # (Re)generate */Kbuild and */Config.in { cd -- "$srctree" && find . -type d; } | while read -r d; do @@ -55,42 +66,25 @@ fi dst="$d/Kbuild" if test -f "$src"; then mkdir -p -- "$d" 2>/dev/null - #echo " CHK $dst" s=`sed -n 's@^//kbuild:@@p' -- "$srctree/$d"/*.c` - - old=`cat "$dst" 2>/dev/null` - new=`echo "# DO NOT EDIT. This file is generated from Kbuild.src" - while IFS='' read -r REPLY; do - test x"$REPLY" = x"INSERT" && REPLY="$s" - printf "%s\n" "$REPLY" - done <"$src"` - if test x"$new" != x"$old"; then - echo " GEN $dst" - printf "%s\n" "$new" >"$dst" - fi + generate \ + "${src}" "${dst}" \ + "# DO NOT EDIT. This file is generated from Kbuild.src" \ + "${s}" fi src="$srctree/$d/Config.src" dst="$d/Config.in" if test -f "$src"; then mkdir -p -- "$d" 2>/dev/null - #echo " CHK $dst" s=`sed -n 's@^//config:@@p' -- "$srctree/$d"/*.c` - - old=`cat "$dst" 2>/dev/null` - new=`echo "# DO NOT EDIT. This file is generated from Config.src" - while IFS='' read -r REPLY; do - test x"$REPLY" = x"INSERT" && REPLY="$s" - printf "%s\n" "$REPLY" - done <"$src"` - if test x"$new" != x"$old"; then - echo " GEN $dst" - printf "%s\n" "$new" >"$dst" - fi + generate \ + "${src}" "${dst}" \ + "# DO NOT EDIT. This file is generated from Config.src" \ + "${s}" fi done -# Last read failed. This is normal. Don't exit with its error code: exit 0 -- cgit v1.2.3-55-g6feb From b82ae98ea4d5216d20a5deedab2aa6153562337b Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sun, 21 Nov 2010 05:53:34 +0100 Subject: patch: busyboxify by migrating from toybox to busybox helpers function old new delta get_line 90 128 +38 bbconfig_config_bz2 4959 4965 +6 makedevs_main 1038 1035 -3 fail_hunk 133 130 -3 finish_oldfile 174 124 -50 patch_main 2066 1987 -79 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 2/4 up/down: 44/-135) Total: -91 bytes Signed-off-by: Denys Vlasenko --- editors/patch.c | 245 ++++++++++++++++++-------------------------------- testsuite/patch.tests | 4 +- 2 files changed, 87 insertions(+), 162 deletions(-) diff --git a/editors/patch.c b/editors/patch.c index 33ff8b569..4fadbb8fe 100644 --- a/editors/patch.c +++ b/editors/patch.c @@ -1,8 +1,7 @@ -/* Adapted from toybox's patch. */ - /* vi: set sw=4 ts=4: * - * patch.c - Apply a "universal" diff. + * Apply a "universal" diff. + * Adapted from toybox's patch implementation. * * Copyright 2007 Rob Landley * @@ -20,29 +19,41 @@ * -f force (no questions asked) * -F fuzz (number, default 2) * [file] which file to patch + */ + +//applet:IF_PATCH(APPLET(patch, _BB_DIR_USR_BIN, _BB_SUID_DROP)) + +//kbuild:lib-$(CONFIG_PATCH) += patch.o + +//config:config PATCH +//config: bool "patch" +//config: default y +//config: help +//config: Apply a unified diff formatted patch. + +//usage:#define patch_trivial_usage +//usage: "[OPTIONS] [ORIGFILE [PATCHFILE]]" +//usage:#define patch_full_usage "\n\n" +//usage: IF_LONG_OPTS( +//usage: " -p,--strip N Strip N leading components from file names" +//usage: "\n -i,--input DIFF Read DIFF instead of stdin" +//usage: "\n -R,--reverse Reverse patch" +//usage: "\n -N,--forward Ignore already applied patches" +//usage: "\n --dry-run Don't actually change files" +//usage: "\n -E,--remove-empty-files Remove output files if they become empty" +//usage: ) +//usage: IF_NOT_LONG_OPTS( +//usage: " -p N Strip N leading components from file names" +//usage: "\n -i DIFF Read DIFF instead of stdin" +//usage: "\n -R Reverse patch" +//usage: "\n -N Ignore already applied patches" +//usage: "\n -E Remove output files if they become empty" +//usage: ) +//usage: +//usage:#define patch_example_usage +//usage: "$ patch -p1 < example.diff\n" +//usage: "$ patch -p0 -i example.diff" -USE_PATCH(NEWTOY(patch, USE_TOYBOX_DEBUG("x")"up#i:R", TOYFLAG_USR|TOYFLAG_BIN)) - -config PATCH - bool "patch" - default y - help - usage: patch [-i file] [-p depth] [-Ru] - - Apply a unified diff to one or more files. - - -i Input file (defaults=stdin) - -p number of '/' to strip from start of file paths (default=all) - -R Reverse patch. - -u Ignored (only handles "unified" diffs) - - This version of patch only handles unified diffs, and only modifies - a file when all all hunks to that file apply. Patch prints failed - hunks to stderr, and exits with nonzero status if any hunks fail. - - A file compared against /dev/null (or with a date <= the epoch) is - created or deleted if -E or --remove-empty-files set. -*/ #include "libbb.h" struct double_list { @@ -101,125 +112,6 @@ struct double_list *dlist_add(struct double_list **list, char *data) return line; } -// Ensure entire path exists. -// If mode != -1 set permissions on newly created dirs. -// Requires that path string be writable (for temporary null terminators). -static -void xmkpath(char *path, int mode) -{ - char *p, old; - mode_t mask; - int rc; - struct stat st; - - for (p = path; ; p++) { - if (!*p || *p == '/') { - old = *p; - *p = rc = 0; - if (stat(path, &st) || !S_ISDIR(st.st_mode)) { - if (mode != -1) { - mask = umask(0); - rc = mkdir(path, mode); - umask(mask); - } else rc = mkdir(path, 0777); - } - *p = old; - if(rc) bb_perror_msg_and_die("mkpath '%s'", path); - } - if (!*p) break; - } -} - -// Slow, but small. -static -char *get_rawline(int fd, long *plen, char end) -{ - char c, *buf = NULL; - long len = 0; - - for (;;) { - if (1>read(fd, &c, 1)) break; - if (!(len & 63)) buf=xrealloc(buf, len+65); - if ((buf[len++]=c) == end) break; - } - if (buf) buf[len]=0; - if (plen) *plen = len; - - return buf; -} - -static -char *get_line(int fd) -{ - long len; - char *buf = get_rawline(fd, &len, '\n'); - - if (buf && buf[--len]=='\n') buf[len]=0; - - return buf; -} - -// Copy the rest of in to out and close both files. -static -void xsendfile(int in, int out) -{ - long len; - char buf[4096]; - - if (in<0) return; - for (;;) { - len = safe_read(in, buf, 4096); - if (len<1) break; - xwrite(out, buf, len); - } -} - -// Copy the rest of the data and replace the original with the copy. -static -void replace_tempfile(int fdin, int fdout, char **tempname) -{ - char *temp = xstrdup(*tempname); - - temp[strlen(temp)-6]=0; - if (fdin != -1) { - xsendfile(fdin, fdout); - xclose(fdin); - } - xclose(fdout); - rename(*tempname, temp); - free(*tempname); - free(temp); - *tempname = NULL; -} - -// Open a temporary file to copy an existing file into. -static -int copy_tempfile(int fdin, char *name, char **tempname) -{ - struct stat statbuf; - int fd; - - *tempname = xasprintf("%sXXXXXX", name); - fd = xmkstemp(*tempname); - - // Set permissions of output file - fstat(fdin, &statbuf); - fchmod(fd, statbuf.st_mode); - - return fd; -} - -// Abort the copy and delete the temporary file. -static -void delete_tempfile(int fdin, int fdout, char **tempname) -{ - close(fdin); - close(fdout); - unlink(*tempname); - free(*tempname); - *tempname = NULL; -} - struct globals { @@ -229,7 +121,7 @@ struct globals { struct double_list *current_hunk; long oldline, oldlen, newline, newlen; long linenum; - int context, state, filein, fileout, filepatch, hunknum; + int context, state, filein, fileout, hunknum; char *tempname; // was toys.foo: @@ -263,7 +155,7 @@ struct globals { static void do_line(void *data) { - struct double_list *dlist = (struct double_list *)data; + struct double_list *dlist = data; if (TT.state>1 && *dlist->data != TT.state) fdprintf(TT.state == 2 ? 2 : TT.fileout, @@ -272,19 +164,36 @@ static void do_line(void *data) if (PATCH_DEBUG) fdprintf(2, "DO %d: %s\n", TT.state, dlist->data); free(dlist->data); - free(data); + free(dlist); } static void finish_oldfile(void) { - if (TT.tempname) replace_tempfile(TT.filein, TT.fileout, &TT.tempname); + if (TT.tempname) { + // Copy the rest of the data and replace the original with the copy. + char *temp; + + if (TT.filein != -1) { + bb_copyfd_eof(TT.filein, TT.fileout); + xclose(TT.filein); + } + xclose(TT.fileout); + + temp = xstrdup(TT.tempname); + temp[strlen(temp) - 6] = '\0'; + rename(TT.tempname, temp); + free(temp); + + free(TT.tempname); + TT.tempname = NULL; + } TT.fileout = TT.filein = -1; } static void fail_hunk(void) { if (!TT.current_hunk) return; - TT.current_hunk->prev->next = 0; + TT.current_hunk->prev->next = NULL; fdprintf(2, "Hunk %d FAILED %ld/%ld.\n", TT.hunknum, TT.oldline, TT.newline); TT.exitval = 1; @@ -295,7 +204,14 @@ static void fail_hunk(void) TT.state = 2; llist_free(TT.current_hunk, do_line); TT.current_hunk = NULL; - delete_tempfile(TT.filein, TT.fileout, &TT.tempname); + + // Abort the copy and delete the temporary file. + close(TT.filein); + close(TT.fileout); + unlink(TT.tempname); + free(TT.tempname); + TT.tempname = NULL; + TT.state = 0; } @@ -334,7 +250,7 @@ static int apply_one_hunk(void) plist = TT.current_hunk; buf = NULL; if (TT.context) for (;;) { - char *data = get_line(TT.filein); + char *data = xmalloc_reads(TT.filein, NULL, NULL); TT.linenum++; @@ -368,7 +284,9 @@ static int apply_one_hunk(void) // File ended before we found a place for this hunk. fail_hunk(); goto done; - } else if (PATCH_DEBUG) fdprintf(2, "IN: %s\n", data); + } + + if (PATCH_DEBUG) fdprintf(2, "IN: %s\n", data); check = dlist_add(&buf, data); // Compare this line with next expected line of hunk. @@ -398,8 +316,8 @@ static int apply_one_hunk(void) // If we've reached the end of the buffer without confirming a // match, read more lines. - if (check==buf) { - buf = 0; + if (check == buf) { + buf = NULL; break; } check = buf; @@ -453,10 +371,10 @@ int patch_main(int argc UNUSED_PARAM, char **argv) TT.prefix = (opts & FLAG_PATHLEN) ? xatoi(opt_p) : 0; // can be negative! TT.filein = TT.fileout = -1; if (opts & FLAG_INPUT) { - TT.filepatch = xopen_stdin(opt_i); + xmove_fd(xopen_stdin(opt_i), STDIN_FILENO); } else { if (argv[0] && argv[1]) { - TT.filepatch = xopen_stdin(argv[1]); + xmove_fd(xopen_stdin(argv[1]), STDIN_FILENO); } } if (argv[0]) { @@ -468,7 +386,7 @@ int patch_main(int argc UNUSED_PARAM, char **argv) for(;;) { char *patchline; - patchline = get_line(TT.filepatch); + patchline = xmalloc_fgetline(stdin); if (!patchline) break; // Other versions of patch accept damaged patches, @@ -588,13 +506,15 @@ int patch_main(int argc UNUSED_PARAM, char **argv) } // If we've got a file to open, do so. } else if (!(option_mask32 & FLAG_PATHLEN) || i <= TT.prefix) { + struct stat statbuf; + // If the old file was null, we're creating a new one. if (!strcmp(oldname, "/dev/null") || !oldsum) { printf("creating %s\n", name); s = strrchr(name, '/'); if (s) { *s = 0; - xmkpath(name, -1); + bb_make_directory(name, -1, FILEUTILS_RECUR); *s = '/'; } TT.filein = xopen(name, O_CREAT|O_EXCL|O_RDWR); @@ -602,7 +522,13 @@ int patch_main(int argc UNUSED_PARAM, char **argv) printf("patching file %s\n", name); TT.filein = xopen(name, O_RDONLY); } - TT.fileout = copy_tempfile(TT.filein, name, &TT.tempname); + + TT.tempname = xasprintf("%sXXXXXX", name); + TT.fileout = xmkstemp(TT.tempname); + // Set permissions of output file + fstat(TT.filein, &statbuf); + fchmod(TT.fileout, statbuf.st_mode); + TT.linenum = 0; TT.hunknum = 0; } @@ -620,7 +546,6 @@ int patch_main(int argc UNUSED_PARAM, char **argv) finish_oldfile(); if (ENABLE_FEATURE_CLEAN_UP) { - close(TT.filepatch); free(oldname); free(newname); } diff --git a/testsuite/patch.tests b/testsuite/patch.tests index e482304f6..ba37e8218 100755 --- a/testsuite/patch.tests +++ b/testsuite/patch.tests @@ -75,7 +75,7 @@ zxc testing "patch detects already applied hunk" \ 'patch 2>&1; echo $?; cat input' \ "\ -Possibly reversed hunk 1 at 2 +Possibly reversed hunk 1 at 4 Hunk 1 FAILED 1/1. abc +def @@ -103,7 +103,7 @@ def testing "patch detects already applied hunk at the EOF" \ 'patch 2>&1; echo $?; cat input' \ "\ -Possibly reversed hunk 1 at 3 +Possibly reversed hunk 1 at 4 Hunk 1 FAILED 1/1. abc 123 -- cgit v1.2.3-55-g6feb From 400ff226c2e20486b16759a7351ebf678ac327cf Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sun, 21 Nov 2010 05:54:28 +0100 Subject: patch: simplify double list helpers function old new delta dlist_free - 29 +29 fail_hunk 130 132 +2 patch_main 1987 1982 -5 dlist_add 59 54 -5 TOY_llist_pop 9 - -9 TOY_llist_free 54 - -54 ------------------------------------------------------------------------------ (add/remove: 1/2 grow/shrink: 1/2 up/down: 31/-73) Total: -42 bytes Signed-off-by: Denys Vlasenko --- editors/patch.c | 74 +++++++++++++++++++++++++-------------------------------- 1 file changed, 32 insertions(+), 42 deletions(-) diff --git a/editors/patch.c b/editors/patch.c index 4fadbb8fe..1d4a2554e 100644 --- a/editors/patch.c +++ b/editors/patch.c @@ -56,75 +56,64 @@ #include "libbb.h" + +// libbb candidate? + struct double_list { struct double_list *next; struct double_list *prev; char *data; }; -// Return the first item from the list, advancing the list (which must be called -// as &list) -static -void *TOY_llist_pop(void *list) -{ - // I'd use a void ** for the argument, and even accept the typecast in all - // callers as documentation you need the &, except the stupid compiler - // would then scream about type-punned pointers. Screw it. - void **llist = (void **)list; - void **next = (void **)*llist; - *llist = *next; - - return (void *)next; -} - // Free all the elements of a linked list -// if freeit!=NULL call freeit() on each element before freeing it. +// Call freeit() on each element before freeing it. static -void TOY_llist_free(void *list, void (*freeit)(void *data)) +void dlist_free(struct double_list *list, void (*freeit)(void *data)) { while (list) { - void *pop = TOY_llist_pop(&list); - if (freeit) freeit(pop); - else free(pop); - - // End doubly linked list too. - if (list==pop) break; + void *pop = list; + list = list->next; + freeit(pop); + // Bail out also if list is circular. + if (list == pop) break; } } -//Override bbox's names -#define llist_pop TOY_llist_pop -#define llist_free TOY_llist_free -// Add an entry to the end off a doubly linked list +// Add an entry before "list" element in (circular) doubly linked list static struct double_list *dlist_add(struct double_list **list, char *data) { - struct double_list *line = xmalloc(sizeof(struct double_list)); + struct double_list *llist; + struct double_list *line = xmalloc(sizeof(*line)); line->data = data; - if (*list) { - line->next = *list; - line->prev = (*list)->prev; - (*list)->prev->next = line; - (*list)->prev = line; - } else *list = line->next = line->prev = line; + llist = *list; + if (llist) { + struct double_list *p; + line->next = llist; + p = line->prev = llist->prev; + // (list is circular, we assume p is never NULL) + p->next = line; + llist->prev = line; + } else + *list = line->next = line->prev = line; return line; } - struct globals { char *infile; long prefix; struct double_list *current_hunk; + long oldline, oldlen, newline, newlen; long linenum; - int context, state, filein, fileout, hunknum; + int context, state, hunknum; + int filein, fileout; char *tempname; - // was toys.foo: int exitval; }; #define TT (*ptr_to_globals) @@ -193,7 +182,6 @@ static void finish_oldfile(void) static void fail_hunk(void) { if (!TT.current_hunk) return; - TT.current_hunk->prev->next = NULL; fdprintf(2, "Hunk %d FAILED %ld/%ld.\n", TT.hunknum, TT.oldline, TT.newline); TT.exitval = 1; @@ -202,7 +190,8 @@ static void fail_hunk(void) // this file and advance to next file. TT.state = 2; - llist_free(TT.current_hunk, do_line); + TT.current_hunk->prev->next = NULL; + dlist_free(TT.current_hunk, do_line); TT.current_hunk = NULL; // Abort the copy and delete the temporary file. @@ -308,7 +297,8 @@ static int apply_one_hunk(void) fdprintf(2, "NOT: %s\n", plist->data); TT.state = 3; - check = llist_pop(&buf); + check = buf; + buf = buf->next; check->prev->next = buf; buf->prev = check->prev; do_line(check); @@ -335,13 +325,13 @@ static int apply_one_hunk(void) out: // We have a match. Emit changed data. TT.state = "-+"[reverse ^ dummy_revert]; - llist_free(TT.current_hunk, do_line); + dlist_free(TT.current_hunk, do_line); TT.current_hunk = NULL; TT.state = 1; done: if (buf) { buf->prev->next = NULL; - llist_free(buf, do_line); + dlist_free(buf, do_line); } return TT.state; -- cgit v1.2.3-55-g6feb From ac10b30070d31f123ba95cf8e59c33a892efc5b0 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sun, 21 Nov 2010 18:11:40 +0100 Subject: cmp: with -s, do not report open errors Signed-off-by: Denys Vlasenko --- editors/cmp.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/editors/cmp.c b/editors/cmp.c index f495da7d2..f84a56e3e 100644 --- a/editors/cmp.c +++ b/editors/cmp.c @@ -33,8 +33,6 @@ int cmp_main(int argc UNUSED_PARAM, char **argv) unsigned opt; int retval = 0; - xfunc_error_retval = 2; /* 1 is returned if files are different. */ - opt_complementary = "-1" IF_DESKTOP(":?4") IF_NOT_DESKTOP(":?2") @@ -43,8 +41,6 @@ int cmp_main(int argc UNUSED_PARAM, char **argv) argv += optind; filename1 = *argv; - fp1 = xfopen_stdin(filename1); - if (*++argv) { filename2 = *argv; if (ENABLE_DESKTOP && *++argv) { @@ -55,6 +51,10 @@ int cmp_main(int argc UNUSED_PARAM, char **argv) } } + xfunc_error_retval = 2; /* missing file results in exitcode 2 */ + if (opt & CMP_OPT_s) + logmode = 0; /* -s suppresses open error messages */ + fp1 = xfopen_stdin(filename1); fp2 = xfopen_stdin(filename2); if (fp1 == fp2) { /* Paranoia check... stdin == stdin? */ /* Note that we don't bother reading stdin. Neither does gnu wc. @@ -63,6 +63,7 @@ int cmp_main(int argc UNUSED_PARAM, char **argv) */ return 0; } + logmode = LOGMODE_STDIO; if (opt & CMP_OPT_l) fmt = fmt_l_opt; -- cgit v1.2.3-55-g6feb From f9d091316ddaac7b278080f576c37b733427de8b Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sun, 21 Nov 2010 22:10:07 +0100 Subject: gen_build_files.sh: restore deleted comment Signed-off-by: Denys Vlasenko --- scripts/gen_build_files.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/gen_build_files.sh b/scripts/gen_build_files.sh index 1c1edcc12..130269b10 100755 --- a/scripts/gen_build_files.sh +++ b/scripts/gen_build_files.sh @@ -87,4 +87,5 @@ generate \ fi done +# Last read failed. This is normal. Don't exit with its error code: exit 0 -- cgit v1.2.3-55-g6feb From 7c6ed78aaa6f7252212869ab576eae1559645a3e Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Mon, 22 Nov 2010 03:15:21 +0100 Subject: patch: remove out-of-file build machinery Signed-off-by: Denys Vlasenko --- editors/Config.src | 6 ------ editors/Kbuild.src | 1 - include/applets.src.h | 1 - include/usage.src.h | 23 ----------------------- 4 files changed, 31 deletions(-) diff --git a/editors/Config.src b/editors/Config.src index fc824ccd5..201ee6eb9 100644 --- a/editors/Config.src +++ b/editors/Config.src @@ -60,12 +60,6 @@ config ED Small, simple, evil. Part of SUSv3. If you're not already using this, you don't need it. -config PATCH - bool "patch" - default y - help - Apply a unified diff formatted patch. - config SED bool "sed" default y diff --git a/editors/Kbuild.src b/editors/Kbuild.src index 98128064d..2f23ae12f 100644 --- a/editors/Kbuild.src +++ b/editors/Kbuild.src @@ -11,6 +11,5 @@ lib-$(CONFIG_AWK) += awk.o lib-$(CONFIG_CMP) += cmp.o lib-$(CONFIG_DIFF) += diff.o lib-$(CONFIG_ED) += ed.o -lib-$(CONFIG_PATCH) += patch.o lib-$(CONFIG_SED) += sed.o lib-$(CONFIG_VI) += vi.o diff --git a/include/applets.src.h b/include/applets.src.h index 879dbf760..06b4fff35 100644 --- a/include/applets.src.h +++ b/include/applets.src.h @@ -261,7 +261,6 @@ IF_OD(APPLET(od, _BB_DIR_USR_BIN, _BB_SUID_DROP)) IF_OPENVT(APPLET(openvt, _BB_DIR_USR_BIN, _BB_SUID_DROP)) //IF_PARSE(APPLET(parse, _BB_DIR_USR_BIN, _BB_SUID_DROP)) IF_PASSWD(APPLET(passwd, _BB_DIR_USR_BIN, _BB_SUID_REQUIRE)) -IF_PATCH(APPLET(patch, _BB_DIR_USR_BIN, _BB_SUID_DROP)) IF_PGREP(APPLET(pgrep, _BB_DIR_USR_BIN, _BB_SUID_DROP)) IF_PIDOF(APPLET(pidof, _BB_DIR_BIN, _BB_SUID_DROP)) IF_PING(APPLET(ping, _BB_DIR_BIN, _BB_SUID_MAYBE)) diff --git a/include/usage.src.h b/include/usage.src.h index 37b9d0747..30fef2440 100644 --- a/include/usage.src.h +++ b/include/usage.src.h @@ -2817,29 +2817,6 @@ INSERT "\n -m Use MD5 encryption instead of DES" \ ) -#define patch_trivial_usage \ - "[OPTIONS] [ORIGFILE [PATCHFILE]]" -#define patch_full_usage "\n\n" \ - IF_LONG_OPTS( \ - " -p,--strip N Strip N leading components from file names" \ - "\n -i,--input DIFF Read DIFF instead of stdin" \ - "\n -R,--reverse Reverse patch" \ - "\n -N,--forward Ignore already applied patches" \ - "\n --dry-run Don't actually change files" \ - "\n -E,--remove-empty-files Remove output files if they become empty" \ - ) \ - IF_NOT_LONG_OPTS( \ - " -p N Strip N leading components from file names" \ - "\n -i DIFF Read DIFF instead of stdin" \ - "\n -R Reverse patch" \ - "\n -N Ignore already applied patches" \ - "\n -E Remove output files if they become empty" \ - ) - -#define patch_example_usage \ - "$ patch -p1 < example.diff\n" \ - "$ patch -p0 -i example.diff" - #define pgrep_trivial_usage \ "[-flnovx] [-s SID|-P PPID|PATTERN]" #define pgrep_full_usage "\n\n" \ -- cgit v1.2.3-55-g6feb From f3763033e457b100a863731c16a80648d85995c9 Mon Sep 17 00:00:00 2001 From: Mike Shal Date: Mon, 22 Nov 2010 03:49:18 +0100 Subject: lineedit: fix tab-completion of filenames with spaces Using ash in busybox git version dea28e1e, tab completion doesn't seem to work properly for filenames that have special characters (such as spaces) in them. For example, with filenames "foo bar" and "foo zap", typing "ls fo" correctly expands to "ls foo\ ", but then continuing to type "b" will produce "ls foo\ bbar", which is not correct (the 'b' is duplicated). Signed-off-by: Mike Shal Signed-off-by: Denys Vlasenko --- libbb/lineedit.c | 67 +++++++++++++++++++++++++++++++++++++------------------- 1 file changed, 45 insertions(+), 22 deletions(-) diff --git a/libbb/lineedit.c b/libbb/lineedit.c index d6c33541e..5dd835cca 100644 --- a/libbb/lineedit.c +++ b/libbb/lineedit.c @@ -584,6 +584,12 @@ static void input_forward(void) #if ENABLE_FEATURE_TAB_COMPLETION +//FIXME: +//needs to be more clever: currently it thinks that "foo\ b +//matches the file named "foo bar", which is untrue. +//Also, perhaps "foo b needs to complete to "foo bar" , +//not "foo bar ... + static void free_tab_completion_data(void) { if (matches) { @@ -601,7 +607,7 @@ static void add_match(char *matched) num_matches++; } -#if ENABLE_FEATURE_USERNAME_COMPLETION +# if ENABLE_FEATURE_USERNAME_COMPLETION /* Replace "~user/..." with "/homedir/...". * The parameter is malloced, free it or return it * unchanged if no user is matched. @@ -657,7 +663,7 @@ static NOINLINE unsigned complete_username(const char *ud) return 1 + userlen; } -#endif /* FEATURE_USERNAME_COMPLETION */ +# endif /* FEATURE_USERNAME_COMPLETION */ enum { FIND_EXE_ONLY = 0, @@ -734,10 +740,10 @@ static NOINLINE unsigned complete_cmd_dir_file(const char *command, int type) pfind++; /* dirbuf = ".../.../.../" */ dirbuf = xstrndup(command, pfind - command); -#if ENABLE_FEATURE_USERNAME_COMPLETION +# if ENABLE_FEATURE_USERNAME_COMPLETION if (dirbuf[0] == '~') /* ~/... or ~user/... */ dirbuf = username_path_completion(dirbuf); -#endif +# endif path1[0] = dirbuf; } pf_len = strlen(pfind); @@ -1015,13 +1021,18 @@ static void showfiles(void) } } -static char *add_quote_for_spec_chars(char *found) +static const char *is_special_char(char c) +{ + return strchr(" `\"#$%^&*()=+{}[]:;'|\\<>", c); +} + +static char *quote_special_chars(char *found) { int l = 0; char *s = xzalloc((strlen(found) + 1) * 2); while (*found) { - if (strchr(" `\"#$%^&*()=+{}[]:;'|\\<>", *found)) + if (is_special_char(*found)) s[l++] = '\\'; s[l++] = *found++; } @@ -1038,10 +1049,10 @@ static NOINLINE void input_tab(smallint *lastWasTab) /* Length of string used for matching */ unsigned match_pfx_len = match_pfx_len; int find_type; -#if ENABLE_UNICODE_SUPPORT +# if ENABLE_UNICODE_SUPPORT /* cursor pos in command converted to multibyte form */ int cursor_mb; -#endif +# endif if (!(state->flags & TAB_COMPLETION)) return; @@ -1068,9 +1079,9 @@ static NOINLINE void input_tab(smallint *lastWasTab) * (we then also (ab)use this extra space later - see (**)) */ match_buf = xmalloc(MAX_LINELEN * sizeof(int16_t)); -#if !ENABLE_UNICODE_SUPPORT +# if !ENABLE_UNICODE_SUPPORT save_string(match_buf, cursor + 1); /* +1 for NUL */ -#else +# else { CHAR_T wc = command_ps[cursor]; command_ps[cursor] = BB_NUL; @@ -1078,26 +1089,37 @@ static NOINLINE void input_tab(smallint *lastWasTab) command_ps[cursor] = wc; cursor_mb = strlen(match_buf); } -#endif +# endif find_type = build_match_prefix(match_buf); /* Free up any memory already allocated */ free_tab_completion_data(); -#if ENABLE_FEATURE_USERNAME_COMPLETION - /* If the word starts with `~' and there is no slash in the word, +# if ENABLE_FEATURE_USERNAME_COMPLETION + /* If the word starts with ~ and there is no slash in the word, * then try completing this word as a username. */ if (state->flags & USERNAME_COMPLETION) if (match_buf[0] == '~' && strchr(match_buf, '/') == NULL) match_pfx_len = complete_username(match_buf); -#endif - /* Try to match a command in $PATH, or a directory, or a file */ +# endif + /* If complete_username() did not match, + * try to match a command in $PATH, or a directory, or a file */ if (!matches) match_pfx_len = complete_cmd_dir_file(match_buf, find_type); + + /* Account for backslashes which will be inserted + * by quote_special_chars() later */ + { + const char *e = match_buf + strlen(match_buf); + const char *s = e - match_pfx_len; + while (s < e) + if (is_special_char(*s++)) + match_pfx_len++; + } + /* Remove duplicates */ if (matches) { - unsigned i; - unsigned n = 0; + unsigned i, n = 0; qsort_string_vector(matches, num_matches); for (i = 0; i < num_matches - 1; ++i) { //if (matches[i] && matches[i+1]) { /* paranoia */ @@ -1112,6 +1134,7 @@ static NOINLINE void input_tab(smallint *lastWasTab) matches[n++] = matches[i]; num_matches = n; } + /* Did we find exactly one match? */ if (num_matches != 1) { /* no */ char *cp; @@ -1133,7 +1156,7 @@ static NOINLINE void input_tab(smallint *lastWasTab) goto ret; /* no */ } *cp = '\0'; - cp = add_quote_for_spec_chars(chosen_match); + cp = quote_special_chars(chosen_match); free(chosen_match); chosen_match = cp; len_found = strlen(chosen_match); @@ -1141,7 +1164,7 @@ static NOINLINE void input_tab(smallint *lastWasTab) /* Next is not a double-tab */ *lastWasTab = 0; - chosen_match = add_quote_for_spec_chars(matches[0]); + chosen_match = quote_special_chars(matches[0]); len_found = strlen(chosen_match); if (chosen_match[len_found-1] != '/') { chosen_match[len_found] = ' '; @@ -1149,7 +1172,7 @@ static NOINLINE void input_tab(smallint *lastWasTab) } } -#if !ENABLE_UNICODE_SUPPORT +# if !ENABLE_UNICODE_SUPPORT /* Have space to place the match? */ /* The result consists of three parts with these lengths: */ /* cursor + (len_found - match_pfx_len) + (command_len - cursor) */ @@ -1166,7 +1189,7 @@ static NOINLINE void input_tab(smallint *lastWasTab) /* write out the matched command */ redraw(cmdedit_y, command_len - pos); } -#else +# else { /* Use 2nd half of match_buf as scratch space - see (**) */ char *command = match_buf + MAX_LINELEN; @@ -1190,7 +1213,7 @@ static NOINLINE void input_tab(smallint *lastWasTab) redraw(cmdedit_y, pos >= 0 ? pos : 0); } } -#endif +# endif ret: free(chosen_match); free(match_buf); -- cgit v1.2.3-55-g6feb From a945f6190b9ffdd316e8590c0b4fcb25dee7676e Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Mon, 22 Nov 2010 04:57:37 +0100 Subject: inetd: if argv[0] is not specified, set it to program name With inetd.conf files that skip argv[], inetd execs programs with argc==0. Signed-off-by: Mike Frysinger Signed-off-by: Denys Vlasenko --- networking/inetd.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/networking/inetd.c b/networking/inetd.c index ac42c5272..fb00c6cd7 100644 --- a/networking/inetd.c +++ b/networking/inetd.c @@ -778,6 +778,12 @@ static servtab_t *parse_one_line(void) argc = 0; while ((arg = token[6+argc]) != NULL && argc < MAXARGV) sep->se_argv[argc++] = xstrdup(arg); + /* Some inetd.conf files have no argv's, not even argv[0]. + * Fix them up. + * (Technically, programs can be execed with argv[0] = NULL, + * but many programs do not like that at all) */ + if (argc == 0) + sep->se_argv[0] = xstrdup(sep->se_program); /* catch mixups. " stream udp ..." == wtf */ if (sep->se_socktype == SOCK_STREAM) { -- cgit v1.2.3-55-g6feb From 1e23f32453d8aa84c66c8f0bb9f753d68614d05a Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Mon, 22 Nov 2010 05:30:54 +0100 Subject: nc: fix SEGV on -v when NC_EXTRA is off Signed-off-by: Denys Vlasenko --- networking/nc_bloaty.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/networking/nc_bloaty.c b/networking/nc_bloaty.c index 8594a67a6..3c622e51e 100644 --- a/networking/nc_bloaty.c +++ b/networking/nc_bloaty.c @@ -766,7 +766,7 @@ int nc_main(int argc UNUSED_PARAM, char **argv) getopt32(argv, "hnp:s:uvw:" IF_NC_SERVER("l") IF_NC_EXTRA("i:o:z"), &str_p, &str_s, &o_wait - IF_NC_EXTRA(, &str_i, &str_o, &o_verbose)); + IF_NC_EXTRA(, &str_i, &str_o), &o_verbose); argv += optind; #if ENABLE_NC_EXTRA if (option_mask32 & OPT_i) /* line-interval time */ -- cgit v1.2.3-55-g6feb From 7b4c0fd5f4df4541a1659de04823326cd22c254e Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Mon, 22 Nov 2010 17:58:14 +0100 Subject: hush: fix improper handling of newline and hash chars in few corner cases Signed-off-by: Denys Vlasenko --- shell/hush.c | 253 ++++++++++++++-------------- shell/hush_test/hush-misc/assignment3.right | 2 + shell/hush_test/hush-misc/assignment3.tests | 5 + shell/hush_test/hush-parsing/comment1.right | 2 + shell/hush_test/hush-parsing/comment1.tests | 2 + shell/hush_test/hush-parsing/eol1.right | 1 + shell/hush_test/hush-parsing/eol1.tests | 18 ++ 7 files changed, 160 insertions(+), 123 deletions(-) create mode 100644 shell/hush_test/hush-misc/assignment3.right create mode 100755 shell/hush_test/hush-misc/assignment3.tests create mode 100644 shell/hush_test/hush-parsing/comment1.right create mode 100755 shell/hush_test/hush-parsing/comment1.tests create mode 100644 shell/hush_test/hush-parsing/eol1.right create mode 100755 shell/hush_test/hush-parsing/eol1.tests diff --git a/shell/hush.c b/shell/hush.c index 50e9ce333..da32c2435 100644 --- a/shell/hush.c +++ b/shell/hush.c @@ -543,7 +543,6 @@ struct command { #define IS_NULL_CMD(cmd) \ (!(cmd)->group && !(cmd)->argv && !(cmd)->redirects) - struct pipe { struct pipe *next; int num_cmds; /* total number of commands in pipe */ @@ -2622,6 +2621,94 @@ static void free_pipe_list(struct pipe *pi) /*** Parsing routines ***/ +#ifndef debug_print_tree +static void debug_print_tree(struct pipe *pi, int lvl) +{ + static const char *const PIPE[] = { + [PIPE_SEQ] = "SEQ", + [PIPE_AND] = "AND", + [PIPE_OR ] = "OR" , + [PIPE_BG ] = "BG" , + }; + static const char *RES[] = { + [RES_NONE ] = "NONE" , +# if ENABLE_HUSH_IF + [RES_IF ] = "IF" , + [RES_THEN ] = "THEN" , + [RES_ELIF ] = "ELIF" , + [RES_ELSE ] = "ELSE" , + [RES_FI ] = "FI" , +# endif +# if ENABLE_HUSH_LOOPS + [RES_FOR ] = "FOR" , + [RES_WHILE] = "WHILE", + [RES_UNTIL] = "UNTIL", + [RES_DO ] = "DO" , + [RES_DONE ] = "DONE" , +# endif +# if ENABLE_HUSH_LOOPS || ENABLE_HUSH_CASE + [RES_IN ] = "IN" , +# endif +# if ENABLE_HUSH_CASE + [RES_CASE ] = "CASE" , + [RES_CASE_IN ] = "CASE_IN" , + [RES_MATCH] = "MATCH", + [RES_CASE_BODY] = "CASE_BODY", + [RES_ESAC ] = "ESAC" , +# endif + [RES_XXXX ] = "XXXX" , + [RES_SNTX ] = "SNTX" , + }; + static const char *const CMDTYPE[] = { + "{}", + "()", + "[noglob]", +# if ENABLE_HUSH_FUNCTIONS + "func()", +# endif + }; + + int pin, prn; + + pin = 0; + while (pi) { + fprintf(stderr, "%*spipe %d res_word=%s followup=%d %s\n", lvl*2, "", + pin, RES[pi->res_word], pi->followup, PIPE[pi->followup]); + prn = 0; + while (prn < pi->num_cmds) { + struct command *command = &pi->cmds[prn]; + char **argv = command->argv; + + fprintf(stderr, "%*s cmd %d assignment_cnt:%d", + lvl*2, "", prn, + command->assignment_cnt); + if (command->group) { + fprintf(stderr, " group %s: (argv=%p)%s%s\n", + CMDTYPE[command->cmd_type], + argv +# if !BB_MMU + , " group_as_string:", command->group_as_string +# else + , "", "" +# endif + ); + debug_print_tree(command->group, lvl+1); + prn++; + continue; + } + if (argv) while (*argv) { + fprintf(stderr, " '%s'", *argv); + argv++; + } + fprintf(stderr, "\n"); + prn++; + } + pi = pi->next; + pin++; + } +} +#endif /* debug_print_tree */ + static struct pipe *new_pipe(void) { struct pipe *pi; @@ -4011,15 +4098,16 @@ static struct pipe *parse_stream(char **pstring, goto parse_error; } if (ch == '\n') { -#if ENABLE_HUSH_CASE - /* "case ... in word) ..." - - * newlines are ignored (but ';' wouldn't be) */ - if (ctx.command->argv == NULL - && ctx.ctx_res_w == RES_MATCH + /* Is this a case when newline is simply ignored? + * Some examples: + * "cmd | cmd ..." + * "case ... in word) ..." + */ + if (IS_NULL_CMD(ctx.command) + && dest.length == 0 && !dest.has_quoted_part ) { continue; } -#endif /* Treat newline as a command separator. */ done_pipe(&ctx, PIPE_SEQ); debug_printf_parse("heredoc_cnt:%d\n", heredoc_cnt); @@ -4151,6 +4239,31 @@ static struct pipe *parse_stream(char **pstring, if (parse_redirect(&ctx, redir_fd, redir_style, input)) goto parse_error; continue; /* back to top of while (1) */ + case '#': + if (dest.length == 0 && !dest.has_quoted_part) { + /* skip "#comment" */ + while (1) { + ch = i_peek(input); + if (ch == EOF || ch == '\n') + break; + i_getch(input); + /* note: we do not add it to &ctx.as_string */ + } + nommu_addchr(&ctx.as_string, '\n'); + continue; /* back to top of while (1) */ + } + break; + case '\\': + if (next == '\n') { + /* It's "\" */ +#if !BB_MMU + /* Remove trailing '\' from ctx.as_string */ + ctx.as_string.data[--ctx.as_string.length] = '\0'; +#endif + ch = i_getch(input); /* eat it */ + continue; /* back to top of while (1) */ + } + break; } if (dest.o_assignment == MAYBE_ASSIGNMENT @@ -4165,19 +4278,8 @@ static struct pipe *parse_stream(char **pstring, /* Note: nommu_addchr(&ctx.as_string, ch) is already done */ switch (ch) { - case '#': - if (dest.length == 0) { - while (1) { - ch = i_peek(input); - if (ch == EOF || ch == '\n') - break; - i_getch(input); - /* note: we do not add it to &ctx.as_string */ - } - nommu_addchr(&ctx.as_string, '\n'); - } else { - o_addQchr(&dest, ch); - } + case '#': /* non-comment #: "echo a#b" etc */ + o_addQchr(&dest, ch); break; case '\\': if (next == EOF) { @@ -4185,21 +4287,14 @@ static struct pipe *parse_stream(char **pstring, xfunc_die(); } ch = i_getch(input); - if (ch != '\n') { - o_addchr(&dest, '\\'); - /*nommu_addchr(&ctx.as_string, '\\'); - already done */ - o_addchr(&dest, ch); - nommu_addchr(&ctx.as_string, ch); - /* Example: echo Hello \2>file - * we need to know that word 2 is quoted */ - dest.has_quoted_part = 1; - } -#if !BB_MMU - else { - /* It's "\". Remove trailing '\' from ctx.as_string */ - ctx.as_string.data[--ctx.as_string.length] = '\0'; - } -#endif + /* note: ch != '\n' (that case does not reach this place) */ + o_addchr(&dest, '\\'); + /*nommu_addchr(&ctx.as_string, '\\'); - already done */ + o_addchr(&dest, ch); + nommu_addchr(&ctx.as_string, ch); + /* Example: echo Hello \2>file + * we need to know that word 2 is quoted */ + dest.has_quoted_part = 1; break; case '$': if (parse_dollar(&ctx.as_string, &dest, input, /*quote_mask:*/ 0) != 0) { @@ -6869,94 +6964,6 @@ static NOINLINE int run_pipe(struct pipe *pi) return -1; } -#ifndef debug_print_tree -static void debug_print_tree(struct pipe *pi, int lvl) -{ - static const char *const PIPE[] = { - [PIPE_SEQ] = "SEQ", - [PIPE_AND] = "AND", - [PIPE_OR ] = "OR" , - [PIPE_BG ] = "BG" , - }; - static const char *RES[] = { - [RES_NONE ] = "NONE" , -# if ENABLE_HUSH_IF - [RES_IF ] = "IF" , - [RES_THEN ] = "THEN" , - [RES_ELIF ] = "ELIF" , - [RES_ELSE ] = "ELSE" , - [RES_FI ] = "FI" , -# endif -# if ENABLE_HUSH_LOOPS - [RES_FOR ] = "FOR" , - [RES_WHILE] = "WHILE", - [RES_UNTIL] = "UNTIL", - [RES_DO ] = "DO" , - [RES_DONE ] = "DONE" , -# endif -# if ENABLE_HUSH_LOOPS || ENABLE_HUSH_CASE - [RES_IN ] = "IN" , -# endif -# if ENABLE_HUSH_CASE - [RES_CASE ] = "CASE" , - [RES_CASE_IN ] = "CASE_IN" , - [RES_MATCH] = "MATCH", - [RES_CASE_BODY] = "CASE_BODY", - [RES_ESAC ] = "ESAC" , -# endif - [RES_XXXX ] = "XXXX" , - [RES_SNTX ] = "SNTX" , - }; - static const char *const CMDTYPE[] = { - "{}", - "()", - "[noglob]", -# if ENABLE_HUSH_FUNCTIONS - "func()", -# endif - }; - - int pin, prn; - - pin = 0; - while (pi) { - fprintf(stderr, "%*spipe %d res_word=%s followup=%d %s\n", lvl*2, "", - pin, RES[pi->res_word], pi->followup, PIPE[pi->followup]); - prn = 0; - while (prn < pi->num_cmds) { - struct command *command = &pi->cmds[prn]; - char **argv = command->argv; - - fprintf(stderr, "%*s cmd %d assignment_cnt:%d", - lvl*2, "", prn, - command->assignment_cnt); - if (command->group) { - fprintf(stderr, " group %s: (argv=%p)%s%s\n", - CMDTYPE[command->cmd_type], - argv -# if !BB_MMU - , " group_as_string:", command->group_as_string -# else - , "", "" -# endif - ); - debug_print_tree(command->group, lvl+1); - prn++; - continue; - } - if (argv) while (*argv) { - fprintf(stderr, " '%s'", *argv); - argv++; - } - fprintf(stderr, "\n"); - prn++; - } - pi = pi->next; - pin++; - } -} -#endif /* debug_print_tree */ - /* NB: called by pseudo_exec, and therefore must not modify any * global data until exec/_exit (we can be a child after vfork!) */ static int run_list(struct pipe *pi) diff --git a/shell/hush_test/hush-misc/assignment3.right b/shell/hush_test/hush-misc/assignment3.right new file mode 100644 index 000000000..0f02d7cbc --- /dev/null +++ b/shell/hush_test/hush-misc/assignment3.right @@ -0,0 +1,2 @@ +Done:0 +abc=123 diff --git a/shell/hush_test/hush-misc/assignment3.tests b/shell/hush_test/hush-misc/assignment3.tests new file mode 100755 index 000000000..790129be1 --- /dev/null +++ b/shell/hush_test/hush-misc/assignment3.tests @@ -0,0 +1,5 @@ +# This must be interpreted as assignments +a=1 b\ +=2 c=3 +echo Done:$? +echo abc=$a$b$c diff --git a/shell/hush_test/hush-parsing/comment1.right b/shell/hush_test/hush-parsing/comment1.right new file mode 100644 index 000000000..a102b1d4e --- /dev/null +++ b/shell/hush_test/hush-parsing/comment1.right @@ -0,0 +1,2 @@ +Nothing: +String: #should-be-echoed diff --git a/shell/hush_test/hush-parsing/comment1.tests b/shell/hush_test/hush-parsing/comment1.tests new file mode 100755 index 000000000..d268860ff --- /dev/null +++ b/shell/hush_test/hush-parsing/comment1.tests @@ -0,0 +1,2 @@ +echo Nothing: #should-not-be-echoed +echo String: ""#should-be-echoed diff --git a/shell/hush_test/hush-parsing/eol1.right b/shell/hush_test/hush-parsing/eol1.right new file mode 100644 index 000000000..31c896f62 --- /dev/null +++ b/shell/hush_test/hush-parsing/eol1.right @@ -0,0 +1 @@ +Done:0 diff --git a/shell/hush_test/hush-parsing/eol1.tests b/shell/hush_test/hush-parsing/eol1.tests new file mode 100755 index 000000000..f1b55e8b8 --- /dev/null +++ b/shell/hush_test/hush-parsing/eol1.tests @@ -0,0 +1,18 @@ +# bug was that we treated as ';' in this line: +true || echo foo | +echo BAD1 | cat + +# variation on the same theme +true || echo foo | +# comment +echo BAD2 | cat + +# variation on the same theme +true || echo foo | + +echo BAD3 | cat + +# this should error out, but currently works in hush: +#true || echo foo |; + +echo Done:$? -- cgit v1.2.3-55-g6feb From 29ca1591335b2a73522c2c3ef43daff63c71e8dc Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Mon, 22 Nov 2010 18:13:15 +0100 Subject: fix misspelling in comment Signed-off-by: Denys Vlasenko --- libbb/getopt32.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libbb/getopt32.c b/libbb/getopt32.c index eb998009d..25bae319e 100644 --- a/libbb/getopt32.c +++ b/libbb/getopt32.c @@ -115,7 +115,7 @@ const char *opt_complementary found. "ww" Adjacent double options have a counter associated which indicates - the number of occurences of the option. + the number of occurrences of the option. For example the ps applet needs: if w is given once, GNU ps sets the width to 132, if w is given more than once, it is "unlimited" -- cgit v1.2.3-55-g6feb From 26777aa1c659b229f07205291241e45e64712a72 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Mon, 22 Nov 2010 23:49:10 +0100 Subject: fixes for bugs discovered by randomconfig builds and tests Signed-off-by: Denys Vlasenko --- libbb/Kbuild.src | 1 + scripts/randomtest.loop | 2 +- shell/ash.c | 9 ++++++++- shell/hush.c | 6 ++++-- testsuite/du/du-h-works | 2 +- testsuite/md5sum.tests | 5 +++++ util-linux/acpid.c | 11 ++++++----- 7 files changed, 26 insertions(+), 10 deletions(-) diff --git a/libbb/Kbuild.src b/libbb/Kbuild.src index 806cace28..0fa145159 100644 --- a/libbb/Kbuild.src +++ b/libbb/Kbuild.src @@ -158,6 +158,7 @@ lib-$(CONFIG_RTCWAKE) += rtc.o lib-$(CONFIG_IOSTAT) += get_cpu_count.o lib-$(CONFIG_MPSTAT) += get_cpu_count.o +lib-$(CONFIG_POWERTOP) += get_cpu_count.o # We shouldn't build xregcomp.c if we don't need it - this ensures we don't # require regex.h to be in the include dir even if we don't need it thereby diff --git a/scripts/randomtest.loop b/scripts/randomtest.loop index 311536df8..2c8a9bd35 100755 --- a/scripts/randomtest.loop +++ b/scripts/randomtest.loop @@ -4,7 +4,7 @@ test -d "$1" || { echo "'$1' is not a directory"; exit 1; } test -x "$1/scripts/randomtest" || { echo "No scripts/randomtest in '$1'"; exit 1; } export LIBC="uclibc" -export CROSS_COMPILER_PREFIX="i486-linux-uclibc-" +export CROSS_COMPILER_PREFIX="i686-" export MAKEOPTS="-j9" cnt=0 diff --git a/shell/ash.c b/shell/ash.c index 5ef7efbdb..5671a524b 100644 --- a/shell/ash.c +++ b/shell/ash.c @@ -43,7 +43,9 @@ #include #include "shell_common.h" -#include "math.h" +#if ENABLE_SH_MATH_SUPPORT +# include "math.h" +#endif #if ENABLE_ASH_RANDOM_SUPPORT # include "random.h" #else @@ -5510,6 +5512,11 @@ static struct arglist exparg; /* * Our own itoa(). */ +#if !ENABLE_SH_MATH_SUPPORT +/* cvtnum() is used even if math support is off (to prepare $? values and such) */ +typedef long arith_t; +# define ARITH_FMT "%ld" +#endif static int cvtnum(arith_t num) { diff --git a/shell/hush.c b/shell/hush.c index da32c2435..26a50744e 100644 --- a/shell/hush.c +++ b/shell/hush.c @@ -712,11 +712,11 @@ struct globals { int last_jobid; pid_t saved_tty_pgrp; struct pipe *job_list; - char o_opt[NUM_OPT_O]; # define G_saved_tty_pgrp (G.saved_tty_pgrp) #else # define G_saved_tty_pgrp 0 #endif + char o_opt[NUM_OPT_O]; smallint flag_SIGINT; #if ENABLE_HUSH_LOOPS smallint flag_break_continue; @@ -4500,7 +4500,9 @@ static struct pipe *parse_stream(char **pstring, expand_string_to_string(str) #endif static char *expand_string_to_string(const char *str, int do_unbackslash); +#if ENABLE_HUSH_TICK static int process_command_subs(o_string *dest, const char *s); +#endif /* expand_strvec_to_strvec() takes a list of strings, expands * all variable references within and returns a pointer to @@ -6579,7 +6581,7 @@ static int checkjobs_and_fg_shell(struct pipe *fg_pipe) * subshell: ( list ) [&] */ #if !ENABLE_HUSH_MODE_X -#define redirect_and_varexp_helper(new_env_p, old_vars_p, command, squirrel, char argv_expanded) \ +#define redirect_and_varexp_helper(new_env_p, old_vars_p, command, squirrel, argv_expanded) \ redirect_and_varexp_helper(new_env_p, old_vars_p, command, squirrel) #endif static int redirect_and_varexp_helper(char ***new_env_p, diff --git a/testsuite/du/du-h-works b/testsuite/du/du-h-works index c18433c29..1c77b6552 100644 --- a/testsuite/du/du-h-works +++ b/testsuite/du/du-h-works @@ -1,4 +1,4 @@ # FEATURE: CONFIG_FEATURE_HUMAN_READABLE dd if=/dev/zero of=file bs=1M count=1 2>/dev/null -test x"`busybox du -h .`" = x"1.0M ." +test x"`busybox du -h file`" = x"1.0M file" diff --git a/testsuite/md5sum.tests b/testsuite/md5sum.tests index 35ec67cb4..1068b083f 100755 --- a/testsuite/md5sum.tests +++ b/testsuite/md5sum.tests @@ -18,6 +18,11 @@ fi sum="$1" expected="$2" +test -f "$bindir/.config" && . "$bindir/.config" + +test x"$CONFIG_FEATURE_FANCY_HEAD" != x"y" \ +&& { echo "SKIPPED: $sum"; exit 0; } + text="The quick brown fox jumps over the lazy dog" text=`yes "$text" | head -c 9999` diff --git a/util-linux/acpid.c b/util-linux/acpid.c index 0b227a8ae..ce4c98ebe 100644 --- a/util-linux/acpid.c +++ b/util-linux/acpid.c @@ -16,9 +16,9 @@ enum { OPT_e = (1 << 2), OPT_f = (1 << 3), OPT_l = (1 << 4), - OPT_p = (1 << 5) * ENABLE_FEATURE_PIDFILE, - OPT_a = (1 << 6), - OPT_M = (1 << 7), + OPT_a = (1 << 5), + OPT_M = (1 << 6), + OPT_p = (1 << 7) * ENABLE_FEATURE_PIDFILE, }; struct acpi_event { @@ -199,8 +199,9 @@ int acpid_main(int argc UNUSED_PARAM, char **argv) INIT_G(); opt_complementary = "df:e--e"; - opts = getopt32(argv, "c:de:fl:p:a:M:" IF_FEATURE_ACPID_COMPAT("g:m:s:S:v"), - &opt_dir, &opt_input, &opt_logfile, &opt_pidfile, &opt_action, &opt_map + opts = getopt32(argv, "c:de:fl:a:M:" IF_FEATURE_PIDFILE("p:") IF_FEATURE_ACPID_COMPAT("g:m:s:S:v"), + &opt_dir, &opt_input, &opt_logfile, &opt_action, &opt_map + IF_FEATURE_PIDFILE(, &opt_pidfile) IF_FEATURE_ACPID_COMPAT(, NULL, NULL, NULL, NULL) ); -- cgit v1.2.3-55-g6feb From 9e0f15010e09951d02d76d618e055cb118e7d29b Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Tue, 23 Nov 2010 00:15:19 +0100 Subject: date :add a comment about older toolchains Signed-off-by: Denys Vlasenko --- coreutils/date.c | 1 + 1 file changed, 1 insertion(+) diff --git a/coreutils/date.c b/coreutils/date.c index a8040757d..d70957cf6 100644 --- a/coreutils/date.c +++ b/coreutils/date.c @@ -250,6 +250,7 @@ int date_main(int argc UNUSED_PARAM, char **argv) ts.tv_sec = statbuf.st_mtime; #if ENABLE_FEATURE_DATE_NANO ts.tv_nsec = statbuf.st_mtim.tv_nsec; + /* some toolchains use .st_mtimensec instead of st_mtim.tv_nsec */ #endif } else { #if ENABLE_FEATURE_DATE_NANO -- cgit v1.2.3-55-g6feb From 5ab20641d687bfe4d86d255f8c369af54b6026e7 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Tue, 23 Nov 2010 09:21:44 +0100 Subject: Bump version to 1.18.0 Signed-off-by: Denys Vlasenko --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 8fac9e9f9..1a9b676b5 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ VERSION = 1 PATCHLEVEL = 18 SUBLEVEL = 0 -EXTRAVERSION = .git +EXTRAVERSION = NAME = Unnamed # *DOCUMENTATION* -- cgit v1.2.3-55-g6feb From 7386dd1e8a659616e1dab1b013986e4ba00a4835 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Tue, 23 Nov 2010 12:50:40 +0100 Subject: Start 1.19.0 development cycle Signed-off-by: Denys Vlasenko --- Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 1a9b676b5..69854373b 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ VERSION = 1 -PATCHLEVEL = 18 +PATCHLEVEL = 19 SUBLEVEL = 0 -EXTRAVERSION = +EXTRAVERSION = .git NAME = Unnamed # *DOCUMENTATION* -- cgit v1.2.3-55-g6feb From 749e305d3671368a8d08de002f5235298ed1ed53 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Wed, 24 Nov 2010 15:06:49 +0100 Subject: build system: fix for dash Signed-off-by: Denys Vlasenko --- scripts/gen_build_files.sh | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/scripts/gen_build_files.sh b/scripts/gen_build_files.sh index 130269b10..ac8ccb933 100755 --- a/scripts/gen_build_files.sh +++ b/scripts/gen_build_files.sh @@ -18,14 +18,17 @@ generate() local src="$1" dst="$2" header="$3" insert="$4" #chk "${dst}" ( - echo "${header}" + # need to use printf: different shells have inconsistent + # rules re handling of "\n" in their params, + # and ${insert} definitely contains "\n" + printf "%s\n" "${header}" if grep -qs '^INSERT$' "${src}"; then sed -n '1,/^INSERT$/p' "${src}" - echo "${insert}" + printf "%s\n" "${insert}" sed -n '/^INSERT$/,$p' "${src}" else if [ -n "${insert}" ]; then - echo "ERROR: INSERT line missing in: ${src}" 1>&2 + printf "%s\n" "ERROR: INSERT line missing in: ${src}" 1>&2 fi cat "${src}" fi -- cgit v1.2.3-55-g6feb From 7a3f8e2fe13ec45990cab7e53d773fcb782d5fd3 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Thu, 25 Nov 2010 06:55:18 +0100 Subject: gen_build_files.sh: better comment Signed-off-by: Denys Vlasenko --- scripts/gen_build_files.sh | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/scripts/gen_build_files.sh b/scripts/gen_build_files.sh index ac8ccb933..03831f501 100755 --- a/scripts/gen_build_files.sh +++ b/scripts/gen_build_files.sh @@ -18,9 +18,10 @@ generate() local src="$1" dst="$2" header="$3" insert="$4" #chk "${dst}" ( - # need to use printf: different shells have inconsistent - # rules re handling of "\n" in their params, - # and ${insert} definitely contains "\n" + # Need to use printf: different shells have inconsistent + # rules re handling of "\n" in echo params, + # and ${insert} definitely contains "\n". + # Therefore, echo "${header}" would not work: printf "%s\n" "${header}" if grep -qs '^INSERT$' "${src}"; then sed -n '1,/^INSERT$/p' "${src}" -- cgit v1.2.3-55-g6feb From b271ad46dc85655d8ef077d57102b239b874097a Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Thu, 25 Nov 2010 07:59:17 +0100 Subject: blkid: add TODO Signed-off-by: Denys Vlasenko --- util-linux/blkid.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/util-linux/blkid.c b/util-linux/blkid.c index 4ce44b144..53f13a99c 100644 --- a/util-linux/blkid.c +++ b/util-linux/blkid.c @@ -10,6 +10,8 @@ #include "libbb.h" #include "volume_id.h" +//TODO: extend to take BLOCKDEV args, and show TYPE="fstype" + int blkid_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int blkid_main(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) { -- cgit v1.2.3-55-g6feb From fa5e295600b7810b5246daab8fca69de1f9b78b7 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sun, 28 Nov 2010 01:10:51 +0100 Subject: dhcpd: smaller code: do not look for REQUESTED_IP twice text data bss dec hex filename 883235 936 17192 901363 dc0f3 busybox_old 883219 936 17192 901347 dc0e3 busybox_unstripped Signed-off-by: Denys Vlasenko --- networking/udhcp/dhcpd.c | 56 ++++++++++++++++++++++++++---------------------- 1 file changed, 30 insertions(+), 26 deletions(-) diff --git a/networking/udhcp/dhcpd.c b/networking/udhcp/dhcpd.c index a015cf038..ac77b511d 100644 --- a/networking/udhcp/dhcpd.c +++ b/networking/udhcp/dhcpd.c @@ -133,7 +133,10 @@ static uint32_t select_lease_time(struct dhcp_packet *packet) /* We got a DHCP DISCOVER. Send an OFFER. */ /* NOINLINE: limit stack usage in caller */ -static NOINLINE void send_offer(struct dhcp_packet *oldpacket, uint32_t static_lease_nip, struct dyn_lease *lease) +static NOINLINE void send_offer(struct dhcp_packet *oldpacket, + uint32_t static_lease_nip, + struct dyn_lease *lease, + uint8_t *requested_ip_opt) { struct dhcp_packet packet; uint32_t lease_time_sec; @@ -147,7 +150,6 @@ static NOINLINE void send_offer(struct dhcp_packet *oldpacket, uint32_t static_l if (!static_lease_nip) { /* We have no static lease for client's chaddr */ uint32_t req_nip; - uint8_t *req_ip_opt; const char *p_host_name; if (lease) { @@ -158,9 +160,9 @@ static NOINLINE void send_offer(struct dhcp_packet *oldpacket, uint32_t static_l packet.yiaddr = lease->lease_nip; } /* Or: if client has requested an IP */ - else if ((req_ip_opt = udhcp_get_option(oldpacket, DHCP_REQUESTED_IP)) != NULL + else if (requested_ip_opt != NULL /* (read IP) */ - && (move_from_unaligned32(req_nip, req_ip_opt), 1) + && (move_from_unaligned32(req_nip, requested_ip_opt), 1) /* and the IP is in the lease range */ && ntohl(req_nip) >= server_config.start_ip && ntohl(req_nip) <= server_config.end_ip @@ -283,16 +285,12 @@ struct dyn_lease *g_leases; int udhcpd_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int udhcpd_main(int argc UNUSED_PARAM, char **argv) { - fd_set rfds; int server_socket = -1, retval, max_sock; - struct dhcp_packet packet; uint8_t *state; - uint32_t static_lease_nip; unsigned timeout_end; unsigned num_ips; unsigned opt; struct option_set *option; - struct dyn_lease *lease, fake_lease; IF_FEATURE_UDHCP_PORT(char *str_P;) #if ENABLE_FEATURE_UDHCP_PORT @@ -372,11 +370,15 @@ int udhcpd_main(int argc UNUSED_PARAM, char **argv) timeout_end = monotonic_sec() + server_config.auto_time; while (1) { /* loop until universe collapses */ + fd_set rfds; + struct dhcp_packet packet; int bytes; struct timeval tv; uint8_t *server_id_opt; - uint8_t *requested_opt; + uint8_t *requested_ip_opt; uint32_t requested_nip = requested_nip; /* for compiler */ + uint32_t static_lease_nip; + struct dyn_lease *lease, fake_lease; if (server_socket < 0) { server_socket = udhcp_listen_socket(/*INADDR_ANY,*/ SERVER_PORT, @@ -443,6 +445,18 @@ int udhcpd_main(int argc UNUSED_PARAM, char **argv) continue; } + /* Get SERVER_ID if present */ + server_id_opt = udhcp_get_option(&packet, DHCP_SERVER_ID); + if (server_id_opt) { + uint32_t server_id_net; + move_from_unaligned32(server_id_net, server_id_opt); + if (server_id_net != server_config.server_nip) { + /* client talks to somebody else */ + log1("server ID doesn't match, ignoring"); + continue; + } + } + /* Look for a static/dynamic lease */ static_lease_nip = get_static_nip_by_mac(server_config.static_leases, &packet.chaddr); if (static_lease_nip) { @@ -455,20 +469,10 @@ int udhcpd_main(int argc UNUSED_PARAM, char **argv) lease = find_lease_by_mac(packet.chaddr); } - /* Get REQUESTED_IP and SERVER_ID if present */ - server_id_opt = udhcp_get_option(&packet, DHCP_SERVER_ID); - if (server_id_opt) { - uint32_t server_id_net; - move_from_unaligned32(server_id_net, server_id_opt); - if (server_id_net != server_config.server_nip) { - /* client talks to somebody else */ - log1("server ID doesn't match, ignoring"); - continue; - } - } - requested_opt = udhcp_get_option(&packet, DHCP_REQUESTED_IP); - if (requested_opt) { - move_from_unaligned32(requested_nip, requested_opt); + /* Get REQUESTED_IP if present */ + requested_ip_opt = udhcp_get_option(&packet, DHCP_REQUESTED_IP); + if (requested_ip_opt) { + move_from_unaligned32(requested_nip, requested_ip_opt); } switch (state[0]) { @@ -476,7 +480,7 @@ int udhcpd_main(int argc UNUSED_PARAM, char **argv) case DHCPDISCOVER: log1("Received DISCOVER"); - send_offer(&packet, static_lease_nip, lease); + send_offer(&packet, static_lease_nip, lease, requested_ip_opt); break; case DHCPREQUEST: @@ -567,7 +571,7 @@ o DHCPREQUEST generated during REBINDING state: A DHCP server MAY extend a client's lease only if it has local administrative authority to do so. */ - if (!requested_opt) { + if (!requested_ip_opt) { requested_nip = packet.ciaddr; if (requested_nip == 0) { log1("no requested IP and no ciaddr, ignoring"); @@ -603,7 +607,7 @@ o DHCPREQUEST generated during REBINDING state: */ log1("Received DECLINE"); if (server_id_opt - && requested_opt + && requested_ip_opt && lease /* chaddr matches this lease */ && requested_nip == lease->lease_nip ) { -- cgit v1.2.3-55-g6feb From fe9403ad17d6cac5984fcb9b9e18ed755898afff Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sun, 28 Nov 2010 01:41:40 +0100 Subject: add a test for patch which we currently fail Signed-off-by: Denys Vlasenko --- testsuite/patch.tests | 37 +++++++++++++++++++++++++++++++++++++ testsuite/testing.sh | 1 + 2 files changed, 38 insertions(+) diff --git a/testsuite/patch.tests b/testsuite/patch.tests index ba37e8218..c604b9c1d 100755 --- a/testsuite/patch.tests +++ b/testsuite/patch.tests @@ -175,6 +175,43 @@ abc 123 " \ +# testing "test name" "command(s)" "expected result" "file input" "stdin" +testing "patch at the beginning" \ + 'patch 2>&1; cat input' \ +"\ +patching file input +111changed +444 +555 +666 +777 +888 +999 +" \ +"\ +111 +222 +333 +444 +555 +666 +777 +888 +999 +" \ +"\ +--- input ++++ input +@@ -1,6 +1,4 @@ +-111 +-222 +-333 ++111changed + 444 + 555 + 666 +" \ + rm input.orig 2>/dev/null exit $FAILCOUNT diff --git a/testsuite/testing.sh b/testsuite/testing.sh index c7c9ca6af..e7e64e58b 100644 --- a/testsuite/testing.sh +++ b/testsuite/testing.sh @@ -87,6 +87,7 @@ testing() $ECHO -ne "$3" > expected $ECHO -ne "$4" > input + [ -z "$VERBOSE" ] || echo ====================== [ -z "$VERBOSE" ] || echo "echo -ne '$4' >input" [ -z "$VERBOSE" ] || echo "echo -ne '$5' | $2" $ECHO -ne "$5" | eval "$2" > actual -- cgit v1.2.3-55-g6feb From 89ca2f99a20e78f392fb95d52d62cb32925bc9b2 Mon Sep 17 00:00:00 2001 From: Dan Fandrich Date: Sun, 28 Nov 2010 01:54:39 +0100 Subject: hush: display useful help text Signed-off-by: Dan Fandrich Signed-off-by: Denys Vlasenko --- shell/hush.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/shell/hush.c b/shell/hush.c index 26a50744e..a710f7cd9 100644 --- a/shell/hush.c +++ b/shell/hush.c @@ -245,9 +245,15 @@ //config: msh is deprecated and will be removed, please migrate to hush. //config: -//usage:#define hush_trivial_usage NOUSAGE_STR +/* -i (interactive) and -s (read stdin) are also accepted, + * but currently do nothing, therefore aren't shown in help. + * NOMMU-specific options are not meant to be used by users, + * therefore we don't show them either. + */ +//usage:#define hush_trivial_usage +//usage: "[-nx] [-c SCRIPT]" //usage:#define hush_full_usage "" -//usage:#define msh_trivial_usage NOUSAGE_STR +//usage:#define msh_trivial_usage hush_trivial_usage //usage:#define msh_full_usage "" //usage:#define sh_trivial_usage NOUSAGE_STR //usage:#define sh_full_usage "" -- cgit v1.2.3-55-g6feb From 85c62470b75b9256e36d8f488a0701aff94ca512 Mon Sep 17 00:00:00 2001 From: Dan Fandrich Date: Sat, 20 Nov 2010 13:05:17 -0800 Subject: Support set -o xtrace/noexec alternates for set -x/-n Signed-off-by: Dan Fandrich Signed-off-by: Denys Vlasenko --- shell/hush.c | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/shell/hush.c b/shell/hush.c index a710f7cd9..0cc587e19 100644 --- a/shell/hush.c +++ b/shell/hush.c @@ -673,9 +673,19 @@ struct function { * vi off * xtrace off */ -static const char o_opt_strings[] ALIGN1 = "pipefail\0"; +static const char o_opt_strings[] ALIGN1 = + "pipefail\0" + "noexec\0" +#if ENABLE_HUSH_MODE_X + "xtrace\0" +#endif + ; enum { OPT_O_PIPEFAIL, + OPT_O_NOEXEC, +#if ENABLE_HUSH_MODE_X + OPT_O_XTRACE, +#endif NUM_OPT_O }; @@ -734,10 +744,8 @@ struct globals { */ smallint flag_return_in_progress; #endif - smallint n_mode; #if ENABLE_HUSH_MODE_X - smallint x_mode; -# define G_x_mode (G.x_mode) +# define G_x_mode (G.o_opt[OPT_O_XTRACE]) #else # define G_x_mode 0 #endif @@ -7304,7 +7312,7 @@ static int run_and_free_list(struct pipe *pi) { int rcode = 0; debug_printf_exec("run_and_free_list entered\n"); - if (!G.n_mode) { + if (!G.o_opt[OPT_O_NOEXEC]) { debug_printf_exec(": run_list: 1st pipe with %d cmds\n", pi->num_cmds); rcode = run_list(pi); } @@ -7407,7 +7415,7 @@ static int set_mode(int state, char mode, const char *o_opt) int idx; switch (mode) { case 'n': - G.n_mode = state; + G.o_opt[OPT_O_NOEXEC] = state; break; case 'x': IF_HUSH_MODE_X(G_x_mode = state;) -- cgit v1.2.3-55-g6feb From 57542ebe4fee39b6d3091b964c42ce07ecfec7ef Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sun, 28 Nov 2010 03:59:30 +0100 Subject: hush: move G_x_mode define to the more appropriate place Signed-off-by: Denys Vlasenko --- shell/hush.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/shell/hush.c b/shell/hush.c index 0cc587e19..584af9e06 100644 --- a/shell/hush.c +++ b/shell/hush.c @@ -733,6 +733,11 @@ struct globals { # define G_saved_tty_pgrp 0 #endif char o_opt[NUM_OPT_O]; +#if ENABLE_HUSH_MODE_X +# define G_x_mode (G.o_opt[OPT_O_XTRACE]) +#else +# define G_x_mode 0 +#endif smallint flag_SIGINT; #if ENABLE_HUSH_LOOPS smallint flag_break_continue; @@ -743,11 +748,6 @@ struct globals { * 1: return is invoked, skip all till end of func */ smallint flag_return_in_progress; -#endif -#if ENABLE_HUSH_MODE_X -# define G_x_mode (G.o_opt[OPT_O_XTRACE]) -#else -# define G_x_mode 0 #endif smallint exiting; /* used to prevent EXIT trap recursion */ /* These four support $?, $#, and $1 */ -- cgit v1.2.3-55-g6feb From 1c31e9e82b12bdceeec4f8e07955984e20ee6b7e Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sun, 28 Nov 2010 04:34:09 +0100 Subject: use BB_EXECVP_or_die where appropriate Signed-off-by: Denys Vlasenko --- init/bootchartd.c | 3 +-- networking/nc_bloaty.c | 3 +-- selinux/runcon.c | 3 +-- 3 files changed, 3 insertions(+), 6 deletions(-) diff --git a/init/bootchartd.c b/init/bootchartd.c index 5a1b3e8e8..ac3f261c8 100644 --- a/init/bootchartd.c +++ b/init/bootchartd.c @@ -441,8 +441,7 @@ int bootchartd_main(int argc UNUSED_PARAM, char **argv) pid_t pid = xvfork(); if (pid == 0) { /* child */ argv += 2; - execvp(argv[0], argv); - bb_perror_msg_and_die("can't execute '%s'", argv[0]); + BB_EXECVP_or_die(argv); } /* parent */ waitpid(pid, NULL, 0); diff --git a/networking/nc_bloaty.c b/networking/nc_bloaty.c index 3c622e51e..e98a5dd5b 100644 --- a/networking/nc_bloaty.c +++ b/networking/nc_bloaty.c @@ -268,8 +268,7 @@ static int doexec(char **proggie) dup2(0, 1); /* dup2(0, 2); - do we *really* want this? NO! * exec'ed prog can do it yourself, if needed */ - execvp(proggie[0], proggie); - bb_perror_msg_and_die("can't execute '%s'", proggie[0]); + BB_EXECVP_or_die(proggie); } /* connect_w_timeout: diff --git a/selinux/runcon.c b/selinux/runcon.c index b70a5e396..54349b25c 100644 --- a/selinux/runcon.c +++ b/selinux/runcon.c @@ -132,6 +132,5 @@ int runcon_main(int argc UNUSED_PARAM, char **argv) bb_error_msg_and_die("can't set up security context '%s'", context_str(con)); - execvp(argv[0], argv); - bb_perror_msg_and_die("can't execute '%s'", argv[0]); + BB_EXECVP_or_die(argv); } -- cgit v1.2.3-55-g6feb From 713d241852ec726ad07920476fa18d0f9d455246 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sun, 28 Nov 2010 21:51:44 +0100 Subject: dhcpd: reply with NAK to clients in INIT-REBOOT state w/o existing lease We were not responding to them at all. Signed-off-by: Denys Vlasenko --- networking/udhcp/dhcpd.c | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/networking/udhcp/dhcpd.c b/networking/udhcp/dhcpd.c index ac77b511d..6fb48a19a 100644 --- a/networking/udhcp/dhcpd.c +++ b/networking/udhcp/dhcpd.c @@ -448,9 +448,9 @@ int udhcpd_main(int argc UNUSED_PARAM, char **argv) /* Get SERVER_ID if present */ server_id_opt = udhcp_get_option(&packet, DHCP_SERVER_ID); if (server_id_opt) { - uint32_t server_id_net; - move_from_unaligned32(server_id_net, server_id_opt); - if (server_id_net != server_config.server_nip) { + uint32_t server_id_network_order; + move_from_unaligned32(server_id_network_order, server_id_opt); + if (server_id_network_order != server_config.server_nip) { /* client talks to somebody else */ log1("server ID doesn't match, ignoring"); continue; @@ -584,11 +584,15 @@ o DHCPREQUEST generated during REBINDING state: send_ACK(&packet, lease->lease_nip); break; } - if (server_id_opt) { - /* client was talking specifically to us. - * "No, we don't have this IP for you". */ + /* No lease for this MAC, or lease IP != requested IP */ + + if (server_id_opt /* client is in SELECTING state */ + || requested_ip_opt /* client is in INIT-REBOOT state */ + ) { + /* "No, we don't have this IP for you" */ send_NAK(&packet); - } + } /* else: client is in RENEWING or REBINDING, do not answer */ + break; case DHCPDECLINE: -- cgit v1.2.3-55-g6feb From 714e2b7e6ab9cef6cb853c52b6c128d390964a25 Mon Sep 17 00:00:00 2001 From: Joachim Nilsson Date: Sun, 28 Nov 2010 23:01:18 +0100 Subject: ping: add -t TTL option function old new delta common_ping_main 1755 1796 +41 packed_usage 27954 27971 +17 bbconfig_config_bz2 4965 4966 +1 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 3/0 up/down: 59/0) Total: 59 bytes Signed-off-by: Joachim Nilsson Signed-off-by: Denys Vlasenko --- include/applets.src.h | 2 - include/usage.src.h | 55 ------------------------- networking/Config.src | 23 ----------- networking/Kbuild.src | 2 - networking/ping.c | 111 ++++++++++++++++++++++++++++++++++++++++++++++---- 5 files changed, 102 insertions(+), 91 deletions(-) diff --git a/include/applets.src.h b/include/applets.src.h index 06b4fff35..131fca504 100644 --- a/include/applets.src.h +++ b/include/applets.src.h @@ -263,8 +263,6 @@ IF_OPENVT(APPLET(openvt, _BB_DIR_USR_BIN, _BB_SUID_DROP)) IF_PASSWD(APPLET(passwd, _BB_DIR_USR_BIN, _BB_SUID_REQUIRE)) IF_PGREP(APPLET(pgrep, _BB_DIR_USR_BIN, _BB_SUID_DROP)) IF_PIDOF(APPLET(pidof, _BB_DIR_BIN, _BB_SUID_DROP)) -IF_PING(APPLET(ping, _BB_DIR_BIN, _BB_SUID_MAYBE)) -IF_PING6(APPLET(ping6, _BB_DIR_BIN, _BB_SUID_MAYBE)) IF_PIPE_PROGRESS(APPLET(pipe_progress, _BB_DIR_BIN, _BB_SUID_DROP)) IF_PIVOT_ROOT(APPLET(pivot_root, _BB_DIR_SBIN, _BB_SUID_DROP)) IF_PKILL(APPLET_ODDNAME(pkill, pgrep, _BB_DIR_USR_BIN, _BB_SUID_DROP, pkill)) diff --git a/include/usage.src.h b/include/usage.src.h index 30fef2440..7de2c6928 100644 --- a/include/usage.src.h +++ b/include/usage.src.h @@ -2859,61 +2859,6 @@ INSERT IF_FEATURE_PIDOF_OMIT( \ "$ pidof /bin/sh -o %PPID\n20351 5950") -#if !ENABLE_FEATURE_FANCY_PING -#define ping_trivial_usage \ - "host" -#define ping_full_usage "\n\n" \ - "Send ICMP ECHO_REQUEST packets to network hosts" -#define ping6_trivial_usage \ - "host" -#define ping6_full_usage "\n\n" \ - "Send ICMP ECHO_REQUEST packets to network hosts" -#else -#define ping_trivial_usage \ - "[OPTIONS] HOST" -#define ping_full_usage "\n\n" \ - "Send ICMP ECHO_REQUEST packets to network hosts\n" \ - "\nOptions:" \ - "\n -4,-6 Force IP or IPv6 name resolution" \ - "\n -c CNT Send only CNT pings" \ - "\n -s SIZE Send SIZE data bytes in packets (default:56)" \ - "\n -I IFACE/IP Use interface or IP address as source" \ - "\n -W SEC Seconds to wait for the first response (default:10)" \ - "\n (after all -c CNT packets are sent)" \ - "\n -w SEC Seconds until ping exits (default:infinite)" \ - "\n (can exit earlier with -c CNT)" \ - "\n -q Quiet, only displays output at start" \ - "\n and when finished" \ - -#define ping6_trivial_usage \ - "[OPTIONS] HOST" -#define ping6_full_usage "\n\n" \ - "Send ICMP ECHO_REQUEST packets to network hosts\n" \ - "\nOptions:" \ - "\n -c CNT Send only CNT pings" \ - "\n -s SIZE Send SIZE data bytes in packets (default:56)" \ - "\n -I IFACE/IP Use interface or IP address as source" \ - "\n -q Quiet, only displays output at start" \ - "\n and when finished" \ - -#endif -#define ping_example_usage \ - "$ ping localhost\n" \ - "PING slag (127.0.0.1): 56 data bytes\n" \ - "64 bytes from 127.0.0.1: icmp_seq=0 ttl=255 time=20.1 ms\n" \ - "\n" \ - "--- debian ping statistics ---\n" \ - "1 packets transmitted, 1 packets received, 0% packet loss\n" \ - "round-trip min/avg/max = 20.1/20.1/20.1 ms\n" -#define ping6_example_usage \ - "$ ping6 ip6-localhost\n" \ - "PING ip6-localhost (::1): 56 data bytes\n" \ - "64 bytes from ::1: icmp6_seq=0 ttl=64 time=20.1 ms\n" \ - "\n" \ - "--- ip6-localhost ping statistics ---\n" \ - "1 packets transmitted, 1 packets received, 0% packet loss\n" \ - "round-trip min/avg/max = 20.1/20.1/20.1 ms\n" - #define pipe_progress_trivial_usage NOUSAGE_STR #define pipe_progress_full_usage "" diff --git a/networking/Config.src b/networking/Config.src index 6dd7df754..274fcae3a 100644 --- a/networking/Config.src +++ b/networking/Config.src @@ -684,29 +684,6 @@ config FEATURE_NTPD_SERVER Make ntpd usable as a NTP server. If you disable this option ntpd will be usable only as a NTP client. -config PING - bool "ping" - default y - depends on PLATFORM_LINUX - help - ping uses the ICMP protocol's mandatory ECHO_REQUEST datagram to - elicit an ICMP ECHO_RESPONSE from a host or gateway. - -config PING6 - bool "ping6" - default y - depends on FEATURE_IPV6 && PING - help - This will give you a ping that can talk IPv6. - -config FEATURE_FANCY_PING - bool "Enable fancy ping output" - default y - depends on PING - help - Make the output from the ping applet include statistics, and at the - same time provide full support for ICMP packets. - config PSCAN bool "pscan" default y diff --git a/networking/Kbuild.src b/networking/Kbuild.src index f41a2df70..944f27be1 100644 --- a/networking/Kbuild.src +++ b/networking/Kbuild.src @@ -30,8 +30,6 @@ lib-$(CONFIG_NC) += nc.o lib-$(CONFIG_NETSTAT) += netstat.o lib-$(CONFIG_NSLOOKUP) += nslookup.o lib-$(CONFIG_NTPD) += ntpd.o -lib-$(CONFIG_PING) += ping.o -lib-$(CONFIG_PING6) += ping.o lib-$(CONFIG_PSCAN) += pscan.o lib-$(CONFIG_ROUTE) += route.o lib-$(CONFIG_SLATTACH) += slattach.o diff --git a/networking/ping.c b/networking/ping.c index 3aba4906e..8571d179b 100644 --- a/networking/ping.c +++ b/networking/ping.c @@ -29,6 +29,92 @@ #include #include "libbb.h" +//config:config PING +//config: bool "ping" +//config: default y +//config: depends on PLATFORM_LINUX +//config: help +//config: ping uses the ICMP protocol's mandatory ECHO_REQUEST datagram to +//config: elicit an ICMP ECHO_RESPONSE from a host or gateway. +//config: +//config:config PING6 +//config: bool "ping6" +//config: default y +//config: depends on FEATURE_IPV6 && PING +//config: help +//config: This will give you a ping that can talk IPv6. +//config: +//config:config FEATURE_FANCY_PING +//config: bool "Enable fancy ping output" +//config: default y +//config: depends on PING +//config: help +//config: Make the output from the ping applet include statistics, and at the +//config: same time provide full support for ICMP packets. + +//applet:IF_PING(APPLET(ping, _BB_DIR_BIN, _BB_SUID_MAYBE)) +//applet:IF_PING6(APPLET(ping6, _BB_DIR_BIN, _BB_SUID_MAYBE)) + +//kbuild:lib-$(CONFIG_PING) += ping.o +//kbuild:lib-$(CONFIG_PING6) += ping.o + +//usage:#if !ENABLE_FEATURE_FANCY_PING +//usage:# define ping_trivial_usage +//usage: "HOST" +//usage:# define ping_full_usage "\n\n" +//usage: "Send ICMP ECHO_REQUEST packets to network hosts" +//usage:# define ping6_trivial_usage +//usage: "HOST" +//usage:# define ping6_full_usage "\n\n" +//usage: "Send ICMP ECHO_REQUEST packets to network hosts" +//usage:#else +//usage:# define ping_trivial_usage +//usage: "[OPTIONS] HOST" +//usage:# define ping_full_usage "\n\n" +//usage: "Send ICMP ECHO_REQUEST packets to network hosts\n" +//usage: "\nOptions:" +//usage: "\n -4,-6 Force IP or IPv6 name resolution" +//usage: "\n -c CNT Send only CNT pings" +//usage: "\n -s SIZE Send SIZE data bytes in packets (default:56)" +//usage: "\n -t TTL Set TTL" +//usage: "\n -I IFACE/IP Use interface or IP address as source" +//usage: "\n -W SEC Seconds to wait for the first response (default:10)" +//usage: "\n (after all -c CNT packets are sent)" +//usage: "\n -w SEC Seconds until ping exits (default:infinite)" +//usage: "\n (can exit earlier with -c CNT)" +//usage: "\n -q Quiet, only displays output at start" +//usage: "\n and when finished" +//usage: +//usage:# define ping6_trivial_usage +//usage: "[OPTIONS] HOST" +//usage:# define ping6_full_usage "\n\n" +//usage: "Send ICMP ECHO_REQUEST packets to network hosts\n" +//usage: "\nOptions:" +//usage: "\n -c CNT Send only CNT pings" +//usage: "\n -s SIZE Send SIZE data bytes in packets (default:56)" +//usage: "\n -I IFACE/IP Use interface or IP address as source" +//usage: "\n -q Quiet, only displays output at start" +//usage: "\n and when finished" +//usage: +//usage:#endif +//usage: +//usage:#define ping_example_usage +//usage: "$ ping localhost\n" +//usage: "PING slag (127.0.0.1): 56 data bytes\n" +//usage: "64 bytes from 127.0.0.1: icmp_seq=0 ttl=255 time=20.1 ms\n" +//usage: "\n" +//usage: "--- debian ping statistics ---\n" +//usage: "1 packets transmitted, 1 packets received, 0% packet loss\n" +//usage: "round-trip min/avg/max = 20.1/20.1/20.1 ms\n" +//usage:#define ping6_example_usage +//usage: "$ ping6 ip6-localhost\n" +//usage: "PING ip6-localhost (::1): 56 data bytes\n" +//usage: "64 bytes from ::1: icmp6_seq=0 ttl=64 time=20.1 ms\n" +//usage: "\n" +//usage: "--- ip6-localhost ping statistics ---\n" +//usage: "1 packets transmitted, 1 packets received, 0% packet loss\n" +//usage: "round-trip min/avg/max = 20.1/20.1/20.1 ms\n" + #if ENABLE_PING6 # include /* I see RENUMBERED constants in bits/in.h - !!? @@ -223,17 +309,18 @@ static int common_ping_main(sa_family_t af, char **argv) /* Full(er) version */ -#define OPT_STRING ("qvc:s:w:W:I:4" IF_PING6("6")) +#define OPT_STRING ("qvc:s:t:w:W:I:4" IF_PING6("6")) enum { OPT_QUIET = 1 << 0, OPT_VERBOSE = 1 << 1, OPT_c = 1 << 2, OPT_s = 1 << 3, - OPT_w = 1 << 4, - OPT_W = 1 << 5, - OPT_I = 1 << 6, - OPT_IPV4 = 1 << 7, - OPT_IPV6 = (1 << 8) * ENABLE_PING6, + OPT_t = 1 << 4, + OPT_w = 1 << 5, + OPT_W = 1 << 6, + OPT_I = 1 << 7, + OPT_IPV4 = 1 << 8, + OPT_IPV6 = (1 << 9) * ENABLE_PING6, }; @@ -244,6 +331,7 @@ struct globals { len_and_sockaddr *source_lsa; unsigned datalen; unsigned pingcount; /* must be int-sized */ + unsigned opt_ttl; unsigned long ntransmitted, nreceived, nrepeats; uint16_t myid; unsigned tmin, tmax; /* in us */ @@ -275,6 +363,7 @@ struct globals { #define nreceived (G.nreceived ) #define nrepeats (G.nrepeats ) #define pingcount (G.pingcount ) +#define opt_ttl (G.opt_ttl ) #define myid (G.myid ) #define tmin (G.tmin ) #define tmax (G.tmax ) @@ -586,6 +675,10 @@ static void ping4(len_and_sockaddr *lsa) sockopt = (datalen * 2) + 7 * 1024; /* giving it a bit of extra room */ setsockopt(pingsock, SOL_SOCKET, SO_RCVBUF, &sockopt, sizeof(sockopt)); + if (opt_ttl != 0) + //setsockopt(pingsock, IPPROTO_IP, IP_MULTICAST_TTL, &opt_ttl, sizeof(opt_ttl)); + setsockopt(pingsock, IPPROTO_IP, IP_TTL, &opt_ttl, sizeof(opt_ttl)); + signal(SIGINT, print_stats_and_exit); /* start the ping's going ... */ @@ -735,9 +828,9 @@ static int common_ping_main(int opt, char **argv) INIT_G(); - /* exactly one argument needed; -v and -q don't mix; -c NUM, -w NUM, -W NUM */ - opt_complementary = "=1:q--v:v--q:c+:w+:W+"; - opt |= getopt32(argv, OPT_STRING, &pingcount, &str_s, &deadline, &timeout, &str_I); + /* exactly one argument needed; -v and -q don't mix; -c NUM, -t NUM, -w NUM, -W NUM */ + opt_complementary = "=1:q--v:v--q:c+:t+:w+:W+"; + opt |= getopt32(argv, OPT_STRING, &pingcount, &str_s, &opt_ttl, &deadline, &timeout, &str_I); if (opt & OPT_s) datalen = xatou16(str_s); // -s if (opt & OPT_I) { // -I -- cgit v1.2.3-55-g6feb From 8f0af3b0013156b8aa3bae802af5e33c3a440915 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Mon, 29 Nov 2010 02:55:35 +0100 Subject: if only one applet is enabled, make "busybox applet [params]" work as expected Signed-off-by: Denys Vlasenko --- libbb/appletlib.c | 62 +++++++++++++++++++++++++++++-------------------------- 1 file changed, 33 insertions(+), 29 deletions(-) diff --git a/libbb/appletlib.c b/libbb/appletlib.c index c417a270d..c65180c5e 100644 --- a/libbb/appletlib.c +++ b/libbb/appletlib.c @@ -227,7 +227,7 @@ bool re_execed; IF_FEATURE_SUID(static uid_t ruid;) /* real uid */ -#if ENABLE_FEATURE_SUID_CONFIG +# if ENABLE_FEATURE_SUID_CONFIG /* applets[] is const, so we have to define this "override" structure */ static struct BB_suid_config { @@ -498,15 +498,15 @@ static void parse_config_file(void) sct_head = sct; } } -#else +# else static inline void parse_config_file(void) { IF_FEATURE_SUID(ruid = getuid();) } -#endif /* FEATURE_SUID_CONFIG */ +# endif /* FEATURE_SUID_CONFIG */ -#if ENABLE_FEATURE_SUID +# if ENABLE_FEATURE_SUID static void check_suid(int applet_no) { gid_t rgid; /* real gid */ @@ -515,7 +515,7 @@ static void check_suid(int applet_no) return; /* run by root - no need to check more */ rgid = getgid(); -#if ENABLE_FEATURE_SUID_CONFIG +# if ENABLE_FEATURE_SUID_CONFIG if (suid_cfg_readable) { uid_t uid; struct BB_suid_config *sct; @@ -558,7 +558,7 @@ static void check_suid(int applet_no) bb_perror_msg_and_die("setresuid"); return; } -#if !ENABLE_FEATURE_SUID_CONFIG_QUIET +# if !ENABLE_FEATURE_SUID_CONFIG_QUIET { static bool onetime = 0; @@ -567,9 +567,9 @@ static void check_suid(int applet_no) fprintf(stderr, "Using fallback suid method\n"); } } -#endif +# endif check_need_suid: -#endif +# endif if (APPLET_SUID(applet_no) == _BB_SUID_REQUIRE) { /* Real uid is not 0. If euid isn't 0 too, suid bit * is most probably not set on our executable */ @@ -580,25 +580,24 @@ static void check_suid(int applet_no) xsetuid(ruid); } } -#else -#define check_suid(x) ((void)0) -#endif /* FEATURE_SUID */ +# else +# define check_suid(x) ((void)0) +# endif /* FEATURE_SUID */ -#if ENABLE_FEATURE_INSTALLER +# if ENABLE_FEATURE_INSTALLER static const char usr_bin [] ALIGN1 = "/usr/bin/"; static const char usr_sbin[] ALIGN1 = "/usr/sbin/"; static const char *const install_dir[] = { &usr_bin [8], /* "/" */ &usr_bin [4], /* "/bin/" */ &usr_sbin[4] /* "/sbin/" */ -# if !ENABLE_INSTALL_NO_USR +# if !ENABLE_INSTALL_NO_USR ,usr_bin ,usr_sbin -# endif +# endif }; - /* create (sym)links for each applet */ static void install_links(const char *busybox, int use_symbolic_links, char *custom_install_dir) @@ -628,9 +627,9 @@ static void install_links(const char *busybox, int use_symbolic_links, free(fpc); } } -#else -# define install_links(x,y,z) ((void)0) -#endif +# else +# define install_links(x,y,z) ((void)0) +# endif /* If we were called as "busybox..." */ static int busybox_main(char **argv) @@ -695,10 +694,10 @@ static int busybox_main(char **argv) const char *a = applet_names; dup2(1, 2); while (*a) { -#if ENABLE_FEATURE_INSTALLER +# if ENABLE_FEATURE_INSTALLER if (argv[1][6]) /* --list-path? */ full_write2_str(install_dir[APPLET_INSTALL_LOC(i)] + 1); -#endif +# endif full_write2_str(a); full_write2_str("\n"); i++; @@ -771,7 +770,7 @@ void FAST_FUNC run_applet_and_exit(const char *name, char **argv) int applet = find_applet_by_name(name); if (applet >= 0) run_applet_no_and_exit(applet, argv); - if (!strncmp(name, "busybox", 7)) + if (strncmp(name, "busybox", 7) == 0) exit(busybox_main(argv)); } @@ -803,14 +802,6 @@ int main(int argc UNUSED_PARAM, char **argv) mallopt(M_MMAP_THRESHOLD, 8 * PAGE_SIZE - 256); #endif -#if defined(SINGLE_APPLET_MAIN) - /* Only one applet is selected by the user! */ - /* applet_names in this case is just "applet\0\0" */ - lbb_prepare(applet_names IF_FEATURE_INDIVIDUAL(, argv)); - return SINGLE_APPLET_MAIN(argc, argv); -#else - lbb_prepare("busybox" IF_FEATURE_INDIVIDUAL(, argv)); - #if !BB_MMU /* NOMMU re-exec trick sets high-order bit in first byte of name */ if (argv[0][0] & 0x80) { @@ -818,6 +809,19 @@ int main(int argc UNUSED_PARAM, char **argv) argv[0][0] &= 0x7f; } #endif + +#if defined(SINGLE_APPLET_MAIN) + /* Only one applet is selected in .config */ + if (strncmp(argv[0], "busybox", 7) == 0) { + /* "busybox " should still work as expected */ + argv++; + } + /* applet_names in this case is just "applet\0\0" */ + lbb_prepare(applet_names IF_FEATURE_INDIVIDUAL(, argv)); + return SINGLE_APPLET_MAIN(argc, argv); +#else + lbb_prepare("busybox" IF_FEATURE_INDIVIDUAL(, argv)); + applet_name = argv[0]; if (applet_name[0] == '-') applet_name++; -- cgit v1.2.3-55-g6feb From 0ab45da92990072a23fda0f35d068743b1067cf3 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Mon, 29 Nov 2010 03:21:55 +0100 Subject: exclude the case of just "busybox" from previous commit Signed-off-by: Denys Vlasenko --- libbb/appletlib.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libbb/appletlib.c b/libbb/appletlib.c index c65180c5e..efd7a5a81 100644 --- a/libbb/appletlib.c +++ b/libbb/appletlib.c @@ -812,7 +812,7 @@ int main(int argc UNUSED_PARAM, char **argv) #if defined(SINGLE_APPLET_MAIN) /* Only one applet is selected in .config */ - if (strncmp(argv[0], "busybox", 7) == 0) { + if (argv[1] && strncmp(argv[0], "busybox", 7) == 0) { /* "busybox " should still work as expected */ argv++; } -- cgit v1.2.3-55-g6feb From 8027a202a89b31b33c94eae29895f14ceceef5af Mon Sep 17 00:00:00 2001 From: Rob Landley Date: Mon, 29 Nov 2010 03:24:51 +0100 Subject: patch: fix "patch at the beginning" testcase failure Signed-off-by: Rob Landley Signed-off-by: Denys Vlasenko --- editors/patch.c | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/editors/patch.c b/editors/patch.c index 1d4a2554e..9c6d967b9 100644 --- a/editors/patch.c +++ b/editors/patch.c @@ -238,7 +238,7 @@ static int apply_one_hunk(void) // complete hunk. plist = TT.current_hunk; buf = NULL; - if (TT.context) for (;;) { + if (reverse ? TT.oldlen : TT.newlen) for (;;) { char *data = xmalloc_reads(TT.filein, NULL, NULL); TT.linenum++; @@ -352,6 +352,8 @@ int patch_main(int argc UNUSED_PARAM, char **argv) int reverse, state = 0; char *oldname = NULL, *newname = NULL; char *opt_p, *opt_i; + long oldlen = oldlen; /* for compiler */ + long newlen = newlen; /* for compiler */ INIT_TT(); @@ -391,8 +393,8 @@ int patch_main(int argc UNUSED_PARAM, char **argv) if (*patchline==' ' || *patchline=='+' || *patchline=='-') { dlist_add(&TT.current_hunk, patchline); - if (*patchline != '+') TT.oldlen--; - if (*patchline != '-') TT.newlen--; + if (*patchline != '+') oldlen--; + if (*patchline != '-') newlen--; // Context line? if (*patchline==' ' && state==2) TT.context++; @@ -400,7 +402,7 @@ int patch_main(int argc UNUSED_PARAM, char **argv) // If we've consumed all expected hunk lines, apply the hunk. - if (!TT.oldlen && !TT.newlen) state = apply_one_hunk(); + if (!oldlen && !newlen) state = apply_one_hunk(); continue; } fail_hunk(); @@ -447,11 +449,14 @@ int patch_main(int argc UNUSED_PARAM, char **argv) // Read oldline[,oldlen] +newline[,newlen] - TT.oldlen = TT.newlen = 1; + TT.oldlen = oldlen = TT.newlen = newlen = 1; TT.oldline = strtol(s, &s, 10); - if (*s == ',') TT.oldlen=strtol(s+1, &s, 10); + if (*s == ',') TT.oldlen = oldlen = strtol(s+1, &s, 10); TT.newline = strtol(s+2, &s, 10); - if (*s == ',') TT.newlen = strtol(s+1, &s, 10); + if (*s == ',') TT.newlen = newlen = strtol(s+1, &s, 10); + + if (oldlen < 1 && newlen < 1) + bb_error_msg_and_die("Really? %s", patchline); TT.context = 0; state = 2; @@ -461,8 +466,8 @@ int patch_main(int argc UNUSED_PARAM, char **argv) int oldsum, newsum, empty = 0; char *name; - oldsum = TT.oldline + TT.oldlen; - newsum = TT.newline + TT.newlen; + oldsum = TT.oldline + oldlen; + newsum = TT.newline + newlen; name = reverse ? oldname : newname; -- cgit v1.2.3-55-g6feb From 3c8799b8a45def567705bfd07b8745e99d5f2dd9 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Mon, 29 Nov 2010 12:07:12 +0100 Subject: ping: set not only IP_TTL, but also IP_MULTICAST_TTL Signed-off-by: Denys Vlasenko --- networking/ping.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/networking/ping.c b/networking/ping.c index 8571d179b..7f74c26fa 100644 --- a/networking/ping.c +++ b/networking/ping.c @@ -675,9 +675,11 @@ static void ping4(len_and_sockaddr *lsa) sockopt = (datalen * 2) + 7 * 1024; /* giving it a bit of extra room */ setsockopt(pingsock, SOL_SOCKET, SO_RCVBUF, &sockopt, sizeof(sockopt)); - if (opt_ttl != 0) - //setsockopt(pingsock, IPPROTO_IP, IP_MULTICAST_TTL, &opt_ttl, sizeof(opt_ttl)); + if (opt_ttl != 0) { setsockopt(pingsock, IPPROTO_IP, IP_TTL, &opt_ttl, sizeof(opt_ttl)); + /* above doesnt affect packets sent to bcast IP, so... */ + setsockopt(pingsock, IPPROTO_IP, IP_MULTICAST_TTL, &opt_ttl, sizeof(opt_ttl)); + } signal(SIGINT, print_stats_and_exit); -- cgit v1.2.3-55-g6feb From 58c3d21c2e3caa5e5f3736a72136903dbf3c69d1 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Tue, 30 Nov 2010 09:17:30 +0100 Subject: telnetd: write utmp record with correct pid Signed-off-by: Denys Vlasenko --- networking/telnetd.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/networking/telnetd.c b/networking/telnetd.c index 671529d37..07c6a6a73 100644 --- a/networking/telnetd.c +++ b/networking/telnetd.c @@ -314,6 +314,8 @@ make_new_session( /* Restore default signal handling ASAP */ bb_signals((1 << SIGCHLD) + (1 << SIGPIPE), SIG_DFL); + pid = getpid(); + if (ENABLE_FEATURE_UTMP) { len_and_sockaddr *lsa = get_peer_lsa(sock); char *hostname = NULL; @@ -335,7 +337,6 @@ make_new_session( xopen(tty_name, O_RDWR); /* becomes our ctty */ xdup2(0, 1); xdup2(0, 2); - pid = getpid(); tcsetpgrp(0, pid); /* switch this tty's process group to us */ /* The pseudo-terminal allocated to the client is configured to operate -- cgit v1.2.3-55-g6feb From 12caabfa2da59ef877ad7ccbe949164dcc6d69e4 Mon Sep 17 00:00:00 2001 From: Chris Rees Date: Tue, 30 Nov 2010 09:41:39 +0100 Subject: build system: do not use GNU-isms in find Signed-off-by: Chris Rees Signed-off-by: Denys Vlasenko --- Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 69854373b..d9204f411 100644 --- a/Makefile +++ b/Makefile @@ -1008,8 +1008,8 @@ $(mrproper-dirs): mrproper: clean archmrproper $(mrproper-dirs) $(call cmd,rmdirs) $(call cmd,rmfiles) - @find -name Config.src | sed 's/.src$$/.in/' | xargs -r rm -f - @find -name Kbuild.src | sed 's/.src$$//' | xargs -r rm -f + @find . -name Config.src | sed 's/.src$$/.in/' | xargs -r rm -f + @find . -name Kbuild.src | sed 's/.src$$//' | xargs -r rm -f # distclean # -- cgit v1.2.3-55-g6feb From 631fd5ccd7372e2c09e953cc3c5d0176ee2bc6d2 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Tue, 30 Nov 2010 09:47:56 +0100 Subject: su: suppress "warning: unused variable 'user_buf'" Signed-off-by: Denys Vlasenko --- loginutils/su.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/loginutils/su.c b/loginutils/su.c index 5bec4bc8b..c31e7e771 100644 --- a/loginutils/su.c +++ b/loginutils/su.c @@ -42,7 +42,9 @@ int su_main(int argc UNUSED_PARAM, char **argv) struct passwd *pw; uid_t cur_uid = getuid(); const char *tty; +#if ENABLE_FEATURE_UTMP char user_buf[64]; +#endif const char *old_user; flags = getopt32(argv, "mplc:s:", &opt_command, &opt_shell); -- cgit v1.2.3-55-g6feb From 3f2477e8a89ddadd1dfdd9d990ac8c6fdb8ad4b3 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Wed, 1 Dec 2010 13:06:03 +0100 Subject: touch: fix help text to not show options disabled in .config Signed-off-by: Denys Vlasenko --- coreutils/Config.src | 7 ------- coreutils/Kbuild.src | 1 - coreutils/touch.c | 29 +++++++++++++++++++++++++++++ include/applets.src.h | 1 - include/usage.src.h | 16 ---------------- 5 files changed, 29 insertions(+), 25 deletions(-) diff --git a/coreutils/Config.src b/coreutils/Config.src index 0eb70af55..c2fd73e59 100644 --- a/coreutils/Config.src +++ b/coreutils/Config.src @@ -661,13 +661,6 @@ config FEATURE_TEE_USE_BLOCK_IO help Enable this option for a faster tee, at expense of size. -config TOUCH - bool "touch" - default y - help - touch is used to create or change the access and/or - modification timestamp of specified files. - config TRUE bool "true" default y diff --git a/coreutils/Kbuild.src b/coreutils/Kbuild.src index 630b048df..4ea0fa50a 100644 --- a/coreutils/Kbuild.src +++ b/coreutils/Kbuild.src @@ -74,7 +74,6 @@ lib-$(CONFIG_SYNC) += sync.o lib-$(CONFIG_TAC) += tac.o lib-$(CONFIG_TAIL) += tail.o lib-$(CONFIG_TEE) += tee.o -lib-$(CONFIG_TOUCH) += touch.o lib-$(CONFIG_TRUE) += true.o lib-$(CONFIG_TTY) += tty.o lib-$(CONFIG_UNAME) += uname.o diff --git a/coreutils/touch.c b/coreutils/touch.c index afff36b4d..352177111 100644 --- a/coreutils/touch.c +++ b/coreutils/touch.c @@ -19,6 +19,35 @@ #include "libbb.h" +//config:config TOUCH +//config: bool "touch" +//config: default y +//config: help +//config: touch is used to create or change the access and/or +//config: modification timestamp of specified files. + +//applet:IF_TOUCH(APPLET_NOFORK(touch, touch, _BB_DIR_BIN, _BB_SUID_DROP, touch)) + +//kbuild:lib-$(CONFIG_TOUCH) += touch.o + +//usage:#define touch_trivial_usage +//usage: "[-c]" IF_DESKTOP(" [-d DATE] [-r FILE]") " FILE [FILE]..." +//usage:#define touch_full_usage "\n\n" +//usage: "Update the last-modified date on the given FILE[s]\n" +//usage: "\nOptions:" +//usage: "\n -c Don't create files" +//usage: IF_DESKTOP( +//usage: "\n -d DT Date/time to use" +//usage: "\n -r FILE Use FILE's date/time" +//usage: ) +//usage: +//usage:#define touch_example_usage +//usage: "$ ls -l /tmp/foo\n" +//usage: "/bin/ls: /tmp/foo: No such file or directory\n" +//usage: "$ touch /tmp/foo\n" +//usage: "$ ls -l /tmp/foo\n" +//usage: "-rw-rw-r-- 1 andersen andersen 0 Apr 15 01:11 /tmp/foo\n" + /* This is a NOFORK applet. Be very careful! */ /* coreutils implements: diff --git a/include/applets.src.h b/include/applets.src.h index 131fca504..9dd5b6d84 100644 --- a/include/applets.src.h +++ b/include/applets.src.h @@ -356,7 +356,6 @@ IF_TFTPD(APPLET(tftpd, _BB_DIR_USR_BIN, _BB_SUID_DROP)) IF_TIME(APPLET(time, _BB_DIR_USR_BIN, _BB_SUID_DROP)) IF_TIMEOUT(APPLET(timeout, _BB_DIR_USR_BIN, _BB_SUID_DROP)) IF_TOP(APPLET(top, _BB_DIR_USR_BIN, _BB_SUID_DROP)) -IF_TOUCH(APPLET_NOFORK(touch, touch, _BB_DIR_BIN, _BB_SUID_DROP, touch)) IF_TR(APPLET(tr, _BB_DIR_USR_BIN, _BB_SUID_DROP)) IF_TRACEROUTE(APPLET(traceroute, _BB_DIR_USR_BIN, _BB_SUID_MAYBE)) IF_TRACEROUTE6(APPLET(traceroute6, _BB_DIR_USR_BIN, _BB_SUID_MAYBE)) diff --git a/include/usage.src.h b/include/usage.src.h index 7de2c6928..c413fbb91 100644 --- a/include/usage.src.h +++ b/include/usage.src.h @@ -4005,22 +4005,6 @@ INSERT "and display a screenful of them." \ //TODO: add options and keyboard commands -#define touch_trivial_usage \ - "[-c] [-d DATE] [-r FILE] FILE [FILE]..." -#define touch_full_usage "\n\n" \ - "Update the last-modified date on the given FILE[s]\n" \ - "\nOptions:" \ - "\n -c Don't create files" \ - "\n -d DT Date/time to use" \ - "\n -r FILE Use FILE's date/time" \ - -#define touch_example_usage \ - "$ ls -l /tmp/foo\n" \ - "/bin/ls: /tmp/foo: No such file or directory\n" \ - "$ touch /tmp/foo\n" \ - "$ ls -l /tmp/foo\n" \ - "-rw-rw-r-- 1 andersen andersen 0 Apr 15 01:11 /tmp/foo\n" - #define tr_trivial_usage \ "[-cds] STRING1 [STRING2]" #define tr_full_usage "\n\n" \ -- cgit v1.2.3-55-g6feb From 5dcc6606cb6ef41e0e0b0f828f670cc61311a3f7 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Wed, 1 Dec 2010 13:57:25 +0100 Subject: libbb/pw_encrypt_sha: forgot to move &ctx to 1st param here in sha hash rework Signed-off-by: Denys Vlasenko --- libbb/pw_encrypt_sha.c | 50 +++++++++++++++++++++++++------------------------- 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/libbb/pw_encrypt_sha.c b/libbb/pw_encrypt_sha.c index e46848b71..8aeaacad6 100644 --- a/libbb/pw_encrypt_sha.c +++ b/libbb/pw_encrypt_sha.c @@ -3,7 +3,7 @@ */ /* Prefix for optional rounds specification. */ -static const char str_rounds[] = "rounds=%u$"; +static const char str_rounds[] ALIGN1 = "rounds=%u$"; /* Maximum salt string length. */ #define SALT_LEN_MAX 16 @@ -19,8 +19,8 @@ NOINLINE sha_crypt(/*const*/ char *key_data, /*const*/ char *salt_data) { void (*sha_begin)(void *ctx) FAST_FUNC; - void (*sha_hash)(const void *buffer, size_t len, void *ctx) FAST_FUNC; - void (*sha_end)(void *resbuf, void *ctx) FAST_FUNC; + void (*sha_hash)(void *ctx, const void *buffer, size_t len) FAST_FUNC; + void (*sha_end)(void *ctx, void *resbuf) FAST_FUNC; int _32or64; char *result, *resptr; @@ -103,40 +103,40 @@ sha_crypt(/*const*/ char *key_data, /*const*/ char *salt_data) /* Add KEY, SALT. */ sha_begin(&ctx); - sha_hash(key_data, key_len, &ctx); - sha_hash(salt_data, salt_len, &ctx); + sha_hash(&ctx, key_data, key_len); + sha_hash(&ctx, salt_data, salt_len); /* Compute alternate SHA sum with input KEY, SALT, and KEY. The final result will be added to the first context. */ sha_begin(&alt_ctx); - sha_hash(key_data, key_len, &alt_ctx); - sha_hash(salt_data, salt_len, &alt_ctx); - sha_hash(key_data, key_len, &alt_ctx); - sha_end(alt_result, &alt_ctx); + sha_hash(&alt_ctx, key_data, key_len); + sha_hash(&alt_ctx, salt_data, salt_len); + sha_hash(&alt_ctx, key_data, key_len); + sha_end(&alt_ctx, alt_result); /* Add result of this to the other context. */ /* Add for any character in the key one byte of the alternate sum. */ for (cnt = key_len; cnt > _32or64; cnt -= _32or64) - sha_hash(alt_result, _32or64, &ctx); - sha_hash(alt_result, cnt, &ctx); + sha_hash(&ctx, alt_result, _32or64); + sha_hash(&ctx, alt_result, cnt); /* Take the binary representation of the length of the key and for every 1 add the alternate sum, for every 0 the key. */ for (cnt = key_len; cnt != 0; cnt >>= 1) if ((cnt & 1) != 0) - sha_hash(alt_result, _32or64, &ctx); + sha_hash(&ctx, alt_result, _32or64); else - sha_hash(key_data, key_len, &ctx); + sha_hash(&ctx, key_data, key_len); /* Create intermediate result. */ - sha_end(alt_result, &ctx); + sha_end(&ctx, alt_result); /* Start computation of P byte sequence. */ /* For every character in the password add the entire password. */ sha_begin(&alt_ctx); for (cnt = 0; cnt < key_len; ++cnt) - sha_hash(key_data, key_len, &alt_ctx); - sha_end(temp_result, &alt_ctx); + sha_hash(&alt_ctx, key_data, key_len); + sha_end(&alt_ctx, temp_result); /* NB: past this point, raw key_data is not used anymore */ @@ -153,8 +153,8 @@ sha_crypt(/*const*/ char *key_data, /*const*/ char *salt_data) /* For every character in the password add the entire password. */ sha_begin(&alt_ctx); for (cnt = 0; cnt < 16 + alt_result[0]; ++cnt) - sha_hash(salt_data, salt_len, &alt_ctx); - sha_end(temp_result, &alt_ctx); + sha_hash(&alt_ctx, salt_data, salt_len); + sha_end(&alt_ctx, temp_result); /* NB: past this point, raw salt_data is not used anymore */ @@ -174,22 +174,22 @@ sha_crypt(/*const*/ char *key_data, /*const*/ char *salt_data) /* Add key or last result. */ if ((cnt & 1) != 0) - sha_hash(p_bytes, key_len, &ctx); + sha_hash(&ctx, p_bytes, key_len); else - sha_hash(alt_result, _32or64, &ctx); + sha_hash(&ctx, alt_result, _32or64); /* Add salt for numbers not divisible by 3. */ if (cnt % 3 != 0) - sha_hash(s_bytes, salt_len, &ctx); + sha_hash(&ctx, s_bytes, salt_len); /* Add key for numbers not divisible by 7. */ if (cnt % 7 != 0) - sha_hash(p_bytes, key_len, &ctx); + sha_hash(&ctx, p_bytes, key_len); /* Add key or last result. */ if ((cnt & 1) != 0) - sha_hash(alt_result, _32or64, &ctx); + sha_hash(&ctx, alt_result, _32or64); else - sha_hash(p_bytes, key_len, &ctx); + sha_hash(&ctx, p_bytes, key_len); - sha_end(alt_result, &ctx); + sha_end(&ctx, alt_result); } /* Append encrypted password to result buffer */ -- cgit v1.2.3-55-g6feb From 8da415ef2503936bc9730f78a25b00177ff2db1d Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sun, 5 Dec 2010 01:30:14 +0100 Subject: add if guards around include Signed-off-by: Denys Vlasenko --- libbb/appletlib.c | 6 +++++- shell/hush.c | 6 +++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/libbb/appletlib.c b/libbb/appletlib.c index efd7a5a81..3e32fa1ef 100644 --- a/libbb/appletlib.c +++ b/libbb/appletlib.c @@ -28,7 +28,11 @@ */ #include "busybox.h" #include -#include +#if !(defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) \ + || defined(__APPLE__) \ + ) +# include /* for mallopt */ +#endif /* Try to pull in PAGE_SIZE */ #ifdef __linux__ # include diff --git a/shell/hush.c b/shell/hush.c index 584af9e06..087636b6d 100644 --- a/shell/hush.c +++ b/shell/hush.c @@ -82,7 +82,11 @@ * aaa */ #include "busybox.h" /* for APPLET_IS_NOFORK/NOEXEC */ -#include /* for malloc_trim */ +#if !(defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) \ + || defined(__APPLE__) \ + ) +# include /* for malloc_trim */ +#endif #include /* #include */ #if ENABLE_HUSH_CASE -- cgit v1.2.3-55-g6feb From a04440ccadbee947cb9d3f37969eea3e2c570ebf Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sun, 5 Dec 2010 05:02:49 +0100 Subject: typo fix Signed-off-by: Denys Vlasenko --- libbb/xfuncs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libbb/xfuncs.c b/libbb/xfuncs.c index 07504b75b..a02a504b0 100644 --- a/libbb/xfuncs.c +++ b/libbb/xfuncs.c @@ -234,7 +234,7 @@ static int wh_helper(int value, int def_val, const char *env_name, int *err) char *s = getenv(env_name); if (s) { value = atoi(s); - /* If LINES/COLUMNS are set, pretent that there is + /* If LINES/COLUMNS are set, pretend that there is * no error getting w/h, this prevents some ugly * cursor tricks by our callers */ *err = 0; -- cgit v1.2.3-55-g6feb From 6578f2cf5b97a72562b56e7d9ad5d49dee9953b0 Mon Sep 17 00:00:00 2001 From: Lauri Kasanen Date: Sun, 5 Dec 2010 05:22:29 +0100 Subject: pstree: new applet. +1664 bytes text data bss dec hex filename 883379 936 17192 901507 dc183 busybox_old 885043 936 17192 903171 dc803 busybox_unstripped Signed-off-by: Lauri Kasanen Signed-off-by: Denys Vlasenko --- include/libbb.h | 1 + libbb/procps.c | 2 + procps/pstree.c | 415 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 418 insertions(+) create mode 100644 procps/pstree.c diff --git a/include/libbb.h b/include/libbb.h index 7c1db3f40..d3ad6e294 100644 --- a/include/libbb.h +++ b/include/libbb.h @@ -1426,6 +1426,7 @@ typedef struct procps_status_t { char *argv0; char *exe; IF_SELINUX(char *context;) + IF_FEATURE_SHOW_THREADS(unsigned main_thread_pid;) /* Everything below must contain no ptrs to malloc'ed data: * it is memset(0) for each process in procps_scan() */ unsigned long vsz, rss; /* we round it to kbytes */ diff --git a/libbb/procps.c b/libbb/procps.c index 792466048..f22a55d15 100644 --- a/libbb/procps.c +++ b/libbb/procps.c @@ -302,6 +302,7 @@ procps_status_t* FAST_FUNC procps_scan(procps_status_t* sp, int flags) goto got_entry; closedir(sp->task_dir); sp->task_dir = NULL; + sp->main_thread_pid = 0; } #endif entry = readdir(sp->dir); @@ -321,6 +322,7 @@ procps_status_t* FAST_FUNC procps_scan(procps_status_t* sp, int flags) char task_dir[sizeof("/proc/%u/task") + sizeof(int)*3]; sprintf(task_dir, "/proc/%u/task", pid); sp->task_dir = xopendir(task_dir); + sp->main_thread_pid = pid; continue; } #endif diff --git a/procps/pstree.c b/procps/pstree.c new file mode 100644 index 000000000..f09e8da34 --- /dev/null +++ b/procps/pstree.c @@ -0,0 +1,415 @@ +/* + * pstree.c - display process tree + * + * Copyright (C) 1993-2002 Werner Almesberger + * Copyright (C) 2002-2009 Craig Small + * Copyright (C) 2010 Lauri Kasanen + * + * Based on pstree (PSmisc) 22.13. + * + * Licensed under GPLv2, see file LICENSE in this source tree. + */ + +//config:config PSTREE +//config: bool "pstree" +//config: default y +//config: help +//config: Display a tree of processes. + +//applet:IF_PSTREE(APPLET(pstree, _BB_DIR_USR_BIN, _BB_SUID_DROP)) + +//kbuild:lib-$(CONFIG_PSTREE) += pstree.o + +//usage:#define pstree_trivial_usage +//usage: "[-p] [PID|USER]" +//usage:#define pstree_full_usage "\n\n" +//usage: "Display process tree, optionally start from USER or PID\n" +//usage: "\nOptions:" +//usage: "\n -p Show pids" + +#include "libbb.h" + +#define PROC_BASE "/proc" + +#define OPT_PID (1 << 0) + +struct child; + +typedef struct proc { + char comm[COMM_LEN + 1]; +// char flags; - unused, delete? + pid_t pid; + uid_t uid; + struct child *children; + struct proc *parent; + struct proc *next; +} PROC; + +/* For flags above */ +//#define PFLAG_THREAD 0x01 + +typedef struct child { + PROC *child; + struct child *next; +} CHILD; + +#define empty_2 " " +#define branch_2 "|-" +#define vert_2 "| " +#define last_2 "`-" +#define single_3 "---" +#define first_3 "-+-" + +struct globals { + PROC *list; + + /* The buffers will be dynamically increased in size as needed */ + unsigned capacity; + int *width; + int *more; + +// Disabled, since code is broken anyway and needs fixing +// unsigned output_width; + unsigned cur_x; + smallint dumped; /* used by dump_by_user */ +}; +#define G (*ptr_to_globals) +#define INIT_G() do { \ + SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \ +} while (0) + + +/* + * Allocates additional buffer space for width and more as needed. + * The first call will allocate the first buffer. + * + * bufindex the index that will be used after the call + * to this function. + */ +static void ensure_buffer_capacity(int bufindex) +{ + if (bufindex >= G.capacity) { + G.capacity += 0x100; + G.width = xrealloc(G.width, G.capacity * sizeof(G.width[0])); + G.more = xrealloc(G.more, G.capacity * sizeof(G.more[0])); + } +} + +#if ENABLE_FEATURE_CLEAN_UP +static void maybe_free_buffers(void) +{ + free(G.width); + free(G.more); +} +#else +# define maybe_free_buffers() ((void)0) +#endif + +/* NB: this function is never called with "bad" chars + * (control chars or chars >= 0x7f) + */ +static void out_char(char c) +{ + G.cur_x++; +// if (G.cur_x <= G.output_width) + putchar(c); +// else if (G.cur_x == G.output_width - 1) +// putchar('+'); +} + +/* NB: this function is never called with "bad" chars + * (control chars or chars >= 0x7f) + */ +static void out_string(const char *str) +{ + while (*str) + out_char(*str++); +} + +static void out_newline(void) +{ + putchar('\n'); + G.cur_x = 1; +} + +static PROC *find_proc(pid_t pid) +{ + PROC *walk; + + for (walk = G.list; walk; walk = walk->next) + if (walk->pid == pid) + break; + + return walk; +} + +static PROC *new_proc(const char *comm, pid_t pid, uid_t uid) +{ + PROC *new = xzalloc(sizeof(*new)); + + strcpy(new->comm, comm); + new->pid = pid; + new->uid = uid; + new->next = G.list; + + G.list = new; + return G.list; +} + +static void add_child(PROC *parent, PROC *child) +{ + CHILD *new, **walk; + int cmp; + + new = xmalloc(sizeof(*new)); + + new->child = child; + for (walk = &parent->children; *walk; walk = &(*walk)->next) { + cmp = strcmp((*walk)->child->comm, child->comm); + if (cmp > 0) + break; + if (cmp == 0 && (*walk)->child->uid > child->uid) + break; + } + new->next = *walk; + *walk = new; +} + +static void add_proc(const char *comm, pid_t pid, pid_t ppid, + uid_t uid /*, char isthread*/) +{ + PROC *this, *parent; + + this = find_proc(pid); + if (!this) + this = new_proc(comm, pid, uid); + else { + strcpy(this->comm, comm); + this->uid = uid; + } + + if (pid == ppid) + ppid = 0; +// if (isthread) +// this->flags |= PFLAG_THREAD; + + parent = find_proc(ppid); + if (!parent) + parent = new_proc("?", ppid, 0); + + add_child(parent, this); + this->parent = parent; +} + +static int tree_equal(const PROC *a, const PROC *b) +{ + const CHILD *walk_a, *walk_b; + + if (strcmp(a->comm, b->comm) != 0) + return 0; + if ((option_mask32 /*& OPT_PID*/) && a->pid != b->pid) + return 0; + + for (walk_a = a->children, walk_b = b->children; + walk_a && walk_b; + walk_a = walk_a->next, walk_b = walk_b->next + ) { + if (!tree_equal(walk_a->child, walk_b->child)) + return 0; + } + + return !(walk_a || walk_b); +} + +static int out_args(const char *mystr) +{ + const char *here; + int strcount = 0; + char tmpstr[5]; + + for (here = mystr; *here; here++) { + if (*here == '\\') { + out_string("\\\\"); + strcount += 2; + } else if (*here >= ' ' && *here < 0x7f) { + out_char(*here); + strcount++; + } else { + sprintf(tmpstr, "\\%03o", (unsigned char) *here); + out_string(tmpstr); + strcount += 4; + } + } + + return strcount; +} + +static void +dump_tree(PROC *current, int level, int rep, int leaf, int last, int closing) +{ + CHILD *walk, *next, **scan; + int lvl, i, add, offset, count, comm_len, first; + + if (!current) + return; + + if (!leaf) { + for (lvl = 0; lvl < level; lvl++) { + i = G.width[lvl] + 1; + while (--i >= 0) + out_char(' '); + + if (lvl == level - 1) { + if (last) { + out_string(last_2); + } else { + out_string(branch_2); + } + } else { + if (G.more[lvl + 1]) { + out_string(vert_2); + } else { + out_string(empty_2); + } + } + } + } + + if (rep < 2) + add = 0; + else { + add = printf("%d", rep) + 2; + out_string("*["); + } + comm_len = out_args(current->comm); + if (option_mask32 /*& OPT_PID*/) { + out_char('('); + comm_len += printf("%d", (int)current->pid) + 2; + out_char(')'); + } + offset = G.cur_x; + + if (!current->children) { + while (closing--) + out_char(']'); + out_newline(); + } + ensure_buffer_capacity(level); + G.more[level] = !last; + + G.width[level] = comm_len + G.cur_x - offset + add; +// if (G.cur_x >= G.output_width) { +// out_string(first_3); +// out_char('+'); +// out_newline(); +// return; +// } + + first = 1; + for (walk = current->children; walk; walk = next) { + count = 0; + next = walk->next; + scan = &walk->next; + while (*scan) { + if (!tree_equal(walk->child, (*scan)->child)) + scan = &(*scan)->next; + else { + if (next == *scan) + next = (*scan)->next; + count++; + *scan = (*scan)->next; + } + } + if (first) { + out_string(next ? first_3 : single_3); + first = 0; + } + + dump_tree(walk->child, level + 1, count + 1, + walk == current->children, !next, + closing + (count ? 1 : 0)); + } +} + +static void dump_by_user(PROC *current, uid_t uid) +{ + const CHILD *walk; + + if (!current) + return; + + if (current->uid == uid) { + if (G.dumped) + putchar('\n'); + dump_tree(current, 0, 1, 1, 1, 0); + G.dumped = 1; + return; + } + for (walk = current->children; walk; walk = walk->next) + dump_by_user(walk->child, uid); +} + +static void handle_thread(const char *comm, pid_t pid, pid_t ppid, uid_t uid) +{ + char threadname[COMM_LEN + 2]; + sprintf(threadname, "{%.*s}", COMM_LEN - 2, comm); + add_proc(threadname, pid, ppid, uid/*, 1*/); +} + +static void mread_proc(void) +{ + procps_status_t *p = NULL; + pid_t parent = 0; + int flags = PSSCAN_COMM | PSSCAN_PID | PSSCAN_PPID | PSSCAN_UIDGID | PSSCAN_TASKS; + + while ((p = procps_scan(p, flags)) != NULL) { +#if ENABLE_FEATURE_SHOW_THREADS + if (p->pid != p->main_thread_pid) + handle_thread(p->comm, p->pid, parent, p->uid); + else +#endif + { + add_proc(p->comm, p->pid, p->ppid, p->uid/*, 0*/); + parent = p->pid; + } + } +} + +int pstree_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +int pstree_main(int argc UNUSED_PARAM, char **argv) +{ + pid_t pid = 1; + long uid = 0; + + INIT_G(); + G.cur_x = 1; + +// get_terminal_width_height(1, &G.output_width, NULL); + + getopt32(argv, "p"); + argv += optind; + + if (argv[0]) { + if (argv[1]) + bb_show_usage(); + if (argv[0][0] >= '0' && argv[0][0] <= '9') { + pid = xatoi(argv[0]); + } else { + uid = xuname2uid(argv[0]); + } + } + + mread_proc(); + + if (!uid) + dump_tree(find_proc(pid), 0, 1, 1, 1, 0); + else { + dump_by_user(find_proc(1), uid); + if (!G.dumped) { + bb_error_msg_and_die("no processes found"); + } + } + + maybe_free_buffers(); + return 0; +} -- cgit v1.2.3-55-g6feb From e48e6f85bf1966cb3a6350f5c2276ca73251a2f6 Mon Sep 17 00:00:00 2001 From: Lauri Kasanen Date: Sun, 5 Dec 2010 15:53:55 +0100 Subject: pstree: fix width logic. +30 bytes Signed-off-by: Lauri Kasanen Signed-off-by: Denys Vlasenko --- procps/pstree.c | 54 ++++++++++++++++++++++++++---------------------------- 1 file changed, 26 insertions(+), 28 deletions(-) diff --git a/procps/pstree.c b/procps/pstree.c index f09e8da34..25fb65d79 100644 --- a/procps/pstree.c +++ b/procps/pstree.c @@ -61,16 +61,17 @@ typedef struct child { #define first_3 "-+-" struct globals { - PROC *list; + /* 0-based. IOW: the number of chars we printer on current line */ + unsigned cur_x; + unsigned output_width; /* The buffers will be dynamically increased in size as needed */ unsigned capacity; - int *width; - int *more; + unsigned *width; + uint8_t *more; + + PROC *list; -// Disabled, since code is broken anyway and needs fixing -// unsigned output_width; - unsigned cur_x; smallint dumped; /* used by dump_by_user */ }; #define G (*ptr_to_globals) @@ -83,8 +84,7 @@ struct globals { * Allocates additional buffer space for width and more as needed. * The first call will allocate the first buffer. * - * bufindex the index that will be used after the call - * to this function. + * bufindex the index that will be used after the call to this function. */ static void ensure_buffer_capacity(int bufindex) { @@ -111,10 +111,10 @@ static void maybe_free_buffers(void) static void out_char(char c) { G.cur_x++; -// if (G.cur_x <= G.output_width) + if (G.cur_x == G.output_width) + c = '+'; + if (G.cur_x <= G.output_width) putchar(c); -// else if (G.cur_x == G.output_width - 1) -// putchar('+'); } /* NB: this function is never called with "bad" chars @@ -129,7 +129,7 @@ static void out_string(const char *str) static void out_newline(void) { putchar('\n'); - G.cur_x = 1; + G.cur_x = 0; } static PROC *find_proc(pid_t pid) @@ -249,6 +249,7 @@ dump_tree(PROC *current, int level, int rep, int leaf, int last, int closing) { CHILD *walk, *next, **scan; int lvl, i, add, offset, count, comm_len, first; + char tmp[sizeof(int)*3 + 4]; if (!current) return; @@ -275,17 +276,15 @@ dump_tree(PROC *current, int level, int rep, int leaf, int last, int closing) } } - if (rep < 2) - add = 0; - else { - add = printf("%d", rep) + 2; - out_string("*["); + add = 0; + if (rep > 1) { + add += sprintf(tmp, "%d*[", rep); + out_string(tmp); } comm_len = out_args(current->comm); if (option_mask32 /*& OPT_PID*/) { - out_char('('); - comm_len += printf("%d", (int)current->pid) + 2; - out_char(')'); + comm_len += sprintf(tmp, "(%d)", (int)current->pid); + out_string(tmp); } offset = G.cur_x; @@ -298,12 +297,12 @@ dump_tree(PROC *current, int level, int rep, int leaf, int last, int closing) G.more[level] = !last; G.width[level] = comm_len + G.cur_x - offset + add; -// if (G.cur_x >= G.output_width) { -// out_string(first_3); -// out_char('+'); -// out_newline(); -// return; -// } + if (G.cur_x >= G.output_width) { + //out_string(first_3); - why? it won't print anything + //out_char('+'); + out_newline(); + return; + } first = 1; for (walk = current->children; walk; walk = next) { @@ -382,9 +381,8 @@ int pstree_main(int argc UNUSED_PARAM, char **argv) long uid = 0; INIT_G(); - G.cur_x = 1; -// get_terminal_width_height(1, &G.output_width, NULL); + get_terminal_width_height(1, &G.output_width, NULL); getopt32(argv, "p"); argv += optind; -- cgit v1.2.3-55-g6feb From c32e626988ab35ba62bbe5b64dc8b86cd9a76bac Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sun, 5 Dec 2010 16:05:03 +0100 Subject: pstree: tiny shrink Signed-off-by: Denys Vlasenko --- procps/pstree.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/procps/pstree.c b/procps/pstree.c index 25fb65d79..7e127739c 100644 --- a/procps/pstree.c +++ b/procps/pstree.c @@ -111,10 +111,11 @@ static void maybe_free_buffers(void) static void out_char(char c) { G.cur_x++; + if (G.cur_x > G.output_width) + return; if (G.cur_x == G.output_width) c = '+'; - if (G.cur_x <= G.output_width) - putchar(c); + putchar(c); } /* NB: this function is never called with "bad" chars -- cgit v1.2.3-55-g6feb From 2161bd701a9267c04aa68fb43b2d40d7793884d4 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sun, 5 Dec 2010 19:36:58 +0100 Subject: pstree: another tiny shrink function old new delta pstree_main 327 324 -3 Signed-off-by: Denys Vlasenko --- procps/pstree.c | 20 ++++++-------------- 1 file changed, 6 insertions(+), 14 deletions(-) diff --git a/procps/pstree.c b/procps/pstree.c index 7e127739c..54a910f76 100644 --- a/procps/pstree.c +++ b/procps/pstree.c @@ -61,7 +61,7 @@ typedef struct child { #define first_3 "-+-" struct globals { - /* 0-based. IOW: the number of chars we printer on current line */ + /* 0-based. IOW: the number of chars we printed on current line */ unsigned cur_x; unsigned output_width; @@ -95,16 +95,6 @@ static void ensure_buffer_capacity(int bufindex) } } -#if ENABLE_FEATURE_CLEAN_UP -static void maybe_free_buffers(void) -{ - free(G.width); - free(G.more); -} -#else -# define maybe_free_buffers() ((void)0) -#endif - /* NB: this function is never called with "bad" chars * (control chars or chars >= 0x7f) */ @@ -385,12 +375,11 @@ int pstree_main(int argc UNUSED_PARAM, char **argv) get_terminal_width_height(1, &G.output_width, NULL); + opt_complementary = "?1"; getopt32(argv, "p"); argv += optind; if (argv[0]) { - if (argv[1]) - bb_show_usage(); if (argv[0][0] >= '0' && argv[0][0] <= '9') { pid = xatoi(argv[0]); } else { @@ -409,6 +398,9 @@ int pstree_main(int argc UNUSED_PARAM, char **argv) } } - maybe_free_buffers(); + if (ENABLE_FEATURE_CLEAN_UP) { + free(G.width); + free(G.more); + } return 0; } -- cgit v1.2.3-55-g6feb From dc160039ad4218c954afc1236e77f8a3127ca9df Mon Sep 17 00:00:00 2001 From: Joachim Nilsson Date: Sun, 5 Dec 2010 23:05:38 +0100 Subject: build system: fix "make install" to skip /usr when configured so Fix regression in BusyBox 1.18.0 where the NO_USR config option no longer bites for "make install". The busybox.mkll script stumbles without these lines and as a result *always* creates /usr/ symlinks. Signed-off-by: Joachim Nilsson Signed-off-by: Denys Vlasenko --- include/applets.src.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/include/applets.src.h b/include/applets.src.h index 9dd5b6d84..5058feb3a 100644 --- a/include/applets.src.h +++ b/include/applets.src.h @@ -56,6 +56,11 @@ s - suid type: # define APPLET_NOFORK(name,main,l,s,name2) { #name, #main, l, s, 1, 1 }, #endif +#if ENABLE_INSTALL_NO_USR +# define _BB_DIR_USR_BIN _BB_DIR_BIN +# define _BB_DIR_USR_SBIN _BB_DIR_SBIN +#endif + INSERT IF_TEST(APPLET_NOFORK([, test, _BB_DIR_USR_BIN, _BB_SUID_DROP, test)) -- cgit v1.2.3-55-g6feb From c60e88a5b9d750993f8e25a322ad7f6f09db8bda Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sun, 5 Dec 2010 23:11:15 +0100 Subject: tweak INSTALL_NO_USR help text Signed-off-by: Denys Vlasenko --- Config.in | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Config.in b/Config.in index d9c823199..140572e2d 100644 --- a/Config.in +++ b/Config.in @@ -128,8 +128,9 @@ config INSTALL_NO_USR default n depends on FEATURE_INSTALLER help - Disable use of /usr. busybox --install will install applets - only to /bin and /sbin, never to /usr/bin or /usr/sbin. + Disable use of /usr. busybox --install and "make install" + will install applets only to /bin and /sbin, + never to /usr/bin or /usr/sbin. config LOCALE_SUPPORT bool "Enable locale support (system needs locale for this to work)" -- cgit v1.2.3-55-g6feb From 31905f94777ae6e7181e9fbcc0cc7c4cf70abfaf Mon Sep 17 00:00:00 2001 From: Eric Lammerts Date: Mon, 6 Dec 2010 01:26:26 +0100 Subject: runsvdir: do not miss closely spaced service dir changes Signed-off-by: Eric Lammerts Signed-off-by: Denys Vlasenko --- runit/runsvdir.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/runit/runsvdir.c b/runit/runsvdir.c index e77eeff04..166664237 100644 --- a/runit/runsvdir.c +++ b/runit/runsvdir.c @@ -312,8 +312,11 @@ int runsvdir_main(int argc UNUSED_PARAM, char **argv) last_mtime = s.st_mtime; last_dev = s.st_dev; last_ino = s.st_ino; - //if (now <= mtime) - // sleep(1); + /* if the svdir changed this very second, wait until the + * next second, because we won't be able to detect more + * changes within this second */ + while (time(NULL) == last_mtime) + usleep(100000); need_rescan = do_rescan(); while (fchdir(curdir) == -1) { warn2_cannot("change directory, pausing", ""); -- cgit v1.2.3-55-g6feb From 86aa8030470b6978a099194402de0f692c477c79 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Mon, 6 Dec 2010 12:54:24 +0100 Subject: pstree: use stdin for screen size detection Signed-off-by: Denys Vlasenko --- procps/pstree.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/procps/pstree.c b/procps/pstree.c index 54a910f76..180d0939a 100644 --- a/procps/pstree.c +++ b/procps/pstree.c @@ -373,7 +373,7 @@ int pstree_main(int argc UNUSED_PARAM, char **argv) INIT_G(); - get_terminal_width_height(1, &G.output_width, NULL); + get_terminal_width_height(0, &G.output_width, NULL); opt_complementary = "?1"; getopt32(argv, "p"); -- cgit v1.2.3-55-g6feb From 75bb332dbd3105cda90d9d544a16ffdd9be19bbd Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Mon, 6 Dec 2010 15:13:58 +0100 Subject: add examples/var_service/README Signed-off-by: Denys Vlasenko --- examples/var_service/README | 54 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) create mode 100644 examples/var_service/README diff --git a/examples/var_service/README b/examples/var_service/README new file mode 100644 index 000000000..75d2ab8c2 --- /dev/null +++ b/examples/var_service/README @@ -0,0 +1,54 @@ +In many cases, network configuration makes it necessary to run several daemons: +dhcp, zeroconf, ppp, openvpn and such. They need to be controlled, +and in many cases you also want to babysit them. runsvdir is a good tool for this. +examples/var_service directory provides a few examples. It is meant to be used +this way: copy it somewhere (say, /var/service) and run something like + +env - PATH=... runsvdir /var/service & + +from one of system startup scripts. (Google "man runsvdir" and "man runsv" +for more info about these tools). + +Some existing examples: + +var_service/dhcp_if - +controls a udhcpc instance which provides dhpc-assigned IP +address on interface named "if". Copy/rename this directory as needed to run +udhcpc on other interfaces (var_service/dhcp_if/run script uses _foo suffix +or the parent directory as interface name). When IP address is obtained or lost, +var_service/dhcp_if/dhcp_handler is run. It saves new config data to +/var/run/service/fw/dhcp_if.ipconf and (re)starts /var/service/fw service. + +var_service/ifplugd_if - +watches link status of interface if. Downs and ups /var/service/dhcp_if +service accordingly. In effect, it allows you to unplug/plug-to-different-network +and have your IP properly re-negotiated at once. + +var_service/dhcp_if_pinger - +Uses var_service/dhcp_if's data (/var/service/dhcp_if/dhcp_if.out file) +to determine router IP. Pings it. If ping fails, restarts /var/service/dhcp_if +service. Basically, an example of watchdog service for networks +which are not reliable and need babysitting. + +var_service/fw - +An *one-shot* service which reconfigures network based on current known state +of ALL interfaces. Uses conf/*.ipconf (static config) and /var/run/service/fw/*.ipconf +(dynamic config from dhcp/ppp/vpn/etc) to determine what to do. +One-shot-ness of this service means that it shuts itself off after single run. + +However, any dhcp/ppp/vpn or similar service can restart it anytime +when it senses the change in network configuration. +This even works while fw service runs: if dhcp signals fw to (re)start +while fw runs, fw will not stop after its execution, but will re-execute once, +picking up dhcp's new configuration. +This is achieved very simply by having +# Make ourself one-shot +sv o . +at the very beginning of fw/run script, not at the end. +Therefore, any "sv u /var/run/service/fw" command by any other +script "undoes" o(ne-shot) command if fw still runs, thus +runsv will rerun it; or start it in a normal way if fw is not running. + +System administrators are expected to edit fw/run script, since +network configuration needs are likely to be very complex and different +for non-trivial installations. -- cgit v1.2.3-55-g6feb From bc3cdf8ed156eadb80bd5f83389ab368df6e5656 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Mon, 6 Dec 2010 15:42:44 +0100 Subject: update examples/var_service/README Signed-off-by: Denys Vlasenko --- examples/var_service/README | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/examples/var_service/README b/examples/var_service/README index 75d2ab8c2..69e1981fd 100644 --- a/examples/var_service/README +++ b/examples/var_service/README @@ -18,6 +18,8 @@ udhcpc on other interfaces (var_service/dhcp_if/run script uses _foo suffix or the parent directory as interface name). When IP address is obtained or lost, var_service/dhcp_if/dhcp_handler is run. It saves new config data to /var/run/service/fw/dhcp_if.ipconf and (re)starts /var/service/fw service. +This example can be used as a template for other dynamic network link services +(ppp/vpn/zcip). var_service/ifplugd_if - watches link status of interface if. Downs and ups /var/service/dhcp_if @@ -35,6 +37,9 @@ An *one-shot* service which reconfigures network based on current known state of ALL interfaces. Uses conf/*.ipconf (static config) and /var/run/service/fw/*.ipconf (dynamic config from dhcp/ppp/vpn/etc) to determine what to do. One-shot-ness of this service means that it shuts itself off after single run. +IOW: it is not a constantly running daemon sort of thing. +It starts, it configures the network, it shuts down, all done +(unlike infamous NetworkManagers which sit in RAM forever, doing hell knows what). However, any dhcp/ppp/vpn or similar service can restart it anytime when it senses the change in network configuration. -- cgit v1.2.3-55-g6feb From 309974412a05138805d9d9244e6a39e6dad89e29 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Mon, 6 Dec 2010 15:44:13 +0100 Subject: typo fix Signed-off-by: Denys Vlasenko --- examples/var_service/README | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/var_service/README b/examples/var_service/README index 69e1981fd..2d8928199 100644 --- a/examples/var_service/README +++ b/examples/var_service/README @@ -15,7 +15,7 @@ var_service/dhcp_if - controls a udhcpc instance which provides dhpc-assigned IP address on interface named "if". Copy/rename this directory as needed to run udhcpc on other interfaces (var_service/dhcp_if/run script uses _foo suffix -or the parent directory as interface name). When IP address is obtained or lost, +of the parent directory as interface name). When IP address is obtained or lost, var_service/dhcp_if/dhcp_handler is run. It saves new config data to /var/run/service/fw/dhcp_if.ipconf and (re)starts /var/service/fw service. This example can be used as a template for other dynamic network link services -- cgit v1.2.3-55-g6feb From 1f3709ec741cab0ef635059b225fed02b18ca664 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Wed, 8 Dec 2010 06:08:47 +0100 Subject: fix typo in README Signed-off-by: Denys Vlasenko --- examples/var_service/README | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/var_service/README b/examples/var_service/README index 2d8928199..06817c8bc 100644 --- a/examples/var_service/README +++ b/examples/var_service/README @@ -33,7 +33,7 @@ service. Basically, an example of watchdog service for networks which are not reliable and need babysitting. var_service/fw - -An *one-shot* service which reconfigures network based on current known state +A *one-shot* service which reconfigures network based on current known state of ALL interfaces. Uses conf/*.ipconf (static config) and /var/run/service/fw/*.ipconf (dynamic config from dhcp/ppp/vpn/etc) to determine what to do. One-shot-ness of this service means that it shuts itself off after single run. -- cgit v1.2.3-55-g6feb From 0b90de15375b643d2b21695fae3e46908e1effa6 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Mon, 13 Dec 2010 14:28:38 +0100 Subject: more: exit if write to stdout errors out Signed-off-by: Denys Vlasenko --- util-linux/more.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/util-linux/more.c b/util-linux/more.c index 788609a08..ecac92821 100644 --- a/util-linux/more.c +++ b/util-linux/more.c @@ -191,6 +191,9 @@ int more_main(int argc UNUSED_PARAM, char **argv) } /* My small mind cannot fathom backspaces and UTF-8 */ putchar(c); + + if (ferror(stdout)) /* if tty was destroyed (closed xterm, etc) */ + goto end; } fclose(file); fflush_all(); -- cgit v1.2.3-55-g6feb From 0d1d0f6e54e1980462c9d07c8b94e56cf13cbf08 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Mon, 13 Dec 2010 14:31:59 +0100 Subject: more: smaller version of previous fix Signed-off-by: Denys Vlasenko --- util-linux/more.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/util-linux/more.c b/util-linux/more.c index ecac92821..c424a0e4b 100644 --- a/util-linux/more.c +++ b/util-linux/more.c @@ -191,9 +191,7 @@ int more_main(int argc UNUSED_PARAM, char **argv) } /* My small mind cannot fathom backspaces and UTF-8 */ putchar(c); - - if (ferror(stdout)) /* if tty was destroyed (closed xterm, etc) */ - goto end; + die_if_ferror_stdout(); /* if tty was destroyed (closed xterm, etc) */ } fclose(file); fflush_all(); -- cgit v1.2.3-55-g6feb From da6fb7e33100e5135e3e898dd157e6c729b34d7c Mon Sep 17 00:00:00 2001 From: Lauri Kasanen Date: Wed, 8 Dec 2010 19:00:26 +0200 Subject: procps/Config.src: Add pstree to FEATURE_THREADS deps. Slight text edit Signed-off-by: Lauri Kasanen Signed-off-by: Denys Vlasenko --- procps/Config.src | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/procps/Config.src b/procps/Config.src index 1ff6dfd30..338d75c34 100644 --- a/procps/Config.src +++ b/procps/Config.src @@ -192,11 +192,12 @@ config FEATURE_TOPMEM Enable 's' in top (gives lots of memory info). config FEATURE_SHOW_THREADS - bool "Support for showing threads in ps/top" + bool "Support for showing threads in ps/pstree/top" default y - depends on PS || TOP + depends on PS || TOP || PSTREE help - Enables ps -T option and 'h' command in top + Enables the ps -T option, showing of threads in pstree, + and 'h' command in top. config UPTIME bool "uptime" -- cgit v1.2.3-55-g6feb From a6041860f878142e91be7889a26742e25f323c8f Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Mon, 13 Dec 2010 15:17:22 +0100 Subject: nmeter: deprecate %NNNd specified, use -d MSEC instead Signed-off-by: Denys Vlasenko --- include/applets.src.h | 1 - include/usage.src.h | 29 ++--------------------------- procps/Config.src | 6 ------ procps/Kbuild.src | 1 - procps/nmeter.c | 50 +++++++++++++++++++++++++++++++++++++++++++++----- 5 files changed, 47 insertions(+), 40 deletions(-) diff --git a/include/applets.src.h b/include/applets.src.h index 5058feb3a..c2f90eac0 100644 --- a/include/applets.src.h +++ b/include/applets.src.h @@ -258,7 +258,6 @@ IF_NAMEIF(APPLET(nameif, _BB_DIR_SBIN, _BB_SUID_DROP)) IF_NC(APPLET(nc, _BB_DIR_USR_BIN, _BB_SUID_DROP)) IF_NETSTAT(APPLET(netstat, _BB_DIR_BIN, _BB_SUID_DROP)) IF_NICE(APPLET(nice, _BB_DIR_BIN, _BB_SUID_DROP)) -IF_NMETER(APPLET(nmeter, _BB_DIR_USR_BIN, _BB_SUID_DROP)) IF_NOHUP(APPLET(nohup, _BB_DIR_USR_BIN, _BB_SUID_DROP)) IF_NSLOOKUP(APPLET(nslookup, _BB_DIR_USR_BIN, _BB_SUID_DROP)) IF_NTPD(APPLET(ntpd, _BB_DIR_USR_SBIN, _BB_SUID_DROP)) diff --git a/include/usage.src.h b/include/usage.src.h index c413fbb91..64f2c909f 100644 --- a/include/usage.src.h +++ b/include/usage.src.h @@ -1577,8 +1577,8 @@ INSERT "\n -c One-byte character display" \ "\n -C Canonical hex+ASCII, 16 bytes per line" \ "\n -d Two-byte decimal display" \ - "\n -e FORMAT STRING" \ - "\n -f FORMAT FILE" \ + "\n -e FORMAT_STRING" \ + "\n -f FORMAT_FILE" \ "\n -n LENGTH Interpret only LENGTH bytes of input" \ "\n -o Two-byte octal display" \ "\n -s OFFSET Skip OFFSET bytes" \ @@ -2706,31 +2706,6 @@ INSERT " or\n" \ "$ nameif -c /etc/my_mactab_file\n" \ -#define nmeter_trivial_usage \ - "format_string" -#define nmeter_full_usage "\n\n" \ - "Monitor system in real time\n\n" \ - "Format specifiers:\n" \ - " %Nc or %[cN] Monitor CPU. N - bar size, default 10\n" \ - " (displays: S:system U:user N:niced D:iowait I:irq i:softirq)\n" \ - " %[niface] Monitor network interface 'iface'\n" \ - " %m Monitor allocated memory\n" \ - " %[mf] Monitor free memory\n" \ - " %[mt] Monitor total memory\n" \ - " %s Monitor allocated swap\n" \ - " %f Monitor number of used file descriptors\n" \ - " %Ni Monitor total/specific IRQ rate\n" \ - " %x Monitor context switch rate\n" \ - " %p Monitor forks\n" \ - " %[pn] Monitor # of processes\n" \ - " %b Monitor block io\n" \ - " %Nt Show time (with N decimal points)\n" \ - " %Nd Milliseconds between updates (default:1000)\n" \ - " %r Print instead of at EOL" \ - -#define nmeter_example_usage \ - "nmeter '%250d%t %20c int %i bio %b mem %m forks%p'" - #define nohup_trivial_usage \ "PROG ARGS" #define nohup_full_usage "\n\n" \ diff --git a/procps/Config.src b/procps/Config.src index 338d75c34..cf664eeb2 100644 --- a/procps/Config.src +++ b/procps/Config.src @@ -46,12 +46,6 @@ config KILLALL5 default y depends on KILL -config NMETER - bool "nmeter" - default y - help - Prints selected system stats continuously, one line per update. - config PGREP bool "pgrep" default y diff --git a/procps/Kbuild.src b/procps/Kbuild.src index 791d65670..89b1cc094 100644 --- a/procps/Kbuild.src +++ b/procps/Kbuild.src @@ -11,7 +11,6 @@ lib-$(CONFIG_FREE) += free.o lib-$(CONFIG_FUSER) += fuser.o lib-$(CONFIG_KILL) += kill.o lib-$(CONFIG_ASH) += kill.o # used for built-in kill by ash -lib-$(CONFIG_NMETER) += nmeter.o lib-$(CONFIG_PGREP) += pgrep.o lib-$(CONFIG_PKILL) += pgrep.o lib-$(CONFIG_PIDOF) += pidof.o diff --git a/procps/nmeter.c b/procps/nmeter.c index 7836a90d5..ac019eb53 100644 --- a/procps/nmeter.c +++ b/procps/nmeter.c @@ -6,6 +6,40 @@ * Contact me: vda.linux@googlemail.com */ +//config:config NMETER +//config: bool "nmeter" +//config: default y +//config: help +//config: Prints selected system stats continuously, one line per update. + +//applet:IF_NMETER(APPLET(nmeter, _BB_DIR_USR_BIN, _BB_SUID_DROP)) + +//kbuild:lib-$(CONFIG_NMETER) += nmeter.o + +//usage:#define nmeter_trivial_usage +//usage: "[-d MSEC] FORMAT_STRING" +//usage:#define nmeter_full_usage "\n\n" +//usage: "Monitor system in real time" +//usage: "\n" +//usage: "\n -d MSEC Milliseconds between updates (default:1000)" +//usage: "\n" +//usage: "\nFormat specifiers:" +//usage: "\n %Nc or %[cN] Monitor CPU. N - bar size (default:10)" +//usage: "\n (displays: S:system U:user N:niced D:iowait I:irq i:softirq)" +//usage: "\n %[niface] Monitor network interface 'iface'" +//usage: "\n %m Monitor allocated memory" +//usage: "\n %[mf] Monitor free memory" +//usage: "\n %[mt] Monitor total memory" +//usage: "\n %s Monitor allocated swap" +//usage: "\n %f Monitor number of used file descriptors" +//usage: "\n %Ni Monitor total/specific IRQ rate" +//usage: "\n %x Monitor context switch rate" +//usage: "\n %p Monitor forks" +//usage: "\n %[pn] Monitor # of processes" +//usage: "\n %b Monitor block io" +//usage: "\n %Nt Show time (with N decimal points)" +//usage: "\n %r Print instead of at EOL" + //TODO: // simplify code // /proc/locks @@ -769,6 +803,7 @@ static void FAST_FUNC collect_info(s_stat *s) typedef s_stat* init_func(const char *param); +// Deprecated %NNNd is to be removed, -d MSEC supersedes it static const char options[] ALIGN1 = "ncmsfixptbdr"; static init_func *const init_functions[] = { init_if, @@ -792,23 +827,28 @@ int nmeter_main(int argc UNUSED_PARAM, char **argv) s_stat *first = NULL; s_stat *last = NULL; s_stat *s; + char *opt_d; char *cur, *prev; INIT_G(); xchdir("/proc"); - if (!argv[1]) - bb_show_usage(); - if (open_read_close("version", buf, sizeof(buf)-1) > 0) { buf[sizeof(buf)-1] = '\0'; is26 = (strstr(buf, " 2.4.") == NULL); } - // Can use argv[1] directly, but this will mess up + if (getopt32(argv, "d:", &opt_d)) + init_delay(opt_d); + argv += optind; + + if (!argv[0]) + bb_show_usage(); + + // Can use argv[0] directly, but this will mess up // parameters as seen by e.g. ps. Making a copy... - cur = xstrdup(argv[1]); + cur = xstrdup(argv[0]); while (1) { char *param, *p; prev = cur; -- cgit v1.2.3-55-g6feb From 0d6a4ecb30f596570585bbde29f7c9b42a60b623 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sat, 18 Dec 2010 01:34:49 +0100 Subject: hush: fix build breakage (variable declared in for()) Signed-off-by: Denys Vlasenko --- shell/hush.c | 45 ++++++++++++++++++++++++--------------------- 1 file changed, 24 insertions(+), 21 deletions(-) diff --git a/shell/hush.c b/shell/hush.c index 087636b6d..2bca9aa87 100644 --- a/shell/hush.c +++ b/shell/hush.c @@ -7013,27 +7013,30 @@ static int run_list(struct pipe *pi) #if ENABLE_HUSH_LOOPS /* Check syntax for "for" */ - for (struct pipe *cpipe = pi; cpipe; cpipe = cpipe->next) { - if (cpipe->res_word != RES_FOR && cpipe->res_word != RES_IN) - continue; - /* current word is FOR or IN (BOLD in comments below) */ - if (cpipe->next == NULL) { - syntax_error("malformed for"); - debug_leave(); - debug_printf_exec("run_list lvl %d return 1\n", G.run_list_level); - return 1; - } - /* "FOR v; do ..." and "for v IN a b; do..." are ok */ - if (cpipe->next->res_word == RES_DO) - continue; - /* next word is not "do". It must be "in" then ("FOR v in ...") */ - if (cpipe->res_word == RES_IN /* "for v IN a b; not_do..."? */ - || cpipe->next->res_word != RES_IN /* FOR v not_do_and_not_in..."? */ - ) { - syntax_error("malformed for"); - debug_leave(); - debug_printf_exec("run_list lvl %d return 1\n", G.run_list_level); - return 1; + { + struct pipe *cpipe; + for (cpipe = pi; cpipe; cpipe = cpipe->next) { + if (cpipe->res_word != RES_FOR && cpipe->res_word != RES_IN) + continue; + /* current word is FOR or IN (BOLD in comments below) */ + if (cpipe->next == NULL) { + syntax_error("malformed for"); + debug_leave(); + debug_printf_exec("run_list lvl %d return 1\n", G.run_list_level); + return 1; + } + /* "FOR v; do ..." and "for v IN a b; do..." are ok */ + if (cpipe->next->res_word == RES_DO) + continue; + /* next word is not "do". It must be "in" then ("FOR v in ...") */ + if (cpipe->res_word == RES_IN /* "for v IN a b; not_do..."? */ + || cpipe->next->res_word != RES_IN /* FOR v not_do_and_not_in..."? */ + ) { + syntax_error("malformed for"); + debug_leave(); + debug_printf_exec("run_list lvl %d return 1\n", G.run_list_level); + return 1; + } } } #endif -- cgit v1.2.3-55-g6feb From a3aea32811619e5ed80c2586a9206ad4ea941dfe Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sat, 18 Dec 2010 01:42:50 +0100 Subject: chat: fix build breakage (variable declared in for()) Signed-off-by: Denys Vlasenko --- miscutils/chat.c | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/miscutils/chat.c b/miscutils/chat.c index 8b151fda4..d8370a963 100644 --- a/miscutils/chat.c +++ b/miscutils/chat.c @@ -175,23 +175,24 @@ int chat_main(int argc UNUSED_PARAM, char **argv) llist_add_to_end(&aborts, arg); #if ENABLE_FEATURE_CHAT_CLR_ABORT } else if (DIR_CLR_ABORT == key) { + llist_t *l; // remove the string from abort conditions // N.B. gotta refresh maximum length too... -#if ENABLE_FEATURE_CHAT_VAR_ABORT_LEN +# if ENABLE_FEATURE_CHAT_VAR_ABORT_LEN max_abort_len = 0; -#endif - for (llist_t *l = aborts; l; l = l->link) { -#if ENABLE_FEATURE_CHAT_VAR_ABORT_LEN +# endif + for (l = aborts; l; l = l->link) { +# if ENABLE_FEATURE_CHAT_VAR_ABORT_LEN size_t len = strlen(l->data); -#endif - if (!strcmp(arg, l->data)) { +# endif + if (strcmp(arg, l->data) == 0) { llist_unlink(&aborts, l); continue; } -#if ENABLE_FEATURE_CHAT_VAR_ABORT_LEN +# if ENABLE_FEATURE_CHAT_VAR_ABORT_LEN if (len > max_abort_len) max_abort_len = len; -#endif +# endif } #endif } else if (DIR_TIMEOUT == key) { -- cgit v1.2.3-55-g6feb From 10c36b86574133bb1cd29ad04db64c7953b94ab5 Mon Sep 17 00:00:00 2001 From: Greentime Date: Fri, 17 Dec 2010 11:44:32 +0800 Subject: scripts: fix fixdep.c to let it workable in cygwin Update return character detection in the fixdep.c to let it workable in cygwin. Signed-off-by: Macpaul Lin Signed-off-by: Greentime Signed-off-by: Denys Vlasenko --- scripts/basic/fixdep.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/basic/fixdep.c b/scripts/basic/fixdep.c index 1a5b10f84..f27a17984 100644 --- a/scripts/basic/fixdep.c +++ b/scripts/basic/fixdep.c @@ -329,7 +329,7 @@ void parse_dep_file(void *map, size_t len) clear_config(); while (m < end) { - while (m < end && (*m == ' ' || *m == '\\' || *m == '\n')) + while (m < end && (*m == ' ' || *m == '\\' || *m == '\n' || *m == '\r')) m++; p = m; while (p < end && *p != ' ') p++; -- cgit v1.2.3-55-g6feb From e06884208ad766c1107988741a0e102555c3c4fd Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sat, 18 Dec 2010 01:46:04 +0100 Subject: Revert "scripts: fix fixdep.c to let it workable in cygwin" This reverts commit 10c36b86574133bb1cd29ad04db64c7953b94ab5. --- scripts/basic/fixdep.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/basic/fixdep.c b/scripts/basic/fixdep.c index f27a17984..1a5b10f84 100644 --- a/scripts/basic/fixdep.c +++ b/scripts/basic/fixdep.c @@ -329,7 +329,7 @@ void parse_dep_file(void *map, size_t len) clear_config(); while (m < end) { - while (m < end && (*m == ' ' || *m == '\\' || *m == '\n' || *m == '\r')) + while (m < end && (*m == ' ' || *m == '\\' || *m == '\n')) m++; p = m; while (p < end && *p != ' ') p++; -- cgit v1.2.3-55-g6feb From b2fa0b6219bc8f0e37ea68fc036857a4714fa175 Mon Sep 17 00:00:00 2001 From: Macpaul Lin Date: Fri, 17 Dec 2010 11:44:32 +0800 Subject: scripts: fix fixdep.c to let it workable in cygwin Update retrun character detection in the fixdep.c to let it work in cygwin. Signed-off-by: Macpaul Lin Signed-off-by: Greentime Signed-off-by: Denys Vlasenko --- scripts/basic/fixdep.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/basic/fixdep.c b/scripts/basic/fixdep.c index 1a5b10f84..f27a17984 100644 --- a/scripts/basic/fixdep.c +++ b/scripts/basic/fixdep.c @@ -329,7 +329,7 @@ void parse_dep_file(void *map, size_t len) clear_config(); while (m < end) { - while (m < end && (*m == ' ' || *m == '\\' || *m == '\n')) + while (m < end && (*m == ' ' || *m == '\\' || *m == '\n' || *m == '\r')) m++; p = m; while (p < end && *p != ' ') p++; -- cgit v1.2.3-55-g6feb From 96c8a6b5eade530f28ef73f72f7d188f71bbb1ec Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sat, 18 Dec 2010 02:59:09 +0100 Subject: chrt: correct opt_complementary. Closes bug 2977 Signed-off-by: Denys Vlasenko --- miscutils/chrt.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/miscutils/chrt.c b/miscutils/chrt.c index c40277b39..4477d084c 100644 --- a/miscutils/chrt.c +++ b/miscutils/chrt.c @@ -54,7 +54,7 @@ int chrt_main(int argc UNUSED_PARAM, char **argv) int policy = SCHED_RR; /* at least 1 arg; only one policy accepted */ - opt_complementary = "-1:r--fo:f--ro:r--fo"; + opt_complementary = "-1:r--fo:f--ro:o--rf"; opt = getopt32(argv, "+mprfo"); if (opt & OPT_r) policy = SCHED_RR; @@ -90,13 +90,13 @@ int chrt_main(int argc UNUSED_PARAM, char **argv) print_rt_info: pol = sched_getscheduler(pid); if (pol < 0) - bb_perror_msg_and_die("can't %cet pid %d's policy", 'g', pid); + bb_perror_msg_and_die("can't %cet pid %d's policy", 'g', (int)pid); printf("pid %d's %s scheduling policy: %s\n", pid, current_new, policies[pol].name); if (sched_getparam(pid, &sp)) - bb_perror_msg_and_die("can't get pid %d's attributes", pid); + bb_perror_msg_and_die("can't get pid %d's attributes", (int)pid); printf("pid %d's %s scheduling priority: %d\n", - pid, current_new, sp.sched_priority); + (int)pid, current_new, sp.sched_priority); if (!*argv) { /* Either it was just "-p ", * or it was "-p " and we came here @@ -115,7 +115,7 @@ int chrt_main(int argc UNUSED_PARAM, char **argv) sp.sched_priority = xstrtou_range(priority, 0, policy != SCHED_OTHER ? 1 : 0, 99); if (sched_setscheduler(pid, policy, &sp) < 0) - bb_perror_msg_and_die("can't %cet pid %d's policy", 's', pid); + bb_perror_msg_and_die("can't %cet pid %d's policy", 's', (int)pid); if (!argv[0]) /* "-p [...]" */ goto print_rt_info; -- cgit v1.2.3-55-g6feb From 1393fc116109ba96034470a926933e1bcd518470 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sun, 19 Dec 2010 04:07:50 +0100 Subject: chrt: -m can be used without any arguments. Closes bug 2989 Signed-off-by: Denys Vlasenko --- miscutils/chrt.c | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/miscutils/chrt.c b/miscutils/chrt.c index 4477d084c..1c6737a3c 100644 --- a/miscutils/chrt.c +++ b/miscutils/chrt.c @@ -53,23 +53,25 @@ int chrt_main(int argc UNUSED_PARAM, char **argv) const char *current_new; int policy = SCHED_RR; - /* at least 1 arg; only one policy accepted */ - opt_complementary = "-1:r--fo:f--ro:o--rf"; + /* only one policy accepted */ + opt_complementary = "r--fo:f--ro:o--rf"; opt = getopt32(argv, "+mprfo"); + if (opt & OPT_m) { /* print min/max and exit */ + show_min_max(SCHED_FIFO); + show_min_max(SCHED_RR); + show_min_max(SCHED_OTHER); + fflush_stdout_and_exit(EXIT_SUCCESS); + } if (opt & OPT_r) policy = SCHED_RR; if (opt & OPT_f) policy = SCHED_FIFO; if (opt & OPT_o) policy = SCHED_OTHER; - if (opt & OPT_m) { /* print min/max */ - show_min_max(SCHED_FIFO); - show_min_max(SCHED_RR); - show_min_max(SCHED_OTHER); - fflush_stdout_and_exit(EXIT_SUCCESS); - } argv += optind; + if (!argv[0]) + bb_show_usage(); if (opt & OPT_p) { pid_str = *argv++; if (*argv) { /* "-p [...]" */ -- cgit v1.2.3-55-g6feb From f313746a6d7b992918386a5e6db1cfc8f4da30fd Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sun, 19 Dec 2010 05:05:34 +0100 Subject: ls: for some options, only last takes effect. Closes bug 2959 Signed-off-by: Denys Vlasenko --- coreutils/ls.c | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/coreutils/ls.c b/coreutils/ls.c index 72f58c253..8d1f91921 100644 --- a/coreutils/ls.c +++ b/coreutils/ls.c @@ -984,13 +984,23 @@ int ls_main(int argc UNUSED_PARAM, char **argv) /* process options */ IF_FEATURE_LS_COLOR(applet_long_options = ls_longopts;) -#if ENABLE_FEATURE_AUTOWIDTH - opt_complementary = "T+:w+"; /* -T N, -w N */ - opt = getopt32(argv, ls_options, &tabstops, &terminal_width - IF_FEATURE_LS_COLOR(, &color_opt)); -#else - opt = getopt32(argv, ls_options IF_FEATURE_LS_COLOR(, &color_opt)); -#endif + opt_complementary = + /* http://pubs.opengroup.org/onlinepubs/9699919799/utilities/ls.html: + * in some pairs of opts, only last one takes effect: + */ + IF_FEATURE_LS_TIMESTAMPS(IF_FEATURE_LS_SORTFILES("t-S:S-t")) /* time/size */ + // ":H-L:L-H:" - we don't have -H + // ":m-l:l-m:" - we don't have -m + ":C-xl:x-Cl:l-xC" /* bycols/bylines/long */ + ":C-1:1-C" /* bycols/oneline */ + ":x-1:1-x" /* bylines/oneline (not in SuS, but in GNU coreutils 8.4) */ + ":c-u:u-c" /* mtime/atime */ + /* -T NUM, -w NUM: */ + IF_FEATURE_AUTOWIDTH(":T+:w+"); + opt = getopt32(argv, ls_options + IF_FEATURE_AUTOWIDTH(, &tabstops, &terminal_width) + IF_FEATURE_LS_COLOR(, &color_opt) + ); for (i = 0; opt_flags[i] != (1U<<31); i++) { if (opt & (1 << i)) { unsigned flags = opt_flags[i]; @@ -1054,7 +1064,7 @@ int ls_main(int argc UNUSED_PARAM, char **argv) if ((all_fmt & STYLE_MASK) == STYLE_LONG && (all_fmt & LIST_ID_NUMERIC)) all_fmt &= ~LIST_ID_NAME; /* don't list names if numeric uid */ - /* choose a display format */ + /* choose a display format if one was not already specified by an option */ if (!(all_fmt & STYLE_MASK)) all_fmt |= (isatty(STDOUT_FILENO) ? STYLE_COLUMNS : STYLE_SINGLE); -- cgit v1.2.3-55-g6feb From d87815d5e0721176ee13776956f648e660c895d5 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sun, 19 Dec 2010 05:43:44 +0100 Subject: ls: make -x force columnar output; remove unused parts of TRIGGER code Signed-off-by: Denys Vlasenko --- coreutils/ls.c | 73 ++++++++++++++++++++++++---------------------------------- 1 file changed, 30 insertions(+), 43 deletions(-) diff --git a/coreutils/ls.c b/coreutils/ls.c index 8d1f91921..f515f9f8f 100644 --- a/coreutils/ls.c +++ b/coreutils/ls.c @@ -56,7 +56,7 @@ TERMINAL_WIDTH = 80, /* use 79 if terminal has linefold bug */ COLUMN_GAP = 2, /* includes the file type char */ /* what is the overall style of the listing */ -STYLE_COLUMNS = 1 << 21, /* fill columns */ +STYLE_COLUMNAR = 1 << 21, /* many records per line */ STYLE_LONG = 2 << 21, /* one record per line, extended info */ STYLE_SINGLE = 3 << 21, /* one record per line */ STYLE_MASK = STYLE_SINGLE, @@ -167,52 +167,45 @@ enum { OPT_color = 1 << OPTBIT_color, }; -enum { - LIST_MASK_TRIGGER = 0, - STYLE_MASK_TRIGGER = STYLE_MASK, - DISP_MASK_TRIGGER = DISP_ROWS, - SORT_MASK_TRIGGER = SORT_MASK, -}; - /* TODO: simple toggles may be stored as OPT_xxx bits instead */ static const unsigned opt_flags[] = { - LIST_SHORT | STYLE_COLUMNS, /* C */ - DISP_HIDDEN | DISP_DOT, /* a */ - DISP_NOLIST, /* d */ - LIST_INO, /* i */ - LIST_LONG | STYLE_LONG, /* l - remember LS_DISP_HR in mask! */ - LIST_SHORT | STYLE_SINGLE, /* 1 */ - 0, /* g (don't show owner) - handled via OPT_g */ - LIST_ID_NUMERIC, /* n */ - LIST_BLOCKS, /* s */ - DISP_ROWS, /* x */ - 0, /* Q (quote filename) - handled via OPT_Q */ - DISP_HIDDEN, /* A */ + LIST_SHORT | STYLE_COLUMNAR, /* C */ + DISP_HIDDEN | DISP_DOT, /* a */ + DISP_NOLIST, /* d */ + LIST_INO, /* i */ + LIST_LONG | STYLE_LONG, /* l - remember LS_DISP_HR in mask! */ + LIST_SHORT | STYLE_SINGLE, /* 1 */ + 0, /* g (don't show owner) - handled via OPT_g */ + LIST_ID_NUMERIC, /* n */ + LIST_BLOCKS, /* s */ + LIST_SHORT | DISP_ROWS | STYLE_COLUMNAR, /* x */ + 0, /* Q (quote filename) - handled via OPT_Q */ + DISP_HIDDEN, /* A */ ENABLE_SELINUX * LIST_CONTEXT, /* k (ignored if !SELINUX) */ #if ENABLE_FEATURE_LS_TIMESTAMPS TIME_CHANGE | (ENABLE_FEATURE_LS_SORTFILES * SORT_CTIME), /* c */ - LIST_FULLTIME, /* e */ + LIST_FULLTIME, /* e */ ENABLE_FEATURE_LS_SORTFILES * SORT_MTIME, /* t */ TIME_ACCESS | (ENABLE_FEATURE_LS_SORTFILES * SORT_ATIME), /* u */ #endif #if ENABLE_FEATURE_LS_SORTFILES - SORT_SIZE, /* S */ - SORT_EXT, /* X */ - SORT_REVERSE, /* r */ - SORT_VERSION, /* v */ + SORT_SIZE, /* S */ + SORT_EXT, /* X */ + SORT_REVERSE, /* r */ + SORT_VERSION, /* v */ #endif #if ENABLE_FEATURE_LS_FILETYPES - LIST_FILETYPE | LIST_EXEC, /* F */ - LIST_FILETYPE, /* p */ + LIST_FILETYPE | LIST_EXEC, /* F */ + LIST_FILETYPE, /* p */ #endif #if ENABLE_FEATURE_LS_FOLLOWLINKS - FOLLOW_LINKS, /* L */ + FOLLOW_LINKS, /* L */ #endif #if ENABLE_FEATURE_LS_RECURSIVE - DISP_RECURSIVE, /* R */ + DISP_RECURSIVE, /* R */ #endif #if ENABLE_FEATURE_HUMAN_READABLE - LS_DISP_HR, /* h */ + LS_DISP_HR, /* h */ #endif #if ENABLE_SELINUX LIST_MODEBITS|LIST_NLINKS|LIST_CONTEXT|LIST_SIZE|LIST_DATE_TIME, /* K */ @@ -547,7 +540,7 @@ static unsigned calc_name_len(const char *name) /* Return the number of used columns. - * Note that only STYLE_COLUMNS uses return value. + * Note that only STYLE_COLUMNAR uses return value. * STYLE_SINGLE and STYLE_LONG don't care. * coreutils 7.2 also supports: * ls -b (--escape) = octal escapes (although it doesn't look like working) @@ -581,7 +574,7 @@ static unsigned print_name(const char *name) } /* Return the number of used columns. - * Note that only STYLE_COLUMNS uses return value, + * Note that only STYLE_COLUMNAR uses return value, * STYLE_SINGLE and STYLE_LONG don't care. */ static NOINLINE unsigned list_single(const struct dnode *dn) @@ -739,7 +732,7 @@ static void showfiles(struct dnode **dn, unsigned nfiles) unsigned i, ncols, nrows, row, nc; unsigned column = 0; unsigned nexttab = 0; - unsigned column_width = 0; /* used only by STYLE_COLUMNS */ + unsigned column_width = 0; /* used only by STYLE_COLUMNAR */ if (all_fmt & STYLE_LONG) { /* STYLE_LONG or STYLE_SINGLE */ ncols = 1; @@ -1005,21 +998,15 @@ int ls_main(int argc UNUSED_PARAM, char **argv) if (opt & (1 << i)) { unsigned flags = opt_flags[i]; - if (flags & LIST_MASK_TRIGGER) - all_fmt &= ~LIST_MASK; - if (flags & STYLE_MASK_TRIGGER) + if (flags & STYLE_MASK) all_fmt &= ~STYLE_MASK; - if (flags & SORT_MASK_TRIGGER) + if (flags & SORT_MASK) all_fmt &= ~SORT_MASK; - if (flags & DISP_MASK_TRIGGER) - all_fmt &= ~DISP_MASK; if (flags & TIME_MASK) all_fmt &= ~TIME_MASK; + if (flags & LIST_CONTEXT) all_fmt |= STYLE_SINGLE; - /* huh?? opt cannot be 'l' */ - //if (LS_DISP_HR && opt == 'l') - // all_fmt &= ~LS_DISP_HR; all_fmt |= flags; } } @@ -1066,7 +1053,7 @@ int ls_main(int argc UNUSED_PARAM, char **argv) /* choose a display format if one was not already specified by an option */ if (!(all_fmt & STYLE_MASK)) - all_fmt |= (isatty(STDOUT_FILENO) ? STYLE_COLUMNS : STYLE_SINGLE); + all_fmt |= (isatty(STDOUT_FILENO) ? STYLE_COLUMNAR : STYLE_SINGLE); argv += optind; if (!argv[0]) -- cgit v1.2.3-55-g6feb From 163d86435729cc53d6d4088129f2cde106dd1318 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sun, 19 Dec 2010 06:16:28 +0100 Subject: ls: make -F not follow symlinks of the command line Signed-off-by: Denys Vlasenko --- coreutils/ls.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/coreutils/ls.c b/coreutils/ls.c index f515f9f8f..02e26bedb 100644 --- a/coreutils/ls.c +++ b/coreutils/ls.c @@ -155,15 +155,17 @@ enum { OPT_Q = (1 << 10), //OPT_A = (1 << 11), //OPT_k = (1 << 12), - OPTBIT_color = 13 + OPTBIT_F = 13 + 4 * ENABLE_FEATURE_LS_TIMESTAMPS - + 4 * ENABLE_FEATURE_LS_SORTFILES + + 4 * ENABLE_FEATURE_LS_SORTFILES, + OPTBIT_color = OPTBIT_F + 2 * ENABLE_FEATURE_LS_FILETYPES + 1 * ENABLE_FEATURE_LS_FOLLOWLINKS + 1 * ENABLE_FEATURE_LS_RECURSIVE + 1 * ENABLE_FEATURE_HUMAN_READABLE + 2 * ENABLE_SELINUX + 2 * ENABLE_FEATURE_AUTOWIDTH, + OPT_F = (1 << OPTBIT_F) * ENABLE_FEATURE_LS_FILETYPES, OPT_color = 1 << OPTBIT_color, }; @@ -1066,8 +1068,10 @@ int ls_main(int argc UNUSED_PARAM, char **argv) dn = NULL; nfiles = 0; do { - /* NB: follow links on command line unless -l or -s */ - cur = my_stat(*argv, *argv, !(all_fmt & (STYLE_LONG|LIST_BLOCKS))); + /* NB: follow links on command line unless -l, -s or -F */ + cur = my_stat(*argv, *argv, + !((all_fmt & (STYLE_LONG|LIST_BLOCKS)) || (option_mask32 & OPT_F)) + ); argv++; if (!cur) continue; -- cgit v1.2.3-55-g6feb From 2f7d9e8903029b1b5e51a15f9cb0dcb6ca17c3ac Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sun, 19 Dec 2010 07:06:44 +0100 Subject: ls: print a space after each column. Closes bug 2941 Signed-off-by: Denys Vlasenko --- coreutils/ls.c | 83 ++++++++++++++++++++++++++++++++++++++++++++++------- include/usage.src.h | 61 --------------------------------------- 2 files changed, 72 insertions(+), 72 deletions(-) diff --git a/coreutils/ls.c b/coreutils/ls.c index 02e26bedb..7bc7b28c8 100644 --- a/coreutils/ls.c +++ b/coreutils/ls.c @@ -29,6 +29,70 @@ * [2009-03] * ls sorts listing now, and supports almost all options. */ + +//usage:#define ls_trivial_usage +//usage: "[-1AaCxd" +//usage: IF_FEATURE_LS_FOLLOWLINKS("L") +//usage: IF_FEATURE_LS_RECURSIVE("R") +//usage: IF_FEATURE_LS_FILETYPES("Fp") "lins" +//usage: IF_FEATURE_LS_TIMESTAMPS("e") +//usage: IF_FEATURE_HUMAN_READABLE("h") +//usage: IF_FEATURE_LS_SORTFILES("rSXv") +//usage: IF_FEATURE_LS_TIMESTAMPS("ctu") +//usage: IF_SELINUX("kKZ") "]" +//usage: IF_FEATURE_AUTOWIDTH(" -w WIDTH") " [FILE]..." +//usage:#define ls_full_usage "\n\n" +//usage: "List directory contents\n" +//usage: "\nOptions:" +//usage: "\n -1 List in a single column" +//usage: "\n -A Don't list . and .." +//usage: "\n -a Don't hide entries starting with ." +//usage: "\n -C List by columns" +//usage: "\n -x List by lines" +//usage: "\n -d List directory entries instead of contents" +//usage: IF_FEATURE_LS_FOLLOWLINKS( +//usage: "\n -L List entries pointed to by symlinks" +//usage: ) +//usage: IF_FEATURE_LS_RECURSIVE( +//usage: "\n -R Recurse" +//usage: ) +//usage: IF_FEATURE_LS_FILETYPES( +//usage: "\n -F Append indicator (one of */=@|) to entries" +//usage: "\n -p Append indicator (one of /=@|) to entries" +//usage: ) +//usage: "\n -l Long listing format" +//usage: "\n -i List inode numbers" +//usage: "\n -n List numeric UIDs and GIDs instead of names" +//usage: "\n -s List the size of each file, in blocks" +//usage: IF_FEATURE_LS_TIMESTAMPS( +//usage: "\n -e List full date and time" +//usage: ) +//usage: IF_FEATURE_HUMAN_READABLE( +//usage: "\n -h List sizes in human readable format (1K 243M 2G)" +//usage: ) +//usage: IF_FEATURE_LS_SORTFILES( +//usage: "\n -r Sort in reverse order" +//usage: "\n -S Sort by file size" +//usage: "\n -X Sort by extension" +//usage: "\n -v Sort by version" +//usage: ) +//usage: IF_FEATURE_LS_TIMESTAMPS( +//usage: "\n -c With -l: sort by ctime" +//usage: "\n -t With -l: sort by modification time" +//usage: "\n -u With -l: sort by access time" +//usage: ) +//usage: IF_SELINUX( +//usage: "\n -k List security context" +//usage: "\n -K List security context in long format" +//usage: "\n -Z List security context and permission" +//usage: ) +//usage: IF_FEATURE_AUTOWIDTH( +//usage: "\n -w N Assume the terminal is N columns wide" +//usage: ) +//usage: IF_FEATURE_LS_COLOR( +//usage: "\n --color[={always,never,auto}] Control coloring" +//usage: ) + #include "libbb.h" #include "unicode.h" @@ -53,7 +117,6 @@ enum { TERMINAL_WIDTH = 80, /* use 79 if terminal has linefold bug */ -COLUMN_GAP = 2, /* includes the file type char */ /* what is the overall style of the listing */ STYLE_COLUMNAR = 1 << 21, /* many records per line */ @@ -241,7 +304,6 @@ struct globals { smallint exit_code; unsigned all_fmt; #if ENABLE_FEATURE_AUTOWIDTH - unsigned tabstops; // = COLUMN_GAP; unsigned terminal_width; // = TERMINAL_WIDTH; #endif #if ENABLE_FEATURE_LS_TIMESTAMPS @@ -258,11 +320,9 @@ enum { show_color = 0 }; #define exit_code (G.exit_code ) #define all_fmt (G.all_fmt ) #if ENABLE_FEATURE_AUTOWIDTH -# define tabstops (G.tabstops ) # define terminal_width (G.terminal_width) #else enum { - tabstops = COLUMN_GAP, terminal_width = TERMINAL_WIDTH, }; #endif @@ -270,7 +330,6 @@ enum { #define INIT_G() do { \ /* we have to zero it out because of NOEXEC */ \ memset(&G, 0, sizeof(G)); \ - IF_FEATURE_AUTOWIDTH(tabstops = COLUMN_GAP;) \ IF_FEATURE_AUTOWIDTH(terminal_width = TERMINAL_WIDTH;) \ IF_FEATURE_LS_TIMESTAMPS(time(¤t_time_t);) \ } while (0) @@ -732,8 +791,8 @@ static NOINLINE unsigned list_single(const struct dnode *dn) static void showfiles(struct dnode **dn, unsigned nfiles) { unsigned i, ncols, nrows, row, nc; - unsigned column = 0; - unsigned nexttab = 0; + unsigned column; + unsigned nexttab; unsigned column_width = 0; /* used only by STYLE_COLUMNAR */ if (all_fmt & STYLE_LONG) { /* STYLE_LONG or STYLE_SINGLE */ @@ -745,7 +804,7 @@ static void showfiles(struct dnode **dn, unsigned nfiles) if (column_width < len) column_width = len; } - column_width += tabstops + + column_width += 1 + IF_SELINUX( ((all_fmt & LIST_CONTEXT) ? 33 : 0) + ) ((all_fmt & LIST_INO) ? 8 : 0) + ((all_fmt & LIST_BLOCKS) ? 5 : 0); @@ -761,6 +820,8 @@ static void showfiles(struct dnode **dn, unsigned nfiles) ncols = 1; } + column = 0; + nexttab = 0; for (row = 0; row < nrows; row++) { for (nc = 0; nc < ncols; nc++) { /* reach into the array based on the column and row */ @@ -771,8 +832,8 @@ static void showfiles(struct dnode **dn, unsigned nfiles) if (i < nfiles) { if (column > 0) { nexttab -= column; - printf("%*s", nexttab, ""); - column += nexttab; + printf("%*s ", nexttab, ""); + column += nexttab + 1; } nexttab = column + column_width; column += list_single(dn[i]); @@ -993,7 +1054,7 @@ int ls_main(int argc UNUSED_PARAM, char **argv) /* -T NUM, -w NUM: */ IF_FEATURE_AUTOWIDTH(":T+:w+"); opt = getopt32(argv, ls_options - IF_FEATURE_AUTOWIDTH(, &tabstops, &terminal_width) + IF_FEATURE_AUTOWIDTH(, NULL, &terminal_width) IF_FEATURE_LS_COLOR(, &color_opt) ); for (i = 0; opt_flags[i] != (1U<<31); i++) { diff --git a/include/usage.src.h b/include/usage.src.h index 64f2c909f..cd37a892d 100644 --- a/include/usage.src.h +++ b/include/usage.src.h @@ -2173,67 +2173,6 @@ INSERT "\n -h Print banner page too" \ "\n -V Verbose" \ -#define ls_trivial_usage \ - "[-1Aa" IF_FEATURE_LS_TIMESTAMPS("c") "Cd" \ - IF_FEATURE_LS_TIMESTAMPS("e") IF_FEATURE_LS_FILETYPES("F") "iln" \ - IF_FEATURE_LS_FILETYPES("p") IF_FEATURE_LS_FOLLOWLINKS("L") \ - IF_FEATURE_LS_RECURSIVE("R") IF_FEATURE_LS_SORTFILES("rS") "s" \ - IF_FEATURE_AUTOWIDTH("T") IF_FEATURE_LS_TIMESTAMPS("tu") \ - IF_FEATURE_LS_SORTFILES("v") IF_FEATURE_AUTOWIDTH("w") "x" \ - IF_FEATURE_LS_SORTFILES("X") IF_FEATURE_HUMAN_READABLE("h") "k" \ - IF_SELINUX("K") "] [FILE]..." -#define ls_full_usage "\n\n" \ - "List directory contents\n" \ - "\nOptions:" \ - "\n -1 List in a single column" \ - "\n -A Don't list . and .." \ - "\n -a Don't hide entries starting with ." \ - "\n -C List by columns" \ - IF_FEATURE_LS_TIMESTAMPS( \ - "\n -c With -l: sort by ctime") \ - IF_FEATURE_LS_COLOR( \ - "\n --color[={always,never,auto}] Control coloring") \ - "\n -d List directory entries instead of contents" \ - IF_FEATURE_LS_TIMESTAMPS( \ - "\n -e List full date and time") \ - IF_FEATURE_LS_FILETYPES( \ - "\n -F Append indicator (one of */=@|) to entries") \ - "\n -i List inode numbers" \ - "\n -l Long listing format" \ - "\n -n List numeric UIDs and GIDs instead of names" \ - IF_FEATURE_LS_FILETYPES( \ - "\n -p Append indicator (one of /=@|) to entries") \ - IF_FEATURE_LS_FOLLOWLINKS( \ - "\n -L List entries pointed to by symlinks") \ - IF_FEATURE_LS_RECURSIVE( \ - "\n -R Recurse") \ - IF_FEATURE_LS_SORTFILES( \ - "\n -r Sort in reverse order") \ - IF_FEATURE_LS_SORTFILES( \ - "\n -S Sort by file size") \ - "\n -s List the size of each file, in blocks" \ - IF_FEATURE_AUTOWIDTH( \ - "\n -T N Assume tabstop every N columns") \ - IF_FEATURE_LS_TIMESTAMPS( \ - "\n -t With -l: sort by modification time") \ - IF_FEATURE_LS_TIMESTAMPS( \ - "\n -u With -l: sort by access time") \ - IF_FEATURE_LS_SORTFILES( \ - "\n -v Sort by version") \ - IF_FEATURE_AUTOWIDTH( \ - "\n -w N Assume the terminal is N columns wide") \ - "\n -x List by lines" \ - IF_FEATURE_LS_SORTFILES( \ - "\n -X Sort by extension") \ - IF_FEATURE_HUMAN_READABLE( \ - "\n -h List sizes in human readable format (1K 243M 2G)") \ - IF_SELINUX( \ - "\n -k List security context") \ - IF_SELINUX( \ - "\n -K List security context in long format") \ - IF_SELINUX( \ - "\n -Z List security context and permission") \ - #define lsattr_trivial_usage \ "[-Radlv] [FILE]..." #define lsattr_full_usage "\n\n" \ -- cgit v1.2.3-55-g6feb From 407ab2a4349de67c0a3203cdcb544a3360506291 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sun, 19 Dec 2010 16:29:08 +0100 Subject: ls: tweak -e handling; better comments Signed-off-by: Denys Vlasenko --- coreutils/ls.c | 43 ++++++++++++++++++++++++------------------- 1 file changed, 24 insertions(+), 19 deletions(-) diff --git a/coreutils/ls.c b/coreutils/ls.c index 7bc7b28c8..eadd6cee7 100644 --- a/coreutils/ls.c +++ b/coreutils/ls.c @@ -184,15 +184,20 @@ SPLIT_FILE = 0, SPLIT_SUBDIR = 2, }; -/* "[-]Cadil1", POSIX mandated options, busybox always supports */ -/* "[-]gnsx", POSIX non-mandated options, busybox always supports */ -/* "[-]Q" GNU option? busybox always supports */ -/* "[-]Ak" GNU options, busybox always supports */ -/* "[-]FLRctur", POSIX mandated options, busybox optionally supports */ -/* "[-]p", POSIX non-mandated options, busybox optionally supports */ -/* "[-]SXvThw", GNU options, busybox optionally supports */ -/* "[-]K", SELinux mandated options, busybox optionally supports */ -/* "[-]e", I think we made this one up */ +/* -Cadil1 Std options, busybox always supports */ +/* -gnsxA Std options, busybox always supports */ +/* -Q GNU option? busybox always supports */ +/* -k SELinux option, busybox always supports (ignores if !SELinux) */ +/* Std has -k which means "show sizes in kbytes" */ +/* -FLRctur Std options, busybox optionally supports */ +/* -p Std option, busybox optionally supports */ +/* Not fully compatible - we show not only '/' but other chars too */ +/* -SXvhTw GNU options, busybox optionally supports */ +/* -T TABWIDTH is ignored (we don't use tabs on output) */ +/* -K SELinux mandated options, busybox optionally supports */ +/* -e I think we made this one up (looks similar to GNU --full-time) */ +/* Std opts we do not support: */ +/* -H Follow the links on command line only */ static const char ls_options[] ALIGN1 = "Cadil1gnsxQAk" /* 13 opts, total 13 */ IF_FEATURE_LS_TIMESTAMPS("cetu") /* 4, 17 */ @@ -229,7 +234,7 @@ enum { + 2 * ENABLE_SELINUX + 2 * ENABLE_FEATURE_AUTOWIDTH, OPT_F = (1 << OPTBIT_F) * ENABLE_FEATURE_LS_FILETYPES, - OPT_color = 1 << OPTBIT_color, + OPT_color = (1 << OPTBIT_color), }; /* TODO: simple toggles may be stored as OPT_xxx bits instead */ @@ -248,10 +253,10 @@ static const unsigned opt_flags[] = { DISP_HIDDEN, /* A */ ENABLE_SELINUX * LIST_CONTEXT, /* k (ignored if !SELINUX) */ #if ENABLE_FEATURE_LS_TIMESTAMPS - TIME_CHANGE | (ENABLE_FEATURE_LS_SORTFILES * SORT_CTIME), /* c */ + TIME_CHANGE | (ENABLE_FEATURE_LS_SORTFILES * SORT_CTIME), /* c */ LIST_FULLTIME, /* e */ - ENABLE_FEATURE_LS_SORTFILES * SORT_MTIME, /* t */ - TIME_ACCESS | (ENABLE_FEATURE_LS_SORTFILES * SORT_ATIME), /* u */ + ENABLE_FEATURE_LS_SORTFILES * SORT_MTIME, /* t */ + TIME_ACCESS | (ENABLE_FEATURE_LS_SORTFILES * SORT_ATIME), /* u */ #endif #if ENABLE_FEATURE_LS_SORTFILES SORT_SIZE, /* S */ @@ -274,8 +279,6 @@ static const unsigned opt_flags[] = { #endif #if ENABLE_SELINUX LIST_MODEBITS|LIST_NLINKS|LIST_CONTEXT|LIST_SIZE|LIST_DATE_TIME, /* K */ -#endif -#if ENABLE_SELINUX LIST_MODEBITS|LIST_ID_NAME|LIST_CONTEXT, /* Z */ #endif (1U<<31) @@ -1041,18 +1044,20 @@ int ls_main(int argc UNUSED_PARAM, char **argv) /* process options */ IF_FEATURE_LS_COLOR(applet_long_options = ls_longopts;) opt_complementary = + /* -e implies -l */ + "el" /* http://pubs.opengroup.org/onlinepubs/9699919799/utilities/ls.html: * in some pairs of opts, only last one takes effect: */ - IF_FEATURE_LS_TIMESTAMPS(IF_FEATURE_LS_SORTFILES("t-S:S-t")) /* time/size */ + IF_FEATURE_LS_TIMESTAMPS(IF_FEATURE_LS_SORTFILES(":t-S:S-t")) /* time/size */ // ":H-L:L-H:" - we don't have -H // ":m-l:l-m:" - we don't have -m ":C-xl:x-Cl:l-xC" /* bycols/bylines/long */ ":C-1:1-C" /* bycols/oneline */ ":x-1:1-x" /* bylines/oneline (not in SuS, but in GNU coreutils 8.4) */ ":c-u:u-c" /* mtime/atime */ - /* -T NUM, -w NUM: */ - IF_FEATURE_AUTOWIDTH(":T+:w+"); + /* -w NUM: */ + IF_FEATURE_AUTOWIDTH(":w+"); opt = getopt32(argv, ls_options IF_FEATURE_AUTOWIDTH(, NULL, &terminal_width) IF_FEATURE_LS_COLOR(, &color_opt) @@ -1109,7 +1114,7 @@ int ls_main(int argc UNUSED_PARAM, char **argv) all_fmt = (all_fmt & ~SORT_MASK) | SORT_ATIME; } if ((all_fmt & STYLE_MASK) != STYLE_LONG) /* only for long list */ - all_fmt &= ~(LIST_ID_NUMERIC|LIST_FULLTIME|LIST_ID_NAME|LIST_ID_NUMERIC); + all_fmt &= ~(LIST_ID_NUMERIC|LIST_ID_NAME|LIST_FULLTIME); if (ENABLE_FEATURE_LS_USERNAME) if ((all_fmt & STYLE_MASK) == STYLE_LONG && (all_fmt & LIST_ID_NUMERIC)) all_fmt &= ~LIST_ID_NAME; /* don't list names if numeric uid */ -- cgit v1.2.3-55-g6feb From 86ffe5c15a14dc7f8483faf42ef907c5f861137d Mon Sep 17 00:00:00 2001 From: James Hunt Date: Thu, 16 Dec 2010 12:22:38 +0000 Subject: volume_id: recognize compressed hibernate swap signature util-linux/volume_id/linux_swap.c: Added the new magic LINHIB0001 signature. See: https://bugs.launchpad.net/ubuntu/+source/util-linux/+bug/683605 Signed-off-by: James Hunt Signed-off-by: Denys Vlasenko --- util-linux/volume_id/linux_swap.c | 1 + 1 file changed, 1 insertion(+) diff --git a/util-linux/volume_id/linux_swap.c b/util-linux/volume_id/linux_swap.c index 574354611..0aa43f3de 100644 --- a/util-linux/volume_id/linux_swap.c +++ b/util-linux/volume_id/linux_swap.c @@ -55,6 +55,7 @@ int FAST_FUNC volume_id_probe_linux_swap(struct volume_id *id /*,uint64_t off*/) if (memcmp(buf, "SWAPSPACE2", 10) == 0 || memcmp(buf, "S1SUSPEND", 9) == 0 || memcmp(buf, "S2SUSPEND", 9) == 0 + || memcmp(buf, "LINHIB0001", 10) == 0 || memcmp(buf, "ULSUSPEND", 9) == 0 ) { sw = volume_id_get_buffer(id, off, sizeof(struct swap_header_v1_2)); -- cgit v1.2.3-55-g6feb From 982aa263a0cef10ee4f4c06084a87af736c449ac Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sun, 19 Dec 2010 21:54:39 +0100 Subject: ls: add support for -H Signed-off-by: Denys Vlasenko --- coreutils/ls.c | 159 +++++++++++++++++++++++++++++++-------------------------- 1 file changed, 86 insertions(+), 73 deletions(-) diff --git a/coreutils/ls.c b/coreutils/ls.c index eadd6cee7..d27c36ddc 100644 --- a/coreutils/ls.c +++ b/coreutils/ls.c @@ -32,7 +32,7 @@ //usage:#define ls_trivial_usage //usage: "[-1AaCxd" -//usage: IF_FEATURE_LS_FOLLOWLINKS("L") +//usage: IF_FEATURE_LS_FOLLOWLINKS("LH") //usage: IF_FEATURE_LS_RECURSIVE("R") //usage: IF_FEATURE_LS_FILETYPES("Fp") "lins" //usage: IF_FEATURE_LS_TIMESTAMPS("e") @@ -51,7 +51,8 @@ //usage: "\n -x List by lines" //usage: "\n -d List directory entries instead of contents" //usage: IF_FEATURE_LS_FOLLOWLINKS( -//usage: "\n -L List entries pointed to by symlinks" +//usage: "\n -L Follow symlinks" +//usage: "\n -H Follow symlinks on command line only" //usage: ) //usage: IF_FEATURE_LS_RECURSIVE( //usage: "\n -R Recurse" @@ -118,11 +119,11 @@ enum { TERMINAL_WIDTH = 80, /* use 79 if terminal has linefold bug */ -/* what is the overall style of the listing */ -STYLE_COLUMNAR = 1 << 21, /* many records per line */ -STYLE_LONG = 2 << 21, /* one record per line, extended info */ -STYLE_SINGLE = 3 << 21, /* one record per line */ -STYLE_MASK = STYLE_SINGLE, +SPLIT_DIR = 1, +SPLIT_FILE = 0, +SPLIT_SUBDIR = 2, + +/* Bits in all_fmt: */ /* 51306 lrwxrwxrwx 1 root root 2 May 11 01:43 /bin/view -> vi* */ /* what file information will be listed */ @@ -152,44 +153,41 @@ DISP_RECURSIVE = 1 << 19, /* show directory and everything below it */ DISP_ROWS = 1 << 20, /* print across rows */ DISP_MASK = ((DISP_ROWS << 1) - 1) & ~(DISP_DIRNAME - 1), -/* how will the files be sorted (CONFIG_FEATURE_LS_SORTFILES) */ -SORT_FORWARD = 0, /* sort in reverse order */ -SORT_REVERSE = 1 << 27, /* sort in reverse order */ - -SORT_NAME = 0, /* sort by file name */ -SORT_SIZE = 1 << 28, /* sort by file size */ -SORT_ATIME = 2 << 28, /* sort by last access time */ -SORT_CTIME = 3 << 28, /* sort by last change time */ -SORT_MTIME = 4 << 28, /* sort by last modification time */ -SORT_VERSION = 5 << 28, /* sort by version */ -SORT_EXT = 6 << 28, /* sort by file name extension */ -SORT_DIR = 7 << 28, /* sort by file or directory */ -SORT_MASK = (7 << 28) * ENABLE_FEATURE_LS_SORTFILES, +/* what is the overall style of the listing */ +STYLE_COLUMNAR = 1 << 21, /* many records per line */ +STYLE_LONG = 2 << 21, /* one record per line, extended info */ +STYLE_SINGLE = 3 << 21, /* one record per line */ +STYLE_MASK = STYLE_SINGLE, /* which of the three times will be used */ TIME_CHANGE = (1 << 23) * ENABLE_FEATURE_LS_TIMESTAMPS, TIME_ACCESS = (1 << 24) * ENABLE_FEATURE_LS_TIMESTAMPS, TIME_MASK = (3 << 23) * ENABLE_FEATURE_LS_TIMESTAMPS, -FOLLOW_LINKS = (1 << 25) * ENABLE_FEATURE_LS_FOLLOWLINKS, +/* how will the files be sorted (CONFIG_FEATURE_LS_SORTFILES) */ +SORT_REVERSE = 1 << 25, -LS_DISP_HR = (1 << 26) * ENABLE_FEATURE_HUMAN_READABLE, +SORT_NAME = 0, /* sort by file name */ +SORT_SIZE = 1 << 26, /* sort by file size */ +SORT_ATIME = 2 << 26, /* sort by last access time */ +SORT_CTIME = 3 << 26, /* sort by last change time */ +SORT_MTIME = 4 << 26, /* sort by last modification time */ +SORT_VERSION = 5 << 26, /* sort by version */ +SORT_EXT = 6 << 26, /* sort by file name extension */ +SORT_DIR = 7 << 26, /* sort by file or directory */ +SORT_MASK = (7 << 26) * ENABLE_FEATURE_LS_SORTFILES, LIST_SHORT = LIST_FILENAME, LIST_LONG = LIST_MODEBITS | LIST_NLINKS | LIST_ID_NAME | LIST_SIZE | \ LIST_DATE_TIME | LIST_FILENAME | LIST_SYMLINK, - -SPLIT_DIR = 1, -SPLIT_FILE = 0, -SPLIT_SUBDIR = 2, }; /* -Cadil1 Std options, busybox always supports */ /* -gnsxA Std options, busybox always supports */ -/* -Q GNU option? busybox always supports */ +/* -Q GNU option, busybox always supports */ /* -k SELinux option, busybox always supports (ignores if !SELinux) */ /* Std has -k which means "show sizes in kbytes" */ -/* -FLRctur Std options, busybox optionally supports */ +/* -FLHRctur Std options, busybox optionally supports */ /* -p Std option, busybox optionally supports */ /* Not fully compatible - we show not only '/' but other chars too */ /* -SXvhTw GNU options, busybox optionally supports */ @@ -199,15 +197,15 @@ SPLIT_SUBDIR = 2, /* Std opts we do not support: */ /* -H Follow the links on command line only */ static const char ls_options[] ALIGN1 = - "Cadil1gnsxQAk" /* 13 opts, total 13 */ + "Cadil1gnsxQAk" /* 13 opts, total 13 */ IF_FEATURE_LS_TIMESTAMPS("cetu") /* 4, 17 */ IF_FEATURE_LS_SORTFILES("SXrv") /* 4, 21 */ IF_FEATURE_LS_FILETYPES("Fp") /* 2, 23 */ - IF_FEATURE_LS_FOLLOWLINKS("L") /* 1, 24 */ - IF_FEATURE_LS_RECURSIVE("R") /* 1, 25 */ - IF_FEATURE_HUMAN_READABLE("h") /* 1, 26 */ - IF_SELINUX("KZ") /* 2, 28 */ - IF_FEATURE_AUTOWIDTH("T:w:") /* 2, 30 */ + IF_FEATURE_LS_RECURSIVE("R") /* 1, 24 */ + IF_SELINUX("KZ") /* 2, 26 */ + IF_FEATURE_LS_FOLLOWLINKS("LH") /* 2, 28 */ + IF_FEATURE_HUMAN_READABLE("h") /* 1, 29 */ + IF_FEATURE_AUTOWIDTH("T:w:") /* 2, 31 */ ; enum { //OPT_C = (1 << 0), @@ -223,27 +221,55 @@ enum { OPT_Q = (1 << 10), //OPT_A = (1 << 11), //OPT_k = (1 << 12), - OPTBIT_F = 13 - + 4 * ENABLE_FEATURE_LS_TIMESTAMPS - + 4 * ENABLE_FEATURE_LS_SORTFILES, - OPTBIT_color = OPTBIT_F - + 2 * ENABLE_FEATURE_LS_FILETYPES - + 1 * ENABLE_FEATURE_LS_FOLLOWLINKS - + 1 * ENABLE_FEATURE_LS_RECURSIVE - + 1 * ENABLE_FEATURE_HUMAN_READABLE - + 2 * ENABLE_SELINUX - + 2 * ENABLE_FEATURE_AUTOWIDTH, - OPT_F = (1 << OPTBIT_F) * ENABLE_FEATURE_LS_FILETYPES, - OPT_color = (1 << OPTBIT_color), + + OPTBIT_c = 13, + OPTBIT_e, + OPTBIT_t, + OPTBIT_u, + OPTBIT_S = OPTBIT_c + 4 * ENABLE_FEATURE_LS_TIMESTAMPS, + OPTBIT_X, /* 18 */ + OPTBIT_r, + OPTBIT_v, + OPTBIT_F = OPTBIT_S + 4 * ENABLE_FEATURE_LS_SORTFILES, + OPTBIT_p, /* 22 */ + OPTBIT_R = OPTBIT_F + 2 * ENABLE_FEATURE_LS_FILETYPES, + OPTBIT_K = OPTBIT_R + 1 * ENABLE_FEATURE_LS_RECURSIVE, + OPTBIT_Z, /* 25 */ + OPTBIT_L = OPTBIT_K + 2 * ENABLE_SELINUX, + OPTBIT_H, /* 27 */ + OPTBIT_h = OPTBIT_L + 1 * ENABLE_FEATURE_LS_FOLLOWLINKS, + OPTBIT_T = OPTBIT_h + 2 * ENABLE_FEATURE_HUMAN_READABLE, + OPTBIT_w, /* 30 */ + OPTBIT_color = OPTBIT_T + 2 * ENABLE_FEATURE_AUTOWIDTH, + + OPT_c = (1 << OPTBIT_c) * ENABLE_FEATURE_LS_TIMESTAMPS, + OPT_e = (1 << OPTBIT_e) * ENABLE_FEATURE_LS_TIMESTAMPS, + OPT_t = (1 << OPTBIT_t) * ENABLE_FEATURE_LS_TIMESTAMPS, + OPT_u = (1 << OPTBIT_u) * ENABLE_FEATURE_LS_TIMESTAMPS, + OPT_S = (1 << OPTBIT_S) * ENABLE_FEATURE_LS_SORTFILES, + OPT_X = (1 << OPTBIT_X) * ENABLE_FEATURE_LS_SORTFILES, + OPT_r = (1 << OPTBIT_r) * ENABLE_FEATURE_LS_SORTFILES, + OPT_v = (1 << OPTBIT_v) * ENABLE_FEATURE_LS_SORTFILES, + OPT_F = (1 << OPTBIT_F) * ENABLE_FEATURE_LS_FILETYPES, + OPT_p = (1 << OPTBIT_p) * ENABLE_FEATURE_LS_FILETYPES, + OPT_R = (1 << OPTBIT_R) * ENABLE_FEATURE_LS_RECURSIVE, + OPT_K = (1 << OPTBIT_K) * ENABLE_SELINUX, + OPT_Z = (1 << OPTBIT_Z) * ENABLE_SELINUX, + OPT_L = (1 << OPTBIT_L) * ENABLE_FEATURE_LS_FOLLOWLINKS, + OPT_H = (1 << OPTBIT_H) * ENABLE_FEATURE_LS_FOLLOWLINKS, + OPT_h = (1 << OPTBIT_h) * ENABLE_FEATURE_HUMAN_READABLE, + OPT_T = (1 << OPTBIT_T) * ENABLE_FEATURE_AUTOWIDTH, + OPT_w = (1 << OPTBIT_w) * ENABLE_FEATURE_AUTOWIDTH, + OPT_color = (1 << OPTBIT_color) * ENABLE_FEATURE_LS_COLOR, }; /* TODO: simple toggles may be stored as OPT_xxx bits instead */ -static const unsigned opt_flags[] = { +static const uint32_t opt_flags[] = { LIST_SHORT | STYLE_COLUMNAR, /* C */ DISP_HIDDEN | DISP_DOT, /* a */ DISP_NOLIST, /* d */ LIST_INO, /* i */ - LIST_LONG | STYLE_LONG, /* l - remember LS_DISP_HR in mask! */ + LIST_LONG | STYLE_LONG, /* l */ LIST_SHORT | STYLE_SINGLE, /* 1 */ 0, /* g (don't show owner) - handled via OPT_g */ LIST_ID_NUMERIC, /* n */ @@ -268,23 +294,15 @@ static const unsigned opt_flags[] = { LIST_FILETYPE | LIST_EXEC, /* F */ LIST_FILETYPE, /* p */ #endif -#if ENABLE_FEATURE_LS_FOLLOWLINKS - FOLLOW_LINKS, /* L */ -#endif #if ENABLE_FEATURE_LS_RECURSIVE DISP_RECURSIVE, /* R */ #endif -#if ENABLE_FEATURE_HUMAN_READABLE - LS_DISP_HR, /* h */ -#endif #if ENABLE_SELINUX LIST_MODEBITS|LIST_NLINKS|LIST_CONTEXT|LIST_SIZE|LIST_DATE_TIME, /* K */ LIST_MODEBITS|LIST_ID_NAME|LIST_CONTEXT, /* Z */ #endif - (1U<<31) - /* options after Z are not processed through opt_flags: - * T, w - ignored - */ + (1U << 31) + /* options after Z are not processed through opt_flags */ }; @@ -344,7 +362,7 @@ static struct dnode *my_stat(const char *fullname, const char *name, int force_f struct dnode *cur; IF_SELINUX(security_context_t sid = NULL;) - if ((all_fmt & FOLLOW_LINKS) || force_follow) { + if ((option_mask32 & OPT_L) || force_follow) { #if ENABLE_SELINUX if (is_selinux_enabled()) { getfilecon(fullname, &sid); @@ -699,7 +717,7 @@ static NOINLINE unsigned list_single(const struct dnode *dn) (int) major(dn->dstat.st_rdev), (int) minor(dn->dstat.st_rdev)); } else { - if (all_fmt & LS_DISP_HR) { + if (option_mask32 & OPT_h) { column += printf("%"HUMAN_READABLE_MAX_WIDTH_STR"s ", /* print st_size, show one fractional, use suffixes */ make_human_readable_str(dn->dstat.st_size, 1, 0) @@ -887,12 +905,6 @@ static void showdirs(struct dnode **dn, int first) struct dnode **subdnp; struct dnode **dnd; - /* Never happens: - if (dn == NULL || ndirs < 1) { - return; - } - */ - for (; *dn; dn++) { if (all_fmt & (DISP_DIRNAME | DISP_RECURSIVE)) { if (!first) @@ -1031,8 +1043,7 @@ int ls_main(int argc UNUSED_PARAM, char **argv) init_unicode(); - all_fmt = LIST_SHORT | - (ENABLE_FEATURE_LS_SORTFILES * (SORT_NAME | SORT_FORWARD)); + all_fmt = LIST_SHORT | (ENABLE_FEATURE_LS_SORTFILES * SORT_NAME); #if ENABLE_FEATURE_AUTOWIDTH /* obtain the terminal width */ @@ -1050,8 +1061,8 @@ int ls_main(int argc UNUSED_PARAM, char **argv) * in some pairs of opts, only last one takes effect: */ IF_FEATURE_LS_TIMESTAMPS(IF_FEATURE_LS_SORTFILES(":t-S:S-t")) /* time/size */ - // ":H-L:L-H:" - we don't have -H - // ":m-l:l-m:" - we don't have -m + // ":m-l:l-m" - we don't have -m + IF_FEATURE_LS_FOLLOWLINKS(":H-L:L-H") ":C-xl:x-Cl:l-xC" /* bycols/bylines/long */ ":C-1:1-C" /* bycols/oneline */ ":x-1:1-x" /* bylines/oneline (not in SuS, but in GNU coreutils 8.4) */ @@ -1062,9 +1073,9 @@ int ls_main(int argc UNUSED_PARAM, char **argv) IF_FEATURE_AUTOWIDTH(, NULL, &terminal_width) IF_FEATURE_LS_COLOR(, &color_opt) ); - for (i = 0; opt_flags[i] != (1U<<31); i++) { + for (i = 0; opt_flags[i] != (1U << 31); i++) { if (opt & (1 << i)) { - unsigned flags = opt_flags[i]; + uint32_t flags = opt_flags[i]; if (flags & STYLE_MASK) all_fmt &= ~STYLE_MASK; @@ -1134,9 +1145,11 @@ int ls_main(int argc UNUSED_PARAM, char **argv) dn = NULL; nfiles = 0; do { - /* NB: follow links on command line unless -l, -s or -F */ cur = my_stat(*argv, *argv, + /* follow links on command line unless -l, -s or -F: */ !((all_fmt & (STYLE_LONG|LIST_BLOCKS)) || (option_mask32 & OPT_F)) + /* ... or if -H: */ + || (option_mask32 & OPT_H) ); argv++; if (!cur) -- cgit v1.2.3-55-g6feb From a4bc10cec7645d72c7284deec070c0f56ebdadaf Mon Sep 17 00:00:00 2001 From: James Youngman Date: Mon, 20 Dec 2010 01:36:16 +0100 Subject: ls: remove redundant constants LIST_FILENAME and LIST_SHORT LIST_FILENAME is always true and LIST_SHORT affects nothing. Signed-off-by: James Youngman Signed-off-by: Denys Vlasenko --- coreutils/ls.c | 91 ++++++++++++++++++++++++++++------------------------------ 1 file changed, 44 insertions(+), 47 deletions(-) diff --git a/coreutils/ls.c b/coreutils/ls.c index d27c36ddc..2be3afadf 100644 --- a/coreutils/ls.c +++ b/coreutils/ls.c @@ -135,51 +135,48 @@ LIST_ID_NAME = 1 << 4, LIST_ID_NUMERIC = 1 << 5, LIST_CONTEXT = 1 << 6, LIST_SIZE = 1 << 7, -//LIST_DEV = 1 << 8, - unused, synonym to LIST_SIZE -LIST_DATE_TIME = 1 << 9, -LIST_FULLTIME = 1 << 10, -LIST_FILENAME = 1 << 11, -LIST_SYMLINK = 1 << 12, -LIST_FILETYPE = 1 << 13, -LIST_EXEC = 1 << 14, +LIST_DATE_TIME = 1 << 8, +LIST_FULLTIME = 1 << 9, +LIST_SYMLINK = 1 << 10, +LIST_FILETYPE = 1 << 11, +LIST_EXEC = 1 << 12, LIST_MASK = (LIST_EXEC << 1) - 1, /* what files will be displayed */ -DISP_DIRNAME = 1 << 15, /* 2 or more items? label directories */ -DISP_HIDDEN = 1 << 16, /* show filenames starting with . */ -DISP_DOT = 1 << 17, /* show . and .. */ -DISP_NOLIST = 1 << 18, /* show directory as itself, not contents */ -DISP_RECURSIVE = 1 << 19, /* show directory and everything below it */ -DISP_ROWS = 1 << 20, /* print across rows */ +DISP_DIRNAME = 1 << 13, /* 2 or more items? label directories */ +DISP_HIDDEN = 1 << 14, /* show filenames starting with . */ +DISP_DOT = 1 << 15, /* show . and .. */ +DISP_NOLIST = 1 << 16, /* show directory as itself, not contents */ +DISP_RECURSIVE = 1 << 17, /* show directory and everything below it */ +DISP_ROWS = 1 << 18, /* print across rows */ DISP_MASK = ((DISP_ROWS << 1) - 1) & ~(DISP_DIRNAME - 1), /* what is the overall style of the listing */ -STYLE_COLUMNAR = 1 << 21, /* many records per line */ -STYLE_LONG = 2 << 21, /* one record per line, extended info */ -STYLE_SINGLE = 3 << 21, /* one record per line */ +STYLE_COLUMNAR = 1 << 19, /* many records per line */ +STYLE_LONG = 2 << 19, /* one record per line, extended info */ +STYLE_SINGLE = 3 << 19, /* one record per line */ STYLE_MASK = STYLE_SINGLE, /* which of the three times will be used */ -TIME_CHANGE = (1 << 23) * ENABLE_FEATURE_LS_TIMESTAMPS, -TIME_ACCESS = (1 << 24) * ENABLE_FEATURE_LS_TIMESTAMPS, -TIME_MASK = (3 << 23) * ENABLE_FEATURE_LS_TIMESTAMPS, +TIME_CHANGE = (1 << 21) * ENABLE_FEATURE_LS_TIMESTAMPS, +TIME_ACCESS = (1 << 22) * ENABLE_FEATURE_LS_TIMESTAMPS, +TIME_MASK = (3 << 21) * ENABLE_FEATURE_LS_TIMESTAMPS, /* how will the files be sorted (CONFIG_FEATURE_LS_SORTFILES) */ -SORT_REVERSE = 1 << 25, +SORT_REVERSE = 1 << 23, SORT_NAME = 0, /* sort by file name */ -SORT_SIZE = 1 << 26, /* sort by file size */ -SORT_ATIME = 2 << 26, /* sort by last access time */ -SORT_CTIME = 3 << 26, /* sort by last change time */ -SORT_MTIME = 4 << 26, /* sort by last modification time */ -SORT_VERSION = 5 << 26, /* sort by version */ -SORT_EXT = 6 << 26, /* sort by file name extension */ -SORT_DIR = 7 << 26, /* sort by file or directory */ -SORT_MASK = (7 << 26) * ENABLE_FEATURE_LS_SORTFILES, - -LIST_SHORT = LIST_FILENAME, +SORT_SIZE = 1 << 24, /* sort by file size */ +SORT_ATIME = 2 << 24, /* sort by last access time */ +SORT_CTIME = 3 << 24, /* sort by last change time */ +SORT_MTIME = 4 << 24, /* sort by last modification time */ +SORT_VERSION = 5 << 24, /* sort by version */ +SORT_EXT = 6 << 24, /* sort by file name extension */ +SORT_DIR = 7 << 24, /* sort by file or directory */ +SORT_MASK = (7 << 24) * ENABLE_FEATURE_LS_SORTFILES, + LIST_LONG = LIST_MODEBITS | LIST_NLINKS | LIST_ID_NAME | LIST_SIZE | \ - LIST_DATE_TIME | LIST_FILENAME | LIST_SYMLINK, + LIST_DATE_TIME | LIST_SYMLINK, }; /* -Cadil1 Std options, busybox always supports */ @@ -265,16 +262,16 @@ enum { /* TODO: simple toggles may be stored as OPT_xxx bits instead */ static const uint32_t opt_flags[] = { - LIST_SHORT | STYLE_COLUMNAR, /* C */ + STYLE_COLUMNAR, /* C */ DISP_HIDDEN | DISP_DOT, /* a */ DISP_NOLIST, /* d */ LIST_INO, /* i */ LIST_LONG | STYLE_LONG, /* l */ - LIST_SHORT | STYLE_SINGLE, /* 1 */ + STYLE_SINGLE, /* 1 */ 0, /* g (don't show owner) - handled via OPT_g */ LIST_ID_NUMERIC, /* n */ LIST_BLOCKS, /* s */ - LIST_SHORT | DISP_ROWS | STYLE_COLUMNAR, /* x */ + DISP_ROWS | STYLE_COLUMNAR, /* x */ 0, /* Q (quote filename) - handled via OPT_Q */ DISP_HIDDEN, /* A */ ENABLE_SELINUX * LIST_CONTEXT, /* k (ignored if !SELINUX) */ @@ -711,7 +708,7 @@ static NOINLINE unsigned list_single(const struct dnode *dn) (int) dn->dstat.st_uid, (int) dn->dstat.st_gid); } - if (all_fmt & (LIST_SIZE /*|LIST_DEV*/ )) { + if (all_fmt & LIST_SIZE) { if (S_ISBLK(dn->dstat.st_mode) || S_ISCHR(dn->dstat.st_mode)) { column += printf("%4u, %3u ", (int) major(dn->dstat.st_rdev), @@ -759,20 +756,20 @@ static NOINLINE unsigned list_single(const struct dnode *dn) freecon(dn->sid); } #endif - if (all_fmt & LIST_FILENAME) { + #if ENABLE_FEATURE_LS_COLOR - if (show_color) { - info.st_mode = 0; /* for fgcolor() */ - lstat(dn->fullname, &info); - printf("\033[%u;%um", bold(info.st_mode), - fgcolor(info.st_mode)); - } + if (show_color) { + info.st_mode = 0; /* for fgcolor() */ + lstat(dn->fullname, &info); + printf("\033[%u;%um", bold(info.st_mode), + fgcolor(info.st_mode)); + } #endif - column += print_name(dn->name); - if (show_color) { - printf("\033[0m"); - } + column += print_name(dn->name); + if (show_color) { + printf("\033[0m"); } + if (all_fmt & LIST_SYMLINK) { if (S_ISLNK(dn->dstat.st_mode) && lpath) { printf(" -> "); @@ -1043,7 +1040,7 @@ int ls_main(int argc UNUSED_PARAM, char **argv) init_unicode(); - all_fmt = LIST_SHORT | (ENABLE_FEATURE_LS_SORTFILES * SORT_NAME); + all_fmt = ENABLE_FEATURE_LS_SORTFILES * SORT_NAME; #if ENABLE_FEATURE_AUTOWIDTH /* obtain the terminal width */ -- cgit v1.2.3-55-g6feb From 27c6c00a7cf141aaa972c0f9691072db287a36ae Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Mon, 20 Dec 2010 03:43:20 +0100 Subject: test: add examples when "%s: unknown operand" happens Signed-off-by: Denys Vlasenko --- coreutils/test.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/coreutils/test.c b/coreutils/test.c index 6524c4f07..8248a1ef5 100644 --- a/coreutils/test.c +++ b/coreutils/test.c @@ -878,7 +878,10 @@ int test_main(int argc, char **argv) res = !oexpr(check_operator(*args)); if (*args != NULL && *++args != NULL) { - /* TODO: example when this happens? */ + /* Examples: + * test 3 -lt 5 6 + * test -t 1 2 + */ bb_error_msg("%s: unknown operand", *args); res = 2; } -- cgit v1.2.3-55-g6feb From 5707b52fd4de0d9d5ebb496f459fa4fa66215226 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Mon, 20 Dec 2010 05:12:39 +0100 Subject: mailutils/*: add verbose option to sendmail; remove -m and -j from makemime Signed-off-by: Denys Vlasenko --- include/usage.src.h | 30 ----------------------- mailutils/mail.c | 11 +++++---- mailutils/mail.h | 18 ++++++++++---- mailutils/mime.c | 32 +++++++++++++++++++++---- mailutils/popmaildir.c | 5 ++-- mailutils/sendmail.c | 64 +++++++++++++++++++++++++++++++++++++++++++------- 6 files changed, 106 insertions(+), 54 deletions(-) diff --git a/include/usage.src.h b/include/usage.src.h index cd37a892d..4640338e6 100644 --- a/include/usage.src.h +++ b/include/usage.src.h @@ -3211,36 +3211,6 @@ INSERT #define selinuxenabled_trivial_usage NOUSAGE_STR #define selinuxenabled_full_usage "" -#define sendmail_trivial_usage \ - "[OPTIONS] [RECIPIENT_EMAIL]..." -#define sendmail_full_usage "\n\n" \ - "Read email from stdin and send it\n" \ - "\nStandard options:" \ - "\n -t Read additional recipients from message body" \ - "\n -f sender Sender (required)" \ - "\n -o options Various options. -oi implied, others are ignored" \ - "\n -i -oi synonym. implied and ignored" \ - "\n" \ - "\nBusybox specific options:" \ - "\n -w seconds Network timeout" \ - "\n -H 'PROG ARGS' Run connection helper" \ - "\n Examples:" \ - "\n -H 'exec openssl s_client -quiet -tls1 -starttls smtp" \ - "\n -connect smtp.gmail.com:25' -ap]" \ - "\n -H 'exec openssl s_client -quiet -tls1" \ - "\n -connect smtp.gmail.com:465' -ap]" \ - "\n -S server[:port] Server" \ - "\n -au Username for AUTH LOGIN" \ - "\n -ap Password for AUTH LOGIN" \ - "\n -am Authentication method. Ignored. LOGIN is implied" \ - "\n" \ - "\nOther options are silently ignored; -oi -t is implied" \ - IF_MAKEMIME( \ - "\nUse makemime applet to create message with attachments" \ - ) - #define seq_trivial_usage \ "[-w] [-s SEP] [FIRST [INC]] LAST" #define seq_full_usage "\n\n" \ diff --git a/mailutils/mail.c b/mailutils/mail.c index 9b4bebce5..44957016f 100644 --- a/mailutils/mail.c +++ b/mailutils/mail.c @@ -75,13 +75,16 @@ void FAST_FUNC launch_helper(const char **argv) atexit(kill_helper); } -const FAST_FUNC char *command(const char *fmt, const char *param) +char* FAST_FUNC send_mail_command(const char *fmt, const char *param) { - const char *msg = fmt; + char *msg; if (timeout) alarm(timeout); - if (msg) { + msg = (char*)fmt; + if (fmt) { msg = xasprintf(fmt, param); + if (verbose) + bb_error_msg("send:'%s'", msg); printf("%s\r\n", msg); } fflush_all(); @@ -90,7 +93,7 @@ const FAST_FUNC char *command(const char *fmt, const char *param) // NB: parse_url can modify url[] (despite const), but only if '@' is there /* -static char FAST_FUNC *parse_url(char *url, char **user, char **pass) +static char* FAST_FUNC parse_url(char *url, char **user, char **pass) { // parse [user[:pass]@]host // return host diff --git a/mailutils/mail.h b/mailutils/mail.h index e0048fbfa..d1d783055 100644 --- a/mailutils/mail.h +++ b/mailutils/mail.h @@ -1,7 +1,16 @@ +/* vi: set sw=4 ts=4: */ +/* + * helper routines + * + * Copyright (C) 2008 by Vladimir Dronnikov + * + * Licensed under GPLv2, see file LICENSE in this source tree. + */ struct globals { pid_t helper_pid; unsigned timeout; + unsigned verbose; unsigned opts; char *user; char *pass; @@ -12,6 +21,7 @@ struct globals { #define G (*ptr_to_globals) #define timeout (G.timeout ) +#define verbose (G.verbose ) #define opts (G.opts ) //#define user (G.user ) //#define pass (G.pass ) @@ -26,9 +36,9 @@ struct globals { //char FAST_FUNC *parse_url(char *url, char **user, char **pass); -void FAST_FUNC launch_helper(const char **argv); -void FAST_FUNC get_cred_or_die(int fd); +void launch_helper(const char **argv) FAST_FUNC; +void get_cred_or_die(int fd) FAST_FUNC; -const FAST_FUNC char *command(const char *fmt, const char *param); +char *send_mail_command(const char *fmt, const char *param) FAST_FUNC; -void FAST_FUNC encode_base64(char *fname, const char *text, const char *eol); +void encode_base64(char *fname, const char *text, const char *eol) FAST_FUNC; diff --git a/mailutils/mime.c b/mailutils/mime.c index 682cf4536..1e393ed31 100644 --- a/mailutils/mime.c +++ b/mailutils/mime.c @@ -99,6 +99,28 @@ Content-Transfer-Encoding: 7bit ...random junk added by mailing list robots and such... */ +/* man makemime: + + * -c TYPE: create a (non-multipart) MIME section with Content-Type: TYPE + * makemime -c TYPE [-e ENCODING] [-o OUTFILE] [-C CHARSET] [-N NAME] [-a HEADER...] FILE + * The -C option sets the MIME charset attribute for text/plain content. + * The -N option sets the name attribute for Content-Type: + * Encoding must be one of the following: 7bit, 8bit, quoted-printable, or base64. + + * -m multipart/TYPE: create a multipart MIME collection with Content-Type: multipart/TYPE + * makemime -m multipart/TYPE [-e ENCODING] [-o OUTFILE] [-a HEADER...] FILE + * Type must be either "multipart/mixed", "multipart/alternative", or some other MIME multipart content type. + * Additionally, encoding can only be "7bit" or "8bit", and will default to "8bit" if not specified. + * Finally, filename must be a MIME-formatted section, NOT a regular file. + * The -m option creates an initial multipart MIME collection, that contains only one MIME section, taken from filename. + * The collection is written to standard output, or the pipe or to outputfile. + + * -j FILE1: add a section to a multipart MIME collection + * makemime -j FILE1 [-o OUTFILE] FILE2 + * FILE1 must be a MIME collection that was previously created by the -m option. + * FILE2 must be a MIME section that was previously created by the -c option. + * The -j options adds the MIME section in FILE2 to the MIME collection in FILE1. + */ int makemime_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int makemime_main(int argc UNUSED_PARAM, char **argv) { @@ -107,14 +129,14 @@ int makemime_main(int argc UNUSED_PARAM, char **argv) #define boundary opt_output enum { - OPT_c = 1 << 0, // Content-Type: + OPT_c = 1 << 0, // create (non-multipart) section OPT_e = 1 << 1, // Content-Transfer-Encoding. Ignored. Assumed base64 OPT_o = 1 << 2, // output to OPT_C = 1 << 3, // charset OPT_N = 1 << 4, // COMPAT OPT_a = 1 << 5, // additional headers - OPT_m = 1 << 6, // COMPAT - OPT_j = 1 << 7, // COMPAT + //OPT_m = 1 << 6, // create mutipart section + //OPT_j = 1 << 7, // join section to multipart section }; INIT_G(); @@ -122,8 +144,8 @@ int makemime_main(int argc UNUSED_PARAM, char **argv) // parse options opt_complementary = "a::"; opts = getopt32(argv, - "c:e:o:C:N:a:m:j:", - &G.content_type, NULL, &opt_output, &G.opt_charset, NULL, &opt_headers, NULL, NULL + "c:e:o:C:N:a", //:m:j:", + &G.content_type, NULL, &opt_output, &G.opt_charset, NULL, &opt_headers //, NULL, NULL ); //argc -= optind; argv += optind; diff --git a/mailutils/popmaildir.c b/mailutils/popmaildir.c index 77ec71129..6b733441f 100644 --- a/mailutils/popmaildir.c +++ b/mailutils/popmaildir.c @@ -14,9 +14,10 @@ static void pop3_checkr(const char *fmt, const char *param, char **ret) { - const char *msg = command(fmt, param); + char *msg = send_mail_command(fmt, param); char *answer = xmalloc_fgetline(stdin); if (answer && '+' == answer[0]) { + free(msg); if (timeout) alarm(0); if (ret) { @@ -27,7 +28,7 @@ static void pop3_checkr(const char *fmt, const char *param, char **ret) free(answer); return; } - bb_error_msg_and_die("%s failed: %s", msg, answer); + bb_error_msg_and_die("%s failed, reply was: %s", msg, answer); } static void pop3_check(const char *fmt, const char *param) diff --git a/mailutils/sendmail.c b/mailutils/sendmail.c index ec97cf8af..a2eda6937 100644 --- a/mailutils/sendmail.c +++ b/mailutils/sendmail.c @@ -6,6 +6,38 @@ * * Licensed under GPLv2, see file LICENSE in this source tree. */ + +//usage:#define sendmail_trivial_usage +//usage: "[OPTIONS] [RECIPIENT_EMAIL]..." +//usage:#define sendmail_full_usage "\n\n" +//usage: "Read email from stdin and send it\n" +//usage: "\nStandard options:" +//usage: "\n -t Read additional recipients from message body" +//usage: "\n -f SENDER Sender (required)" +//usage: "\n -o OPTIONS Various options. -oi implied, others are ignored" +//usage: "\n -i -oi synonym. implied and ignored" +//usage: "\n" +//usage: "\nBusybox specific options:" +//usage: "\n -v Verbose" +//usage: "\n -w SECS Network timeout" +//usage: "\n -H 'PROG ARGS' Run connection helper" +//usage: "\n Examples:" +//usage: "\n -H 'exec openssl s_client -quiet -tls1 -starttls smtp" +//usage: "\n -connect smtp.gmail.com:25' -ap]" +//usage: "\n -H 'exec openssl s_client -quiet -tls1" +//usage: "\n -connect smtp.gmail.com:465' -ap]" +//usage: "\n -S HOST[:PORT] Server" +//usage: "\n -au Username for AUTH LOGIN" +//usage: "\n -ap Password for AUTH LOGIN" +//usage: "\n -am Authentication method. Ignored. LOGIN is implied" +//usage: "\n" +//usage: "\nOther options are silently ignored; -oi -t is implied" +//usage: IF_MAKEMIME( +//usage: "\nUse makemime applet to create message with attachments" +//usage: ) + #include "libbb.h" #include "mail.h" @@ -13,23 +45,35 @@ // set to 0 to not limit #define MAX_HEADERS 256 +static void send_r_n(const char *s) +{ + if (verbose) + bb_error_msg("send:'%s'", s); + printf("%s\r\n", s); +} + static int smtp_checkp(const char *fmt, const char *param, int code) { char *answer; - const char *msg = command(fmt, param); + char *msg = send_mail_command(fmt, param); // read stdin - // if the string has a form \d\d\d- -- read next string. E.g. EHLO response + // if the string has a form NNN- -- read next string. E.g. EHLO response // parse first bytes to a number // if code = -1 then just return this number // if code != -1 then checks whether the number equals the code // if not equal -> die saying msg - while ((answer = xmalloc_fgetline(stdin)) != NULL) + while ((answer = xmalloc_fgetline(stdin)) != NULL) { +// if (verbose) + bb_error_msg("recv:'%.*s' %d", (int)(strchrnul(answer, '\r') - answer), answer, verbose); if (strlen(answer) <= 3 || '-' != answer[3]) break; + free(answer); + } if (answer) { int n = atoi(answer); if (timeout) alarm(0); + free(msg); free(answer); if (-1 == code || n == code) return n; @@ -86,6 +130,7 @@ int sendmail_main(int argc UNUSED_PARAM, char **argv) OPT_H = 1 << 5, // use external connection helper OPT_S = 1 << 6, // specify connection string OPT_a = 1 << 7, // authentication tokens + OPT_v = 1 << 8, // verbosity }; // init global variables @@ -96,12 +141,13 @@ int sendmail_main(int argc UNUSED_PARAM, char **argv) G.fp0 = xfdopen_for_read(3); // parse options - // -f is required. -H and -S are mutually exclusive - opt_complementary = "f:w+:H--S:S--H:a::"; + // -v is a counter, -f is required. -H and -S are mutually exclusive, -a is a list + opt_complementary = "vv:f:w+:H--S:S--H:a::"; // N.B. since -H and -S are mutually exclusive they do not interfere in opt_connect // -a is for ssmtp (http://downloads.openwrt.org/people/nico/man/man8/ssmtp.8.html) compatibility, // it is still under development. - opts = getopt32(argv, "tf:o:iw:H:S:a::", &opt_from, NULL, &timeout, &opt_connect, &opt_connect, &list); + opts = getopt32(argv, "tf:o:iw:H:S:a::v", &opt_from, NULL, + &timeout, &opt_connect, &opt_connect, &list, &verbose); //argc -= optind; argv += optind; @@ -214,7 +260,7 @@ int sendmail_main(int argc UNUSED_PARAM, char **argv) if ('.' == s[0] /*&& '\0' == s[1] */) printf("."); // dump read line - printf("%s\r\n", s); + send_r_n(s); free(s); continue; } @@ -261,14 +307,14 @@ int sendmail_main(int argc UNUSED_PARAM, char **argv) goto bail; // dump the headers while (list) { - printf("%s\r\n", (char *) llist_pop(&list)); + send_r_n((char *) llist_pop(&list)); } // stop analyzing headers code++; // N.B. !s means: we read nothing, and nothing to be read in the future. // just dump empty line and break the loop if (!s) { - puts("\r"); + send_r_n(""); break; } // go dump message body -- cgit v1.2.3-55-g6feb From 51d714ce7e8d68f0762d89b2a67cf42d2c991685 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Mon, 20 Dec 2010 12:19:46 +0100 Subject: sendmail: remove forgotten commenting-out on a "if (verbose)" Signed-off-by: Denys Vlasenko --- mailutils/sendmail.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mailutils/sendmail.c b/mailutils/sendmail.c index a2eda6937..8096288ef 100644 --- a/mailutils/sendmail.c +++ b/mailutils/sendmail.c @@ -63,7 +63,7 @@ static int smtp_checkp(const char *fmt, const char *param, int code) // if code != -1 then checks whether the number equals the code // if not equal -> die saying msg while ((answer = xmalloc_fgetline(stdin)) != NULL) { -// if (verbose) + if (verbose) bb_error_msg("recv:'%.*s' %d", (int)(strchrnul(answer, '\r') - answer), answer, verbose); if (strlen(answer) <= 3 || '-' != answer[3]) break; -- cgit v1.2.3-55-g6feb From 75eb9d20e9e672c33e377221d1f7d4546f919f9e Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Tue, 21 Dec 2010 21:18:12 +0100 Subject: hush: fix FEATURE_CLEAN_UP code (was freeing unallocated memory) Signed-off-by: Denys Vlasenko --- shell/hush.c | 94 +++++++++++++++++++++++++++++++----------------------------- 1 file changed, 49 insertions(+), 45 deletions(-) diff --git a/shell/hush.c b/shell/hush.c index 2bca9aa87..a771e9cd9 100644 --- a/shell/hush.c +++ b/shell/hush.c @@ -931,7 +931,7 @@ static const struct built_in_command bltins2[] = { */ #if HUSH_DEBUG /* prevent disasters with G.debug_indent < 0 */ -# define indent() fprintf(stderr, "%*s", (G.debug_indent * 2) & 0xff, "") +# define indent() fdprintf(2, "%*s", (G.debug_indent * 2) & 0xff, "") # define debug_enter() (G.debug_indent++) # define debug_leave() (G.debug_indent--) #else @@ -941,56 +941,56 @@ static const struct built_in_command bltins2[] = { #endif #ifndef debug_printf -# define debug_printf(...) (indent(), fprintf(stderr, __VA_ARGS__)) +# define debug_printf(...) (indent(), fdprintf(2, __VA_ARGS__)) #endif #ifndef debug_printf_parse -# define debug_printf_parse(...) (indent(), fprintf(stderr, __VA_ARGS__)) +# define debug_printf_parse(...) (indent(), fdprintf(2, __VA_ARGS__)) #endif #ifndef debug_printf_exec -#define debug_printf_exec(...) (indent(), fprintf(stderr, __VA_ARGS__)) +#define debug_printf_exec(...) (indent(), fdprintf(2, __VA_ARGS__)) #endif #ifndef debug_printf_env -# define debug_printf_env(...) (indent(), fprintf(stderr, __VA_ARGS__)) +# define debug_printf_env(...) (indent(), fdprintf(2, __VA_ARGS__)) #endif #ifndef debug_printf_jobs -# define debug_printf_jobs(...) (indent(), fprintf(stderr, __VA_ARGS__)) +# define debug_printf_jobs(...) (indent(), fdprintf(2, __VA_ARGS__)) # define DEBUG_JOBS 1 #else # define DEBUG_JOBS 0 #endif #ifndef debug_printf_expand -# define debug_printf_expand(...) (indent(), fprintf(stderr, __VA_ARGS__)) +# define debug_printf_expand(...) (indent(), fdprintf(2, __VA_ARGS__)) # define DEBUG_EXPAND 1 #else # define DEBUG_EXPAND 0 #endif #ifndef debug_printf_varexp -# define debug_printf_varexp(...) (indent(), fprintf(stderr, __VA_ARGS__)) +# define debug_printf_varexp(...) (indent(), fdprintf(2, __VA_ARGS__)) #endif #ifndef debug_printf_glob -# define debug_printf_glob(...) (indent(), fprintf(stderr, __VA_ARGS__)) +# define debug_printf_glob(...) (indent(), fdprintf(2, __VA_ARGS__)) # define DEBUG_GLOB 1 #else # define DEBUG_GLOB 0 #endif #ifndef debug_printf_list -# define debug_printf_list(...) (indent(), fprintf(stderr, __VA_ARGS__)) +# define debug_printf_list(...) (indent(), fdprintf(2, __VA_ARGS__)) #endif #ifndef debug_printf_subst -# define debug_printf_subst(...) (indent(), fprintf(stderr, __VA_ARGS__)) +# define debug_printf_subst(...) (indent(), fdprintf(2, __VA_ARGS__)) #endif #ifndef debug_printf_clean -# define debug_printf_clean(...) (indent(), fprintf(stderr, __VA_ARGS__)) +# define debug_printf_clean(...) (indent(), fdprintf(2, __VA_ARGS__)) # define DEBUG_CLEAN 1 #else # define DEBUG_CLEAN 0 @@ -1000,9 +1000,9 @@ static const struct built_in_command bltins2[] = { static void debug_print_strings(const char *prefix, char **vv) { indent(); - fprintf(stderr, "%s:\n", prefix); + fdprintf(2, "%s:\n", prefix); while (*vv) - fprintf(stderr, " '%s'\n", *vv++); + fdprintf(2, " '%s'\n", *vv++); } #else # define debug_print_strings(prefix, vv) ((void)0) @@ -1434,6 +1434,22 @@ static void hush_exit(int exitcode) builtin_eval(argv); } +#if ENABLE_FEATURE_CLEAN_UP + { + struct variable *cur_var; + if (G.cwd != bb_msg_unknown) + free((char*)G.cwd); + cur_var = G.top_var; + while (cur_var) { + struct variable *tmp = cur_var; + if (!cur_var->max_len) + free(cur_var->varstr); + cur_var = cur_var->next; + free(tmp); + } + } +#endif + #if ENABLE_HUSH_JOB fflush_all(); sigexit(- (exitcode & 0xff)); @@ -2176,22 +2192,22 @@ static void debug_print_list(const char *prefix, o_string *o, int n) int i = 0; indent(); - fprintf(stderr, "%s: list:%p n:%d string_start:%d length:%d maxlen:%d glob:%d quoted:%d escape:%d\n", + fdprintf(2, "%s: list:%p n:%d string_start:%d length:%d maxlen:%d glob:%d quoted:%d escape:%d\n", prefix, list, n, string_start, o->length, o->maxlen, !!(o->o_expflags & EXP_FLAG_GLOB), o->has_quoted_part, !!(o->o_expflags & EXP_FLAG_ESC_GLOB_CHARS)); while (i < n) { indent(); - fprintf(stderr, " list[%d]=%d '%s' %p\n", i, (int)list[i], - o->data + (int)list[i] + string_start, - o->data + (int)list[i] + string_start); + fdprintf(2, " list[%d]=%d '%s' %p\n", i, (int)(uintptr_t)list[i], + o->data + (int)(uintptr_t)list[i] + string_start, + o->data + (int)(uintptr_t)list[i] + string_start); i++; } if (n) { - const char *p = o->data + (int)list[n - 1] + string_start; + const char *p = o->data + (int)(uintptr_t)list[n - 1] + string_start; indent(); - fprintf(stderr, " total_sz:%ld\n", (long)((p + strlen(p) + 1) - o->data)); + fdprintf(2, " total_sz:%ld\n", (long)((p + strlen(p) + 1) - o->data)); } } #else @@ -2690,18 +2706,18 @@ static void debug_print_tree(struct pipe *pi, int lvl) pin = 0; while (pi) { - fprintf(stderr, "%*spipe %d res_word=%s followup=%d %s\n", lvl*2, "", + fdprintf(2, "%*spipe %d res_word=%s followup=%d %s\n", lvl*2, "", pin, RES[pi->res_word], pi->followup, PIPE[pi->followup]); prn = 0; while (prn < pi->num_cmds) { struct command *command = &pi->cmds[prn]; char **argv = command->argv; - fprintf(stderr, "%*s cmd %d assignment_cnt:%d", + fdprintf(2, "%*s cmd %d assignment_cnt:%d", lvl*2, "", prn, command->assignment_cnt); if (command->group) { - fprintf(stderr, " group %s: (argv=%p)%s%s\n", + fdprintf(2, " group %s: (argv=%p)%s%s\n", CMDTYPE[command->cmd_type], argv # if !BB_MMU @@ -2715,10 +2731,10 @@ static void debug_print_tree(struct pipe *pi, int lvl) continue; } if (argv) while (*argv) { - fprintf(stderr, " '%s'", *argv); + fdprintf(2, " '%s'", *argv); argv++; } - fprintf(stderr, "\n"); + fdprintf(2, "\n"); prn++; } pi = pi->next; @@ -7463,7 +7479,7 @@ int hush_main(int argc, char **argv) unsigned builtin_argc; char **e; struct variable *cur_var; - struct variable shell_ver; + struct variable *shell_ver; INIT_G(); if (EXIT_SUCCESS) /* if EXIT_SUCCESS == 0, it is already done */ @@ -7472,17 +7488,17 @@ int hush_main(int argc, char **argv) G.argv0_for_re_execing = argv[0]; #endif /* Deal with HUSH_VERSION */ - memset(&shell_ver, 0, sizeof(shell_ver)); - shell_ver.flg_export = 1; - shell_ver.flg_read_only = 1; + shell_ver = xzalloc(sizeof(*shell_ver)); + shell_ver->flg_export = 1; + shell_ver->flg_read_only = 1; /* Code which handles ${var...} needs writable values for all variables, * therefore we xstrdup: */ - shell_ver.varstr = xstrdup(hush_version_str), - G.top_var = &shell_ver; + shell_ver->varstr = xstrdup(hush_version_str); /* Create shell local variables from the values * currently living in the environment */ debug_printf_env("unsetenv '%s'\n", "HUSH_VERSION"); unsetenv("HUSH_VERSION"); /* in case it exists in initial env */ + G.top_var = shell_ver; cur_var = G.top_var; e = environ; if (e) while (*e) { @@ -7497,8 +7513,8 @@ int hush_main(int argc, char **argv) e++; } /* (Re)insert HUSH_VERSION into env (AFTER we scanned the env!) */ - debug_printf_env("putenv '%s'\n", shell_ver.varstr); - putenv(shell_ver.varstr); + debug_printf_env("putenv '%s'\n", shell_ver->varstr); + putenv(shell_ver->varstr); /* Export PWD */ set_pwd_var(/*exp:*/ 1); @@ -7858,18 +7874,6 @@ int hush_main(int argc, char **argv) parse_and_run_file(stdin); final_return: -#if ENABLE_FEATURE_CLEAN_UP - if (G.cwd != bb_msg_unknown) - free((char*)G.cwd); - cur_var = G.top_var->next; - while (cur_var) { - struct variable *tmp = cur_var; - if (!cur_var->max_len) - free(cur_var->varstr); - cur_var = cur_var->next; - free(tmp); - } -#endif hush_exit(G.last_exitcode); } -- cgit v1.2.3-55-g6feb From 8993c3f260ba50ca8cbbd8a0185dd9d825bbaa2b Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sat, 25 Dec 2010 06:21:54 +0100 Subject: udhcpc: document SIGUSRn effect in help text Signed-off-by: Denys Vlasenko --- networking/udhcp/dhcpc.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/networking/udhcp/dhcpc.c b/networking/udhcp/dhcpc.c index 78aabedf2..7e5ab61fd 100644 --- a/networking/udhcp/dhcpc.c +++ b/networking/udhcp/dhcpc.c @@ -926,6 +926,10 @@ static void client_background(void) //usage: "\n -v Verbose" //usage: ) //usage: ) +//usage: "\nSignals:" +//usage: "\n USR1 Renew current lease" +//usage: "\n USR2 Release current lease" + int udhcpc_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int udhcpc_main(int argc UNUSED_PARAM, char **argv) -- cgit v1.2.3-55-g6feb From 6088e138e1c6d0b73f8004fc4b4e9ec40430e18e Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sat, 25 Dec 2010 23:58:42 +0100 Subject: init: simpler handling of leading dash in commands function old new delta init_exec 233 219 -14 Signed-off-by: Denys Vlasenko --- init/init.c | 20 +++++++++++--------- shell/ash.c | 2 +- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/init/init.c b/init/init.c index 0a0d503b5..a2cc3b5f5 100644 --- a/init/init.c +++ b/init/init.c @@ -401,20 +401,22 @@ static void init_exec(const char *command) char buf[COMMAND_SIZE + 6]; /* COMMAND_SIZE+strlen("exec ")+1 */ int dash = (command[0] == '-' /* maybe? && command[1] == '/' */); + command += dash; + /* See if any special /bin/sh requiring characters are present */ if (strpbrk(command, "~`!$^&*()=|\\{}[];\"'<>?") != NULL) { - strcpy(buf, "exec "); - strcpy(buf + 5, command + dash); /* excluding "-" */ + sprintf(buf, "exec %s", command); /* excluding "-" */ /* NB: LIBBB_DEFAULT_LOGIN_SHELL define has leading dash */ cmd[0] = (char*)(LIBBB_DEFAULT_LOGIN_SHELL + !dash); cmd[1] = (char*)"-c"; cmd[2] = buf; cmd[3] = NULL; + command = LIBBB_DEFAULT_LOGIN_SHELL + 1; } else { /* Convert command (char*) into cmd (char**, one word per string) */ char *word, *next; int i = 0; - next = strcpy(buf, command); /* including "-" */ + next = strcpy(buf, command - dash); /* command including "-" */ while ((word = strsep(&next, " \t")) != NULL) { if (*word != '\0') { /* not two spaces/tabs together? */ cmd[i] = word; @@ -425,14 +427,14 @@ static void init_exec(const char *command) } /* If we saw leading "-", it is interactive shell. * Try harder to give it a controlling tty. - * And skip "-" in actual exec call. */ - if (dash) { + */ + if (ENABLE_FEATURE_INIT_SCTTY && dash) { /* _Attempt_ to make stdin a controlling tty. */ - if (ENABLE_FEATURE_INIT_SCTTY) - ioctl(STDIN_FILENO, TIOCSCTTY, 0 /*only try, don't steal*/); + ioctl(STDIN_FILENO, TIOCSCTTY, 0 /*only try, don't steal*/); } - BB_EXECVP(cmd[0] + dash, cmd); - message(L_LOG | L_CONSOLE, "can't run '%s': %s", cmd[0], strerror(errno)); + /* Here command never contains the dash, cmd[0] might */ + BB_EXECVP(command, cmd); + message(L_LOG | L_CONSOLE, "can't run '%s': %s", command, strerror(errno)); /* returns if execvp fails */ } diff --git a/shell/ash.c b/shell/ash.c index 5671a524b..6f03ac1c6 100644 --- a/shell/ash.c +++ b/shell/ash.c @@ -13063,7 +13063,7 @@ int ash_main(int argc UNUSED_PARAM, char **argv) } } #endif - if (/* argv[0] && */ argv[0][0] == '-') + if (argv[0] && argv[0][0] == '-') isloginsh = 1; if (isloginsh) { state = 1; -- cgit v1.2.3-55-g6feb From e4e911e7124fca9116ca14c31f125b687d0ae57e Mon Sep 17 00:00:00 2001 From: Serj Kalichev Date: Sun, 26 Dec 2010 01:56:19 +0100 Subject: modprobe: add support for --show-depends function old new delta modprobe_longopts - 16 +16 packed_usage 28018 28028 +10 modprobe_main 648 653 +5 do_modprobe 580 536 -44 ------------------------------------------------------------------------------ (add/remove: 1/0 grow/shrink: 2/1 up/down: 31/-44) Total: -13 bytes Signed-off-by: Serj Kalichev Signed-off-by: Denys Vlasenko --- archival/tar.c | 1 - modutils/modprobe.c | 95 +++++++++++++++++++++++++++++++++-------------------- 2 files changed, 60 insertions(+), 36 deletions(-) diff --git a/archival/tar.c b/archival/tar.c index 82caec770..ebaa965c0 100644 --- a/archival/tar.c +++ b/archival/tar.c @@ -882,7 +882,6 @@ int tar_main(int argc UNUSED_PARAM, char **argv) /* Prepend '-' to the first argument if required */ opt_complementary = "--:" // first arg is options "tt:vv:" // count -t,-v - "?:" // bail out with usage instead of error return "X::T::" // cumulative lists #if ENABLE_FEATURE_TAR_LONG_OPTIONS && ENABLE_FEATURE_TAR_FROM "\xff::" // cumulative lists for --exclude diff --git a/modutils/modprobe.c b/modutils/modprobe.c index a5cf4babf..8e83f4107 100644 --- a/modutils/modprobe.c +++ b/modutils/modprobe.c @@ -72,19 +72,21 @@ //usage: " from the command line\n" //usage: //usage:#define modprobe_trivial_usage -//usage: "[-alrqvs" -//usage: IF_FEATURE_MODPROBE_BLACKLIST("b") -//usage: "] MODULE [symbol=value]..." +//usage: "[-alrqvs" IF_FEATURE_MODPROBE_BLACKLIST("b") "]" +//usage: IF_LONG_OPTS(" [--show-depends]") " MODULE [symbol=value]..." //usage:#define modprobe_full_usage "\n\n" //usage: "Options:" -//usage: "\n -a Load multiple MODULEs" -//usage: "\n -l List (MODULE is a pattern)" -//usage: "\n -r Remove MODULE (stacks) or do autoclean" -//usage: "\n -q Quiet" -//usage: "\n -v Verbose" -//usage: "\n -s Log to syslog" +//usage: "\n -a Load multiple MODULEs" +//usage: "\n -l List (MODULE is a pattern)" +//usage: "\n -r Remove MODULE (stacks) or do autoclean" +//usage: "\n -q Quiet" +//usage: "\n -v Verbose" +//usage: "\n -s Log to syslog" //usage: IF_FEATURE_MODPROBE_BLACKLIST( -//usage: "\n -b Apply blacklist to module names too" +//usage: "\n -b Apply blacklist to module names too" +//usage: ) +//usage: IF_LONG_OPTS( +//usage: "\n --show-depends Show dependencies" //usage: ) //usage:#endif /* !ENABLE_MODPROBE_SMALL */ @@ -101,24 +103,35 @@ * Older versions would only export the direct dependency list. */ + /* Note that usage text doesn't document various 2.4 options * we pull in through INSMOD_OPTS define */ - -#define MODPROBE_COMPLEMENTARY "q-v:v-q:l--ar:a--lr:r--al" #define MODPROBE_OPTS "alr" IF_FEATURE_MODPROBE_BLACKLIST("b") -//#define MODPROBE_COMPLEMENTARY "q-v:v-q:l--acr:a--lr:r--al" +#undef SD +#if ENABLE_LONG_OPTS +static const char modprobe_longopts[] ALIGN1 = + "show-depends\0" No_argument "\xff" + ; +# define SD "\xff" +#else +# define SD "" +#endif +#define MODPROBE_COMPLEMENTARY ("q-v:v-q:l--ar"SD":a--lr"SD":r--al"SD IF_LONG_OPTS(":\xff--arl")) //#define MODPROBE_OPTS "acd:lnrt:C:" IF_FEATURE_MODPROBE_BLACKLIST("b") +//#define MODPROBE_COMPLEMENTARY "q-v:v-q:l--acr:a--lr:r--al" enum { - MODPROBE_OPT_INSERT_ALL = (INSMOD_OPT_UNUSED << 0), /* a */ - //MODPROBE_OPT_DUMP_ONLY= (INSMOD_OPT_UNUSED << x), /* c */ - //MODPROBE_OPT_DIRNAME = (INSMOD_OPT_UNUSED << x), /* d */ - MODPROBE_OPT_LIST_ONLY = (INSMOD_OPT_UNUSED << 1), /* l */ - //MODPROBE_OPT_SHOW_ONLY= (INSMOD_OPT_UNUSED << x), /* n */ - MODPROBE_OPT_REMOVE = (INSMOD_OPT_UNUSED << 2), /* r */ - //MODPROBE_OPT_RESTRICT = (INSMOD_OPT_UNUSED << x), /* t */ - //MODPROBE_OPT_VERONLY = (INSMOD_OPT_UNUSED << x), /* V */ - //MODPROBE_OPT_CONFIGFILE=(INSMOD_OPT_UNUSED << x), /* C */ - MODPROBE_OPT_BLACKLIST = (INSMOD_OPT_UNUSED << 3) * ENABLE_FEATURE_MODPROBE_BLACKLIST, + OPT_INSERT_ALL = (INSMOD_OPT_UNUSED << 0), /* a */ + //OPT_DUMP_ONLY = (INSMOD_OPT_UNUSED << x), /* c */ + //OPT_DIRNAME = (INSMOD_OPT_UNUSED << x), /* d */ + OPT_LIST_ONLY = (INSMOD_OPT_UNUSED << 1), /* l */ + //OPT_SHOW_ONLY = (INSMOD_OPT_UNUSED << x), /* n */ + OPT_REMOVE = (INSMOD_OPT_UNUSED << 2), /* r */ + //OPT_RESTRICT = (INSMOD_OPT_UNUSED << x), /* t */ + //OPT_VERONLY = (INSMOD_OPT_UNUSED << x), /* V */ + //OPT_CONFIGFILE =(INSMOD_OPT_UNUSED << x), /* C */ + OPT_BLACKLIST = (INSMOD_OPT_UNUSED << 3) * ENABLE_FEATURE_MODPROBE_BLACKLIST, + OPTBIT_SHOW_DEPS = (3 + ENABLE_FEATURE_MODPROBE_BLACKLIST), + OPT_SHOW_DEPS = (INSMOD_OPT_UNUSED << OPTBIT_SHOW_DEPS) * ENABLE_LONG_OPTS, }; #define MODULE_FLAG_LOADED 0x0001 @@ -145,9 +158,13 @@ struct globals { int num_unresolved_deps; /* bool. "Did we have 'symbol:FOO' requested on cmdline?" */ smallint need_symbols; + struct utsname uts; } FIX_ALIASING; #define G (*(struct globals*)&bb_common_bufsiz1) #define INIT_G() do { } while (0) +struct BUG_G_too_big { + char BUG_G_too_big[sizeof(G) <= COMMON_BUFSIZE ? 1 : -1]; +}; static int read_config(const char *path); @@ -202,7 +219,7 @@ static void add_probe(const char *name) struct module_entry *m; m = get_or_add_modentry(name); - if (!(option_mask32 & MODPROBE_OPT_REMOVE) + if (!(option_mask32 & (OPT_REMOVE | OPT_SHOW_DEPS)) && (m->flags & MODULE_FLAG_LOADED) ) { DBG("skipping %s, it is already loaded", name); @@ -366,7 +383,7 @@ static int do_modprobe(struct module_entry *m) } DBG("do_modprob'ing %s", m->modname); - if (!(option_mask32 & MODPROBE_OPT_REMOVE)) + if (!(option_mask32 & OPT_REMOVE)) m->deps = llist_rev(m->deps); for (l = m->deps; l != NULL; l = l->link) @@ -379,7 +396,13 @@ static int do_modprobe(struct module_entry *m) fn = llist_pop(&m->deps); /* we leak it */ m2 = get_or_add_modentry(fn); - if (option_mask32 & MODPROBE_OPT_REMOVE) { + if (option_mask32 & OPT_SHOW_DEPS) { + printf("insmod %s/%s/%s\n", CONFIG_DEFAULT_MODULES_DIR, + G.uts.release, fn); + continue; + } + + if (option_mask32 & OPT_REMOVE) { /* modprobe -r */ if (m2->flags & MODULE_FLAG_LOADED) { rc = bb_delete_module(m2->modname, O_EXCL); @@ -456,7 +479,7 @@ static void load_modules_dep(void) /* Optimization... */ if ((m->flags & MODULE_FLAG_LOADED) - && !(option_mask32 & MODPROBE_OPT_REMOVE) + && !(option_mask32 & (OPT_REMOVE | OPT_SHOW_DEPS)) ) { DBG("skip deps of %s, it's already loaded", tokens[0]); continue; @@ -477,21 +500,23 @@ static void load_modules_dep(void) int modprobe_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int modprobe_main(int argc UNUSED_PARAM, char **argv) { - struct utsname uts; int rc; unsigned opt; struct module_entry *me; + INIT_G(); + + IF_LONG_OPTS(applet_long_options = modprobe_longopts;) opt_complementary = MODPROBE_COMPLEMENTARY; opt = getopt32(argv, INSMOD_OPTS MODPROBE_OPTS INSMOD_ARGS); argv += optind; /* Goto modules location */ xchdir(CONFIG_DEFAULT_MODULES_DIR); - uname(&uts); - xchdir(uts.release); + uname(&G.uts); + xchdir(G.uts.release); - if (opt & MODPROBE_OPT_LIST_ONLY) { + if (opt & OPT_LIST_ONLY) { char name[MODULE_NAME_LEN]; char *colon, *tokens[2]; parser_t *p = config_open2(CONFIG_DEFAULT_DEPMOD_FILE, xfopen_for_read); @@ -521,7 +546,7 @@ int modprobe_main(int argc UNUSED_PARAM, char **argv) logmode = LOGMODE_SYSLOG; if (!argv[0]) { - if (opt & MODPROBE_OPT_REMOVE) { + if (opt & OPT_REMOVE) { /* "modprobe -r" (w/o params). * "If name is NULL, all unused modules marked * autoclean will be removed". @@ -541,7 +566,7 @@ int modprobe_main(int argc UNUSED_PARAM, char **argv) config_close(parser); } - if (opt & (MODPROBE_OPT_INSERT_ALL | MODPROBE_OPT_REMOVE)) { + if (opt & (OPT_INSERT_ALL | OPT_REMOVE)) { /* Each argument is a module name */ do { DBG("adding module %s", *argv); @@ -575,7 +600,7 @@ int modprobe_main(int argc UNUSED_PARAM, char **argv) /* This is not an alias. Literal names are blacklisted * only if '-b' is given. */ - if (!(opt & MODPROBE_OPT_BLACKLIST) + if (!(opt & OPT_BLACKLIST) || !(me->flags & MODULE_FLAG_BLACKLISTED) ) { rc |= do_modprobe(me); @@ -592,7 +617,7 @@ int modprobe_main(int argc UNUSED_PARAM, char **argv) m2 = get_or_add_modentry(realname); if (!(m2->flags & MODULE_FLAG_BLACKLISTED) && (!(m2->flags & MODULE_FLAG_LOADED) - || (opt & MODPROBE_OPT_REMOVE)) + || (opt & (OPT_REMOVE | OPT_SHOW_DEPS))) ) { //TODO: we can pass "me" as 2nd param to do_modprobe, //and make do_modprobe emit more meaningful error messages -- cgit v1.2.3-55-g6feb From 1f937d64686d9a71c9325f2e9b23eba235a9255e Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sun, 26 Dec 2010 02:22:51 +0100 Subject: cpio: allow cpio -i to take params - names of files to extract Also, improve help text function old new delta packed_usage 28028 28035 +7 cpio_main 542 532 -10 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 1/1 up/down: 7/-10) Total: -3 bytes Signed-off-by: Denys Vlasenko --- archival/cpio.c | 105 +++++++++++++++++++++++++++++++++------------------- include/usage.src.h | 29 --------------- 2 files changed, 66 insertions(+), 68 deletions(-) diff --git a/archival/cpio.c b/archival/cpio.c index 6ab268821..c746a71fa 100644 --- a/archival/cpio.c +++ b/archival/cpio.c @@ -14,13 +14,43 @@ #include "libbb.h" #include "archive.h" +//usage:#define cpio_trivial_usage +//usage: "[-dmvu] [-F FILE]" IF_FEATURE_CPIO_O(" [-H newc]") +//usage: " [-ti"IF_FEATURE_CPIO_O("o")"]" IF_FEATURE_CPIO_P(" [-p DIR]") +//usage: " [EXTR_FILE]..." +//usage:#define cpio_full_usage "\n\n" +//usage: "Extract or list files from a cpio archive" +//usage: IF_FEATURE_CPIO_O(", or" +//usage: "\ncreate an archive" IF_FEATURE_CPIO_P(" (-o) or copy files (-p)") +//usage: " using file list on stdin" +//usage: ) +//usage: "\n" +//usage: "\nMain operation mode:" +//usage: "\n -t List" +//usage: "\n -i Extract EXTR_FILEs (or all)" +//usage: IF_FEATURE_CPIO_O( +//usage: "\n -o Create (requires -H newc)" +//usage: ) +//usage: IF_FEATURE_CPIO_P( +//usage: "\n -p DIR Copy files to DIR" +//usage: ) +//usage: "\nOptions:" +//usage: "\n -d Make leading directories" +//usage: "\n -m Preserve mtime" +//usage: "\n -v Verbose" +//usage: "\n -u Overwrite" +//usage: "\n -F FILE Input (-t,-i,-p) or output (-o) file" +//usage: IF_FEATURE_CPIO_O( +//usage: "\n -H newc Archive format" +//usage: ) + /* GNU cpio 2.9 --help (abridged): Modes: -t, --list List the archive -i, --extract Extract files from an archive -o, --create Create the archive - -p, --pass-through Copy-pass mode [was ist das?!] + -p, --pass-through Copy-pass mode Options valid in any mode: --block-size=SIZE I/O block size = SIZE * 512 bytes @@ -78,27 +108,28 @@ --sparse Write files with blocks of zeros as sparse files -u, --unconditional Replace all files unconditionally */ + enum { - CPIO_OPT_EXTRACT = (1 << 0), - CPIO_OPT_TEST = (1 << 1), - CPIO_OPT_NUL_TERMINATED = (1 << 2), - CPIO_OPT_UNCONDITIONAL = (1 << 3), - CPIO_OPT_VERBOSE = (1 << 4), - CPIO_OPT_CREATE_LEADING_DIR = (1 << 5), - CPIO_OPT_PRESERVE_MTIME = (1 << 6), - CPIO_OPT_DEREF = (1 << 7), - CPIO_OPT_FILE = (1 << 8), + OPT_EXTRACT = (1 << 0), + OPT_TEST = (1 << 1), + OPT_NUL_TERMINATED = (1 << 2), + OPT_UNCONDITIONAL = (1 << 3), + OPT_VERBOSE = (1 << 4), + OPT_CREATE_LEADING_DIR = (1 << 5), + OPT_PRESERVE_MTIME = (1 << 6), + OPT_DEREF = (1 << 7), + OPT_FILE = (1 << 8), OPTBIT_FILE = 8, IF_FEATURE_CPIO_O(OPTBIT_CREATE ,) IF_FEATURE_CPIO_O(OPTBIT_FORMAT ,) IF_FEATURE_CPIO_P(OPTBIT_PASSTHROUGH,) IF_LONG_OPTS( OPTBIT_QUIET ,) IF_LONG_OPTS( OPTBIT_2STDOUT ,) - CPIO_OPT_CREATE = IF_FEATURE_CPIO_O((1 << OPTBIT_CREATE )) + 0, - CPIO_OPT_FORMAT = IF_FEATURE_CPIO_O((1 << OPTBIT_FORMAT )) + 0, - CPIO_OPT_PASSTHROUGH = IF_FEATURE_CPIO_P((1 << OPTBIT_PASSTHROUGH)) + 0, - CPIO_OPT_QUIET = IF_LONG_OPTS( (1 << OPTBIT_QUIET )) + 0, - CPIO_OPT_2STDOUT = IF_LONG_OPTS( (1 << OPTBIT_2STDOUT )) + 0, + OPT_CREATE = IF_FEATURE_CPIO_O((1 << OPTBIT_CREATE )) + 0, + OPT_FORMAT = IF_FEATURE_CPIO_O((1 << OPTBIT_FORMAT )) + 0, + OPT_PASSTHROUGH = IF_FEATURE_CPIO_P((1 << OPTBIT_PASSTHROUGH)) + 0, + OPT_QUIET = IF_LONG_OPTS( (1 << OPTBIT_QUIET )) + 0, + OPT_2STDOUT = IF_LONG_OPTS( (1 << OPTBIT_2STDOUT )) + 0, }; #define OPTION_STR "it0uvdmLF:" @@ -138,7 +169,7 @@ static NOINLINE int cpio_o(void) char *line; struct stat st; - line = (option_mask32 & CPIO_OPT_NUL_TERMINATED) + line = (option_mask32 & OPT_NUL_TERMINATED) ? bb_get_chunk_from_file(stdin, NULL) : xmalloc_fgetline(stdin); @@ -153,7 +184,7 @@ static NOINLINE int cpio_o(void) free(line); continue; } - if ((option_mask32 & CPIO_OPT_DEREF) + if ((option_mask32 & OPT_DEREF) ? stat(name, &st) : lstat(name, &st) ) { @@ -308,28 +339,24 @@ int cpio_main(int argc UNUSED_PARAM, char **argv) /* -L makes sense only with -o or -p */ #if !ENABLE_FEATURE_CPIO_O - /* no parameters */ - opt_complementary = "=0"; opt = getopt32(argv, OPTION_STR, &cpio_filename); argv += optind; - if (opt & CPIO_OPT_FILE) { /* -F */ + if (opt & OPT_FILE) { /* -F */ xmove_fd(xopen(cpio_filename, O_RDONLY), STDIN_FILENO); } #else - /* _exactly_ one parameter for -p, thus <= 1 param if -p is allowed */ - opt_complementary = ENABLE_FEATURE_CPIO_P ? "?1" : "=0"; opt = getopt32(argv, OPTION_STR "oH:" IF_FEATURE_CPIO_P("p"), &cpio_filename, &cpio_fmt); argv += optind; - if ((opt & (CPIO_OPT_FILE|CPIO_OPT_CREATE)) == CPIO_OPT_FILE) { /* -F without -o */ + if ((opt & (OPT_FILE|OPT_CREATE)) == OPT_FILE) { /* -F without -o */ xmove_fd(xopen(cpio_filename, O_RDONLY), STDIN_FILENO); } - if (opt & CPIO_OPT_PASSTHROUGH) { + if (opt & OPT_PASSTHROUGH) { pid_t pid; struct fd_pair pp; if (argv[0] == NULL) bb_show_usage(); - if (opt & CPIO_OPT_CREATE_LEADING_DIR) + if (opt & OPT_CREATE_LEADING_DIR) mkdir(argv[0], 0777); /* Crude existence check: * close(xopen(argv[0], O_RDONLY | O_DIRECTORY)); @@ -361,15 +388,15 @@ int cpio_main(int argc UNUSED_PARAM, char **argv) xchdir(*argv++); close(pp.wr); xmove_fd(pp.rd, STDIN_FILENO); - //opt &= ~CPIO_OPT_PASSTHROUGH; - opt |= CPIO_OPT_EXTRACT; + //opt &= ~OPT_PASSTHROUGH; + opt |= OPT_EXTRACT; goto skip; } /* -o */ - if (opt & CPIO_OPT_CREATE) { + if (opt & OPT_CREATE) { if (cpio_fmt[0] != 'n') /* we _require_ "-H newc" */ bb_show_usage(); - if (opt & CPIO_OPT_FILE) { + if (opt & OPT_FILE) { xmove_fd(xopen(cpio_filename, O_WRONLY | O_CREAT | O_TRUNC), STDOUT_FILENO); } dump: @@ -379,35 +406,35 @@ int cpio_main(int argc UNUSED_PARAM, char **argv) #endif /* One of either extract or test options must be given */ - if ((opt & (CPIO_OPT_TEST | CPIO_OPT_EXTRACT)) == 0) { + if ((opt & (OPT_TEST | OPT_EXTRACT)) == 0) { bb_show_usage(); } - if (opt & CPIO_OPT_TEST) { + if (opt & OPT_TEST) { /* if both extract and test options are given, ignore extract option */ - opt &= ~CPIO_OPT_EXTRACT; + opt &= ~OPT_EXTRACT; archive_handle->action_header = header_list; } - if (opt & CPIO_OPT_EXTRACT) { + if (opt & OPT_EXTRACT) { archive_handle->action_data = data_extract_all; - if (opt & CPIO_OPT_2STDOUT) + if (opt & OPT_2STDOUT) archive_handle->action_data = data_extract_to_stdout; } - if (opt & CPIO_OPT_UNCONDITIONAL) { + if (opt & OPT_UNCONDITIONAL) { archive_handle->ah_flags |= ARCHIVE_UNLINK_OLD; archive_handle->ah_flags &= ~ARCHIVE_EXTRACT_NEWER; } - if (opt & CPIO_OPT_VERBOSE) { + if (opt & OPT_VERBOSE) { if (archive_handle->action_header == header_list) { archive_handle->action_header = header_verbose_list; } else { archive_handle->action_header = header_list; } } - if (opt & CPIO_OPT_CREATE_LEADING_DIR) { + if (opt & OPT_CREATE_LEADING_DIR) { archive_handle->ah_flags |= ARCHIVE_CREATE_LEADING_DIRS; } - if (opt & CPIO_OPT_PRESERVE_MTIME) { + if (opt & OPT_PRESERVE_MTIME) { archive_handle->ah_flags |= ARCHIVE_RESTORE_DATE; } @@ -423,7 +450,7 @@ int cpio_main(int argc UNUSED_PARAM, char **argv) continue; if (archive_handle->cpio__blocks != (off_t)-1 - && !(opt & CPIO_OPT_QUIET) + && !(opt & OPT_QUIET) ) { fprintf(stderr, "%"OFF_FMT"u blocks\n", archive_handle->cpio__blocks); } diff --git a/include/usage.src.h b/include/usage.src.h index 4640338e6..69a9fa159 100644 --- a/include/usage.src.h +++ b/include/usage.src.h @@ -592,35 +592,6 @@ INSERT "\n -i Prompt before overwrite" \ "\n -l,-s Create (sym)links" \ -#define cpio_trivial_usage \ - "[-dmvu] [-F FILE]" IF_FEATURE_CPIO_O(" [-H newc]") \ - " [-ti"IF_FEATURE_CPIO_O("o")"]" IF_FEATURE_CPIO_P(" [-p DIR]") -#define cpio_full_usage "\n\n" \ - "Extract or list files from a cpio archive" \ - IF_FEATURE_CPIO_O(", or" \ - "\ncreate an archive" IF_FEATURE_CPIO_P(" (-o) or copy files (-p)") \ - " using file list on stdin" \ - ) \ - "\n" \ - "\nMain operation mode:" \ - "\n -t List" \ - "\n -i Extract" \ - IF_FEATURE_CPIO_O( \ - "\n -o Create (requires -H newc)" \ - ) \ - IF_FEATURE_CPIO_P( \ - "\n -p DIR Copy files to DIR" \ - ) \ - "\nOptions:" \ - "\n -d Make leading directories" \ - "\n -m Preserve mtime" \ - "\n -v Verbose" \ - "\n -u Overwrite" \ - "\n -F FILE Input (-t,-i,-p) or output (-o) file" \ - IF_FEATURE_CPIO_O( \ - "\n -H newc Archive format" \ - ) \ - #define crond_trivial_usage \ "-fbS -l N " IF_FEATURE_CROND_D("-d N ") "-L LOGFILE -c DIR" #define crond_full_usage "\n\n" \ -- cgit v1.2.3-55-g6feb From 260fb551ff4ba0cb8a5fdff848bce10588611231 Mon Sep 17 00:00:00 2001 From: Ian Wienand Date: Mon, 20 Dec 2010 11:33:38 -0800 Subject: login: apply PAM environment login should apply the PAM environment modified by plugins such as pam_env. Other 'login's do a similar thing. I tested this by setting some env variables with pam_env which were correctly applied. Signed-off-by: Ian Wienand Signed-off-by: Denys Vlasenko --- loginutils/login.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/loginutils/login.c b/loginutils/login.c index 9a624df9a..c285b45a1 100644 --- a/loginutils/login.c +++ b/loginutils/login.c @@ -217,6 +217,7 @@ int login_main(int argc UNUSED_PARAM, char **argv) const char *failed_msg; struct passwd pwdstruct; char pwdbuf[256]; + char **pamenv; #endif username[0] = '\0'; @@ -400,6 +401,16 @@ int login_main(int argc UNUSED_PARAM, char **argv) (!(opt & LOGIN_OPT_p) * SETUP_ENV_CLEARENV) + SETUP_ENV_CHANGEENV, pw); +#if ENABLE_PAM + /* Modules such as pam_env will setup the PAM environment, + * which should be copied into the new environment. */ + pamenv = pam_getenvlist(pamh); + if (pamenv) while (*pamenv) { + putenv(*pamenv); + pamenv++; + } +#endif + motd(); if (pw->pw_uid == 0) -- cgit v1.2.3-55-g6feb From 8578196b763a70746f2ab17170eb7ca9399ab8ac Mon Sep 17 00:00:00 2001 From: Serj Kalichev Date: Tue, 28 Dec 2010 04:18:18 +0100 Subject: modprobe: add -D option (synonym of --show-depends) The modern module-init-tools 3.12 has "-D" option and it works. The --show-depends and -a options can be used together due to upstream modprobe behaviour. function old new delta do_modprobe 536 579 +43 packed_usage 28035 28042 +7 modprobe_main 653 657 +4 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 3/0 up/down: 54/0) Total: 54 bytes Signed-off-by: Serj Kalichev Signed-off-by: Denys Vlasenko --- modutils/modprobe.c | 121 +++++++++++++++++++++++++++++----------------------- 1 file changed, 67 insertions(+), 54 deletions(-) diff --git a/modutils/modprobe.c b/modutils/modprobe.c index 8e83f4107..73df39c6c 100644 --- a/modutils/modprobe.c +++ b/modutils/modprobe.c @@ -10,6 +10,20 @@ //applet:IF_MODPROBE(APPLET(modprobe, _BB_DIR_SBIN, _BB_SUID_DROP)) +#include "libbb.h" +#include "modutils.h" +#include +#include + +//#define DBG(fmt, ...) bb_error_msg("%s: " fmt, __func__, ## __VA_ARGS__) +#define DBG(...) ((void)0) + +/* Note that unlike older versions of modules.dep/depmod (busybox and m-i-t), + * we expect the full dependency list to be specified in modules.dep. + * Older versions would only export the direct dependency list. + */ + + //usage:#if !ENABLE_MODPROBE_SMALL //usage:#define modprobe_notes_usage //usage: "modprobe can (un)load a stack of modules, passing each module options (when\n" @@ -72,51 +86,27 @@ //usage: " from the command line\n" //usage: //usage:#define modprobe_trivial_usage -//usage: "[-alrqvs" IF_FEATURE_MODPROBE_BLACKLIST("b") "]" -//usage: IF_LONG_OPTS(" [--show-depends]") " MODULE [symbol=value]..." +//usage: "[-alrqvsD" IF_FEATURE_MODPROBE_BLACKLIST("b") "]" +//usage: " MODULE [symbol=value]..." //usage:#define modprobe_full_usage "\n\n" //usage: "Options:" -//usage: "\n -a Load multiple MODULEs" -//usage: "\n -l List (MODULE is a pattern)" -//usage: "\n -r Remove MODULE (stacks) or do autoclean" -//usage: "\n -q Quiet" -//usage: "\n -v Verbose" -//usage: "\n -s Log to syslog" +//usage: "\n -a Load multiple MODULEs" +//usage: "\n -l List (MODULE is a pattern)" +//usage: "\n -r Remove MODULE (stacks) or do autoclean" +//usage: "\n -q Quiet" +//usage: "\n -v Verbose" +//usage: "\n -s Log to syslog" +//usage: "\n -D Show dependencies" //usage: IF_FEATURE_MODPROBE_BLACKLIST( -//usage: "\n -b Apply blacklist to module names too" -//usage: ) -//usage: IF_LONG_OPTS( -//usage: "\n --show-depends Show dependencies" +//usage: "\n -b Apply blacklist to module names too" //usage: ) //usage:#endif /* !ENABLE_MODPROBE_SMALL */ -#include "libbb.h" -#include "modutils.h" -#include -#include - -//#define DBG(fmt, ...) bb_error_msg("%s: " fmt, __func__, ## __VA_ARGS__) -#define DBG(...) ((void)0) - -/* Note that unlike older versions of modules.dep/depmod (busybox and m-i-t), - * we expect the full dependency list to be specified in modules.dep. - * Older versions would only export the direct dependency list. - */ - - /* Note that usage text doesn't document various 2.4 options * we pull in through INSMOD_OPTS define */ -#define MODPROBE_OPTS "alr" IF_FEATURE_MODPROBE_BLACKLIST("b") -#undef SD -#if ENABLE_LONG_OPTS -static const char modprobe_longopts[] ALIGN1 = - "show-depends\0" No_argument "\xff" - ; -# define SD "\xff" -#else -# define SD "" -#endif -#define MODPROBE_COMPLEMENTARY ("q-v:v-q:l--ar"SD":a--lr"SD":r--al"SD IF_LONG_OPTS(":\xff--arl")) +#define MODPROBE_OPTS "alrD" IF_FEATURE_MODPROBE_BLACKLIST("b") +/* -a and -D _are_ in fact compatible */ +#define MODPROBE_COMPLEMENTARY ("q-v:v-q:l--arD:r--alD:a--lr:D--rl") //#define MODPROBE_OPTS "acd:lnrt:C:" IF_FEATURE_MODPROBE_BLACKLIST("b") //#define MODPROBE_COMPLEMENTARY "q-v:v-q:l--acr:a--lr:r--al" enum { @@ -128,11 +118,28 @@ enum { OPT_REMOVE = (INSMOD_OPT_UNUSED << 2), /* r */ //OPT_RESTRICT = (INSMOD_OPT_UNUSED << x), /* t */ //OPT_VERONLY = (INSMOD_OPT_UNUSED << x), /* V */ - //OPT_CONFIGFILE =(INSMOD_OPT_UNUSED << x), /* C */ - OPT_BLACKLIST = (INSMOD_OPT_UNUSED << 3) * ENABLE_FEATURE_MODPROBE_BLACKLIST, - OPTBIT_SHOW_DEPS = (3 + ENABLE_FEATURE_MODPROBE_BLACKLIST), - OPT_SHOW_DEPS = (INSMOD_OPT_UNUSED << OPTBIT_SHOW_DEPS) * ENABLE_LONG_OPTS, + //OPT_CONFIGFILE = (INSMOD_OPT_UNUSED << x), /* C */ + OPT_SHOW_DEPS = (INSMOD_OPT_UNUSED << 3), /* D */ + OPT_BLACKLIST = (INSMOD_OPT_UNUSED << 4) * ENABLE_FEATURE_MODPROBE_BLACKLIST, }; +#if ENABLE_LONG_OPTS +static const char modprobe_longopts[] ALIGN1 = + /* nobody asked for long opts (yet) */ + // "all\0" No_argument "a" + // "list\0" No_argument "l" + // "remove\0" No_argument "r" + // "quiet\0" No_argument "q" + // "verbose\0" No_argument "v" + // "syslog\0" No_argument "s" + /* module-init-tools 3.11.1 has only long opt --show-depends + * but no short -D, we provide long opt for scripts which + * were written for 3.11.1: */ + "show-depends\0" No_argument "D" + // IF_FEATURE_MODPROBE_BLACKLIST( + // "use-blacklist\0" No_argument "b" + // ) + ; +#endif #define MODULE_FLAG_LOADED 0x0001 #define MODULE_FLAG_NEED_DEPS 0x0002 @@ -370,8 +377,6 @@ static char *parse_and_add_kcmdline_module_options(char *options, const char *mo */ static int do_modprobe(struct module_entry *m) { - struct module_entry *m2 = m2; /* for compiler */ - char *fn, *options; int rc, first; llist_t *l; @@ -392,16 +397,13 @@ static int do_modprobe(struct module_entry *m) first = 1; rc = 0; while (m->deps) { + struct module_entry *m2; + char *fn, *options; + rc = 0; fn = llist_pop(&m->deps); /* we leak it */ m2 = get_or_add_modentry(fn); - if (option_mask32 & OPT_SHOW_DEPS) { - printf("insmod %s/%s/%s\n", CONFIG_DEFAULT_MODULES_DIR, - G.uts.release, fn); - continue; - } - if (option_mask32 & OPT_REMOVE) { /* modprobe -r */ if (m2->flags & MODULE_FLAG_LOADED) { @@ -422,16 +424,27 @@ static int do_modprobe(struct module_entry *m) continue; } - if (m2->flags & MODULE_FLAG_LOADED) { - DBG("%s is already loaded, skipping", fn); - continue; - } - options = m2->options; m2->options = NULL; options = parse_and_add_kcmdline_module_options(options, m2->modname); if (m == m2) options = gather_options_str(options, G.cmdline_mopts); + + if (option_mask32 & OPT_SHOW_DEPS) { + printf(options ? "insmod %s/%s/%s %s\n" + : "insmod %s/%s/%s\n", + CONFIG_DEFAULT_MODULES_DIR, G.uts.release, fn, + options); + free(options); + continue; + } + + if (m2->flags & MODULE_FLAG_LOADED) { + DBG("%s is already loaded, skipping", fn); + free(options); + continue; + } + rc = bb_init_module(fn, options); DBG("loaded %s '%s', rc:%d", fn, options, rc); if (rc == EEXIST) -- cgit v1.2.3-55-g6feb From 2272129a93d9492a42ef43987f829940d26dc862 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Tue, 28 Dec 2010 10:25:03 +0100 Subject: plug a DIR* leak on error path Signed-off-by: Denys Vlasenko --- libbb/find_root_device.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/libbb/find_root_device.c b/libbb/find_root_device.c index 32c86cea8..8436cd664 100644 --- a/libbb/find_root_device.c +++ b/libbb/find_root_device.c @@ -29,14 +29,15 @@ static char *find_block_device_in_dir(struct arena *ap) char *retpath = NULL; int len, rem; - dir = opendir(ap->devpath); - if (!dir) - return NULL; - len = strlen(ap->devpath); rem = DEVNAME_MAX-2 - len; if (rem <= 0) return NULL; + + dir = opendir(ap->devpath); + if (!dir) + return NULL; + ap->devpath[len++] = '/'; while ((entry = readdir(dir)) != NULL) { -- cgit v1.2.3-55-g6feb From 90615a0c5c326fa3cf78fc719f7b16207f47395a Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Thu, 30 Dec 2010 00:40:11 +0100 Subject: blkid: optional support for TYPE="fstype" Adapted from patch created by T4ndeta Signed-off-by: Denys Vlasenko --- include/volume_id.h | 1 + util-linux/Config.src | 7 ++++ util-linux/blkid.c | 7 +++- util-linux/volume_id/cramfs.c | 2 +- util-linux/volume_id/ext.c | 10 +++--- util-linux/volume_id/fat.c | 2 +- util-linux/volume_id/get_devname.c | 59 +++++++++++++++++++++++-------- util-linux/volume_id/hfs.c | 2 +- util-linux/volume_id/iso9660.c | 2 +- util-linux/volume_id/jfs.c | 2 +- util-linux/volume_id/linux_raid.c | 2 +- util-linux/volume_id/linux_swap.c | 2 +- util-linux/volume_id/luks.c | 2 +- util-linux/volume_id/ntfs.c | 2 +- util-linux/volume_id/ocfs2.c | 2 +- util-linux/volume_id/reiserfs.c | 2 +- util-linux/volume_id/romfs.c | 2 +- util-linux/volume_id/sysv.c | 4 +-- util-linux/volume_id/udf.c | 3 +- util-linux/volume_id/volume_id_internal.h | 4 ++- util-linux/volume_id/xfs.c | 2 +- 21 files changed, 84 insertions(+), 37 deletions(-) diff --git a/include/volume_id.h b/include/volume_id.h index 77e874d40..4a78cd1e4 100644 --- a/include/volume_id.h +++ b/include/volume_id.h @@ -28,3 +28,4 @@ void display_uuid_cache(void); * *fsname is replaced if device with such UUID or LABEL is found */ int resolve_mount_spec(char **fsname); +int add_to_uuid_cache(const char *device); diff --git a/util-linux/Config.src b/util-linux/Config.src index c71b4de38..dbf2b0d85 100644 --- a/util-linux/Config.src +++ b/util-linux/Config.src @@ -40,6 +40,13 @@ config BLKID WARNING: With all submodules selected, it will add ~8k to busybox. +config FEATURE_BLKID_TYPE + bool "Print filesystem type" + default n + depends on BLKID + help + Show TYPE="filesystem type" + config DMESG bool "dmesg" default y diff --git a/util-linux/blkid.c b/util-linux/blkid.c index 53f13a99c..fe88fb31d 100644 --- a/util-linux/blkid.c +++ b/util-linux/blkid.c @@ -13,8 +13,13 @@ //TODO: extend to take BLOCKDEV args, and show TYPE="fstype" int blkid_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; -int blkid_main(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) +int blkid_main(int argc UNUSED_PARAM, char **argv) { + while (*++argv) { + /* Note: bogus device names don't cause any error messages */ + add_to_uuid_cache(*argv); + } + display_uuid_cache(); return 0; } diff --git a/util-linux/volume_id/cramfs.c b/util-linux/volume_id/cramfs.c index b84a6f0b2..28e997043 100644 --- a/util-linux/volume_id/cramfs.c +++ b/util-linux/volume_id/cramfs.c @@ -51,7 +51,7 @@ int FAST_FUNC volume_id_probe_cramfs(struct volume_id *id /*,uint64_t off*/) volume_id_set_label_string(id, cs->name, 16); // volume_id_set_usage(id, VOLUME_ID_FILESYSTEM); -// id->type = "cramfs"; + IF_FEATURE_BLKID_TYPE(id->type = "cramfs";) return 0; } diff --git a/util-linux/volume_id/ext.c b/util-linux/volume_id/ext.c index 80c217f98..b5194a7b5 100644 --- a/util-linux/volume_id/ext.c +++ b/util-linux/volume_id/ext.c @@ -65,10 +65,12 @@ int FAST_FUNC volume_id_probe_ext(struct volume_id *id /*,uint64_t off*/) volume_id_set_uuid(id, es->uuid, UUID_DCE); dbg("ext: label '%s' uuid '%s'", id->label, id->uuid); -// if ((le32_to_cpu(es->feature_compat) & EXT3_FEATURE_COMPAT_HAS_JOURNAL) != 0) -// id->type = "ext3"; -// else -// id->type = "ext2"; +#if ENABLE_FEATURE_BLKID_TYPE + if ((le32_to_cpu(es->feature_compat) & EXT3_FEATURE_COMPAT_HAS_JOURNAL) != 0) + id->type = "ext3"; + else + id->type = "ext2"; +#endif return 0; } diff --git a/util-linux/volume_id/fat.c b/util-linux/volume_id/fat.c index b0f427c74..904fbb201 100644 --- a/util-linux/volume_id/fat.c +++ b/util-linux/volume_id/fat.c @@ -332,7 +332,7 @@ int FAST_FUNC volume_id_probe_vfat(struct volume_id *id /*,uint64_t fat_partitio ret: // volume_id_set_usage(id, VOLUME_ID_FILESYSTEM); -// id->type = "vfat"; + IF_FEATURE_BLKID_TYPE(id->type = "vfat";) return 0; } diff --git a/util-linux/volume_id/get_devname.c b/util-linux/volume_id/get_devname.c index bf32e6a8c..7c9930543 100644 --- a/util-linux/volume_id/get_devname.c +++ b/util-linux/volume_id/get_devname.c @@ -19,14 +19,22 @@ static struct uuidCache_s { char *device; char *label; char *uc_uuid; /* prefix makes it easier to grep for */ + IF_FEATURE_BLKID_TYPE(const char *type;) } *uuidCache; +#if !ENABLE_FEATURE_BLKID_TYPE +#define get_label_uuid(fd, label, uuid, type) \ + get_label_uuid(fd, label, uuid) +#define uuidcache_addentry(device, label, uuid, type) \ + uuidcache_addentry(device, label, uuid) +#endif + /* Returns !0 on error. * Otherwise, returns malloc'ed strings for label and uuid * (and they can't be NULL, although they can be ""). * NB: closes fd. */ static int -get_label_uuid(int fd, char **label, char **uuid) +get_label_uuid(int fd, char **label, char **uuid, const char **type) { int rv = 1; uint64_t size; @@ -44,7 +52,12 @@ get_label_uuid(int fd, char **label, char **uuid) if (vid->label[0] != '\0' || vid->uuid[0] != '\0') { *label = xstrndup(vid->label, sizeof(vid->label)); *uuid = xstrndup(vid->uuid, sizeof(vid->uuid)); +#if ENABLE_FEATURE_BLKID_TYPE + *type = vid->type; + dbg("found label '%s', uuid '%s', type '%s'", *label, *uuid, *type); +#else dbg("found label '%s', uuid '%s'", *label, *uuid); +#endif rv = 0; } ret: @@ -54,7 +67,7 @@ get_label_uuid(int fd, char **label, char **uuid) /* NB: we take ownership of (malloc'ed) label and uuid */ static void -uuidcache_addentry(char *device, /*int major, int minor,*/ char *label, char *uuid) +uuidcache_addentry(char *device, /*int major, int minor,*/ char *label, char *uuid, const char *type) { struct uuidCache_s *last; @@ -72,6 +85,7 @@ uuidcache_addentry(char *device, /*int major, int minor,*/ char *label, char *uu last->device = device; last->label = label; last->uc_uuid = uuid; + IF_FEATURE_BLKID_TYPE(last->type = type;) } /* If get_label_uuid() on device_name returns success, @@ -83,10 +97,6 @@ uuidcache_check_device(const char *device, void *userData UNUSED_PARAM, int depth UNUSED_PARAM) { - char *uuid = uuid; /* for compiler */ - char *label = label; - int fd; - /* note: this check rejects links to devices, among other nodes */ if (!S_ISBLK(statbuf->st_mode)) return TRUE; @@ -99,21 +109,15 @@ uuidcache_check_device(const char *device, if (major(statbuf->st_rdev) == 2) return TRUE; - fd = open(device, O_RDONLY); - if (fd < 0) - return TRUE; + add_to_uuid_cache(device); - /* get_label_uuid() closes fd in all cases (success & failure) */ - if (get_label_uuid(fd, &label, &uuid) == 0) { - /* uuidcache_addentry() takes ownership of all three params */ - uuidcache_addentry(xstrdup(device), /*ma, mi,*/ label, uuid); - } return TRUE; } static void uuidcache_init(void) { + dbg("DBG: uuidCache=%x, uuidCache"); if (uuidCache) return; @@ -223,11 +227,38 @@ void display_uuid_cache(void) printf(" LABEL=\"%s\"", u->label); if (u->uc_uuid[0]) printf(" UUID=\"%s\"", u->uc_uuid); +#if ENABLE_FEATURE_BLKID_TYPE + if (u->type) + printf(" TYPE=\"%s\"", u->type); +#endif bb_putchar('\n'); u = u->next; } } +int add_to_uuid_cache(const char *device) +{ + char *uuid = uuid; /* for compiler */ + char *label = label; +#if ENABLE_FEATURE_BLKID_TYPE + const char *type = type; +#endif + int fd; + + fd = open(device, O_RDONLY); + if (fd < 0) + return 0; + + /* get_label_uuid() closes fd in all cases (success & failure) */ + if (get_label_uuid(fd, &label, &uuid, &type) == 0) { + /* uuidcache_addentry() takes ownership of all four params */ + uuidcache_addentry(xstrdup(device), /*ma, mi,*/ label, uuid, type); + return 1; + } + return 0; +} + + /* Used by mount and findfs */ char *get_devname_from_label(const char *spec) diff --git a/util-linux/volume_id/hfs.c b/util-linux/volume_id/hfs.c index cf7585138..f3f19dba7 100644 --- a/util-linux/volume_id/hfs.c +++ b/util-linux/volume_id/hfs.c @@ -195,7 +195,7 @@ int FAST_FUNC volume_id_probe_hfs_hfsplus(struct volume_id *id /*,uint64_t off*/ volume_id_set_uuid(id, hfs->finder_info.id, UUID_HFS); // volume_id_set_usage(id, VOLUME_ID_FILESYSTEM); -// id->type = "hfs"; + IF_FEATURE_BLKID_TYPE(id->type = "hfs";) return 0; diff --git a/util-linux/volume_id/iso9660.c b/util-linux/volume_id/iso9660.c index 1519de496..1d7693a9c 100644 --- a/util-linux/volume_id/iso9660.c +++ b/util-linux/volume_id/iso9660.c @@ -114,7 +114,7 @@ int FAST_FUNC volume_id_probe_iso9660(struct volume_id *id /*,uint64_t off*/) found: // volume_id_set_usage(id, VOLUME_ID_FILESYSTEM); -// id->type = "iso9660"; + IF_FEATURE_BLKID_TYPE(id->type = "iso9660";) return 0; } diff --git a/util-linux/volume_id/jfs.c b/util-linux/volume_id/jfs.c index eb7a44872..5333af2c3 100644 --- a/util-linux/volume_id/jfs.c +++ b/util-linux/volume_id/jfs.c @@ -54,7 +54,7 @@ int FAST_FUNC volume_id_probe_jfs(struct volume_id *id /*,uint64_t off*/) volume_id_set_uuid(id, js->uuid, UUID_DCE); // volume_id_set_usage(id, VOLUME_ID_FILESYSTEM); -// id->type = "jfs"; + IF_FEATURE_BLKID_TYPE(id->type = "jfs";) return 0; } diff --git a/util-linux/volume_id/linux_raid.c b/util-linux/volume_id/linux_raid.c index e1c86369d..761e54f9f 100644 --- a/util-linux/volume_id/linux_raid.c +++ b/util-linux/volume_id/linux_raid.c @@ -75,7 +75,7 @@ int FAST_FUNC volume_id_probe_linux_raid(struct volume_id *id /*,uint64_t off*/, dbg("found raid signature"); // volume_id_set_usage(id, VOLUME_ID_RAID); -// id->type = "linux_raid_member"; + IF_FEATURE_BLKID_TYPE(id->type = "linux_raid_member";) return 0; } diff --git a/util-linux/volume_id/linux_swap.c b/util-linux/volume_id/linux_swap.c index 0aa43f3de..62d588522 100644 --- a/util-linux/volume_id/linux_swap.c +++ b/util-linux/volume_id/linux_swap.c @@ -73,7 +73,7 @@ int FAST_FUNC volume_id_probe_linux_swap(struct volume_id *id /*,uint64_t off*/) found: // volume_id_set_usage(id, VOLUME_ID_OTHER); -// id->type = "swap"; + IF_FEATURE_BLKID_TYPE(id->type = "swap";) return 0; } diff --git a/util-linux/volume_id/luks.c b/util-linux/volume_id/luks.c index 8ab09e381..f9b376672 100644 --- a/util-linux/volume_id/luks.c +++ b/util-linux/volume_id/luks.c @@ -94,7 +94,7 @@ int FAST_FUNC volume_id_probe_luks(struct volume_id *id /*,uint64_t off*/) // volume_id_set_usage(id, VOLUME_ID_CRYPTO); volume_id_set_uuid(id, header->uuid, UUID_DCE_STRING); -// id->type = "crypto_LUKS"; + IF_FEATURE_BLKID_TYPE(id->type = "crypto_LUKS";) return 0; } diff --git a/util-linux/volume_id/ntfs.c b/util-linux/volume_id/ntfs.c index 17b1fe8b3..547f141c9 100644 --- a/util-linux/volume_id/ntfs.c +++ b/util-linux/volume_id/ntfs.c @@ -188,7 +188,7 @@ int FAST_FUNC volume_id_probe_ntfs(struct volume_id *id /*,uint64_t off*/) found: // volume_id_set_usage(id, VOLUME_ID_FILESYSTEM); -// id->type = "ntfs"; + IF_FEATURE_BLKID_TYPE(id->type = "ntfs";) return 0; } diff --git a/util-linux/volume_id/ocfs2.c b/util-linux/volume_id/ocfs2.c index e6c455965..fcdb15192 100644 --- a/util-linux/volume_id/ocfs2.c +++ b/util-linux/volume_id/ocfs2.c @@ -101,6 +101,6 @@ int FAST_FUNC volume_id_probe_ocfs2(struct volume_id *id /*,uint64_t off*/) volume_id_set_label_string(id, os->s_label, OCFS2_MAX_VOL_LABEL_LEN < VOLUME_ID_LABEL_SIZE ? OCFS2_MAX_VOL_LABEL_LEN : VOLUME_ID_LABEL_SIZE); volume_id_set_uuid(id, os->s_uuid, UUID_DCE); -// id->type = "ocfs2"; + IF_FEATURE_BLKID_TYPE(id->type = "ocfs2";) return 0; } diff --git a/util-linux/volume_id/reiserfs.c b/util-linux/volume_id/reiserfs.c index 3120b29a0..67b4a1877 100644 --- a/util-linux/volume_id/reiserfs.c +++ b/util-linux/volume_id/reiserfs.c @@ -107,7 +107,7 @@ int FAST_FUNC volume_id_probe_reiserfs(struct volume_id *id /*,uint64_t off*/) found: // volume_id_set_usage(id, VOLUME_ID_FILESYSTEM); -// id->type = "reiserfs"; + IF_FEATURE_BLKID_TYPE(id->type = "reiserfs";) return 0; } diff --git a/util-linux/volume_id/romfs.c b/util-linux/volume_id/romfs.c index 228e77a41..15653bedf 100644 --- a/util-linux/volume_id/romfs.c +++ b/util-linux/volume_id/romfs.c @@ -47,7 +47,7 @@ int FAST_FUNC volume_id_probe_romfs(struct volume_id *id /*,uint64_t off*/) } // volume_id_set_usage(id, VOLUME_ID_FILESYSTEM); -// id->type = "romfs"; + IF_FEATURE_BLKID_TYPE(id->type = "romfs";) return 0; } diff --git a/util-linux/volume_id/sysv.c b/util-linux/volume_id/sysv.c index e0fa20a8c..6eb96464d 100644 --- a/util-linux/volume_id/sysv.c +++ b/util-linux/volume_id/sysv.c @@ -99,7 +99,7 @@ int FAST_FUNC volume_id_probe_sysv(struct volume_id *id /*,uint64_t off*/) if (vs->s_magic == cpu_to_le32(SYSV_MAGIC) || vs->s_magic == cpu_to_be32(SYSV_MAGIC)) { // volume_id_set_label_raw(id, vs->s_fname, 6); volume_id_set_label_string(id, vs->s_fname, 6); -// id->type = "sysv"; + IF_FEATURE_BLKID_TYPE(id->type = "sysv"); goto found; } } @@ -112,7 +112,7 @@ int FAST_FUNC volume_id_probe_sysv(struct volume_id *id /*,uint64_t off*/) if (xs->s_magic == cpu_to_le32(XENIX_MAGIC) || xs->s_magic == cpu_to_be32(XENIX_MAGIC)) { // volume_id_set_label_raw(id, xs->s_fname, 6); volume_id_set_label_string(id, xs->s_fname, 6); -// id->type = "xenix"; + IF_FEATURE_BLKID_TYPE(id->type = "xenix";) goto found; } } diff --git a/util-linux/volume_id/udf.c b/util-linux/volume_id/udf.c index dd2573171..cd63c8d8a 100644 --- a/util-linux/volume_id/udf.c +++ b/util-linux/volume_id/udf.c @@ -167,7 +167,6 @@ anchor: found: // volume_id_set_usage(id, VOLUME_ID_FILESYSTEM); -// id->type = "udf"; - + IF_FEATURE_BLKID_TYPE(id->type = "udf";) return 0; } diff --git a/util-linux/volume_id/volume_id_internal.h b/util-linux/volume_id/volume_id_internal.h index 9b808ff6b..1c64046e5 100644 --- a/util-linux/volume_id/volume_id_internal.h +++ b/util-linux/volume_id/volume_id_internal.h @@ -80,7 +80,9 @@ struct volume_id { // char type_version[VOLUME_ID_FORMAT_SIZE]; // smallint usage_id; // const char *usage; -// const char *type; +#if ENABLE_FEATURE_BLKID_TYPE + const char *type; +#endif }; struct volume_id* FAST_FUNC volume_id_open_node(int fd); diff --git a/util-linux/volume_id/xfs.c b/util-linux/volume_id/xfs.c index 1017d077b..84746020e 100644 --- a/util-linux/volume_id/xfs.c +++ b/util-linux/volume_id/xfs.c @@ -54,7 +54,7 @@ int FAST_FUNC volume_id_probe_xfs(struct volume_id *id /*,uint64_t off*/) volume_id_set_uuid(id, xs->uuid, UUID_DCE); // volume_id_set_usage(id, VOLUME_ID_FILESYSTEM); -// id->type = "xfs"; + IF_FEATURE_BLKID_TYPE(id->type = "xfs";) return 0; } -- cgit v1.2.3-55-g6feb From 2753aae0e8728f527bedf103b1207857b7c3e151 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Thu, 30 Dec 2010 01:17:03 +0100 Subject: libbb: optionally support RTMIN[+n] and RTMAX[-n] signal names function old new delta get_signum 140 336 +196 __libc_allocate_rtsig - 56 +56 __libc_current_sigrtmin - 6 +6 __libc_current_sigrtmax - 6 +6 current_rtmin - 4 +4 current_rtmax - 4 +4 bbconfig_config_bz2 4961 4962 +1 ------------------------------------------------------------------------------ (add/remove: 6/0 grow/shrink: 2/0 up/down: 273/0) Total: 273 bytes Signed-off-by: Denys Vlasenko --- libbb/Config.src | 2 +- libbb/u_signal_names.c | 42 +++++++++++++++++++++++++++++++++++++----- 2 files changed, 38 insertions(+), 6 deletions(-) diff --git a/libbb/Config.src b/libbb/Config.src index f6c7a11ea..85892d3fe 100644 --- a/libbb/Config.src +++ b/libbb/Config.src @@ -135,7 +135,7 @@ config FEATURE_NON_POSIX_CP and create a regular file. This does not conform to POSIX, but prevents a symlink attack. Similarly, "cp file device" will not send file's data - to the device. + to the device. (To do that, use "cat file >device") config FEATURE_VERBOSE_CP_MESSAGE bool "Give more precise messages when copy fails (cp, mv etc)" diff --git a/libbb/u_signal_names.c b/libbb/u_signal_names.c index 9263859f5..53ccdd1a7 100644 --- a/libbb/u_signal_names.c +++ b/libbb/u_signal_names.c @@ -7,6 +7,13 @@ * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ +//config:config FEATURE_RTMINMAX +//config: bool "Support RTMIN[+n] and RTMAX[-n] signal names" +//config: default y +//config: help +//config: Support RTMIN[+n] and RTMAX[-n] signal names +//config: in kill, killall etc. This costs ~250 bytes. + #include "libbb.h" /* Believe it or not, but some arches have more than 32 SIGs! @@ -134,20 +141,45 @@ int FAST_FUNC get_signum(const char *name) if (strcasecmp(name, signals[i]) == 0) return i; -#if ENABLE_DESKTOP && (defined(SIGIOT) || defined(SIGIO)) +#if ENABLE_DESKTOP +# if defined(SIGIOT) || defined(SIGIO) /* SIGIO[T] are aliased to other names, * thus cannot be stored in the signals[] array. * Need special code to recognize them */ if ((name[0] | 0x20) == 'i' && (name[1] | 0x20) == 'o') { -#ifdef SIGIO +# ifdef SIGIO if (!name[2]) return SIGIO; -#endif -#ifdef SIGIOT +# endif +# ifdef SIGIOT if ((name[2] | 0x20) == 't' && !name[3]) return SIGIOT; -#endif +# endif + } +# endif +#endif + +#if ENABLE_FEATURE_RTMINMAX +# if defined(SIGRTMIN) && defined(SIGRTMAX) + if (strncasecmp(name, "RTMAX", 5) == 0) { + if (!name[5]) + return SIGRTMAX; + if (name[5] == '-') { + i = bb_strtou(name + 6, NULL, 10); + if (!errno && i <= SIGRTMAX - SIGRTMIN) + return SIGRTMAX - i; + } + } + if (strncasecmp(name, "RTMIN", 5) == 0) { + if (!name[5]) + return SIGRTMIN; + if (name[5] == '+') { + i = bb_strtou(name + 6, NULL, 10); + if (!errno && i <= SIGRTMAX - SIGRTMIN) + return SIGRTMIN + i; + } } +# endif #endif return -1; -- cgit v1.2.3-55-g6feb From ed9b08d1c1bbccd1bcb2c3e06b0095b6b99dc96c Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Thu, 30 Dec 2010 04:43:35 +0100 Subject: bzip2: plug memory leak on every processed file Signed-off-by: Denys Vlasenko --- archival/bzip2.c | 6 ++++-- archival/libarchive/bz/bzlib.c | 4 +--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/archival/bzip2.c b/archival/bzip2.c index a6abc931c..ab08ffc1a 100644 --- a/archival/bzip2.c +++ b/archival/bzip2.c @@ -128,10 +128,12 @@ IF_DESKTOP(long long) int FAST_FUNC compressStream(unpack_info_t *info UNUSED_PA break; } -#if ENABLE_FEATURE_CLEAN_UP + /* Can't be conditional on ENABLE_FEATURE_CLEAN_UP - + * we are called repeatedly + */ BZ2_bzCompressEnd(strm); free(iobuf); -#endif + return total; } diff --git a/archival/libarchive/bz/bzlib.c b/archival/libarchive/bz/bzlib.c index b3beeabed..5f7db747a 100644 --- a/archival/libarchive/bz/bzlib.c +++ b/archival/libarchive/bz/bzlib.c @@ -361,7 +361,6 @@ int BZ2_bzCompress(bz_stream *strm, int action) /*---------------------------------------------------*/ -#if ENABLE_FEATURE_CLEAN_UP static void BZ2_bzCompressEnd(bz_stream *strm) { @@ -372,9 +371,8 @@ void BZ2_bzCompressEnd(bz_stream *strm) free(s->arr2); free(s->ftab); free(s->crc32table); - free(strm->state); + free(s); } -#endif /*---------------------------------------------------*/ -- cgit v1.2.3-55-g6feb From d1e46651a349b809e42083e3fd4d120ccb2f0c4f Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Thu, 30 Dec 2010 23:56:47 +0100 Subject: date: add a comment about _SVID_SOURCE Signed-off-by: Denys Vlasenko --- coreutils/date.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/coreutils/date.c b/coreutils/date.c index d70957cf6..a1a004d45 100644 --- a/coreutils/date.c +++ b/coreutils/date.c @@ -250,7 +250,10 @@ int date_main(int argc UNUSED_PARAM, char **argv) ts.tv_sec = statbuf.st_mtime; #if ENABLE_FEATURE_DATE_NANO ts.tv_nsec = statbuf.st_mtim.tv_nsec; - /* some toolchains use .st_mtimensec instead of st_mtim.tv_nsec */ + /* Some toolchains use .st_mtimensec instead of st_mtim.tv_nsec. + * If you need #define SVID_SOURCE 1 to enable st_mtim.tv_nsec, + * drop a mail to project mailing list please + */ #endif } else { #if ENABLE_FEATURE_DATE_NANO -- cgit v1.2.3-55-g6feb From 0cd4f3039b5a6518eb322f26ed8430529befc3ae Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Fri, 31 Dec 2010 00:01:59 +0100 Subject: add missed underscore Signed-off-by: Denys Vlasenko --- coreutils/date.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/coreutils/date.c b/coreutils/date.c index a1a004d45..c73fb5be6 100644 --- a/coreutils/date.c +++ b/coreutils/date.c @@ -251,7 +251,7 @@ int date_main(int argc UNUSED_PARAM, char **argv) #if ENABLE_FEATURE_DATE_NANO ts.tv_nsec = statbuf.st_mtim.tv_nsec; /* Some toolchains use .st_mtimensec instead of st_mtim.tv_nsec. - * If you need #define SVID_SOURCE 1 to enable st_mtim.tv_nsec, + * If you need #define _SVID_SOURCE 1 to enable st_mtim.tv_nsec, * drop a mail to project mailing list please */ #endif -- cgit v1.2.3-55-g6feb From a9e25ffa678a357c581b9b7f65a7b2ce1ae2a63e Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Fri, 31 Dec 2010 02:52:35 +0100 Subject: su: document -l in --help text. Closes bug 2761 Signed-off-by: Denys Vlasenko --- include/usage.src.h | 9 --------- loginutils/su.c | 10 ++++++++++ 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/include/usage.src.h b/include/usage.src.h index 69a9fa159..ea0e6a452 100644 --- a/include/usage.src.h +++ b/include/usage.src.h @@ -3524,15 +3524,6 @@ INSERT "\n -g Print in stty-readable form" \ "\n [SETTING] See manpage" \ -#define su_trivial_usage \ - "[OPTIONS] [-] [USERNAME]" -#define su_full_usage "\n\n" \ - "Change user id or become root\n" \ - "\nOptions:" \ - "\n -p,-m Preserve environment" \ - "\n -c CMD Command to pass to 'sh -c'" \ - "\n -s SH Shell to use instead of default shell" \ - #define sulogin_trivial_usage \ "[-t N] [TTY]" #define sulogin_full_usage "\n\n" \ diff --git a/loginutils/su.c b/loginutils/su.c index c31e7e771..db303af6d 100644 --- a/loginutils/su.c +++ b/loginutils/su.c @@ -8,6 +8,16 @@ #include "libbb.h" #include +//usage:#define su_trivial_usage +//usage: "[OPTIONS] [-] [USER]" +//usage:#define su_full_usage "\n\n" +//usage: "Run shell under USER (by default, root)\n" +//usage: "\nOptions:" +//usage: "\n -,-l Clear environment, run shell as login shell" +//usage: "\n -p,-m Do not set new $HOME, $SHELL, $USER, $LOGNAME" +//usage: "\n -c CMD Command to pass to 'sh -c'" +//usage: "\n -s SH Shell to use instead of user's default" + #if ENABLE_FEATURE_SU_CHECKS_SHELLS /* Return 1 if SHELL is a restricted shell (one not returned by * getusershell), else 0, meaning it is a standard shell. */ -- cgit v1.2.3-55-g6feb From a5d3d3436b16bf6e1a92ed969e171ac812e8f906 Mon Sep 17 00:00:00 2001 From: Alexey Soloviev Date: Fri, 31 Dec 2010 05:21:51 +0100 Subject: date: preserve isdst value if date is in time_t (unix time) format Signed-off-by: Alexey Soloviev Signed-off-by: Denys Vlasenko --- coreutils/date.c | 4 +++- testsuite/date/date-@-works | 13 +++++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) create mode 100644 testsuite/date/date-@-works diff --git a/coreutils/date.c b/coreutils/date.c index c73fb5be6..6ad5f1bb6 100644 --- a/coreutils/date.c +++ b/coreutils/date.c @@ -282,7 +282,9 @@ int date_main(int argc UNUSED_PARAM, char **argv) } /* Correct any day of week and day of year etc. fields */ - tm_time.tm_isdst = -1; /* Be sure to recheck dst */ + /* Be sure to recheck dst (but not if date is time_t format) */ + if (date_str[0] != '@') + tm_time.tm_isdst = -1; ts.tv_sec = validate_tm_time(date_str, &tm_time); maybe_set_utc(opt); diff --git a/testsuite/date/date-@-works b/testsuite/date/date-@-works new file mode 100644 index 000000000..03b4c7f03 --- /dev/null +++ b/testsuite/date/date-@-works @@ -0,0 +1,13 @@ +# Tests for time_t value (unix time format) + +# Just before DST switched off +test x"Sun Oct 31 03:59:59 EEST 2010" = x"`TZ=EET-2EEST,M3.5.0/3,M10.5.0/4 busybox date -d @1288486799`" + +# Just after DST switched off +test x"Sun Oct 31 03:00:01 EET 2010" = x"`TZ=EET-2EEST,M3.5.0/3,M10.5.0/4 busybox date -d @1288486801`" + +# Just before DST switched on +test x"Sun Mar 28 02:59:59 EET 2010" = x"`TZ=EET-2EEST,M3.5.0/3,M10.5.0/4 busybox date -d @1269737999`" + +# Just after DST switched on +test x"Sun Mar 28 04:00:01 EEST 2010" = x"`TZ=EET-2EEST,M3.5.0/3,M10.5.0/4 busybox date -d @1269738001`" -- cgit v1.2.3-55-g6feb From 92ffe0571a49077f06fc65bf0ada753b30fd8a53 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sun, 2 Jan 2011 20:02:09 +0100 Subject: date,touch: treat 2-digit years better (fit them into +-50 yrs around today) Signed-off-by: Denys Vlasenko --- coreutils/touch.c | 7 ++++--- libbb/time.c | 12 ++++++++++++ 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/coreutils/touch.c b/coreutils/touch.c index 352177111..6c2b948e6 100644 --- a/coreutils/touch.c +++ b/coreutils/touch.c @@ -120,9 +120,10 @@ int touch_main(int argc UNUSED_PARAM, char **argv) struct tm tm_time; time_t t; - //time(&t); - //localtime_r(&t, &tm_time); - memset(&tm_time, 0, sizeof(tm_time)); + //memset(&tm_time, 0, sizeof(tm_time)); + /* Better than memset: makes "HH:MM" dates meaningful */ + time(&t); + localtime_r(&t, &tm_time); parse_datestr(date_str, &tm_time); /* Correct any day of week and day of year etc. fields */ diff --git a/libbb/time.c b/libbb/time.c index 2a74d34c2..1eb2d75c2 100644 --- a/libbb/time.c +++ b/libbb/time.c @@ -93,6 +93,7 @@ void FAST_FUNC parse_datestr(const char *date_str, struct tm *ptm) * * This coincides with the format of "touch -t TIME" */ + unsigned cur_year = ptm->tm_year; int len = strchrnul(date_str, '.') - date_str; /* MM[.SS] */ @@ -133,6 +134,17 @@ void FAST_FUNC parse_datestr(const char *date_str, struct tm *ptm) &end) >= 5) { /* Adjust month from 1-12 to 0-11 */ ptm->tm_mon -= 1; + if ((int)cur_year >= 50) { /* >= 1950 */ + /* Adjust year: */ + /* 1. Put it in the current century */ + ptm->tm_year += (cur_year / 100) * 100; + /* 2. If too far in the past, +100 years */ + if (ptm->tm_year < cur_year - 50) + ptm->tm_year += 100; + /* 3. If too far in the future, -100 years */ + if (ptm->tm_year > cur_year + 50) + ptm->tm_year -= 100; + } } else /* ccyymmddHHMM[.SS] */ if (len == 12 && sscanf(date_str, "%4u%2u%2u%2u%2u%c", -- cgit v1.2.3-55-g6feb From 7b276fc17594b89040f1eda054858860c1dc1522 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Mon, 3 Jan 2011 12:51:13 +0100 Subject: kill[all[5]],pkill: more correct, and smaller, SIGRTMIN/MAX code function old new delta __libc_current_sigrtmin 6 - -6 __libc_current_sigrtmax 6 - -6 get_signum 339 295 -44 ------------------------------------------------------------------------------ (add/remove: 0/3 grow/shrink: 0/1 up/down: 0/-56) Total: -56 bytes Signed-off-by: Denys Vlasenko --- libbb/u_signal_names.c | 29 +++++++++++++++++++---------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/libbb/u_signal_names.c b/libbb/u_signal_names.c index 53ccdd1a7..93cebe2fb 100644 --- a/libbb/u_signal_names.c +++ b/libbb/u_signal_names.c @@ -161,22 +161,31 @@ int FAST_FUNC get_signum(const char *name) #if ENABLE_FEATURE_RTMINMAX # if defined(SIGRTMIN) && defined(SIGRTMAX) - if (strncasecmp(name, "RTMAX", 5) == 0) { +/* libc may use some rt sigs for pthreads and therefore "remap" SIGRTMIN/MAX, + * but we want to use "raw" SIGRTMIN/MAX. Underscored names, if exist, provide + * them. If they don't exist, fall back to non-underscored ones: */ +# if !defined(__SIGRTMIN) +# define __SIGRTMIN SIGRTMIN +# endif +# if !defined(__SIGRTMAX) +# define __SIGRTMAX SIGRTMAX +# endif + if (strncasecmp(name, "RTMIN", 5) == 0) { if (!name[5]) - return SIGRTMAX; - if (name[5] == '-') { + return __SIGRTMIN; + if (name[5] == '+') { i = bb_strtou(name + 6, NULL, 10); - if (!errno && i <= SIGRTMAX - SIGRTMIN) - return SIGRTMAX - i; + if (!errno && i <= __SIGRTMAX - __SIGRTMIN) + return __SIGRTMIN + i; } } - if (strncasecmp(name, "RTMIN", 5) == 0) { + else if (strncasecmp(name, "RTMAX", 5) == 0) { if (!name[5]) - return SIGRTMIN; - if (name[5] == '+') { + return __SIGRTMAX; + if (name[5] == '-') { i = bb_strtou(name + 6, NULL, 10); - if (!errno && i <= SIGRTMAX - SIGRTMIN) - return SIGRTMIN + i; + if (!errno && i <= __SIGRTMAX - __SIGRTMIN) + return __SIGRTMAX - i; } } # endif -- cgit v1.2.3-55-g6feb From 327d2885ecab7fb8e876026c428c2e415c5742c1 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Mon, 3 Jan 2011 13:08:58 +0100 Subject: kill[all[5]],pkill: make signal list show signal numbers, and show RTMIN/MAX function old new delta print_signames 31 64 +33 signals 224 231 +7 Signed-off-by: Denys Vlasenko --- libbb/u_signal_names.c | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/libbb/u_signal_names.c b/libbb/u_signal_names.c index 93cebe2fb..8c78f5e20 100644 --- a/libbb/u_signal_names.c +++ b/libbb/u_signal_names.c @@ -124,6 +124,16 @@ static const char signals[][7] = { #ifdef SIGSYS [SIGSYS ] = "SYS", #endif +#if ENABLE_FEATURE_RTMINMAX +# ifdef __SIGRTMIN + [__SIGRTMIN] = "RTMIN", +# endif +// This makes array about x2 bigger. +// More compact approach is to special-case SIGRTMAX in print_signames() +//# ifdef __SIGRTMAX +// [__SIGRTMAX] = "RTMAX", +//# endif +#endif }; // Convert signal name to number. @@ -216,6 +226,11 @@ void FAST_FUNC print_signames(void) for (signo = 1; signo < ARRAY_SIZE(signals); signo++) { const char *name = signals[signo]; if (name[0]) - puts(name); + printf("%2u) %s\n", signo, name); } +#if ENABLE_FEATURE_RTMINMAX +# ifdef __SIGRTMAX + printf("%2u) %s\n", __SIGRTMAX, "RTMAX"); +# endif +#endif } -- cgit v1.2.3-55-g6feb From 6100b51ca81721ac364f101a17cbce0d9f6fcb59 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Mon, 3 Jan 2011 13:57:49 +0100 Subject: explain every non-SUID_DROP applet. No code changes Signed-off-by: Denys Vlasenko --- include/applets.src.h | 19 ++++++++++++++++++- networking/ping.c | 1 + 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/include/applets.src.h b/include/applets.src.h index c2f90eac0..261ef2333 100644 --- a/include/applets.src.h +++ b/include/applets.src.h @@ -16,6 +16,8 @@ s - suid type: and is run by non-root (applet_main() will not be called at all) _BB_SUID_DROP: will drop suid prior to applet_main() _BB_SUID_MAYBE: neither of the above + (every instance of _BB_SUID_REQUIRE and _BB_SUID_MAYBE + needs to be justified in comment) */ #if defined(PROTOTYPES) @@ -100,6 +102,7 @@ IF_COMM(APPLET(comm, _BB_DIR_USR_BIN, _BB_SUID_DROP)) IF_CP(APPLET_NOEXEC(cp, cp, _BB_DIR_BIN, _BB_SUID_DROP, cp)) IF_CPIO(APPLET(cpio, _BB_DIR_BIN, _BB_SUID_DROP)) IF_CROND(APPLET(crond, _BB_DIR_USR_SBIN, _BB_SUID_DROP)) +/* Needs to be run by root or be suid root - needs to change /var/spool/cron* files: */ IF_CRONTAB(APPLET(crontab, _BB_DIR_USR_BIN, _BB_SUID_REQUIRE)) IF_CRYPTPW(APPLET(cryptpw, _BB_DIR_USR_BIN, _BB_SUID_DROP)) IF_CUT(APPLET_NOEXEC(cut, cut, _BB_DIR_USR_BIN, _BB_SUID_DROP, cut)) @@ -115,6 +118,7 @@ IF_DHCPRELAY(APPLET(dhcprelay, _BB_DIR_USR_SBIN, _BB_SUID_DROP)) IF_DIFF(APPLET(diff, _BB_DIR_USR_BIN, _BB_SUID_DROP)) IF_DIRNAME(APPLET_NOFORK(dirname, dirname, _BB_DIR_USR_BIN, _BB_SUID_DROP, dirname)) IF_DMESG(APPLET(dmesg, _BB_DIR_BIN, _BB_SUID_DROP)) +/* Why _BB_SUID_REQUIRE? */ IF_DNSD(APPLET(dnsd, _BB_DIR_USR_SBIN, _BB_SUID_REQUIRE)) IF_HOSTNAME(APPLET_ODDNAME(dnsdomainname, hostname, _BB_DIR_BIN, _BB_SUID_DROP, dnsdomainname)) IF_DOS2UNIX(APPLET_NOEXEC(dos2unix, dos2unix, _BB_DIR_USR_BIN, _BB_SUID_DROP, dos2unix)) @@ -142,6 +146,7 @@ IF_FDFLUSH(APPLET_ODDNAME(fdflush, freeramdisk, _BB_DIR_BIN, _BB_SUID_DROP, fdfl IF_FDFORMAT(APPLET(fdformat, _BB_DIR_USR_BIN, _BB_SUID_DROP)) IF_FDISK(APPLET(fdisk, _BB_DIR_SBIN, _BB_SUID_DROP)) IF_FGCONSOLE(APPLET(fgconsole, _BB_DIR_USR_BIN, _BB_SUID_DROP)) +/* Benefits from suid root: better access to /dev/BLOCKDEVs: */ IF_FINDFS(APPLET(findfs, _BB_DIR_SBIN, _BB_SUID_MAYBE)) IF_FLASH_ERASEALL(APPLET(flash_eraseall, _BB_DIR_USR_SBIN, _BB_SUID_DROP)) IF_FLASH_LOCK(APPLET_ODDNAME(flash_lock, flash_lock_unlock, _BB_DIR_USR_SBIN, _BB_SUID_DROP, flash_lock)) @@ -193,7 +198,9 @@ IF_IP(APPLET(ip, _BB_DIR_BIN, _BB_SUID_DROP)) #endif IF_IPADDR(APPLET(ipaddr, _BB_DIR_BIN, _BB_SUID_DROP)) IF_IPCALC(APPLET(ipcalc, _BB_DIR_BIN, _BB_SUID_DROP)) +/* Why _BB_SUID_REQUIRE? On Fedora, it isn't suid root */ IF_IPCRM(APPLET(ipcrm, _BB_DIR_USR_BIN, _BB_SUID_REQUIRE)) +/* Why _BB_SUID_REQUIRE? On Fedora, it isn't suid root */ IF_IPCS(APPLET(ipcs, _BB_DIR_USR_BIN, _BB_SUID_REQUIRE)) IF_IPLINK(APPLET(iplink, _BB_DIR_BIN, _BB_SUID_DROP)) IF_IPROUTE(APPLET(iproute, _BB_DIR_BIN, _BB_SUID_DROP)) @@ -214,6 +221,7 @@ IF_LOAD_POLICY(APPLET(load_policy, _BB_DIR_USR_SBIN, _BB_SUID_DROP)) IF_LOADFONT(APPLET(loadfont, _BB_DIR_USR_SBIN, _BB_SUID_DROP)) IF_LOADKMAP(APPLET(loadkmap, _BB_DIR_SBIN, _BB_SUID_DROP)) IF_LOGGER(APPLET(logger, _BB_DIR_USR_BIN, _BB_SUID_DROP)) +/* Needs to be run by root or be suid root - needs to change uid and gid: */ IF_LOGIN(APPLET(login, _BB_DIR_BIN, _BB_SUID_REQUIRE)) IF_LOGNAME(APPLET_NOFORK(logname, logname, _BB_DIR_USR_BIN, _BB_SUID_DROP, logname)) IF_LOGREAD(APPLET(logread, _BB_DIR_SBIN, _BB_SUID_DROP)) @@ -250,6 +258,10 @@ IF_CRYPTPW(APPLET_ODDNAME(mkpasswd, cryptpw, _BB_DIR_USR_BIN, _BB_SUID_DROP, mkp IF_MKSWAP(APPLET(mkswap, _BB_DIR_SBIN, _BB_SUID_DROP)) IF_MKTEMP(APPLET(mktemp, _BB_DIR_BIN, _BB_SUID_DROP)) IF_MORE(APPLET(more, _BB_DIR_BIN, _BB_SUID_DROP)) +/* On full-blown systems, requires suid for user mounts. + * But it's not unthinkable to have it available in non-suid flavor on some systems, + * for viewing mount table. + * Therefore we use _BB_SUID_MAYBE instead of _BB_SUID_REQUIRE: */ IF_MOUNT(APPLET(mount, _BB_DIR_BIN, IF_DESKTOP(_BB_SUID_MAYBE) IF_NOT_DESKTOP(_BB_SUID_DROP))) IF_MOUNTPOINT(APPLET(mountpoint, _BB_DIR_BIN, _BB_SUID_DROP)) IF_MT(APPLET(mt, _BB_DIR_BIN, _BB_SUID_DROP)) @@ -264,6 +276,7 @@ IF_NTPD(APPLET(ntpd, _BB_DIR_USR_SBIN, _BB_SUID_DROP)) IF_OD(APPLET(od, _BB_DIR_USR_BIN, _BB_SUID_DROP)) IF_OPENVT(APPLET(openvt, _BB_DIR_USR_BIN, _BB_SUID_DROP)) //IF_PARSE(APPLET(parse, _BB_DIR_USR_BIN, _BB_SUID_DROP)) +/* Needs to be run by root or be suid root - needs to change /etc/{passwd,shadow}: */ IF_PASSWD(APPLET(passwd, _BB_DIR_USR_BIN, _BB_SUID_REQUIRE)) IF_PGREP(APPLET(pgrep, _BB_DIR_USR_BIN, _BB_SUID_DROP)) IF_PIDOF(APPLET(pidof, _BB_DIR_BIN, _BB_SUID_DROP)) @@ -323,7 +336,7 @@ IF_SHA256SUM(APPLET_NOEXEC(sha256sum, md5_sha1_sum, _BB_DIR_USR_BIN, _BB_SUID_DR IF_SHA512SUM(APPLET_NOEXEC(sha512sum, md5_sha1_sum, _BB_DIR_USR_BIN, _BB_SUID_DROP, sha512sum)) IF_SHOWKEY(APPLET(showkey, _BB_DIR_USR_BIN, _BB_SUID_DROP)) IF_SLATTACH(APPLET(slattach, _BB_DIR_SBIN, _BB_SUID_DROP)) -/* Do not make this applet NOFORK. It breaks ^C-ing of pauses in shells */ +/* Do not make this applet NOFORK. It breaks ^C-ing of pauses in shells: */ IF_SLEEP(APPLET(sleep, _BB_DIR_BIN, _BB_SUID_DROP)) IF_SOFTLIMIT(APPLET_ODDNAME(softlimit, chpst, _BB_DIR_USR_BIN, _BB_SUID_DROP, softlimit)) IF_SORT(APPLET_NOEXEC(sort, sort, _BB_DIR_USR_BIN, _BB_SUID_DROP, sort)) @@ -332,6 +345,7 @@ IF_START_STOP_DAEMON(APPLET_ODDNAME(start-stop-daemon, start_stop_daemon, _BB_DI IF_STAT(APPLET(stat, _BB_DIR_BIN, _BB_SUID_DROP)) IF_STRINGS(APPLET(strings, _BB_DIR_USR_BIN, _BB_SUID_DROP)) IF_STTY(APPLET(stty, _BB_DIR_BIN, _BB_SUID_DROP)) +/* Needs to be run by root or be suid root - needs to change uid and gid: */ IF_SU(APPLET(su, _BB_DIR_BIN, _BB_SUID_REQUIRE)) IF_SULOGIN(APPLET(sulogin, _BB_DIR_SBIN, _BB_SUID_DROP)) IF_SUM(APPLET(sum, _BB_DIR_USR_BIN, _BB_SUID_DROP)) @@ -361,6 +375,7 @@ IF_TIME(APPLET(time, _BB_DIR_USR_BIN, _BB_SUID_DROP)) IF_TIMEOUT(APPLET(timeout, _BB_DIR_USR_BIN, _BB_SUID_DROP)) IF_TOP(APPLET(top, _BB_DIR_USR_BIN, _BB_SUID_DROP)) IF_TR(APPLET(tr, _BB_DIR_USR_BIN, _BB_SUID_DROP)) +/* Needs socket(AF_INET, SOCK_RAW, IPPROTO_ICMP), therefore _BB_SUID_MAYBE: */ IF_TRACEROUTE(APPLET(traceroute, _BB_DIR_USR_BIN, _BB_SUID_MAYBE)) IF_TRACEROUTE6(APPLET(traceroute6, _BB_DIR_USR_BIN, _BB_SUID_MAYBE)) IF_TRUE(APPLET_NOFORK(true, true, _BB_DIR_BIN, _BB_SUID_DROP, true)) @@ -387,8 +402,10 @@ IF_UUDECODE(APPLET(uudecode, _BB_DIR_USR_BIN, _BB_SUID_DROP)) IF_UUENCODE(APPLET(uuencode, _BB_DIR_USR_BIN, _BB_SUID_DROP)) IF_VCONFIG(APPLET(vconfig, _BB_DIR_SBIN, _BB_SUID_DROP)) IF_VI(APPLET(vi, _BB_DIR_BIN, _BB_SUID_DROP)) +/* Needs to be run by root or be suid root - needs to change uid and gid: */ IF_VLOCK(APPLET(vlock, _BB_DIR_USR_BIN, _BB_SUID_REQUIRE)) IF_VOLNAME(APPLET(volname, _BB_DIR_USR_BIN, _BB_SUID_DROP)) +/* Needs to be run by root or be suid root - needs to write to /dev/TTY: */ IF_WALL(APPLET(wall, _BB_DIR_USR_BIN, _BB_SUID_REQUIRE)) IF_WATCH(APPLET(watch, _BB_DIR_BIN, _BB_SUID_DROP)) IF_WATCHDOG(APPLET(watchdog, _BB_DIR_SBIN, _BB_SUID_DROP)) diff --git a/networking/ping.c b/networking/ping.c index 7f74c26fa..366a98668 100644 --- a/networking/ping.c +++ b/networking/ping.c @@ -52,6 +52,7 @@ //config: Make the output from the ping applet include statistics, and at the //config: same time provide full support for ICMP packets. +/* Needs socket(AF_INET, SOCK_RAW, IPPROTO_ICMP), therefore _BB_SUID_MAYBE: */ //applet:IF_PING(APPLET(ping, _BB_DIR_BIN, _BB_SUID_MAYBE)) //applet:IF_PING6(APPLET(ping6, _BB_DIR_BIN, _BB_SUID_MAYBE)) -- cgit v1.2.3-55-g6feb From a116552869db5e7793ae10968eb3c962c69b3d8c Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Tue, 4 Jan 2011 08:46:26 +0100 Subject: tar: add a note about -C and symlink-in-tarball attack Signed-off-by: Denys Vlasenko --- archival/tar.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/archival/tar.c b/archival/tar.c index ebaa965c0..813f86e82 100644 --- a/archival/tar.c +++ b/archival/tar.c @@ -23,6 +23,25 @@ * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ +/* TODO: security with -C DESTDIR option can be enhanced. + * Consider tar file created via: + * $ tar cvf bug.tar anything.txt + * $ ln -s /tmp symlink + * $ tar --append -f bug.tar symlink + * $ rm symlink + * $ mkdir symlink + * $ tar --append -f bug.tar symlink/evil.py + * + * This will result in an archive which contains: + * $ tar --list -f bug.tar + * anything.txt + * symlink + * symlink/evil.py + * + * Untarring it puts evil.py in '/tmp' even if the -C DESTDIR is given. + * This doesn't feel right, and IIRC GNU tar doesn't do that. + */ + #include #include "libbb.h" #include "archive.h" -- cgit v1.2.3-55-g6feb