From a85b66e0f906fedbba7fbaf5ea9ac0dbfc0e4916 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sun, 23 May 2010 23:04:15 +0200 Subject: ifconfig: do not truncate interface names. closes bug 1795 Signed-off-by: Denys Vlasenko --- networking/interface.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/networking/interface.c b/networking/interface.c index a59f310a6..659ac36ea 100644 --- a/networking/interface.c +++ b/networking/interface.c @@ -1002,7 +1002,7 @@ static void ife_print(struct interface *ptr) if (hw == NULL) hw = get_hwntype(-1); - printf("%-9.9s Link encap:%s ", ptr->name, hw->title); + printf("%-9s Link encap:%s ", ptr->name, hw->title); /* For some hardware types (eg Ash, ATM) we don't print the hardware address if it's null. */ if (hw->print != NULL @@ -1178,7 +1178,6 @@ static int for_all_interfaces(int (*doit) (struct interface *, void *), return -1; for (ife = int_list; ife; ife = ife->next) { int err = doit(ife, cookie); - if (err) return err; } -- cgit v1.2.3-55-g6feb From ad7a5d436c8dec563f834a0a9bdad9e69b333cc9 Mon Sep 17 00:00:00 2001 From: Grigory Batalov Date: Sun, 23 May 2010 23:22:10 +0200 Subject: fgconsole: new applet by Grigory Batalov function old new delta fgconsole_main - 51 +51 applet_names 2227 2237 +10 applet_main 1304 1308 +4 applet_nameofs 652 654 +2 applet_install_loc 163 164 +1 packed_usage 27079 27073 -6 ------------------------------------------------------------------------------ (add/remove: 2/0 grow/shrink: 4/1 up/down: 68/-6) Total: 62 bytes Signed-off-by: Grigory Batalov Signed-off-by: Denys Vlasenko --- console-tools/Config.in | 6 ++++++ console-tools/Kbuild | 1 + console-tools/fgconsole.c | 30 ++++++++++++++++++++++++++++++ include/applets.h | 1 + include/usage.h | 13 +++++++++---- scripts/defconfig | 1 + 6 files changed, 48 insertions(+), 4 deletions(-) create mode 100644 console-tools/fgconsole.c diff --git a/console-tools/Config.in b/console-tools/Config.in index 195685b97..a7e995936 100644 --- a/console-tools/Config.in +++ b/console-tools/Config.in @@ -12,6 +12,12 @@ config CHVT This program is used to change to another terminal. Example: chvt 4 (change to terminal /dev/tty4) +config FGCONSOLE + bool "fgconsole" + default n + help + This program prints active (foreground) console number. + config CLEAR bool "clear" default n diff --git a/console-tools/Kbuild b/console-tools/Kbuild index df5ffdb96..ad8b8ce77 100644 --- a/console-tools/Kbuild +++ b/console-tools/Kbuild @@ -6,6 +6,7 @@ lib-y:= lib-$(CONFIG_CHVT) += chvt.o +lib-$(CONFIG_FGCONSOLE) += fgconsole.o lib-$(CONFIG_CLEAR) += clear.o lib-$(CONFIG_DEALLOCVT) += deallocvt.o lib-$(CONFIG_DUMPKMAP) += dumpkmap.o diff --git a/console-tools/fgconsole.c b/console-tools/fgconsole.c new file mode 100644 index 000000000..75fd98fd5 --- /dev/null +++ b/console-tools/fgconsole.c @@ -0,0 +1,30 @@ +/* vi: set sw=4 ts=4: */ +/* + * Mini fgconsole implementation for busybox + * + * Copyright (C) 2010 by Grigory Batalov + * + * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + */ + +#include "libbb.h" + +/* From */ +struct vt_stat { + unsigned short v_active; /* active vt */ + unsigned short v_signal; /* signal to send */ + unsigned short v_state; /* vt bitmask */ +}; +enum { VT_GETSTATE = 0x5603 }; /* get global vt state info */ + +int fgconsole_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +int fgconsole_main(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) +{ + struct vt_stat vtstat; + + vtstat.v_active = 0; + xioctl(get_console_fd_or_die(), VT_GETSTATE, &vtstat); + printf("%d\n", vtstat.v_active); + + return EXIT_SUCCESS; +} diff --git a/include/applets.h b/include/applets.h index ff8799c63..33c3c2555 100644 --- a/include/applets.h +++ b/include/applets.h @@ -157,6 +157,7 @@ IF_FBSPLASH(APPLET(fbsplash, _BB_DIR_SBIN, _BB_SUID_DROP)) IF_FDFLUSH(APPLET_ODDNAME(fdflush, freeramdisk, _BB_DIR_BIN, _BB_SUID_DROP, fdflush)) 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)) IF_FEATURE_GREP_FGREP_ALIAS(APPLET_ODDNAME(fgrep, grep, _BB_DIR_BIN, _BB_SUID_DROP, fgrep)) IF_FIND(APPLET_NOEXEC(find, find, _BB_DIR_USR_BIN, _BB_SUID_DROP, find)) IF_FINDFS(APPLET(findfs, _BB_DIR_SBIN, _BB_SUID_MAYBE)) diff --git a/include/usage.h b/include/usage.h index d53b86731..8b8bd2c78 100644 --- a/include/usage.h +++ b/include/usage.h @@ -156,6 +156,11 @@ "\n -r Repetitions" \ "\n -n Start new tone" \ +#define blkid_trivial_usage \ + "" +#define blkid_full_usage "\n\n" \ + "Print UUIDs of all filesystems" + #define bootchartd_trivial_usage \ "start [PROG ARGS]|stop|init" #define bootchartd_full_usage "\n\n" \ @@ -1243,10 +1248,10 @@ "\n -H HEADS" \ "\n -S SECTORS" \ -#define blkid_trivial_usage \ - "" -#define blkid_full_usage "\n\n" \ - "Print UUIDs of all filesystems" +#define fgconsole_trivial_usage \ + "" +#define fgconsole_full_usage "\n\n" \ + "Get active console" #define findfs_trivial_usage \ "LABEL=label or UUID=uuid" diff --git a/scripts/defconfig b/scripts/defconfig index 0a748febc..8b88f79b3 100644 --- a/scripts/defconfig +++ b/scripts/defconfig @@ -287,6 +287,7 @@ CONFIG_FEATURE_MD5_SHA1_SUM_CHECK=y # Console Utilities # CONFIG_CHVT=y +CONFIG_FGCONSOLE=n CONFIG_CLEAR=y CONFIG_DEALLOCVT=y CONFIG_DUMPKMAP=y -- cgit v1.2.3-55-g6feb From 4e8ff73e20ed15e5552f960358f1e5bb4d25c44b Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Mon, 24 May 2010 04:33:02 +0200 Subject: unzip: restore unix file mode if possible. closes bug 1045 function old new delta unzip_main 2197 2188 -9 ------------------------------------------------------------------------------ (add/remove: 1/1 grow/shrink: 0/1 up/down: 173/-182) Total: -9 bytes Signed-off-by: Denys Vlasenko --- archival/unzip.c | 143 ++++++++++++++++++++++++++++++++++--------------------- 1 file changed, 88 insertions(+), 55 deletions(-) diff --git a/archival/unzip.c b/archival/unzip.c index afab3280d..868166bb1 100644 --- a/archival/unzip.c +++ b/archival/unzip.c @@ -25,12 +25,12 @@ enum { #if BB_BIG_ENDIAN ZIP_FILEHEADER_MAGIC = 0x504b0304, - ZIP_CDS_MAGIC = 0x504b0102, - ZIP_CDE_MAGIC = 0x504b0506, + ZIP_CDF_MAGIC = 0x504b0102, /* central directory's file header */ + ZIP_CDE_MAGIC = 0x504b0506, /* "end of central directory" record */ ZIP_DD_MAGIC = 0x504b0708, #else ZIP_FILEHEADER_MAGIC = 0x04034b50, - ZIP_CDS_MAGIC = 0x02014b50, + ZIP_CDF_MAGIC = 0x02014b50, ZIP_CDE_MAGIC = 0x06054b50, ZIP_DD_MAGIC = 0x08074b50, #endif @@ -77,15 +77,15 @@ struct BUG_zip_header_must_be_26_bytes { (zip_header).formatted.extra_len = SWAP_LE16((zip_header).formatted.extra_len ); \ } while (0) -#define CDS_HEADER_LEN 42 +#define CDF_HEADER_LEN 42 typedef union { - uint8_t raw[CDS_HEADER_LEN]; + uint8_t raw[CDF_HEADER_LEN]; struct { /* uint32_t signature; 50 4b 01 02 */ uint16_t version_made_by; /* 0-1 */ uint16_t version_needed; /* 2-3 */ - uint16_t cds_flags; /* 4-5 */ + uint16_t cdf_flags; /* 4-5 */ uint16_t method; /* 6-7 */ uint16_t mtime; /* 8-9 */ uint16_t mdate; /* 10-11 */ @@ -100,21 +100,25 @@ typedef union { uint32_t external_file_attributes PACKED; /* 34-37 */ uint32_t relative_offset_of_local_header PACKED; /* 38-41 */ } formatted PACKED; -} cds_header_t; +} cdf_header_t; -struct BUG_cds_header_must_be_42_bytes { - char BUG_cds_header_must_be_42_bytes[ - offsetof(cds_header_t, formatted.relative_offset_of_local_header) + 4 - == CDS_HEADER_LEN ? 1 : -1]; +struct BUG_cdf_header_must_be_42_bytes { + char BUG_cdf_header_must_be_42_bytes[ + offsetof(cdf_header_t, formatted.relative_offset_of_local_header) + 4 + == CDF_HEADER_LEN ? 1 : -1]; }; -#define FIX_ENDIANNESS_CDS(cds_header) do { \ - (cds_header).formatted.crc32 = SWAP_LE32((cds_header).formatted.crc32 ); \ - (cds_header).formatted.cmpsize = SWAP_LE32((cds_header).formatted.cmpsize ); \ - (cds_header).formatted.ucmpsize = SWAP_LE32((cds_header).formatted.ucmpsize ); \ - (cds_header).formatted.file_name_length = SWAP_LE16((cds_header).formatted.file_name_length); \ - (cds_header).formatted.extra_field_length = SWAP_LE16((cds_header).formatted.extra_field_length); \ - (cds_header).formatted.file_comment_length = SWAP_LE16((cds_header).formatted.file_comment_length); \ +#define FIX_ENDIANNESS_CDF(cdf_header) do { \ + (cdf_header).formatted.crc32 = SWAP_LE32((cdf_header).formatted.crc32 ); \ + (cdf_header).formatted.cmpsize = SWAP_LE32((cdf_header).formatted.cmpsize ); \ + (cdf_header).formatted.ucmpsize = SWAP_LE32((cdf_header).formatted.ucmpsize ); \ + (cdf_header).formatted.file_name_length = SWAP_LE16((cdf_header).formatted.file_name_length); \ + (cdf_header).formatted.extra_field_length = SWAP_LE16((cdf_header).formatted.extra_field_length); \ + (cdf_header).formatted.file_comment_length = SWAP_LE16((cdf_header).formatted.file_comment_length); \ + IF_DESKTOP( \ + (cdf_header).formatted.version_made_by = SWAP_LE16((cdf_header).formatted.version_made_by); \ + (cdf_header).formatted.external_file_attributes = SWAP_LE32((cdf_header).formatted.external_file_attributes); \ + ) \ } while (0) #define CDE_HEADER_LEN 16 @@ -124,11 +128,11 @@ typedef union { struct { /* uint32_t signature; 50 4b 05 06 */ uint16_t this_disk_no; - uint16_t disk_with_cds_no; - uint16_t cds_entries_on_this_disk; - uint16_t cds_entries_total; - uint32_t cds_size; - uint32_t cds_offset; + uint16_t disk_with_cdf_no; + uint16_t cdf_entries_on_this_disk; + uint16_t cdf_entries_total; + uint32_t cdf_size; + uint32_t cdf_offset; /* uint16_t file_comment_length; */ /* .ZIP file comment (variable size) */ } formatted PACKED; @@ -140,7 +144,7 @@ struct BUG_cde_header_must_be_16_bytes { }; #define FIX_ENDIANNESS_CDE(cde_header) do { \ - (cde_header).formatted.cds_offset = SWAP_LE32((cde_header).formatted.cds_offset); \ + (cde_header).formatted.cdf_offset = SWAP_LE32((cde_header).formatted.cdf_offset); \ } while (0) enum { zip_fd = 3 }; @@ -148,7 +152,7 @@ enum { zip_fd = 3 }; #if ENABLE_DESKTOP /* NB: does not preserve file position! */ -static uint32_t find_cds_offset(void) +static uint32_t find_cdf_offset(void) { unsigned char buf[1024]; cde_header_t cde_header; @@ -177,32 +181,30 @@ static uint32_t find_cds_offset(void) /* we found CDE! */ memcpy(cde_header.raw, p + 1, CDE_HEADER_LEN); FIX_ENDIANNESS_CDE(cde_header); - return cde_header.formatted.cds_offset; + return cde_header.formatted.cdf_offset; } bb_error_msg_and_die("can't find file table"); }; -static uint32_t read_next_cds(int count_m1, uint32_t cds_offset, cds_header_t *cds_ptr) +static uint32_t read_next_cdf(uint32_t cdf_offset, cdf_header_t *cdf_ptr) { off_t org; org = xlseek(zip_fd, 0, SEEK_CUR); - if (!cds_offset) - cds_offset = find_cds_offset(); - - while (count_m1-- >= 0) { - xlseek(zip_fd, cds_offset + 4, SEEK_SET); - xread(zip_fd, cds_ptr->raw, CDS_HEADER_LEN); - FIX_ENDIANNESS_CDS(*cds_ptr); - cds_offset += 4 + CDS_HEADER_LEN - + cds_ptr->formatted.file_name_length - + cds_ptr->formatted.extra_field_length - + cds_ptr->formatted.file_comment_length; - } + if (!cdf_offset) + cdf_offset = find_cdf_offset(); + + xlseek(zip_fd, cdf_offset + 4, SEEK_SET); + xread(zip_fd, cdf_ptr->raw, CDF_HEADER_LEN); + FIX_ENDIANNESS_CDF(*cdf_ptr); + cdf_offset += 4 + CDF_HEADER_LEN + + cdf_ptr->formatted.file_name_length + + cdf_ptr->formatted.extra_field_length + + cdf_ptr->formatted.file_comment_length; xlseek(zip_fd, org, SEEK_SET); - return cds_offset; + return cdf_offset; }; #endif @@ -258,8 +260,7 @@ int unzip_main(int argc, char **argv) smallint listing = 0; smallint overwrite = O_PROMPT; #if ENABLE_DESKTOP - uint32_t cds_offset; - unsigned cds_entries; + uint32_t cdf_offset; #endif unsigned long total_usize; unsigned long total_size; @@ -435,20 +436,42 @@ int unzip_main(int argc, char **argv) } } +/* Example of an archive with one 0-byte long file named 'z' + * created by Zip 2.31 on Unix: + * 0000 [50 4b]03 04 0a 00 00 00 00 00 42 1a b8 3c 00 00 |PK........B..<..| + * sig........ vneed flags compr mtime mdate crc32> + * 0010 00 00 00 00 00 00 00 00 00 00 01 00 15 00 7a 55 |..............zU| + * >..... csize...... usize...... fnlen exlen fn ex> + * 0020 54 09 00 03 cc d3 f9 4b cc d3 f9 4b 55 78 04 00 |T......K...KUx..| + * >tra_field...................................... + * 0030 00 00 00 00[50 4b]01 02 17 03 0a 00 00 00 00 00 |....PK..........| + * ........... sig........ vmade vneed flags compr + * 0040 42 1a b8 3c 00 00 00 00 00 00 00 00 00 00 00 00 |B..<............| + * mtime mdate crc32...... csize...... usize...... + * 0050 01 00 0d 00 00 00 00 00 00 00 00 00 a4 81 00 00 |................| + * fnlen exlen clen. dnum. iattr eattr...... relofs> (eattr = rw-r--r--) + * 0060 00 00 7a 55 54 05 00 03 cc d3 f9 4b 55 78 00 00 |..zUT......KUx..| + * >..... fn extra_field........................... + * 0070 [50 4b]05 06 00 00 00 00 01 00 01 00 3c 00 00 00 |PK..........<...| + * 0080 34 00 00 00 00 00 |4.....| + */ total_usize = 0; total_size = 0; total_entries = 0; #if ENABLE_DESKTOP - cds_entries = 0; - cds_offset = 0; + cdf_offset = 0; #endif while (1) { uint32_t magic; + mode_t dir_mode = 0777; +#if ENABLE_DESKTOP + mode_t file_mode = 0666; +#endif /* Check magic number */ xread(zip_fd, &magic, 4); /* Central directory? It's at the end, so exit */ - if (magic == ZIP_CDS_MAGIC) + if (magic == ZIP_CDF_MAGIC) break; #if ENABLE_DESKTOP /* Data descriptor? It was a streaming file, go on */ @@ -476,15 +499,21 @@ int unzip_main(int argc, char **argv) /* 0x0001 - encrypted */ bb_error_msg_and_die("zip flag 1 (encryption) is not supported"); } - if (zip_header.formatted.flags & 0x0008) { - cds_header_t cds_header; - /* 0x0008 - streaming. [u]cmpsize can be reliably gotten - * only from Central Directory. See unzip_doc.txt */ - cds_offset = read_next_cds(total_entries - cds_entries, cds_offset, &cds_header); - cds_entries = total_entries + 1; - zip_header.formatted.crc32 = cds_header.formatted.crc32; - zip_header.formatted.cmpsize = cds_header.formatted.cmpsize; - zip_header.formatted.ucmpsize = cds_header.formatted.ucmpsize; + + { + cdf_header_t cdf_header; + cdf_offset = read_next_cdf(cdf_offset, &cdf_header); + if (zip_header.formatted.flags & 0x0008) { + /* 0x0008 - streaming. [u]cmpsize can be reliably gotten + * only from Central Directory. See unzip_doc.txt */ + zip_header.formatted.crc32 = cdf_header.formatted.crc32; + zip_header.formatted.cmpsize = cdf_header.formatted.cmpsize; + zip_header.formatted.ucmpsize = cdf_header.formatted.ucmpsize; + } + if ((cdf_header.formatted.version_made_by >> 8) == 3) { + /* this archive is created on Unix */ + dir_mode = file_mode = (cdf_header.formatted.external_file_attributes >> 16); + } } #endif @@ -550,7 +579,7 @@ int unzip_main(int argc, char **argv) printf(" creating: %s\n", dst_fn); } unzip_create_leading_dirs(dst_fn); - if (bb_make_directory(dst_fn, 0777, 0)) { + if (bb_make_directory(dst_fn, dir_mode, 0)) { bb_error_msg_and_die("exiting"); } } else { @@ -592,7 +621,11 @@ int unzip_main(int argc, char **argv) overwrite = O_ALWAYS; case 'y': /* Open file and fall into unzip */ unzip_create_leading_dirs(dst_fn); +#if ENABLE_DESKTOP + dst_fd = xopen3(dst_fn, O_WRONLY | O_CREAT | O_TRUNC, file_mode); +#else dst_fd = xopen(dst_fn, O_WRONLY | O_CREAT | O_TRUNC); +#endif case -1: /* Unzip */ if (!quiet) { printf(" inflating: %s\n", dst_fn); -- cgit v1.2.3-55-g6feb From e98884b9bec7cca415f1813764741bf18b70e8cf Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Mon, 24 May 2010 04:46:18 +0200 Subject: unzip: tiny code shrink -2 bytes Signed-off-by: Denys Vlasenko --- archival/unzip.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/archival/unzip.c b/archival/unzip.c index 868166bb1..5e8bac356 100644 --- a/archival/unzip.c +++ b/archival/unzip.c @@ -42,7 +42,7 @@ typedef union { uint8_t raw[ZIP_HEADER_LEN]; struct { uint16_t version; /* 0-1 */ - uint16_t flags; /* 2-3 */ + uint16_t zip_flags; /* 2-3 */ uint16_t method; /* 4-5 */ uint16_t modtime; /* 6-7 */ uint16_t moddate; /* 8-9 */ @@ -66,7 +66,6 @@ struct BUG_zip_header_must_be_26_bytes { #define FIX_ENDIANNESS_ZIP(zip_header) do { \ (zip_header).formatted.version = SWAP_LE16((zip_header).formatted.version ); \ - (zip_header).formatted.flags = SWAP_LE16((zip_header).formatted.flags ); \ (zip_header).formatted.method = SWAP_LE16((zip_header).formatted.method ); \ (zip_header).formatted.modtime = SWAP_LE16((zip_header).formatted.modtime ); \ (zip_header).formatted.moddate = SWAP_LE16((zip_header).formatted.moddate ); \ @@ -491,11 +490,11 @@ int unzip_main(int argc, char **argv) bb_error_msg_and_die("unsupported method %d", zip_header.formatted.method); } #if !ENABLE_DESKTOP - if (zip_header.formatted.flags & 0x0009) { + if (zip_header.formatted.zip_flags & SWAP_LE16(0x0009)) { bb_error_msg_and_die("zip flags 1 and 8 are not supported"); } #else - if (zip_header.formatted.flags & 0x0001) { + if (zip_header.formatted.zip_flags & SWAP_LE16(0x0001)) { /* 0x0001 - encrypted */ bb_error_msg_and_die("zip flag 1 (encryption) is not supported"); } @@ -503,7 +502,7 @@ int unzip_main(int argc, char **argv) { cdf_header_t cdf_header; cdf_offset = read_next_cdf(cdf_offset, &cdf_header); - if (zip_header.formatted.flags & 0x0008) { + if (zip_header.formatted.zip_flags & SWAP_LE16(0x0008)) { /* 0x0008 - streaming. [u]cmpsize can be reliably gotten * only from Central Directory. See unzip_doc.txt */ zip_header.formatted.crc32 = cdf_header.formatted.crc32; -- cgit v1.2.3-55-g6feb From fc2bb8f04f048bf60a8b53bd6ad04eef1b8d3626 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Mon, 24 May 2010 13:07:55 +0200 Subject: unzip: another small code shrink function old new delta find_cdf_offset 173 160 -13 Signed-off-by: Denys Vlasenko --- archival/unzip.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/archival/unzip.c b/archival/unzip.c index 5e8bac356..1d3291ab8 100644 --- a/archival/unzip.c +++ b/archival/unzip.c @@ -159,9 +159,9 @@ static uint32_t find_cdf_offset(void) off_t end; end = xlseek(zip_fd, 0, SEEK_END); - if (end < 1024) - end = 1024; end -= 1024; + if (end < 0) + end = 0; xlseek(zip_fd, end, SEEK_SET); full_read(zip_fd, buf, 1024); -- cgit v1.2.3-55-g6feb From 49ee8393f4d11ee3091dcad41ce36741c6a4b4f8 Mon Sep 17 00:00:00 2001 From: Bernhard Reutner-Fischer Date: Tue, 25 May 2010 09:55:42 +0200 Subject: ipaddress: print OPERSTATEs and NO-CARRIER Signed-off-by: Bernhard Reutner-Fischer --- networking/libiproute/ipaddress.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/networking/libiproute/ipaddress.c b/networking/libiproute/ipaddress.c index daea9dd03..3f360f455 100644 --- a/networking/libiproute/ipaddress.c +++ b/networking/libiproute/ipaddress.c @@ -54,6 +54,8 @@ static void print_link_flags(unsigned flags, unsigned mdown) "MULTICAST\0""NOARP\0""UP\0""LOWER_UP\0"; bb_putchar('<'); + if (flags & IFF_UP && !(flags & IFF_RUNNING)) + printf("NO-CARRIER,"); flags &= ~IFF_RUNNING; #if 0 _PF(ALLMULTI); @@ -162,6 +164,13 @@ static NOINLINE int print_linkinfo(const struct nlmsghdr *n) printf("master %s ", ll_idx_n2a(*(int*)RTA_DATA(tb[IFLA_MASTER]), b1)); } #endif + if (tb[IFLA_OPERSTATE]) { + static const char operstate_labels[] ALIGN1 = + "UNKNOWN\0""NOTPRESENT\0""DOWN\0""LOWERLAYERDOWN\0" + "TESTING\0""DORMANT\0""UP\0"; + printf("state %s ", nth_string(operstate_labels, + *(__u8 *)RTA_DATA(tb[IFLA_OPERSTATE]))); + } if (G_filter.showqueue) print_queuelen((char*)RTA_DATA(tb[IFLA_IFNAME])); -- cgit v1.2.3-55-g6feb From 6faebfa663fd008fa28f0d69d0663fe80675ebec Mon Sep 17 00:00:00 2001 From: Bernhard Reutner-Fischer Date: Tue, 25 May 2010 10:34:27 +0200 Subject: iplink: support add/delete function old new delta do_change - 490 +490 .rodata 135193 135225 +32 do_iplink 1146 1169 +23 ------------------------------------------------------------------------------ (add/remove: 1/0 grow/shrink: 2/0 up/down: 545/0) Total: 545 bytes Signed-off-by: Bernhard Reutner-Fischer --- networking/libiproute/iplink.c | 93 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 91 insertions(+), 2 deletions(-) diff --git a/networking/libiproute/iplink.c b/networking/libiproute/iplink.c index df8a354a1..a28df6e79 100644 --- a/networking/libiproute/iplink.c +++ b/networking/libiproute/iplink.c @@ -283,11 +283,98 @@ static int ipaddr_list_link(char **argv) return ipaddr_list_or_flush(argv, 0); } +#ifndef NLMSG_TAIL +#define NLMSG_TAIL(nmsg) \ + ((struct rtattr *) (((void *) (nmsg)) + NLMSG_ALIGN((nmsg)->nlmsg_len))) +#endif +/* Return value becomes exitcode. It's okay to not return at all */ +static int do_change(char **argv, const unsigned rtm) +{ + static const char keywords[] ALIGN1 = + "link\0""name\0""type\0""dev\0"; + enum { + ARG_link, + ARG_name, + ARG_type, + ARG_dev, + }; + struct rtnl_handle rth; + struct { + struct nlmsghdr n; + struct ifinfomsg i; + char buf[1024]; + } req; + int arg; + char *name_str = NULL, *link_str = NULL, *type_str = NULL, *dev_str = NULL; + + memset(&req, 0, sizeof(req)); + + req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)); + req.n.nlmsg_flags = NLM_F_REQUEST; + req.n.nlmsg_type = rtm; + req.i.ifi_family = preferred_family; + if (rtm == RTM_NEWLINK) + req.n.nlmsg_flags |= NLM_F_CREATE|NLM_F_EXCL; + + while (*argv) { + arg = index_in_substrings(keywords, *argv); + if (arg == ARG_link) { + NEXT_ARG(); + link_str = *argv; + } else if (arg == ARG_name) { + NEXT_ARG(); + name_str = *argv; + } else if (arg == ARG_type) { + NEXT_ARG(); + type_str = *argv; + } else { + if (arg == ARG_dev) { + if (dev_str) + duparg(*argv, "dev"); + NEXT_ARG(); + } + dev_str = *argv; + } + argv++; + } + xrtnl_open(&rth); + ll_init_map(&rth); + if (type_str) { + struct rtattr *linkinfo = NLMSG_TAIL(&req.n); + + addattr_l(&req.n, sizeof(req), IFLA_LINKINFO, NULL, 0); + addattr_l(&req.n, sizeof(req), IFLA_INFO_KIND, type_str, + strlen(type_str)); + linkinfo->rta_len = (void *)NLMSG_TAIL(&req.n) - (void *)linkinfo; + } + if (rtm != RTM_NEWLINK) { + if (!dev_str) + return 1; /* Need a device to delete */ + req.i.ifi_index = xll_name_to_index(dev_str); + } else { + if (!name_str) + name_str = dev_str; + if (link_str) { + int idx = xll_name_to_index(link_str); + addattr_l(&req.n, sizeof(req), IFLA_LINK, &idx, 4); + } + } + if (name_str) { + const size_t name_len = strlen(name_str) + 1; + if (name_len < 2 || name_len > IFNAMSIZ) + invarg(name_str, "name"); + addattr_l(&req.n, sizeof(req), IFLA_IFNAME, name_str, name_len); + } + if (rtnl_talk(&rth, &req.n, 0, 0, NULL, NULL, NULL) < 0) + return 2; + return 0; +} + /* Return value becomes exitcode. It's okay to not return at all */ int do_iplink(char **argv) { static const char keywords[] ALIGN1 = - "set\0""show\0""lst\0""list\0"; + "add\0""delete\0""set\0""show\0""lst\0""list\0"; int key; if (!*argv) return ipaddr_list_link(argv); @@ -295,7 +382,9 @@ int do_iplink(char **argv) if (key < 0) bb_error_msg_and_die(bb_msg_invalid_arg, *argv, applet_name); argv++; - if (key == 0) /* set */ + if (key <= 1) /* add/delete */ + return do_change(argv, key ? RTM_DELLINK : RTM_NEWLINK); + else if (key == 2) /* set */ return do_set(argv); /* show, lst, list */ return ipaddr_list_link(argv); -- cgit v1.2.3-55-g6feb From d148e484db143c801f806c4e055a5c8b80d0c5ee Mon Sep 17 00:00:00 2001 From: Bernhard Reutner-Fischer Date: Tue, 25 May 2010 16:16:28 +0200 Subject: iplink: shrink function old new delta do_change 490 487 -3 ipaddr_list_link 18 - -18 do_iplink 1169 1113 -56 ------------------------------------------------------------------------------ (add/remove: 0/1 grow/shrink: 0/2 up/down: 0/-77) Total: -77 bytes Signed-off-by: Bernhard Reutner-Fischer --- networking/libiproute/iplink.c | 93 ++++++++++++++++++------------------------ 1 file changed, 39 insertions(+), 54 deletions(-) diff --git a/networking/libiproute/iplink.c b/networking/libiproute/iplink.c index a28df6e79..583a2801c 100644 --- a/networking/libiproute/iplink.c +++ b/networking/libiproute/iplink.c @@ -186,56 +186,48 @@ static int do_set(char **argv) if (key == ARG_up) { mask |= IFF_UP; flags |= IFF_UP; - } - if (key == ARG_down) { + } else if (key == ARG_down) { mask |= IFF_UP; flags &= ~IFF_UP; - } - if (key == ARG_name) { + } else if (key == ARG_name) { NEXT_ARG(); newname = *argv; - } - if (key == ARG_mtu) { + } else if (key == ARG_mtu) { NEXT_ARG(); if (mtu != -1) duparg("mtu", *argv); mtu = get_unsigned(*argv, "mtu"); - } - if (key == ARG_multicast) { - int param; - NEXT_ARG(); - mask |= IFF_MULTICAST; - param = index_in_strings(str_on_off, *argv); - if (param < 0) - die_must_be_on_off("multicast"); - if (param == PARM_on) - flags |= IFF_MULTICAST; - else - flags &= ~IFF_MULTICAST; - } - if (key == ARG_arp) { - int param; - NEXT_ARG(); - mask |= IFF_NOARP; - param = index_in_strings(str_on_off, *argv); - if (param < 0) - die_must_be_on_off("arp"); - if (param == PARM_on) - flags &= ~IFF_NOARP; - else - flags |= IFF_NOARP; - } - if (key == ARG_addr) { + } else if (key == ARG_addr) { NEXT_ARG(); newaddr = *argv; - } - if (key >= ARG_dev) { + } else if (key >= ARG_dev) { if (key == ARG_dev) { NEXT_ARG(); } if (dev) duparg2("dev", *argv); dev = *argv; + } else { + int param; + NEXT_ARG(); + param = index_in_strings(str_on_off, *argv); + if (key == ARG_multicast) { + if (param < 0) + die_must_be_on_off("multicast"); + mask |= IFF_MULTICAST; + if (param == PARM_on) + flags |= IFF_MULTICAST; + else + flags &= ~IFF_MULTICAST; + } else if (key == ARG_arp) { + if (param < 0) + die_must_be_on_off("arp"); + mask |= IFF_NOARP; + if (param == PARM_on) + flags &= ~IFF_NOARP; + else + flags |= IFF_NOARP; + } } argv++; } @@ -248,9 +240,11 @@ static int do_set(char **argv) halen = get_address(dev, &htype); if (newaddr) { parse_address(dev, htype, halen, newaddr, &ifr0); + set_address(&ifr0, 0); } if (newbrd) { parse_address(dev, htype, halen, newbrd, &ifr1); + set_address(&ifr1, 1); } } @@ -264,14 +258,6 @@ static int do_set(char **argv) if (mtu != -1) { set_mtu(dev, mtu); } - if (newaddr || newbrd) { - if (newbrd) { - set_address(&ifr1, 1); - } - if (newaddr) { - set_address(&ifr0, 0); - } - } if (mask) do_chflags(dev, flags, mask); return 0; @@ -304,7 +290,7 @@ static int do_change(char **argv, const unsigned rtm) struct ifinfomsg i; char buf[1024]; } req; - int arg; + smalluint arg; char *name_str = NULL, *link_str = NULL, *type_str = NULL, *dev_str = NULL; memset(&req, 0, sizeof(req)); @@ -375,17 +361,16 @@ int do_iplink(char **argv) { static const char keywords[] ALIGN1 = "add\0""delete\0""set\0""show\0""lst\0""list\0"; - int key; - if (!*argv) - return ipaddr_list_link(argv); - key = index_in_substrings(keywords, *argv); - if (key < 0) - bb_error_msg_and_die(bb_msg_invalid_arg, *argv, applet_name); - argv++; - if (key <= 1) /* add/delete */ - return do_change(argv, key ? RTM_DELLINK : RTM_NEWLINK); - else if (key == 2) /* set */ - return do_set(argv); + if (*argv) { + smalluint key = index_in_substrings(keywords, *argv); + if (key > 5) /* invalid argument */ + bb_error_msg_and_die(bb_msg_invalid_arg, *argv, applet_name); + argv++; + if (key <= 1) /* add/delete */ + return do_change(argv, key ? RTM_DELLINK : RTM_NEWLINK); + else if (key == 2) /* set */ + return do_set(argv); + } /* show, lst, list */ return ipaddr_list_link(argv); } -- cgit v1.2.3-55-g6feb From ab0e412937a358fe4f7110d4222e12b14f320ad0 Mon Sep 17 00:00:00 2001 From: Bernhard Reutner-Fischer Date: Tue, 25 May 2010 16:57:08 +0200 Subject: ip link: add qlen qlen had a variable but was not handled.. function old new delta do_iplink 1113 1261 +148 .rodata 135225 135249 +24 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 2/0 up/down: 172/0) Total: 172 bytes Signed-off-by: Bernhard Reutner-Fischer --- networking/libiproute/iplink.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/networking/libiproute/iplink.c b/networking/libiproute/iplink.c index 583a2801c..8bf892797 100644 --- a/networking/libiproute/iplink.c +++ b/networking/libiproute/iplink.c @@ -171,9 +171,9 @@ static int do_set(char **argv) char *newname = NULL; int htype, halen; static const char keywords[] ALIGN1 = - "up\0""down\0""name\0""mtu\0""multicast\0" + "up\0""down\0""name\0""mtu\0""qlen\0""multicast\0" "arp\0""address\0""dev\0"; - enum { ARG_up = 0, ARG_down, ARG_name, ARG_mtu, ARG_multicast, + enum { ARG_up = 0, ARG_down, ARG_name, ARG_mtu, ARG_qlen, ARG_multicast, ARG_arp, ARG_addr, ARG_dev }; static const char str_on_off[] ALIGN1 = "on\0""off\0"; enum { PARM_on = 0, PARM_off }; @@ -197,6 +197,11 @@ static int do_set(char **argv) if (mtu != -1) duparg("mtu", *argv); mtu = get_unsigned(*argv, "mtu"); + } else if (key == ARG_qlen) { + NEXT_ARG(); + if (qlen != -1) + duparg("qlen", *argv); + qlen = get_unsigned(*argv, "qlen"); } else if (key == ARG_addr) { NEXT_ARG(); newaddr = *argv; -- cgit v1.2.3-55-g6feb From 96913f9254d288d61d893015f92e9f75b13f5d2a Mon Sep 17 00:00:00 2001 From: Bernhard Reutner-Fischer Date: Tue, 25 May 2010 17:19:35 +0200 Subject: ip tunnel: unify parsing args; no obj-code changes Signed-off-by: Bernhard Reutner-Fischer --- networking/libiproute/iptunnel.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/networking/libiproute/iptunnel.c b/networking/libiproute/iptunnel.c index c36c7136f..257343826 100644 --- a/networking/libiproute/iptunnel.c +++ b/networking/libiproute/iptunnel.c @@ -561,11 +561,10 @@ int do_iptunnel(char **argv) static const char keywords[] ALIGN1 = "add\0""change\0""delete\0""show\0""list\0""lst\0"; enum { ARG_add = 0, ARG_change, ARG_del, ARG_show, ARG_list, ARG_lst }; - int key; if (*argv) { - key = index_in_substrings(keywords, *argv); - if (key < 0) + smalluint key = index_in_substrings(keywords, *argv); + if (key > 5) bb_error_msg_and_die(bb_msg_invalid_arg, *argv, applet_name); argv++; if (key == ARG_add) -- cgit v1.2.3-55-g6feb From 1b3549875cf8beb236a17a456fc0cab66bfd1d72 Mon Sep 17 00:00:00 2001 From: Bernhard Reutner-Fischer Date: Tue, 25 May 2010 17:22:17 +0200 Subject: ip rule: unify parsing args function old new delta do_iprule 83 134 +51 print_rule 736 726 -10 iprule_list 73 - -73 ------------------------------------------------------------------------------ (add/remove: 0/1 grow/shrink: 1/1 up/down: 51/-83) Total: -32 bytes Signed-off-by: Bernhard Reutner-Fischer --- networking/libiproute/iprule.c | 36 +++++++++++------------------------- 1 file changed, 11 insertions(+), 25 deletions(-) diff --git a/networking/libiproute/iprule.c b/networking/libiproute/iprule.c index 535019d87..835529ec4 100644 --- a/networking/libiproute/iprule.c +++ b/networking/libiproute/iprule.c @@ -69,11 +69,9 @@ static int FAST_FUNC print_rule(const struct sockaddr_nl *who UNUSED_PARAM, else if (r->rtm_family == AF_IPX) host_len = 80; */ - if (tb[RTA_PRIORITY]) - printf("%u:\t", *(unsigned*)RTA_DATA(tb[RTA_PRIORITY])); - else - printf("0:\t"); - + printf("%u:\t", tb[RTA_PRIORITY] ? + *(unsigned*)RTA_DATA(tb[RTA_PRIORITY]) + : 0); printf("from "); if (tb[RTA_SRC]) { if (r->rtm_src_len != host_len) { @@ -310,25 +308,13 @@ int do_iprule(char **argv) { static const char ip_rule_commands[] ALIGN1 = "add\0""delete\0""list\0""show\0"; - int cmd = 2; /* list */ - - if (!*argv) - return iprule_list(argv); - - cmd = index_in_substrings(ip_rule_commands, *argv); - switch (cmd) { - case 0: /* add */ - cmd = RTM_NEWRULE; - break; - case 1: /* delete */ - cmd = RTM_DELRULE; - break; - case 2: /* list */ - case 3: /* show */ - return iprule_list(argv+1); - break; - default: - bb_error_msg_and_die("unknown command %s", *argv); + if (*argv) { + smalluint cmd = index_in_substrings(ip_rule_commands, *argv); + if (cmd > 3) + bb_error_msg_and_die(bb_msg_invalid_arg, *argv, applet_name); + argv++; + if (cmd < 2) + return iprule_modify((cmd == 0) ? RTM_NEWRULE : RTM_DELRULE, argv); } - return iprule_modify(cmd, argv+1); + return iprule_list(argv); } -- cgit v1.2.3-55-g6feb From cc4493a95c877354ee267e29629b72cd9d010262 Mon Sep 17 00:00:00 2001 From: Bernhard Reutner-Fischer Date: Tue, 25 May 2010 17:42:01 +0200 Subject: ip addr: unify parsing args function old new delta do_ipaddr 87 84 -3 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 0/1 up/down: 0/-3) Total: -3 bytes Signed-off-by: Bernhard Reutner-Fischer --- networking/libiproute/ipaddress.c | 20 +++++++------------- 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/networking/libiproute/ipaddress.c b/networking/libiproute/ipaddress.c index 3f360f455..8a5edb968 100644 --- a/networking/libiproute/ipaddress.c +++ b/networking/libiproute/ipaddress.c @@ -773,21 +773,15 @@ int do_ipaddr(char **argv) { static const char commands[] ALIGN1 = "add\0""delete\0""list\0""show\0""lst\0""flush\0"; - - int command_num = 2; /* default command is list */ - + smalluint cmd = 2; if (*argv) { - command_num = index_in_substrings(commands, *argv); - if (command_num < 0 || command_num > 5) - bb_error_msg_and_die("unknown command %s", *argv); + cmd = index_in_substrings(commands, *argv); + if (cmd > 5) + bb_error_msg_and_die(bb_msg_invalid_arg, *argv, applet_name); argv++; + if (cmd <= 1) + return ipaddr_modify((cmd == 0) ? RTM_NEWADDR : RTM_DELADDR, argv); } - if (command_num == 0) /* add */ - return ipaddr_modify(RTM_NEWADDR, argv); - if (command_num == 1) /* delete */ - return ipaddr_modify(RTM_DELADDR, argv); - if (command_num == 5) /* flush */ - return ipaddr_list_or_flush(argv, 1); /* 2 == list, 3 == show, 4 == lst */ - return ipaddr_list_or_flush(argv, 0); + return ipaddr_list_or_flush(argv, cmd == 5); } -- cgit v1.2.3-55-g6feb From c5f30c0df8f0ce5e94ca22a5100496233067708a Mon Sep 17 00:00:00 2001 From: Bernhard Reutner-Fischer Date: Tue, 25 May 2010 18:46:09 +0200 Subject: ip addr: shrink function old new delta ipaddr_list_or_flush 1254 1248 -6 ipaddr_modify 1299 1279 -20 .rodata 135249 135193 -56 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 0/3 up/down: 0/-82) Total: -82 bytes Signed-off-by: Bernhard Reutner-Fischer --- networking/libiproute/ipaddress.c | 177 +++++++++++++++++--------------------- 1 file changed, 78 insertions(+), 99 deletions(-) diff --git a/networking/libiproute/ipaddress.c b/networking/libiproute/ipaddress.c index 8a5edb968..601b34816 100644 --- a/networking/libiproute/ipaddress.c +++ b/networking/libiproute/ipaddress.c @@ -442,16 +442,14 @@ int ipaddr_list_or_flush(char **argv, int flush) } while (*argv) { - const int option_num = index_in_strings(option, *argv); - switch (option_num) { - case 0: /* to */ + const smalluint key = index_in_strings(option, *argv); + if (key == 0) { /* to */ NEXT_ARG(); get_prefix(&G_filter.pfx, *argv, G_filter.family); if (G_filter.family == AF_UNSPEC) { G_filter.family = G_filter.pfx.family; } - break; - case 1: { /* scope */ + } else if (key == 1) { /* scope */ uint32_t scope = 0; NEXT_ARG(); G_filter.scopemask = -1; @@ -463,22 +461,17 @@ int ipaddr_list_or_flush(char **argv, int flush) G_filter.scopemask = 0; } G_filter.scope = scope; - break; - } - case 2: /* up */ + } else if (key == 2) { /* up */ G_filter.up = 1; - break; - case 3: /* label */ + } else if (key == 3) { /* label */ NEXT_ARG(); G_filter.label = *argv; - break; - case 4: /* dev */ + } else { + if (key == 4) /* dev */ NEXT_ARG(); - default: - if (filter_dev) { - duparg2("dev", *argv); - } - filter_dev = *argv; + if (filter_dev) + duparg2("dev", *argv); + filter_dev = *argv; } argv++; } @@ -631,99 +624,85 @@ static int ipaddr_modify(int cmd, char **argv) req.ifa.ifa_family = preferred_family; while (*argv) { - const int option_num = index_in_strings(option, *argv); - switch (option_num) { - case 0: /* peer */ - case 1: /* remote */ - NEXT_ARG(); + const smalluint arg = index_in_strings(option, *argv); + if (arg <= 1) { /* peer, remote */ + NEXT_ARG(); - if (peer_len) { - duparg("peer", *argv); - } - get_prefix(&peer, *argv, req.ifa.ifa_family); - peer_len = peer.bytelen; - if (req.ifa.ifa_family == AF_UNSPEC) { - req.ifa.ifa_family = peer.family; - } - addattr_l(&req.n, sizeof(req), IFA_ADDRESS, &peer.data, peer.bytelen); - req.ifa.ifa_prefixlen = peer.bitlen; - break; - case 2: /* broadcast */ - case 3: /* brd */ - { - inet_prefix addr; - NEXT_ARG(); - if (brd_len) { - duparg("broadcast", *argv); - } - if (LONE_CHAR(*argv, '+')) { - brd_len = -1; - } else if (LONE_DASH(*argv)) { - brd_len = -2; - } else { - get_addr(&addr, *argv, req.ifa.ifa_family); - if (req.ifa.ifa_family == AF_UNSPEC) - req.ifa.ifa_family = addr.family; - addattr_l(&req.n, sizeof(req), IFA_BROADCAST, &addr.data, addr.bytelen); - brd_len = addr.bytelen; - } - break; + if (peer_len) { + duparg("peer", *argv); } - case 4: /* anycast */ - { - inet_prefix addr; - NEXT_ARG(); - if (any_len) { - duparg("anycast", *argv); - } + get_prefix(&peer, *argv, req.ifa.ifa_family); + peer_len = peer.bytelen; + if (req.ifa.ifa_family == AF_UNSPEC) { + req.ifa.ifa_family = peer.family; + } + addattr_l(&req.n, sizeof(req), IFA_ADDRESS, &peer.data, peer.bytelen); + req.ifa.ifa_prefixlen = peer.bitlen; + } else if (arg <= 3) { /* broadcast, brd */ + inet_prefix addr; + NEXT_ARG(); + if (brd_len) { + duparg("broadcast", *argv); + } + if (LONE_CHAR(*argv, '+')) { + brd_len = -1; + } else if (LONE_DASH(*argv)) { + brd_len = -2; + } else { get_addr(&addr, *argv, req.ifa.ifa_family); - if (req.ifa.ifa_family == AF_UNSPEC) { + if (req.ifa.ifa_family == AF_UNSPEC) req.ifa.ifa_family = addr.family; - } - addattr_l(&req.n, sizeof(req), IFA_ANYCAST, &addr.data, addr.bytelen); - any_len = addr.bytelen; - break; + addattr_l(&req.n, sizeof(req), IFA_BROADCAST, &addr.data, addr.bytelen); + brd_len = addr.bytelen; } - case 5: /* scope */ - { - uint32_t scope = 0; - NEXT_ARG(); - if (rtnl_rtscope_a2n(&scope, *argv)) { - invarg(*argv, "scope"); - } - req.ifa.ifa_scope = scope; - scoped = 1; - break; + } else if (arg == 4) { /* anycast */ + inet_prefix addr; + NEXT_ARG(); + if (any_len) { + duparg("anycast", *argv); } - case 6: /* dev */ - NEXT_ARG(); - d = *argv; - break; - case 7: /* label */ - NEXT_ARG(); - l = *argv; - addattr_l(&req.n, sizeof(req), IFA_LABEL, l, strlen(l)+1); - break; - case 8: /* local */ + get_addr(&addr, *argv, req.ifa.ifa_family); + if (req.ifa.ifa_family == AF_UNSPEC) { + req.ifa.ifa_family = addr.family; + } + addattr_l(&req.n, sizeof(req), IFA_ANYCAST, &addr.data, addr.bytelen); + any_len = addr.bytelen; + } else if (arg == 5) { /* scope */ + uint32_t scope = 0; + NEXT_ARG(); + if (rtnl_rtscope_a2n(&scope, *argv)) { + invarg(*argv, "scope"); + } + req.ifa.ifa_scope = scope; + scoped = 1; + } else if (arg == 6) { /* dev */ + NEXT_ARG(); + d = *argv; + } else if (arg == 7) { /* label */ + NEXT_ARG(); + l = *argv; + addattr_l(&req.n, sizeof(req), IFA_LABEL, l, strlen(l)+1); + } else { + if (arg == 8) /* local */ NEXT_ARG(); - default: - if (local_len) { - duparg2("local", *argv); - } - get_prefix(&lcl, *argv, req.ifa.ifa_family); - if (req.ifa.ifa_family == AF_UNSPEC) { - req.ifa.ifa_family = lcl.family; - } - addattr_l(&req.n, sizeof(req), IFA_LOCAL, &lcl.data, lcl.bytelen); - local_len = lcl.bytelen; + if (local_len) { + duparg2("local", *argv); + } + get_prefix(&lcl, *argv, req.ifa.ifa_family); + if (req.ifa.ifa_family == AF_UNSPEC) { + req.ifa.ifa_family = lcl.family; + } + addattr_l(&req.n, sizeof(req), IFA_LOCAL, &lcl.data, lcl.bytelen); + local_len = lcl.bytelen; } argv++; } - if (d == NULL) { - bb_error_msg(bb_msg_requires_arg, "\"dev\""); - return -1; - } + // d cannot be null here, NEXT_ARG() of "dev" ensures that + //if (d == NULL) { + // bb_error_msg(bb_msg_requires_arg, "\"dev\""); + // return -1; + //} if (l && strncmp(d, l, strlen(d)) != 0) { bb_error_msg_and_die("\"dev\" (%s) must match \"label\" (%s)", d, l); } -- cgit v1.2.3-55-g6feb From ccb88a689e0f603f8d94255a7d9cb8128b6e620d Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Thu, 27 May 2010 02:22:54 +0200 Subject: unlzma: add "lzma -d" alias, add -t support, rename lzmacat->lzcat Also coalesce some common strings text data bss dec hex filename 844110 453 6812 851375 cfdaf busybox_old 844061 453 6812 851326 cfd7e busybox_unstripped Signed-off-by: Denys Vlasenko --- archival/Config.in | 8 +++++ archival/bbunzip.c | 27 +++++++++------ archival/libunarchive/decompress_uncompress.c | 2 +- archival/lzop.c | 6 ++-- include/applets.h | 3 +- include/usage.h | 49 ++++++++++++++++----------- 6 files changed, 59 insertions(+), 36 deletions(-) diff --git a/archival/Config.in b/archival/Config.in index deacc2822..428398377 100644 --- a/archival/Config.in +++ b/archival/Config.in @@ -327,6 +327,14 @@ config FEATURE_LZMA_FAST This option reduces decompression time by about 25% at the cost of a 1K bigger binary. +config FEATURE_LZMA_ALIAS + bool "Provide lzma alias which supports only unpacking" + default n + depends on UNLZMA + help + Enable this option if you want commands like "lzma -d" to work. + IOW: you'll get lzma applet, but it will always require -d option. + config UNZIP bool "unzip" default n diff --git a/archival/bbunzip.c b/archival/bbunzip.c index df674bc6c..1e775f425 100644 --- a/archival/bbunzip.c +++ b/archival/bbunzip.c @@ -9,12 +9,12 @@ #include "unarchive.h" enum { - OPT_STDOUT = 0x1, - OPT_FORCE = 0x2, -/* gunzip and bunzip2 only: */ - OPT_VERBOSE = 0x4, - OPT_DECOMPRESS = 0x8, - OPT_TEST = 0x10, + OPT_STDOUT = 1 << 0, + OPT_FORCE = 1 << 1, + /* only some decompressors: */ + OPT_VERBOSE = 1 << 2, + OPT_DECOMPRESS = 1 << 3, + OPT_TEST = 1 << 4, }; static @@ -333,12 +333,17 @@ IF_DESKTOP(long long) int unpack_unlzma(unpack_info_t *info UNUSED_PARAM) int unlzma_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int unlzma_main(int argc UNUSED_PARAM, char **argv) { - getopt32(argv, "cf"); - argv += optind; - /* lzmacat? */ - if (applet_name[4] == 'c') + int opts = getopt32(argv, "cfvdt"); +# if ENABLE_FEATURE_LZMA_ALIAS + /* lzma without -d or -t? */ + if (applet_name[2] == 'm' && !(opts & (OPT_DECOMPRESS|OPT_TEST))) + bb_show_usage(); +# endif + /* lzcat? */ + if (applet_name[2] == 'c') option_mask32 |= OPT_STDOUT; + argv += optind; return bbunpack(argv, make_new_name_unlzma, unpack_unlzma); } @@ -346,7 +351,7 @@ int unlzma_main(int argc UNUSED_PARAM, char **argv) /* - * Uncompress applet for busybox (c) 2002 Glenn McGrath + * Uncompress applet for busybox (c) 2002 Glenn McGrath * * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. */ diff --git a/archival/libunarchive/decompress_uncompress.c b/archival/libunarchive/decompress_uncompress.c index 2877c8981..1ff89ce3c 100644 --- a/archival/libunarchive/decompress_uncompress.c +++ b/archival/libunarchive/decompress_uncompress.c @@ -229,7 +229,7 @@ unpack_Z_stream(int fd_in, int fd_out) ("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("uncompress: corrupt input"); + bb_error_msg("corrupted data"); goto err; } diff --git a/archival/lzop.c b/archival/lzop.c index 0a15c51aa..d6cf6f4f5 100644 --- a/archival/lzop.c +++ b/archival/lzop.c @@ -738,12 +738,12 @@ static NOINLINE smallint lzo_decompress(const header_t *h) bb_error_msg_and_die("this file is a split lzop file"); if (dst_len > MAX_BLOCK_SIZE) - bb_error_msg_and_die("lzop file corrupted"); + bb_error_msg_and_die("corrupted data"); /* read compressed block size */ src_len = read32(); if (src_len <= 0 || src_len > dst_len) - bb_error_msg_and_die("lzop file corrupted"); + bb_error_msg_and_die("corrupted data"); if (dst_len > block_size) { if (b2) { @@ -797,7 +797,7 @@ static NOINLINE smallint lzo_decompress(const header_t *h) r = lzo1x_decompress_safe(b1, src_len, b2, &d, NULL); if (r != 0 /*LZO_E_OK*/ || dst_len != d) { - bb_error_msg_and_die("corrupted compressed data"); + bb_error_msg_and_die("corrupted data"); } dst = b2; } else { diff --git a/include/applets.h b/include/applets.h index 33c3c2555..4d8ba0a6b 100644 --- a/include/applets.h +++ b/include/applets.h @@ -253,7 +253,8 @@ IF_LSMOD(APPLET(lsmod, _BB_DIR_SBIN, _BB_SUID_DROP)) IF_MODPROBE_SMALL(APPLET_ODDNAME(lsmod, modprobe, _BB_DIR_SBIN, _BB_SUID_DROP, modprobe)) IF_LSPCI(APPLET(lspci, _BB_DIR_USR_BIN, _BB_SUID_DROP)) IF_LSUSB(APPLET(lsusb, _BB_DIR_USR_BIN, _BB_SUID_DROP)) -IF_UNLZMA(APPLET_ODDNAME(lzmacat, unlzma, _BB_DIR_USR_BIN, _BB_SUID_DROP, lzmacat)) +IF_UNLZMA(APPLET_ODDNAME(lzcat, unlzma, _BB_DIR_USR_BIN, _BB_SUID_DROP, lzcat)) +IF_FEATURE_LZMA_ALIAS(APPLET_ODDNAME(lzma, unlzma, _BB_DIR_USR_BIN, _BB_SUID_DROP, lzma)) IF_LZOP(APPLET(lzop, _BB_DIR_BIN, _BB_SUID_DROP)) IF_LZOP(APPLET_ODDNAME(lzopcat, lzop, _BB_DIR_USR_BIN, _BB_SUID_DROP, lzopcat)) IF_MAKEDEVS(APPLET(makedevs, _BB_DIR_SBIN, _BB_SUID_DROP)) diff --git a/include/usage.h b/include/usage.h index 8b8bd2c78..3b03228ee 100644 --- a/include/usage.h +++ b/include/usage.h @@ -197,7 +197,7 @@ #define bunzip2_trivial_usage \ "[OPTIONS] [FILE]..." #define bunzip2_full_usage "\n\n" \ - "Uncompress FILEs (or stdin)\n" \ + "Decompress FILEs (or stdin)\n" \ "\nOptions:" \ "\n -c Write to stdout" \ "\n -f Force" \ @@ -207,10 +207,10 @@ #define bzip2_full_usage "\n\n" \ "Compress FILEs (or stdin) with bzip2 algorithm\n" \ "\nOptions:" \ - "\n -c Write to stdout" \ + "\n -1..9 Compression level" \ "\n -d Decompress" \ + "\n -c Write to stdout" \ "\n -f Force" \ - "\n -1..-9 Compression level" \ #define busybox_notes_usage \ "Hello world!\n" @@ -218,13 +218,14 @@ #define lzop_trivial_usage \ "[-cfvd123456789CF] [FILE]..." #define lzop_full_usage "\n\n" \ - " -c Write to stdout" \ + "Options:" \ + "\n -1..9 Compression level" \ + "\n -d Decompress" \ + "\n -c Write to stdout" \ "\n -f Force" \ "\n -v Verbose" \ - "\n -d Decompress" \ "\n -F Don't store or verify checksum" \ "\n -C Also write checksum of compressed block" \ - "\n -1..9 Compression level" \ #define lzopcat_trivial_usage \ "[-vCF] [FILE]..." @@ -235,7 +236,8 @@ #define unlzop_trivial_usage \ "[-cfvCF] [FILE]..." #define unlzop_full_usage "\n\n" \ - " -c Write to stdout" \ + "Options:" \ + "\n -c Write to stdout" \ "\n -f Force" \ "\n -v Verbose" \ "\n -F Don't store or verify checksum" \ @@ -243,20 +245,29 @@ #define bzcat_trivial_usage \ "FILE" #define bzcat_full_usage "\n\n" \ - "Uncompress to stdout" + "Decompress to stdout" #define unlzma_trivial_usage \ "[OPTIONS] [FILE]..." #define unlzma_full_usage "\n\n" \ - "Uncompress FILE (or stdin)\n" \ + "Decompress FILE (or stdin)\n" \ + "\nOptions:" \ + "\n -c Write to stdout" \ + "\n -f Force" \ + +#define lzma_trivial_usage \ + "-d [OPTIONS] [FILE]..." +#define lzma_full_usage "\n\n" \ + "Decompress FILE (or stdin)\n" \ "\nOptions:" \ + "\n -d Decompress" \ "\n -c Write to stdout" \ "\n -f Force" \ -#define lzmacat_trivial_usage \ +#define lzcat_trivial_usage \ "FILE" -#define lzmacat_full_usage "\n\n" \ - "Uncompress to stdout" +#define lzcat_full_usage "\n\n" \ + "Decompress to stdout" #define cal_trivial_usage \ "[-jy] [[MONTH] YEAR]" @@ -267,11 +278,9 @@ "\n -y Display the entire year" \ #define cat_trivial_usage \ - "[-u] [FILE]..." + "[FILE]..." #define cat_full_usage "\n\n" \ - "Concatenate FILEs and print them to stdout\n" \ - "\nOptions:" \ - "\n -u Use unbuffered i/o (ignored)" \ + "Concatenate FILEs and print them to stdout" \ #define cat_example_usage \ "$ cat /proc/uptime\n" \ @@ -1610,7 +1619,7 @@ #define gunzip_trivial_usage \ "[OPTIONS] [FILE]..." #define gunzip_full_usage "\n\n" \ - "Uncompress FILEs (or stdin)\n" \ + "Decompress FILEs (or stdin)\n" \ "\nOptions:" \ "\n -c Write to stdout" \ "\n -f Force" \ @@ -1628,8 +1637,8 @@ #define gzip_full_usage "\n\n" \ "Compress FILEs (or stdin)\n" \ "\nOptions:" \ - "\n -c Write to stdout" \ "\n -d Decompress" \ + "\n -c Write to stdout" \ "\n -f Force" \ #define gzip_example_usage \ @@ -4977,7 +4986,7 @@ #define uncompress_trivial_usage \ "[-cf] [FILE]..." #define uncompress_full_usage "\n\n" \ - "Uncompress .Z file[s]\n" \ + "Decompress .Z file[s]\n" \ "\nOptions:" \ "\n -c Extract to stdout" \ "\n -f Overwrite an existing file" \ @@ -5224,7 +5233,7 @@ #define zcat_trivial_usage \ "FILE" #define zcat_full_usage "\n\n" \ - "Uncompress to stdout" + "Decompress to stdout" #define zcip_trivial_usage \ "[OPTIONS] IFACE SCRIPT" -- cgit v1.2.3-55-g6feb From a3581409c200568769fc00cddb247456324fb43b Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Thu, 27 May 2010 02:30:04 +0200 Subject: trim help text. -29 bytes Signed-off-by: Denys Vlasenko --- include/usage.h | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/include/usage.h b/include/usage.h index 3b03228ee..13f0b73a2 100644 --- a/include/usage.h +++ b/include/usage.h @@ -569,7 +569,7 @@ "\n -L Follow all symlinks" \ "\n -H Follow symlinks on command line" \ "\n -p Preserve file attributes if possible" \ - "\n -f Force overwrite" \ + "\n -f Overwrite" \ "\n -i Prompt before overwrite" \ "\n -l,-s Create (sym)links" \ @@ -4988,8 +4988,8 @@ #define uncompress_full_usage "\n\n" \ "Decompress .Z file[s]\n" \ "\nOptions:" \ - "\n -c Extract to stdout" \ - "\n -f Overwrite an existing file" \ + "\n -c Write to stdout" \ + "\n -f Overwrite" \ #define unexpand_trivial_usage \ "[-fa][-t N] [FILE]..." @@ -5031,8 +5031,8 @@ "Extract files from ZIP archives\n" \ "\nOptions:" \ "\n -l List archive contents (with -q for short form)" \ - "\n -n Never overwrite existing files (default)" \ - "\n -o Overwrite files without prompting" \ + "\n -n Never overwrite files (default)" \ + "\n -o Overwrite" \ "\n -p Send output to stdout" \ "\n -q Quiet" \ "\n -x XLST Exclude these files" \ -- cgit v1.2.3-55-g6feb From 76c936f5221f4cbd5466cde8716d56fb7dce62e1 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Thu, 27 May 2010 02:33:31 +0200 Subject: build system: make gen_build_files.sh messages more inline with the rest Signed-off-by: Denys Vlasenko --- scripts/gen_build_files.sh | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/scripts/gen_build_files.sh b/scripts/gen_build_files.sh index d2db907f3..b3aa132a3 100755 --- a/scripts/gen_build_files.sh +++ b/scripts/gen_build_files.sh @@ -8,10 +8,11 @@ cd -- "$2" || { echo "Syntax: $0 SRCTREE OBJTREE"; exit 1; } srctree="$1" find -type d | while read -r d; do + d="${d#./}" src="$srctree/$d/Kbuild.src" dst="$d/Kbuild" if test -f "$src"; then - echo " CHK $dst" + #echo " CHK $dst" s=`sed -n 's@^//kbuild:@@p' -- "$srctree/$d"/*.c` echo "# DO NOT EDIT. This file is generated from Kbuild.src" >"$dst.$$.tmp" @@ -36,7 +37,7 @@ find -type d | while read -r d; do src="$srctree/$d/Config.src" dst="$d/Config.in" if test -f "$src"; then - echo " CHK $dst" + #echo " CHK $dst" s=`sed -n 's@^//config:@@p' -- "$srctree/$d"/*.c` echo "# DO NOT EDIT. This file is generated from Config.src" >"$dst.$$.tmp" -- cgit v1.2.3-55-g6feb From eb29e91dc69dc3a93af880268f5cbe86a97fdc64 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Thu, 27 May 2010 13:35:04 +0200 Subject: trivial fixes: use uint8_t, not __u8; fix defconfig for fgconsole Signed-off-by: Denys Vlasenko --- networking/libiproute/ipaddress.c | 2 +- scripts/defconfig | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/networking/libiproute/ipaddress.c b/networking/libiproute/ipaddress.c index 601b34816..a603053e1 100644 --- a/networking/libiproute/ipaddress.c +++ b/networking/libiproute/ipaddress.c @@ -169,7 +169,7 @@ static NOINLINE int print_linkinfo(const struct nlmsghdr *n) "UNKNOWN\0""NOTPRESENT\0""DOWN\0""LOWERLAYERDOWN\0" "TESTING\0""DORMANT\0""UP\0"; printf("state %s ", nth_string(operstate_labels, - *(__u8 *)RTA_DATA(tb[IFLA_OPERSTATE]))); + *(uint8_t *)RTA_DATA(tb[IFLA_OPERSTATE]))); } if (G_filter.showqueue) print_queuelen((char*)RTA_DATA(tb[IFLA_IFNAME])); diff --git a/scripts/defconfig b/scripts/defconfig index 8b88f79b3..896571bd9 100644 --- a/scripts/defconfig +++ b/scripts/defconfig @@ -287,7 +287,7 @@ CONFIG_FEATURE_MD5_SHA1_SUM_CHECK=y # Console Utilities # CONFIG_CHVT=y -CONFIG_FGCONSOLE=n +CONFIG_FGCONSOLE=y CONFIG_CLEAR=y CONFIG_DEALLOCVT=y CONFIG_DUMPKMAP=y -- cgit v1.2.3-55-g6feb From 7bdfb7cbf0697f57d3421460558d6b4615ba14ec Mon Sep 17 00:00:00 2001 From: Bernhard Reutner-Fischer Date: Thu, 27 May 2010 15:39:01 +0200 Subject: bbunzip: silence warning about unused variable Signed-off-by: Bernhard Reutner-Fischer --- archival/bbunzip.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/archival/bbunzip.c b/archival/bbunzip.c index 1e775f425..f6bf337a3 100644 --- a/archival/bbunzip.c +++ b/archival/bbunzip.c @@ -333,7 +333,7 @@ IF_DESKTOP(long long) int unpack_unlzma(unpack_info_t *info UNUSED_PARAM) int unlzma_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int unlzma_main(int argc UNUSED_PARAM, char **argv) { - int opts = getopt32(argv, "cfvdt"); + IF_FEATURE_LZMA_ALIAS(int opts =) getopt32(argv, "cfvdt"); # if ENABLE_FEATURE_LZMA_ALIAS /* lzma without -d or -t? */ if (applet_name[2] == 'm' && !(opts & (OPT_DECOMPRESS|OPT_TEST))) -- cgit v1.2.3-55-g6feb From 8bcaa6a4e9f3c88bc86b2064950fcd06d6424230 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sun, 30 May 2010 01:57:52 +0200 Subject: lzop: fix indentation Signed-off-by: Denys Vlasenko --- archival/lzop.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/archival/lzop.c b/archival/lzop.c index d6cf6f4f5..ceace0436 100644 --- a/archival/lzop.c +++ b/archival/lzop.c @@ -475,7 +475,7 @@ lzo_crc32(uint32_t c, const uint8_t* buf, unsigned len) crc = ~c; if (len != 0) do { - crc = G.lzo_crc32_table[((int)crc ^ *buf) & 0xff] ^ (crc >> 8); + crc = G.lzo_crc32_table[(uint8_t)((int)crc ^ *buf)] ^ (crc >> 8); buf += 1; len -= 1; } while (len > 0); -- cgit v1.2.3-55-g6feb From e04c867a214c4b6318bf1efce9e6681750140d2f Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sun, 30 May 2010 03:33:50 +0200 Subject: rename FEATURE_LZMA_ALIAS to just LZMA Signed-off-by: Denys Vlasenko --- archival/Config.in | 2 +- archival/bbunzip.c | 4 ++-- include/applets.h | 2 +- include/usage.h | 16 ++++++++-------- 4 files changed, 12 insertions(+), 12 deletions(-) diff --git a/archival/Config.in b/archival/Config.in index 428398377..028fce32f 100644 --- a/archival/Config.in +++ b/archival/Config.in @@ -327,7 +327,7 @@ config FEATURE_LZMA_FAST This option reduces decompression time by about 25% at the cost of a 1K bigger binary. -config FEATURE_LZMA_ALIAS +config LZMA bool "Provide lzma alias which supports only unpacking" default n depends on UNLZMA diff --git a/archival/bbunzip.c b/archival/bbunzip.c index f6bf337a3..178dc63be 100644 --- a/archival/bbunzip.c +++ b/archival/bbunzip.c @@ -333,8 +333,8 @@ IF_DESKTOP(long long) int unpack_unlzma(unpack_info_t *info UNUSED_PARAM) int unlzma_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int unlzma_main(int argc UNUSED_PARAM, char **argv) { - IF_FEATURE_LZMA_ALIAS(int opts =) getopt32(argv, "cfvdt"); -# if ENABLE_FEATURE_LZMA_ALIAS + IF_LZMA(int opts =) getopt32(argv, "cfvdt"); +# if ENABLE_LZMA /* lzma without -d or -t? */ if (applet_name[2] == 'm' && !(opts & (OPT_DECOMPRESS|OPT_TEST))) bb_show_usage(); diff --git a/include/applets.h b/include/applets.h index 4d8ba0a6b..a171c5449 100644 --- a/include/applets.h +++ b/include/applets.h @@ -254,7 +254,7 @@ IF_MODPROBE_SMALL(APPLET_ODDNAME(lsmod, modprobe, _BB_DIR_SBIN, _BB_SUID_DROP, m IF_LSPCI(APPLET(lspci, _BB_DIR_USR_BIN, _BB_SUID_DROP)) IF_LSUSB(APPLET(lsusb, _BB_DIR_USR_BIN, _BB_SUID_DROP)) IF_UNLZMA(APPLET_ODDNAME(lzcat, unlzma, _BB_DIR_USR_BIN, _BB_SUID_DROP, lzcat)) -IF_FEATURE_LZMA_ALIAS(APPLET_ODDNAME(lzma, unlzma, _BB_DIR_USR_BIN, _BB_SUID_DROP, lzma)) +IF_LZMA(APPLET_ODDNAME(lzma, unlzma, _BB_DIR_USR_BIN, _BB_SUID_DROP, lzma)) IF_LZOP(APPLET(lzop, _BB_DIR_BIN, _BB_SUID_DROP)) IF_LZOP(APPLET_ODDNAME(lzopcat, lzop, _BB_DIR_USR_BIN, _BB_SUID_DROP, lzopcat)) IF_MAKEDEVS(APPLET(makedevs, _BB_DIR_SBIN, _BB_SUID_DROP)) diff --git a/include/usage.h b/include/usage.h index 13f0b73a2..3aa980cdc 100644 --- a/include/usage.h +++ b/include/usage.h @@ -194,14 +194,6 @@ "\n stp BRIDGE [1/yes/on|0/no/off] STP on/off" \ ) \ -#define bunzip2_trivial_usage \ - "[OPTIONS] [FILE]..." -#define bunzip2_full_usage "\n\n" \ - "Decompress FILEs (or stdin)\n" \ - "\nOptions:" \ - "\n -c Write to stdout" \ - "\n -f Force" \ - #define bzip2_trivial_usage \ "[OPTIONS] [FILE]..." #define bzip2_full_usage "\n\n" \ @@ -242,6 +234,14 @@ "\n -v Verbose" \ "\n -F Don't store or verify checksum" \ +#define bunzip2_trivial_usage \ + "[OPTIONS] [FILE]..." +#define bunzip2_full_usage "\n\n" \ + "Decompress FILEs (or stdin)\n" \ + "\nOptions:" \ + "\n -c Write to stdout" \ + "\n -f Force" \ + #define bzcat_trivial_usage \ "FILE" #define bzcat_full_usage "\n\n" \ -- cgit v1.2.3-55-g6feb From 602ce69afb7c825a5aeed16d0bdb5a6a213d1cb1 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sun, 30 May 2010 03:35:18 +0200 Subject: unxz: new applet, complete with xzcat and xz -d aliases function old new delta unpack_xz_stream_stdin - 3953 +3953 lzma_main - 2601 +2601 lzma_len - 516 +516 dec_vli - 165 +165 dict_repeat - 103 +103 lzma_reset - 98 +98 fill_temp - 98 +98 crc32_validate - 93 +93 xz_dec_reset - 77 +77 unxz_main - 77 +77 index_update - 47 +47 xz_crc32 - 40 +40 packed_usage 27044 27060 +16 make_new_name_unxz - 14 +14 applet_names 2240 2254 +14 applet_main 1312 1324 +12 applet_nameofs 656 662 +6 unpack_unxz - 5 +5 send_tree 355 360 +5 applet_install_loc 164 166 +2 ------------------------------------------------------------------------------ (add/remove: 15/0 grow/shrink: 6/0 up/down: 7942/0) Total: 7942 bytes text data bss dec hex filename 844032 453 6812 851297 cfd61 busybox_old 852063 453 6812 859328 d1cc0 busybox_unstripped Signed-off-by: Denys Vlasenko --- archival/Config.in | 22 +- archival/Kbuild | 19 +- archival/bbunzip.c | 33 + archival/libunarchive/Kbuild | 1 + archival/libunarchive/unxz/README | 136 ++++ archival/libunarchive/unxz/xz.h | 212 +++++ archival/libunarchive/unxz/xz_config.h | 119 +++ archival/libunarchive/unxz/xz_dec_bcj.c | 560 ++++++++++++++ archival/libunarchive/unxz/xz_dec_lzma2.c | 1157 ++++++++++++++++++++++++++++ archival/libunarchive/unxz/xz_dec_stream.c | 787 +++++++++++++++++++ archival/libunarchive/unxz/xz_lzma2.h | 204 +++++ archival/libunarchive/unxz/xz_private.h | 120 +++ archival/libunarchive/unxz/xz_stream.h | 46 ++ include/applets.h | 3 + include/unarchive.h | 1 + include/usage.h | 22 + 16 files changed, 3433 insertions(+), 9 deletions(-) create mode 100644 archival/libunarchive/unxz/README create mode 100644 archival/libunarchive/unxz/xz.h create mode 100644 archival/libunarchive/unxz/xz_config.h create mode 100644 archival/libunarchive/unxz/xz_dec_bcj.c create mode 100644 archival/libunarchive/unxz/xz_dec_lzma2.c create mode 100644 archival/libunarchive/unxz/xz_dec_stream.c create mode 100644 archival/libunarchive/unxz/xz_lzma2.h create mode 100644 archival/libunarchive/unxz/xz_private.h create mode 100644 archival/libunarchive/unxz/xz_stream.h diff --git a/archival/Config.in b/archival/Config.in index 028fce32f..4f762e860 100644 --- a/archival/Config.in +++ b/archival/Config.in @@ -5,6 +5,12 @@ menu "Archival Utilities" +config FEATURE_SEAMLESS_XZ + bool "Make tar, rpm, modprobe etc understand .xz data" + default n + help + Make tar, rpm, modprobe etc understand .xz data. + config FEATURE_SEAMLESS_LZMA bool "Make tar, rpm, modprobe etc understand .lzma data" default n @@ -225,7 +231,7 @@ config FEATURE_TAR_CREATE config FEATURE_TAR_AUTODETECT bool "Autodetect compressed tarballs" default n - depends on TAR && (FEATURE_SEAMLESS_Z || FEATURE_SEAMLESS_GZ || FEATURE_SEAMLESS_BZ2 || FEATURE_SEAMLESS_LZMA) + depends on TAR && (FEATURE_SEAMLESS_Z || FEATURE_SEAMLESS_GZ || FEATURE_SEAMLESS_BZ2 || FEATURE_SEAMLESS_LZMA || FEATURE_SEAMLESS_XZ) help With this option tar can automatically detect compressed tarballs. Currently it works only on files (not pipes etc). @@ -335,6 +341,20 @@ config LZMA Enable this option if you want commands like "lzma -d" to work. IOW: you'll get lzma applet, but it will always require -d option. +config UNXZ + bool "unxz" + default n + help + unxz is a unlzma successor. + +config XZ + bool "Provide xz alias which supports only unpacking" + default n + depends on UNXZ + help + Enable this option if you want commands like "xz -d" to work. + IOW: you'll get xz applet, but it will always require -d option. + config UNZIP bool "unzip" default n diff --git a/archival/Kbuild b/archival/Kbuild index 53bd7e21e..3300ea90f 100644 --- a/archival/Kbuild +++ b/archival/Kbuild @@ -8,18 +8,21 @@ libs-y += libunarchive/ lib-y:= lib-$(CONFIG_AR) += ar.o -lib-$(CONFIG_BUNZIP2) += bbunzip.o -lib-$(CONFIG_BZIP2) += bzip2.o bbunzip.o -lib-$(CONFIG_UNLZMA) += bbunzip.o lib-$(CONFIG_CPIO) += cpio.o lib-$(CONFIG_DPKG) += dpkg.o lib-$(CONFIG_DPKG_DEB) += dpkg_deb.o -lib-$(CONFIG_GUNZIP) += bbunzip.o -lib-$(CONFIG_GZIP) += gzip.o bbunzip.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_RPM2CPIO) += rpm2cpio.o lib-$(CONFIG_RPM) += rpm.o lib-$(CONFIG_TAR) += tar.o -lib-$(CONFIG_UNCOMPRESS) += bbunzip.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_GZIP) += gzip.o bbunzip.o +lib-$(CONFIG_BZIP2) += bzip2.o bbunzip.o + +lib-$(CONFIG_UNXZ) += bbunzip.o +lib-$(CONFIG_UNLZMA) += bbunzip.o +lib-$(CONFIG_BUNZIP2) += bbunzip.o +lib-$(CONFIG_GUNZIP) += bbunzip.o +lib-$(CONFIG_UNCOMPRESS) += bbunzip.o diff --git a/archival/bbunzip.c b/archival/bbunzip.c index 178dc63be..824b0027f 100644 --- a/archival/bbunzip.c +++ b/archival/bbunzip.c @@ -387,3 +387,36 @@ int uncompress_main(int argc UNUSED_PARAM, char **argv) } #endif + +#if ENABLE_UNXZ + +static +char* make_new_name_unxz(char *filename) +{ + return make_new_name_generic(filename, "xz"); +} + +static +IF_DESKTOP(long long) int unpack_unxz(unpack_info_t *info UNUSED_PARAM) +{ + return unpack_xz_stream_stdin(); +} + +int unxz_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +int unxz_main(int argc UNUSED_PARAM, char **argv) +{ + int opts = getopt32(argv, "cfvdt"); +# if ENABLE_XZ + /* xz without -d or -t? */ + if (applet_name[2] == '\0' && !(opts & (OPT_DECOMPRESS|OPT_TEST))) + bb_show_usage(); +# endif + /* xzcat? */ + if (applet_name[2] == 'c') + option_mask32 |= OPT_STDOUT; + + argv += optind; + return bbunpack(argv, make_new_name_unxz, unpack_unxz); +} + +#endif diff --git a/archival/libunarchive/Kbuild b/archival/libunarchive/Kbuild index 11d23b25f..ed8e85793 100644 --- a/archival/libunarchive/Kbuild +++ b/archival/libunarchive/Kbuild @@ -49,6 +49,7 @@ lib-$(CONFIG_FEATURE_SEAMLESS_Z) += open_transformer.o decompress_uncompr 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 ifneq ($(lib-y),) diff --git a/archival/libunarchive/unxz/README b/archival/libunarchive/unxz/README new file mode 100644 index 000000000..f79b0a404 --- /dev/null +++ b/archival/libunarchive/unxz/README @@ -0,0 +1,136 @@ + +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 new file mode 100644 index 000000000..82f16ee22 --- /dev/null +++ b/archival/libunarchive/unxz/xz.h @@ -0,0 +1,212 @@ +/* + * 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 + +#ifndef XZ_DEBUG_MSG +# define XZ_DEBUG_MSG(...) ((void)0) +#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_ret - Return codes + * @XZ_OK: Everything is OK so far. More input or more output + * space is required to continue. + * @XZ_STREAM_END: Operation finished successfully. + * @XZ_MEMLIMIT_ERROR: Not enough memory was preallocated at decoder + * initialization time. + * @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_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 + * @dict_max: Maximum size of the LZMA2 dictionary (history buffer) for + * multi-call decoding, or special value of zero to indicate + * single-call decoding mode. + * + * If dict_max > 0, the decoder is initialized to work in multi-call mode. + * dict_max number of 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. + * + * LZMA2 dictionary is always 2^n bytes or 2^n + 2^(n-1) bytes (the latter + * sizes are less common in practice). In the kernel, dictionary sizes of + * 64 KiB, 128 KiB, 256 KiB, 512 KiB, and 1 MiB are probably the only + * reasonable values. + * + * If dict_max == 0, the decoder is initialized to work in single-call mode. + * In single-call mode, 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. It is enough that the + * output buffer is is big enough to hold the actual uncompressed data; it + * can be smaller than the dictionary size stored in the stream headers. + * + * On success, xz_dec_init() returns a pointer to struct xz_dec, which is + * ready to be used with xz_dec_run(). On error, xz_dec_init() returns NULL. + */ +XZ_EXTERN struct xz_dec * XZ_FUNC xz_dec_init(uint32_t dict_max); + +/** + * xz_dec_run() - Run the XZ decoder + * @s: Decoder state allocated using xz_dec_init() + * @b: Input and output buffers + * + * In multi-call mode, this function may return any of the values listed in + * enum xz_ret. + * + * In single-call mode, this function never returns XZ_OK. 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. + * + * NOTE: In single-call mode, the contents of the output buffer are undefined + * also after XZ_BUF_ERROR. This is 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. + */ +#if !defined(__KERNEL__) || defined(XZ_INTERNAL_CRC32) +/* + * This must be called before any other xz_* function to initialize + * the CRC32 lookup table. + */ +#ifndef xz_crc32_init +XZ_EXTERN void XZ_FUNC xz_crc32_init(uint32_t *crc32_table); +#endif + +/* + * 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. + */ +#ifndef xz_crc32 +XZ_EXTERN uint32_t XZ_FUNC xz_crc32(uint32_t *crc32_table, + const uint8_t *buf, size_t size, uint32_t crc); +#endif +#endif +#endif diff --git a/archival/libunarchive/unxz/xz_config.h b/archival/libunarchive/unxz/xz_config.h new file mode 100644 index 000000000..3259815f0 --- /dev/null +++ b/archival/libunarchive/unxz/xz_config.h @@ -0,0 +1,119 @@ +/* + * 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) + +#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, 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. + */ +#define get_le32 get_unaligned_le32 + +#endif diff --git a/archival/libunarchive/unxz/xz_dec_bcj.c b/archival/libunarchive/unxz/xz_dec_bcj.c new file mode 100644 index 000000000..d4b6ef751 --- /dev/null +++ b/archival/libunarchive/unxz/xz_dec_bcj.c @@ -0,0 +1,560 @@ +/* + * 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" + +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 + +#ifdef XZ_DEC_BCJ +/* + * 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; +} +#endif + +#ifdef XZ_DEC_BCJ +/* + * 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 new file mode 100644 index 000000000..890141b7c --- /dev/null +++ b/archival/libunarchive/unxz/xz_dec_lzma2.c @@ -0,0 +1,1157 @@ +/* + * 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 <= allocated + * + * 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; + + /* + * Amount of memory allocated for the dictionary. A special + * value of zero indicates that we are in single-call mode, + * where the output buffer works as the dictionary. + */ + uint32_t allocated; +}; + +/* 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 { + /* + * 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 */ + + /* Types of the most recently seen LZMA symbols */ + enum lzma_state state; + + /* Distances of latest four matches */ + uint32_t rep0; + uint32_t rep1; + uint32_t rep2; + uint32_t rep3; + + /* + * Length of a match. This is updated so that dict_repeat can + * be called again to finish repeating the whole match. + */ + uint32_t len; + + /* 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 xz_dec_lzma2 { + /* LZMA2 */ + struct { + /* 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; + } lzma2; + + /* + * 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; + + struct dictionary dict; + struct rc_dec rc; + struct lzma_dec lzma; +}; + +/************** + * 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 (dict->allocated == 0) { + 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 (dict->allocated != 0) { + 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 (dict->allocated != 0) { + 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 __always_inline 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 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(uint32_t dict_max) +{ + struct xz_dec_lzma2 *s; + + /* Maximum supported dictionary by this implementation is 3 GiB. */ + if (dict_max > ((uint32_t)3 << 30)) + return NULL; + + s = kmalloc(sizeof(*s), GFP_KERNEL); + if (s == NULL) + return NULL; + + if (dict_max > 0) { + s->dict.buf = vmalloc(dict_max); + if (s->dict.buf == NULL) { + kfree(s); + return NULL; + } + } + + s->dict.allocated = dict_max; + + 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) { + XZ_DEBUG_MSG("props:%d", props); + return XZ_OPTIONS_ERROR; + } + + s->dict.size = 2 + (props & 1); + s->dict.size <<= (props >> 1) + 11; + + if (s->dict.allocated > 0 && s->dict.allocated < s->dict.size) { +#ifdef XZ_REALLOC_DICT_BUF + s->dict.buf = XZ_REALLOC_DICT_BUF(s->dict.buf, s->dict.size); + if (!s->dict.buf) + return XZ_MEMLIMIT_ERROR; + s->dict.allocated = s->dict.size; +#else + return XZ_MEMLIMIT_ERROR; +#endif + } + + s->dict.end = s->dict.size; + + 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 (s->dict.allocated > 0) + vfree(s->dict.buf); + + kfree(s); +} diff --git a/archival/libunarchive/unxz/xz_dec_stream.c b/archival/libunarchive/unxz/xz_dec_stream.c new file mode 100644 index 000000000..e10c9413d --- /dev/null +++ b/archival/libunarchive/unxz/xz_dec_stream.c @@ -0,0 +1,787 @@ +/* + * .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; + + /* True if CRC32 is calculated from uncompressed data */ + uint8_t crc_type; + + /* True if we are operating in single-call mode. */ + bool single_call; + + /* + * 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 + + uint32_t crc32_table[256]; +}; + +/* + * 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->crc_type == 0x01) + s->crc32 = xz_crc32(s->crc32_table, + 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; + if (s->crc_type == 0x01) + s->block.hash.unpadded += 4; + if (s->crc_type == 0x04) /* CRC64 */ + s->block.hash.unpadded += 8; + if (s->crc_type == 0x0A) /* SHA-256 */ + s->block.hash.unpadded += 32; + + s->block.hash.uncompressed += s->block.uncompressed; + s->block.hash.crc32 = xz_crc32(s->crc32_table, + (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(s->crc32_table, 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(s->crc32_table, + (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; +} + +/* 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->crc32_table, s->temp.buf + HEADER_MAGIC_SIZE, 2, 0) + != get_le32(s->temp.buf + HEADER_MAGIC_SIZE + 2)) + return XZ_DATA_ERROR; + + /* + * Decode the Stream Flags field. Of integrity checks, we support + * only none (Check ID = 0) and CRC32 (Check ID = 1). + */ + if (s->temp.buf[HEADER_MAGIC_SIZE] != 0 + || (s->temp.buf[HEADER_MAGIC_SIZE + 1] > 1 + && s->temp.buf[HEADER_MAGIC_SIZE + 1] != 0x04 + && s->temp.buf[HEADER_MAGIC_SIZE + 1] != 0x0A + ) + ) { + XZ_DEBUG_MSG("unsupported stream flags %x:%x", + s->temp.buf[HEADER_MAGIC_SIZE], + s->temp.buf[HEADER_MAGIC_SIZE+1]); + return XZ_OPTIONS_ERROR; + } + + s->crc_type = s->temp.buf[HEADER_MAGIC_SIZE + 1]; + + 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->crc32_table, 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->crc_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->crc32_table, 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 + { + XZ_DEBUG_MSG("s->temp.buf[1] & 0x3E/3F != 0"); + 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) { + XZ_DEBUG_MSG("temp.size - 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) { + XZ_DEBUG_MSG("size of properties != 0"); + 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) { + XZ_DEBUG_MSG("filter ID != 0x21"); + return XZ_OPTIONS_ERROR; + } + + /* Size of Properties = 1-byte Filter Properties */ + if (s->temp.buf[s->temp.pos++] != 0x01) { + XZ_DEBUG_MSG("size of properties != 1"); + 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) { + XZ_DEBUG_MSG("padding is not zero-filled"); + 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; + + ret = dec_stream_header(s); + if (ret != XZ_OK) + return ret; + + s->sequence = SEQ_BLOCK_START; + + 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->crc_type == 0x01) { + ret = crc32_validate(s, b); + if (ret != XZ_STREAM_END) + return ret; + } + + 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 (s->single_call) + xz_dec_reset(s); + + in_start = b->in_pos; + out_start = b->out_pos; + ret = dec_main(s, b); + + if (s->single_call) { + 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(uint32_t dict_max) +{ + struct xz_dec *s = kmalloc(sizeof(*s), GFP_KERNEL); + if (s == NULL) + return NULL; + + s->single_call = dict_max == 0; + +#ifdef XZ_DEC_BCJ + s->bcj = xz_dec_bcj_create(s->single_call); + if (s->bcj == NULL) + goto error_bcj; +#endif + + s->lzma2 = xz_dec_lzma2_create(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 new file mode 100644 index 000000000..47f21afbc --- /dev/null +++ b/archival/libunarchive/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/libunarchive/unxz/xz_private.h b/archival/libunarchive/unxz/xz_private.h new file mode 100644 index 000000000..9da8d7061 --- /dev/null +++ b/archival/libunarchive/unxz/xz_private.h @@ -0,0 +1,120 @@ +/* + * 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 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( + 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); +#endif + +/* Free the memory allocated for the BCJ filters. */ +#define xz_dec_bcj_end(s) kfree(s) + +#endif diff --git a/archival/libunarchive/unxz/xz_stream.h b/archival/libunarchive/unxz/xz_stream.h new file mode 100644 index 000000000..efbe75ae3 --- /dev/null +++ b/archival/libunarchive/unxz/xz_stream.h @@ -0,0 +1,46 @@ +/* + * 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__) && !defined(XZ_INTERNAL_CRC32) +# include +# undef crc32 +# define xz_crc32(crc32_table, 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) + +#endif diff --git a/include/applets.h b/include/applets.h index a171c5449..d8a706b44 100644 --- a/include/applets.h +++ b/include/applets.h @@ -419,6 +419,7 @@ IF_UNCOMPRESS(APPLET(uncompress, _BB_DIR_BIN, _BB_SUID_DROP)) IF_UNEXPAND(APPLET_ODDNAME(unexpand, expand, _BB_DIR_USR_BIN, _BB_SUID_DROP, unexpand)) IF_UNIQ(APPLET(uniq, _BB_DIR_USR_BIN, _BB_SUID_DROP)) IF_UNIX2DOS(APPLET_ODDNAME(unix2dos, dos2unix, _BB_DIR_USR_BIN, _BB_SUID_DROP, unix2dos)) +IF_UNXZ(APPLET(unxz, _BB_DIR_USR_BIN, _BB_SUID_DROP)) IF_UNLZMA(APPLET(unlzma, _BB_DIR_USR_BIN, _BB_SUID_DROP)) IF_LZOP(APPLET_ODDNAME(unlzop, lzop, _BB_DIR_USR_BIN, _BB_SUID_DROP, unlzop)) IF_UNZIP(APPLET(unzip, _BB_DIR_USR_BIN, _BB_SUID_DROP)) @@ -439,6 +440,8 @@ IF_WHICH(APPLET(which, _BB_DIR_USR_BIN, _BB_SUID_DROP)) IF_WHO(APPLET(who, _BB_DIR_USR_BIN, _BB_SUID_DROP)) IF_WHOAMI(APPLET_NOFORK(whoami, whoami, _BB_DIR_USR_BIN, _BB_SUID_DROP, whoami)) IF_XARGS(APPLET_NOEXEC(xargs, xargs, _BB_DIR_USR_BIN, _BB_SUID_DROP, xargs)) +IF_UNXZ(APPLET_ODDNAME(xzcat, unxz, _BB_DIR_USR_BIN, _BB_SUID_DROP, xzcat)) +IF_XZ(APPLET_ODDNAME(xz, unxz, _BB_DIR_USR_BIN, _BB_SUID_DROP, xz)) IF_YES(APPLET_NOFORK(yes, yes, _BB_DIR_USR_BIN, _BB_SUID_DROP, yes)) IF_GUNZIP(APPLET_ODDNAME(zcat, gunzip, _BB_DIR_BIN, _BB_SUID_DROP, zcat)) IF_ZCIP(APPLET(zcip, _BB_DIR_SBIN, _BB_SUID_DROP)) diff --git a/include/unarchive.h b/include/unarchive.h index a834816ba..14cd98e24 100644 --- a/include/unarchive.h +++ b/include/unarchive.h @@ -143,6 +143,7 @@ typedef struct inflate_unzip_result { } 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; +IF_DESKTOP(long long) int unpack_xz_stream_stdin(void) 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 */ diff --git a/include/usage.h b/include/usage.h index 3aa980cdc..a9c4c4294 100644 --- a/include/usage.h +++ b/include/usage.h @@ -269,6 +269,28 @@ #define lzcat_full_usage "\n\n" \ "Decompress to stdout" +#define unxz_trivial_usage \ + "[OPTIONS] [FILE]..." +#define unxz_full_usage "\n\n" \ + "Decompress FILE (or stdin)\n" \ + "\nOptions:" \ + "\n -c Write to stdout" \ + "\n -f Force" \ + +#define xz_trivial_usage \ + "-d [OPTIONS] [FILE]..." +#define xz_full_usage "\n\n" \ + "Decompress FILE (or stdin)\n" \ + "\nOptions:" \ + "\n -d Decompress" \ + "\n -c Write to stdout" \ + "\n -f Force" \ + +#define xzcat_trivial_usage \ + "FILE" +#define xzcat_full_usage "\n\n" \ + "Decompress to stdout" + #define cal_trivial_usage \ "[-jy] [[MONTH] YEAR]" #define cal_full_usage "\n\n" \ -- cgit v1.2.3-55-g6feb From d93f19e443a94a2c107a43a7c0d5415b1c8163da Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sun, 30 May 2010 03:46:54 +0200 Subject: reorder parts of bbunzip.c, no code changes Signed-off-by: Denys Vlasenko --- archival/bbunzip.c | 123 +++++++++++++++++++++-------------------------------- 1 file changed, 48 insertions(+), 75 deletions(-) diff --git a/archival/bbunzip.c b/archival/bbunzip.c index 824b0027f..1c8d0ab55 100644 --- a/archival/bbunzip.c +++ b/archival/bbunzip.c @@ -4,7 +4,6 @@ * * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. */ - #include "libbb.h" #include "unarchive.h" @@ -141,8 +140,7 @@ int FAST_FUNC bbunpack(char **argv, return exitcode; } -#if ENABLE_BUNZIP2 || ENABLE_UNLZMA || ENABLE_UNCOMPRESS - +#if ENABLE_UNCOMPRESS || ENABLE_BUNZIP2 || ENABLE_UNLZMA || ENABLE_UNXZ static char* make_new_name_generic(char *filename, const char *expected_ext) { @@ -155,42 +153,40 @@ char* make_new_name_generic(char *filename, const char *expected_ext) *extension = '\0'; return filename; } - #endif /* - * Modified for busybox by Glenn McGrath - * Added support output to stdout by Thomas Lundquist + * Uncompress applet for busybox (c) 2002 Glenn McGrath * - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. */ - -#if ENABLE_BUNZIP2 - +#if ENABLE_UNCOMPRESS static -char* make_new_name_bunzip2(char *filename) +char* make_new_name_uncompress(char *filename) { - return make_new_name_generic(filename, "bz2"); + return make_new_name_generic(filename, "Z"); } - static -IF_DESKTOP(long long) int unpack_bunzip2(unpack_info_t *info UNUSED_PARAM) +IF_DESKTOP(long long) int unpack_uncompress(unpack_info_t *info UNUSED_PARAM) { - return unpack_bz2_stream_prime(STDIN_FILENO, STDOUT_FILENO); -} + IF_DESKTOP(long long) int status = -1; -int bunzip2_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; -int bunzip2_main(int argc UNUSED_PARAM, char **argv) + if ((xread_char(STDIN_FILENO) != 0x1f) || (xread_char(STDIN_FILENO) != 0x9d)) { + bb_error_msg("invalid magic"); + } else { + status = unpack_Z_stream(STDIN_FILENO, STDOUT_FILENO); + } + return status; +} +int uncompress_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +int uncompress_main(int argc UNUSED_PARAM, char **argv) { - getopt32(argv, "cfvdt"); + getopt32(argv, "cf"); argv += optind; - if (applet_name[2] == 'c') - option_mask32 |= OPT_STDOUT; - return bbunpack(argv, make_new_name_bunzip2, unpack_bunzip2); + return bbunpack(argv, make_new_name_uncompress, unpack_uncompress); } - #endif @@ -221,9 +217,7 @@ int bunzip2_main(int argc UNUSED_PARAM, char **argv) * See the license_msg below and the file COPYING for the software license. * See the file algorithm.doc for the compression algorithms and file formats. */ - #if ENABLE_GUNZIP - static char* make_new_name_gunzip(char *filename) { @@ -249,7 +243,6 @@ char* make_new_name_gunzip(char *filename) } return filename; } - static IF_DESKTOP(long long) int unpack_gunzip(unpack_info_t *info) { @@ -277,7 +270,6 @@ IF_DESKTOP(long long) int unpack_gunzip(unpack_info_t *info) } return status; } - /* * Linux kernel build uses gzip -d -n. We accept and ignore it. * Man page says: @@ -291,7 +283,6 @@ IF_DESKTOP(long long) int unpack_gunzip(unpack_info_t *info) * gzip: always save the original file name and time stamp (this is the default) * gunzip: restore the original file name and time stamp if present. */ - int gunzip_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int gunzip_main(int argc UNUSED_PARAM, char **argv) { @@ -303,7 +294,36 @@ int gunzip_main(int argc UNUSED_PARAM, char **argv) return bbunpack(argv, make_new_name_gunzip, unpack_gunzip); } +#endif + + +/* + * Modified for busybox by Glenn McGrath + * Added support output to stdout by Thomas Lundquist + * + * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + */ +#if ENABLE_BUNZIP2 +static +char* make_new_name_bunzip2(char *filename) +{ + return make_new_name_generic(filename, "bz2"); +} +static +IF_DESKTOP(long long) int unpack_bunzip2(unpack_info_t *info UNUSED_PARAM) +{ + return unpack_bz2_stream_prime(STDIN_FILENO, STDOUT_FILENO); +} +int bunzip2_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +int bunzip2_main(int argc UNUSED_PARAM, char **argv) +{ + getopt32(argv, "cfvdt"); + argv += optind; + if (applet_name[2] == 'c') /* bzcat */ + option_mask32 |= OPT_STDOUT; + return bbunpack(argv, make_new_name_bunzip2, unpack_bunzip2); +} #endif @@ -315,21 +335,17 @@ int gunzip_main(int argc UNUSED_PARAM, char **argv) * * Licensed under GPL v2, see file LICENSE in this tarball for details. */ - #if ENABLE_UNLZMA - static char* make_new_name_unlzma(char *filename) { return make_new_name_generic(filename, "lzma"); } - static IF_DESKTOP(long long) int unpack_unlzma(unpack_info_t *info UNUSED_PARAM) { return unpack_lzma_stream(STDIN_FILENO, STDOUT_FILENO); } - int unlzma_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int unlzma_main(int argc UNUSED_PARAM, char **argv) { @@ -346,62 +362,20 @@ int unlzma_main(int argc UNUSED_PARAM, char **argv) argv += optind; return bbunpack(argv, make_new_name_unlzma, unpack_unlzma); } - #endif -/* - * Uncompress applet for busybox (c) 2002 Glenn McGrath - * - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. - */ - -#if ENABLE_UNCOMPRESS - -static -char* make_new_name_uncompress(char *filename) -{ - return make_new_name_generic(filename, "Z"); -} - -static -IF_DESKTOP(long long) int unpack_uncompress(unpack_info_t *info UNUSED_PARAM) -{ - IF_DESKTOP(long long) int status = -1; - - if ((xread_char(STDIN_FILENO) != 0x1f) || (xread_char(STDIN_FILENO) != 0x9d)) { - bb_error_msg("invalid magic"); - } else { - status = unpack_Z_stream(STDIN_FILENO, STDOUT_FILENO); - } - return status; -} - -int uncompress_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; -int uncompress_main(int argc UNUSED_PARAM, char **argv) -{ - getopt32(argv, "cf"); - argv += optind; - - return bbunpack(argv, make_new_name_uncompress, unpack_uncompress); -} - -#endif - #if ENABLE_UNXZ - static char* make_new_name_unxz(char *filename) { return make_new_name_generic(filename, "xz"); } - static IF_DESKTOP(long long) int unpack_unxz(unpack_info_t *info UNUSED_PARAM) { return unpack_xz_stream_stdin(); } - int unxz_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int unxz_main(int argc UNUSED_PARAM, char **argv) { @@ -418,5 +392,4 @@ int unxz_main(int argc UNUSED_PARAM, char **argv) argv += optind; return bbunpack(argv, make_new_name_unxz, unpack_unxz); } - #endif -- cgit v1.2.3-55-g6feb From fb6c76cb6eaade5693b7e99c33846c902689f1db Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sun, 30 May 2010 03:47:40 +0200 Subject: forgotten "git add"... Signed-off-by: Denys Vlasenko --- archival/libunarchive/decompress_unxz.c | 116 ++++++++++++++++++++++++++++++++ 1 file changed, 116 insertions(+) create mode 100644 archival/libunarchive/decompress_unxz.c diff --git a/archival/libunarchive/decompress_unxz.c b/archival/libunarchive/decompress_unxz.c new file mode 100644 index 000000000..0ae789160 --- /dev/null +++ b/archival/libunarchive/decompress_unxz.c @@ -0,0 +1,116 @@ +/* + * This file uses XZ Embedded library code which is written + * by Lasse Collin + * and Igor Pavlov + * + * See README file in unxzbz/ directory for more information. + * + * This file is: + * Copyright (C) 2010 Denys Vlasenko + * Licensed under GPLv2, see file LICENSE in this tarball for details. + */ +#include "libbb.h" +#include "unarchive.h" + +//#define XZ_DEBUG_MSG(...) bb_error_msg(__VA_ARGS) +#define XZ_REALLOC_DICT_BUF(ptr, size) xrealloc(ptr, size) +#define XZ_FUNC FAST_FUNC +#define XZ_EXTERN static + +#define xz_crc32_init(table) crc32_filltable(table, /*endian:*/ 0) +static uint32_t xz_crc32(uint32_t *crc32_table, + const uint8_t *buf, size_t size, uint32_t crc) +{ + crc = ~crc; + + while (size != 0) { + crc = crc32_table[*buf++ ^ (crc & 0xFF)] ^ (crc >> 8); + --size; + } + + return ~crc; +} +#define xz_crc32 xz_crc32 + +#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.h" +#include "unxz/xz_config.h" + +#include "unxz/xz_dec_bcj.c" +#include "unxz/xz_dec_lzma2.c" +#include "unxz/xz_dec_stream.c" +#include "unxz/xz_lzma2.h" +#include "unxz/xz_private.h" +#include "unxz/xz_stream.h" + +IF_DESKTOP(long long) int FAST_FUNC +unpack_xz_stream_stdin(void) +{ + struct xz_buf iobuf; + struct xz_dec *state; + unsigned char *membuf; + IF_DESKTOP(long long) int total = 0; + enum { + IN_SIZE = 4 * 1024, + OUT_SIZE = 60 * 1024, + }; + + membuf = xmalloc(IN_SIZE + OUT_SIZE); + memset(&iobuf, 0, sizeof(iobuf)); + iobuf.in = membuf; + iobuf.out = membuf + IN_SIZE; + iobuf.out_size = OUT_SIZE; + + state = xz_dec_init(64*1024); /* initial dict of 64k */ + xz_crc32_init(state->crc32_table); + + while (1) { + enum xz_ret r; + int insz, rd, outpos; + + iobuf.in_size -= iobuf.in_pos; + insz = iobuf.in_size; + if (insz) + memmove(membuf, membuf + iobuf.in_pos, insz); + iobuf.in_pos = 0; + rd = IN_SIZE - insz; + if (rd) { + rd = safe_read(STDIN_FILENO, membuf + insz, rd); + if (rd < 0) { + bb_error_msg("read error"); + total = -1; + break; + } + iobuf.in_size = insz + rd; + } +// 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(" Date: Sun, 30 May 2010 04:18:13 +0200 Subject: *: teach tar et. al. to understand .xz by heart function old new delta unpack_xz_stream - 4126 +4126 setup_unzip_on_fd 80 150 +70 open_zipped 113 131 +18 unpack_unxz 5 12 +7 send_tree 360 353 -7 unpack_xz_stream_stdin 3953 - -3953 ------------------------------------------------------------------------------ (add/remove: 1/1 grow/shrink: 3/1 up/down: 4221/-3960) Total: 261 bytes Signed-off-by: Denys Vlasenko --- archival/bbunzip.c | 2 +- archival/libunarchive/decompress_unxz.c | 9 +++--- include/libbb.h | 2 +- include/unarchive.h | 5 ++-- libbb/read.c | 53 ++++++++++++++++++++++----------- 5 files changed, 46 insertions(+), 25 deletions(-) diff --git a/archival/bbunzip.c b/archival/bbunzip.c index 1c8d0ab55..86adb6e24 100644 --- a/archival/bbunzip.c +++ b/archival/bbunzip.c @@ -374,7 +374,7 @@ char* make_new_name_unxz(char *filename) static IF_DESKTOP(long long) int unpack_unxz(unpack_info_t *info UNUSED_PARAM) { - return unpack_xz_stream_stdin(); + return unpack_xz_stream(STDIN_FILENO, STDOUT_FILENO); } int unxz_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int unxz_main(int argc UNUSED_PARAM, char **argv) diff --git a/archival/libunarchive/decompress_unxz.c b/archival/libunarchive/decompress_unxz.c index 0ae789160..9edc2461a 100644 --- a/archival/libunarchive/decompress_unxz.c +++ b/archival/libunarchive/decompress_unxz.c @@ -3,7 +3,7 @@ * by Lasse Collin * and Igor Pavlov * - * See README file in unxzbz/ directory for more information. + * See README file in unxz/ directory for more information. * * This file is: * Copyright (C) 2010 Denys Vlasenko @@ -48,7 +48,7 @@ static uint32_t xz_crc32(uint32_t *crc32_table, #include "unxz/xz_stream.h" IF_DESKTOP(long long) int FAST_FUNC -unpack_xz_stream_stdin(void) +unpack_xz_stream(int src_fd, int dst_fd) { struct xz_buf iobuf; struct xz_dec *state; @@ -79,7 +79,7 @@ unpack_xz_stream_stdin(void) iobuf.in_pos = 0; rd = IN_SIZE - insz; if (rd) { - rd = safe_read(STDIN_FILENO, membuf + insz, rd); + rd = safe_read(src_fd, membuf + insz, rd); if (rd < 0) { bb_error_msg("read error"); total = -1; @@ -94,10 +94,11 @@ unpack_xz_stream_stdin(void) // iobuf.in_pos, iobuf.in_size, iobuf.out_pos, iobuf.out_size, r); outpos = iobuf.out_pos; if (outpos) { - xwrite(STDOUT_FILENO, iobuf.out, outpos); + xwrite(dst_fd, iobuf.out, outpos); IF_DESKTOP(total += outpos;) } if (r == XZ_STREAM_END + /* this happens even with well-formed files: */ || (r == XZ_BUF_ERROR && insz == 0 && outpos == 0) ) { break; diff --git a/include/libbb.h b/include/libbb.h index 2f67c7f72..326179b97 100644 --- a/include/libbb.h +++ b/include/libbb.h @@ -656,7 +656,7 @@ extern void *xmalloc_open_read_close(const char *filename, size_t *maxsz_p) FAST || ENABLE_FEATURE_SEAMLESS_BZ2 \ || ENABLE_FEATURE_SEAMLESS_GZ \ /* || ENABLE_FEATURE_SEAMLESS_Z */ -extern int setup_unzip_on_fd(int fd /*, int fail_if_not_detected*/) FAST_FUNC; +extern void setup_unzip_on_fd(int fd /*, int fail_if_not_detected*/) FAST_FUNC; #else # define setup_unzip_on_fd(...) ((void)0) #endif diff --git a/include/unarchive.h b/include/unarchive.h index 14cd98e24..783a943b6 100644 --- a/include/unarchive.h +++ b/include/unarchive.h @@ -143,14 +143,15 @@ typedef struct inflate_unzip_result { } 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; -IF_DESKTOP(long long) int unpack_xz_stream_stdin(void) FAST_FUNC; +/* xz unpacker takes .xz stream from offset 0 */ +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 fd_in, int fd_out) 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; diff --git a/libbb/read.c b/libbb/read.c index f3af144f0..cd6bbeb13 100644 --- a/libbb/read.c +++ b/libbb/read.c @@ -305,22 +305,26 @@ void* FAST_FUNC xmalloc_xopen_read_close(const char *filename, size_t *maxsz_p) return buf; } +/* Used by e.g. rpm which gives us a fd without filename, + * thus we can't guess the format from filename's extension. + */ #if ZIPPED -int FAST_FUNC setup_unzip_on_fd(int fd /*, int fail_if_not_detected*/) +void FAST_FUNC setup_unzip_on_fd(int fd /*, int fail_if_not_detected*/) { const int fail_if_not_detected = 1; - unsigned char magic[2]; -#if BB_MMU + unsigned char magic[8]; + int offset = -2; +# if BB_MMU IF_DESKTOP(long long) int FAST_FUNC (*xformer)(int src_fd, int dst_fd); enum { xformer_prog = 0 }; -#else +# else enum { xformer = 0 }; const char *xformer_prog; -#endif +# endif /* .gz and .bz2 both have 2-byte signature, and their * unpack_XXX_stream wants this header skipped. */ - xread(fd, &magic, 2); + xread(fd, magic, 2); if (ENABLE_FEATURE_SEAMLESS_GZ && magic[0] == 0x1f && magic[1] == 0x8b ) { @@ -341,28 +345,41 @@ int FAST_FUNC setup_unzip_on_fd(int fd /*, int fail_if_not_detected*/) # endif goto found_magic; } -// TODO: xz format support. rpm adopted it, "rpm -i FILE.rpm" badly needs this. -// Signature: 0xFD, '7', 'z', 'X', 'Z', 0x00 -// More info at: http://tukaani.org/xz/xz-file-format.txt + if (ENABLE_FEATURE_SEAMLESS_XZ + && magic[0] == 0xfd && magic[1] == '7' + ) { + /* .xz signature: 0xfd, '7', 'z', 'X', 'Z', 0x00 */ + /* More info at: http://tukaani.org/xz/xz-file-format.txt */ + offset = -6; + xread(fd, magic + 2, 4); + if (strcmp((char*)magic + 2, "zXZ") == 0) { +# if BB_MMU + xformer = unpack_xz_stream; +# else + xformer_prog = "unxz"; +# endif + xlseek(fd, offset, SEEK_CUR); + goto found_magic; + } + } /* No known magic seen */ if (fail_if_not_detected) bb_error_msg_and_die("no gzip" IF_FEATURE_SEAMLESS_BZ2("/bzip2") + IF_FEATURE_SEAMLESS_XZ("/xz") " magic"); - xlseek(fd, -2, SEEK_CUR); - return fd; + xlseek(fd, offset, SEEK_CUR); + return; found_magic: # if !BB_MMU /* NOMMU version of open_transformer execs * an external unzipper that wants * file position at the start of the file */ - xlseek(fd, -2, SEEK_CUR); + xlseek(fd, offset, SEEK_CUR); # endif open_transformer(fd, xformer, xformer_prog); - - return fd; } #endif /* ZIPPED */ @@ -380,12 +397,14 @@ int FAST_FUNC open_zipped(const char *fname) sfx = strrchr(fname, '.'); if (sfx) { - if (ENABLE_FEATURE_SEAMLESS_LZMA && strcmp(sfx, ".lzma") == 0) + sfx++; + if (ENABLE_FEATURE_SEAMLESS_LZMA && strcmp(sfx, "lzma") == 0) /* .lzma has no header/signature, just trust it */ open_transformer(fd, unpack_lzma_stream, "unlzma"); else - if ((ENABLE_FEATURE_SEAMLESS_GZ && strcmp(sfx, ".gz") == 0) - || (ENABLE_FEATURE_SEAMLESS_BZ2 && strcmp(sfx, ".bz2") == 0) + if ((ENABLE_FEATURE_SEAMLESS_GZ && strcmp(sfx, "gz") == 0) + || (ENABLE_FEATURE_SEAMLESS_BZ2 && strcmp(sfx, "bz2") == 0) + || (ENABLE_FEATURE_SEAMLESS_XZ && strcmp(sfx, "xz") == 0) ) { setup_unzip_on_fd(fd /*, fail_if_not_detected: 1*/); } -- cgit v1.2.3-55-g6feb From acaaca839abada0d0718375ba03dcaeddda15d9e Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sun, 30 May 2010 04:50:21 +0200 Subject: unxz: remove debugging. no code changes Signed-off-by: Denys Vlasenko --- archival/libunarchive/decompress_unxz.c | 1 - archival/libunarchive/unxz/xz.h | 4 ---- archival/libunarchive/unxz/xz_dec_lzma2.c | 4 +--- archival/libunarchive/unxz/xz_dec_stream.c | 35 +++++++++--------------------- 4 files changed, 11 insertions(+), 33 deletions(-) diff --git a/archival/libunarchive/decompress_unxz.c b/archival/libunarchive/decompress_unxz.c index 9edc2461a..924a52513 100644 --- a/archival/libunarchive/decompress_unxz.c +++ b/archival/libunarchive/decompress_unxz.c @@ -12,7 +12,6 @@ #include "libbb.h" #include "unarchive.h" -//#define XZ_DEBUG_MSG(...) bb_error_msg(__VA_ARGS) #define XZ_REALLOC_DICT_BUF(ptr, size) xrealloc(ptr, size) #define XZ_FUNC FAST_FUNC #define XZ_EXTERN static diff --git a/archival/libunarchive/unxz/xz.h b/archival/libunarchive/unxz/xz.h index 82f16ee22..dbb9ba92d 100644 --- a/archival/libunarchive/unxz/xz.h +++ b/archival/libunarchive/unxz/xz.h @@ -19,10 +19,6 @@ # include #endif -#ifndef XZ_DEBUG_MSG -# define XZ_DEBUG_MSG(...) ((void)0) -#endif - /* In Linux, this is used to make extern functions static when needed. */ #ifndef XZ_EXTERN # define XZ_EXTERN extern diff --git a/archival/libunarchive/unxz/xz_dec_lzma2.c b/archival/libunarchive/unxz/xz_dec_lzma2.c index 890141b7c..c22dc5ba5 100644 --- a/archival/libunarchive/unxz/xz_dec_lzma2.c +++ b/archival/libunarchive/unxz/xz_dec_lzma2.c @@ -1117,10 +1117,8 @@ 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) { - XZ_DEBUG_MSG("props:%d", props); + if (props > 39) return XZ_OPTIONS_ERROR; - } s->dict.size = 2 + (props & 1); s->dict.size <<= (props >> 1) + 11; diff --git a/archival/libunarchive/unxz/xz_dec_stream.c b/archival/libunarchive/unxz/xz_dec_stream.c index e10c9413d..121c3b53a 100644 --- a/archival/libunarchive/unxz/xz_dec_stream.c +++ b/archival/libunarchive/unxz/xz_dec_stream.c @@ -365,16 +365,14 @@ static enum xz_ret XZ_FUNC dec_stream_header(struct xz_dec *s) /* * Decode the Stream Flags field. Of integrity checks, we support * only none (Check ID = 0) and CRC32 (Check ID = 1). + * We also accept CRC64 and SHA-256, but they will not be verified. */ if (s->temp.buf[HEADER_MAGIC_SIZE] != 0 - || (s->temp.buf[HEADER_MAGIC_SIZE + 1] > 1 - && s->temp.buf[HEADER_MAGIC_SIZE + 1] != 0x04 - && s->temp.buf[HEADER_MAGIC_SIZE + 1] != 0x0A - ) + || (s->temp.buf[HEADER_MAGIC_SIZE + 1] > 1 + && s->temp.buf[HEADER_MAGIC_SIZE + 1] != 0x04 /* CRC64 */ + && s->temp.buf[HEADER_MAGIC_SIZE + 1] != 0x0A /* SHA-256 */ + ) ) { - XZ_DEBUG_MSG("unsupported stream flags %x:%x", - s->temp.buf[HEADER_MAGIC_SIZE], - s->temp.buf[HEADER_MAGIC_SIZE+1]); return XZ_OPTIONS_ERROR; } @@ -435,10 +433,7 @@ static enum xz_ret XZ_FUNC dec_block_header(struct xz_dec *s) #else if (s->temp.buf[1] & 0x3F) #endif - { - XZ_DEBUG_MSG("s->temp.buf[1] & 0x3E/3F != 0"); return XZ_OPTIONS_ERROR; - } /* Compressed Size */ if (s->temp.buf[1] & 0x40) { @@ -466,10 +461,8 @@ static enum xz_ret XZ_FUNC dec_block_header(struct xz_dec *s) /* 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) { - XZ_DEBUG_MSG("temp.size - temp.pos < 2"); + 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) @@ -479,10 +472,8 @@ static enum xz_ret XZ_FUNC dec_block_header(struct xz_dec *s) * We don't support custom start offset, * so Size of Properties must be zero. */ - if (s->temp.buf[s->temp.pos++] != 0x00) { - XZ_DEBUG_MSG("size of properties != 0"); + if (s->temp.buf[s->temp.pos++] != 0x00) return XZ_OPTIONS_ERROR; - } } #endif @@ -491,16 +482,12 @@ static enum xz_ret XZ_FUNC dec_block_header(struct xz_dec *s) return XZ_DATA_ERROR; /* Filter ID = LZMA2 */ - if (s->temp.buf[s->temp.pos++] != 0x21) { - XZ_DEBUG_MSG("filter ID != 0x21"); + 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) { - XZ_DEBUG_MSG("size of properties != 1"); + 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) @@ -512,10 +499,8 @@ static enum xz_ret XZ_FUNC dec_block_header(struct xz_dec *s) /* The rest must be Header Padding. */ while (s->temp.pos < s->temp.size) - if (s->temp.buf[s->temp.pos++] != 0x00) { - XZ_DEBUG_MSG("padding is not zero-filled"); + if (s->temp.buf[s->temp.pos++] != 0x00) return XZ_OPTIONS_ERROR; - } s->temp.pos = 0; s->block.compressed = 0; -- cgit v1.2.3-55-g6feb From c88c1a01904b5791dfd1ca5342c805a9f392e17f Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sun, 30 May 2010 05:10:16 +0200 Subject: rpm2cpio: teach it to understand xz format Signed-off-by: Denys Vlasenko --- archival/rpm2cpio.c | 35 ++++++++++++++++++++++++----------- 1 file changed, 24 insertions(+), 11 deletions(-) diff --git a/archival/rpm2cpio.c b/archival/rpm2cpio.c index 4ed5b023b..598ec8670 100644 --- a/archival/rpm2cpio.c +++ b/archival/rpm2cpio.c @@ -68,22 +68,35 @@ int rpm2cpio_main(int argc UNUSED_PARAM, char **argv) #else /* BLOAT */ { - unsigned char magic[2]; + unsigned char magic[8]; IF_DESKTOP(long long) int FAST_FUNC (*unpack)(int src_fd, int dst_fd); xread(rpm_fd, &magic, 2); - unpack = unpack_gz_stream; - if (magic[0] != 0x1f || magic[1] != 0x8b) { - if (!ENABLE_FEATURE_SEAMLESS_BZ2 - || magic[0] != 'B' || magic[1] != 'Z' - ) { - bb_error_msg_and_die("invalid gzip" - IF_FEATURE_SEAMLESS_BZ2("/bzip2") - " magic"); - } + if (magic[0] == 0x1f && magic[1] == 0x8b) { + unpack = unpack_gz_stream; + } else + if (ENABLE_FEATURE_SEAMLESS_BZ2 + && magic[0] == 'B' && magic[1] == 'Z' + ) { unpack = unpack_bz2_stream; + } else + if (ENABLE_FEATURE_SEAMLESS_XZ + && magic[0] == 0xfd && magic[1] == '7' + ) { + /* .xz signature: 0xfd, '7', 'z', 'X', 'Z', 0x00 */ + /* More info at: http://tukaani.org/xz/xz-file-format.txt */ + xread(rpm_fd, magic + 2, 4); + if (strcmp((char*)magic + 2, "zXZ") != 0) + goto no_magic; + xlseek(rpm_fd, -6, SEEK_CUR); + unpack = unpack_xz_stream; + } else { + no_magic: + bb_error_msg_and_die("no gzip" + IF_FEATURE_SEAMLESS_BZ2("/bzip2") + IF_FEATURE_SEAMLESS_XZ("/xz") + " magic"); } - if (unpack(rpm_fd, STDOUT_FILENO) < 0) bb_error_msg_and_die("error unpacking"); } -- cgit v1.2.3-55-g6feb From b7d19cc400f14ccd64a1fedebe14022fe115029a Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sun, 30 May 2010 23:41:23 +0200 Subject: dhcp: readability cleanups and small code shrink function old new delta udhcp_run_script 654 617 -37 Signed-off-by: Denys Vlasenko --- networking/udhcp/common.c | 4 ++-- networking/udhcp/common.h | 14 ++++++++++++-- networking/udhcp/dhcpc.c | 39 +++++++++++++++++++++------------------ networking/udhcp/packet.c | 46 +++++++++++++++++++--------------------------- 4 files changed, 54 insertions(+), 49 deletions(-) diff --git a/networking/udhcp/common.c b/networking/udhcp/common.c index 7cda34a18..90a07ed09 100644 --- a/networking/udhcp/common.c +++ b/networking/udhcp/common.c @@ -176,7 +176,7 @@ unsigned FAST_FUNC udhcp_option_idx(const char *name) } } -/* get an option with bounds checking (warning, result is not aligned). */ +/* Get an option with bounds checking (warning, result is not aligned) */ uint8_t* FAST_FUNC udhcp_get_option(struct dhcp_packet *packet, int code) { uint8_t *optionptr; @@ -240,7 +240,7 @@ uint8_t* FAST_FUNC udhcp_get_option(struct dhcp_packet *packet, int code) return NULL; } -/* return the position of the 'end' option (no bounds checking) */ +/* Return the position of the 'end' option (no bounds checking) */ int FAST_FUNC udhcp_end_option(uint8_t *optionptr) { int i = 0; diff --git a/networking/udhcp/common.h b/networking/udhcp/common.h index c9dd0bb25..75b787a80 100644 --- a/networking/udhcp/common.h +++ b/networking/udhcp/common.h @@ -57,10 +57,20 @@ struct ip_udp_dhcp_packet { struct dhcp_packet data; } PACKED; +struct udp_dhcp_packet { + struct udphdr udp; + struct dhcp_packet data; +} PACKED; + +enum { + IP_UPD_DHCP_SIZE = sizeof(struct ip_udp_dhcp_packet) - CONFIG_UDHCPC_SLACK_FOR_BUGGY_SERVERS, + UPD_DHCP_SIZE = sizeof(struct udp_dhcp_packet) - CONFIG_UDHCPC_SLACK_FOR_BUGGY_SERVERS, + DHCP_SIZE = sizeof(struct dhcp_packet) - CONFIG_UDHCPC_SLACK_FOR_BUGGY_SERVERS, +}; + /* Let's see whether compiler understood us right */ struct BUG_bad_sizeof_struct_ip_udp_dhcp_packet { - char BUG_bad_sizeof_struct_ip_udp_dhcp_packet - [(sizeof(struct ip_udp_dhcp_packet) != 576 + CONFIG_UDHCPC_SLACK_FOR_BUGGY_SERVERS) ? -1 : 1]; + char c[IP_UPD_DHCP_SIZE == 576 ? 1 : -1]; }; diff --git a/networking/udhcp/dhcpc.c b/networking/udhcp/dhcpc.c index 24ff82d2f..c2b21c695 100644 --- a/networking/udhcp/dhcpc.c +++ b/networking/udhcp/dhcpc.c @@ -229,37 +229,41 @@ static NOINLINE char *xmalloc_optname_optval(uint8_t *option, const struct dhcp_ /* put all the parameters into the environment */ static char **fill_envp(struct dhcp_packet *packet) { - int num_options = 0; + int envc; int i; char **envp, **curr; const char *opt_name; uint8_t *temp; - uint8_t over = 0; - + uint8_t overload = 0; + + /* We need 6 elements for: + * "interface=IFACE" + * "ip=N.N.N.N" from packet->yiaddr + * "siaddr=IP" from packet->siaddr_nip (unless 0) + * "boot_file=FILE" from packet->file (unless overloaded) + * "sname=SERVER_HOSTNAME" from packet->sname (unless overloaded) + * terminating NULL + */ + envc = 6; + /* +1 element for each option, +2 for subnet option: */ if (packet) { for (i = 0; dhcp_optflags[i].code; i++) { if (udhcp_get_option(packet, dhcp_optflags[i].code)) { - num_options++; if (dhcp_optflags[i].code == DHCP_SUBNET) - num_options++; /* for mton */ + envc++; /* for mton */ + envc++; } } - if (packet->siaddr_nip) - num_options++; temp = udhcp_get_option(packet, DHCP_OPTION_OVERLOAD); if (temp) - over = *temp; - if (!(over & FILE_FIELD) && packet->file[0]) - num_options++; - if (!(over & SNAME_FIELD) && packet->sname[0]) - num_options++; + overload = *temp; } + curr = envp = xzalloc(sizeof(char *) * envc); - curr = envp = xzalloc(sizeof(char *) * (num_options + 3)); *curr = xasprintf("interface=%s", client_config.interface); putenv(*curr++); - if (packet == NULL) + if (!packet) return envp; *curr = xmalloc(sizeof("ip=255.255.255.255")); @@ -274,9 +278,8 @@ static char **fill_envp(struct dhcp_packet *packet) goto next; *curr = xmalloc_optname_optval(temp, &dhcp_optflags[i], opt_name); putenv(*curr++); - - /* Fill in a subnet bits option for things like /24 */ if (dhcp_optflags[i].code == DHCP_SUBNET) { + /* Subnet option: make things like "$ip/$mask" possible */ uint32_t subnet; move_from_unaligned32(subnet, temp); *curr = xasprintf("mask=%d", mton(subnet)); @@ -291,12 +294,12 @@ static char **fill_envp(struct dhcp_packet *packet) sprint_nip(*curr, "siaddr=", (uint8_t *) &packet->siaddr_nip); putenv(*curr++); } - if (!(over & FILE_FIELD) && packet->file[0]) { + if (!(overload & FILE_FIELD) && packet->file[0]) { /* watch out for invalid packets */ *curr = xasprintf("boot_file=%."DHCP_PKT_FILE_LEN_STR"s", packet->file); putenv(*curr++); } - if (!(over & SNAME_FIELD) && packet->sname[0]) { + if (!(overload & SNAME_FIELD) && packet->sname[0]) { /* watch out for invalid packets */ *curr = xasprintf("sname=%."DHCP_PKT_SNAME_LEN_STR"s", packet->sname); putenv(*curr++); diff --git a/networking/udhcp/packet.c b/networking/udhcp/packet.c index 1bfe12041..c01fb7d7c 100644 --- a/networking/udhcp/packet.c +++ b/networking/udhcp/packet.c @@ -167,44 +167,40 @@ uint16_t FAST_FUNC udhcp_checksum(void *addr, int count) /* Construct a ip/udp header for a packet, send packet */ int FAST_FUNC udhcp_send_raw_packet(struct dhcp_packet *dhcp_pkt, - uint32_t source_ip, int source_port, - uint32_t dest_ip, int dest_port, const uint8_t *dest_arp, + uint32_t source_nip, int source_port, + uint32_t dest_nip, int dest_port, const uint8_t *dest_arp, int ifindex) { - struct sockaddr_ll dest; + struct sockaddr_ll dest_sll; struct ip_udp_dhcp_packet packet; int fd; int result = -1; const char *msg; - enum { - IP_UPD_DHCP_SIZE = sizeof(struct ip_udp_dhcp_packet) - CONFIG_UDHCPC_SLACK_FOR_BUGGY_SERVERS, - UPD_DHCP_SIZE = IP_UPD_DHCP_SIZE - offsetof(struct ip_udp_dhcp_packet, udp), - }; - fd = socket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_IP)); if (fd < 0) { msg = "socket(%s)"; goto ret_msg; } - memset(&dest, 0, sizeof(dest)); - memset(&packet, 0, sizeof(packet)); + memset(&dest_sll, 0, sizeof(dest_sll)); + memset(&packet, 0, offsetof(struct ip_udp_dhcp_packet, data)); packet.data = *dhcp_pkt; /* struct copy */ - dest.sll_family = AF_PACKET; - dest.sll_protocol = htons(ETH_P_IP); - dest.sll_ifindex = ifindex; - dest.sll_halen = 6; - memcpy(dest.sll_addr, dest_arp, 6); - if (bind(fd, (struct sockaddr *)&dest, sizeof(dest)) < 0) { + dest_sll.sll_family = AF_PACKET; + dest_sll.sll_protocol = htons(ETH_P_IP); + dest_sll.sll_ifindex = ifindex; + dest_sll.sll_halen = 6; + memcpy(dest_sll.sll_addr, dest_arp, 6); + + if (bind(fd, (struct sockaddr *)&dest_sll, sizeof(dest_sll)) < 0) { msg = "bind(%s)"; goto ret_close; } packet.ip.protocol = IPPROTO_UDP; - packet.ip.saddr = source_ip; - packet.ip.daddr = dest_ip; + packet.ip.saddr = source_nip; + packet.ip.daddr = dest_nip; packet.udp.source = htons(source_port); packet.udp.dest = htons(dest_port); /* size, excluding IP header: */ @@ -225,7 +221,7 @@ int FAST_FUNC udhcp_send_raw_packet(struct dhcp_packet *dhcp_pkt, */ udhcp_dump_packet(dhcp_pkt); result = sendto(fd, &packet, IP_UPD_DHCP_SIZE, 0, - (struct sockaddr *) &dest, sizeof(dest)); + (struct sockaddr *) &dest_sll, sizeof(dest_sll)); msg = "sendto"; ret_close: close(fd); @@ -239,18 +235,14 @@ int FAST_FUNC udhcp_send_raw_packet(struct dhcp_packet *dhcp_pkt, /* Let the kernel do all the work for packet generation */ int FAST_FUNC udhcp_send_kernel_packet(struct dhcp_packet *dhcp_pkt, - uint32_t source_ip, int source_port, - uint32_t dest_ip, int dest_port) + uint32_t source_nip, int source_port, + uint32_t dest_nip, int dest_port) { struct sockaddr_in client; int fd; int result = -1; const char *msg; - enum { - DHCP_SIZE = sizeof(struct dhcp_packet) - CONFIG_UDHCPC_SLACK_FOR_BUGGY_SERVERS, - }; - fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP); if (fd < 0) { msg = "socket(%s)"; @@ -261,7 +253,7 @@ int FAST_FUNC udhcp_send_kernel_packet(struct dhcp_packet *dhcp_pkt, memset(&client, 0, sizeof(client)); client.sin_family = AF_INET; client.sin_port = htons(source_port); - client.sin_addr.s_addr = source_ip; + client.sin_addr.s_addr = source_nip; if (bind(fd, (struct sockaddr *)&client, sizeof(client)) == -1) { msg = "bind(%s)"; goto ret_close; @@ -270,7 +262,7 @@ int FAST_FUNC udhcp_send_kernel_packet(struct dhcp_packet *dhcp_pkt, memset(&client, 0, sizeof(client)); client.sin_family = AF_INET; client.sin_port = htons(dest_port); - client.sin_addr.s_addr = dest_ip; + client.sin_addr.s_addr = dest_nip; if (connect(fd, (struct sockaddr *)&client, sizeof(client)) == -1) { msg = "connect"; goto ret_close; -- cgit v1.2.3-55-g6feb From e58c6e2e13030bea91f7cd41a62229b0f5927d51 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sun, 30 May 2010 23:43:35 +0200 Subject: dhcp: indicate IP network order in prototypes too Signed-off-by: Denys Vlasenko --- networking/udhcp/common.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/networking/udhcp/common.h b/networking/udhcp/common.h index 75b787a80..ce81d1807 100644 --- a/networking/udhcp/common.h +++ b/networking/udhcp/common.h @@ -280,13 +280,13 @@ void udhcp_init_header(struct dhcp_packet *packet, char type) FAST_FUNC; int udhcp_recv_kernel_packet(struct dhcp_packet *packet, int fd) FAST_FUNC; int udhcp_send_raw_packet(struct dhcp_packet *dhcp_pkt, - uint32_t source_ip, int source_port, - uint32_t dest_ip, int dest_port, const uint8_t *dest_arp, + uint32_t source_nip, int source_port, + uint32_t dest_nip, int dest_port, const uint8_t *dest_arp, int ifindex) FAST_FUNC; int udhcp_send_kernel_packet(struct dhcp_packet *dhcp_pkt, - uint32_t source_ip, int source_port, - uint32_t dest_ip, int dest_port) FAST_FUNC; + uint32_t source_nip, int source_port, + uint32_t dest_nip, int dest_port) FAST_FUNC; void udhcp_sp_setup(void) FAST_FUNC; int udhcp_sp_fd_set(fd_set *rfds, int extra_fd) FAST_FUNC; -- cgit v1.2.3-55-g6feb From b8b72f02f01017d0f9584666fa572221f2b58613 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Mon, 31 May 2010 00:45:09 +0200 Subject: dhcp: truncate packets instead of padding them to 574 bytes. closes bug 1849 function old new delta udhcp_send_raw_packet 411 456 +45 udhcp_send_kernel_packet 259 271 +12 Signed-off-by: Denys Vlasenko --- networking/udhcp/packet.c | 32 ++++++++++++++++++++------------ 1 file changed, 20 insertions(+), 12 deletions(-) diff --git a/networking/udhcp/packet.c b/networking/udhcp/packet.c index c01fb7d7c..4badc9cbc 100644 --- a/networking/udhcp/packet.c +++ b/networking/udhcp/packet.c @@ -173,6 +173,7 @@ int FAST_FUNC udhcp_send_raw_packet(struct dhcp_packet *dhcp_pkt, { struct sockaddr_ll dest_sll; struct ip_udp_dhcp_packet packet; + unsigned padding; int fd; int result = -1; const char *msg; @@ -198,34 +199,40 @@ int FAST_FUNC udhcp_send_raw_packet(struct dhcp_packet *dhcp_pkt, goto ret_close; } + /* We were sending full-sized DHCP packets (zero padded), + * but some badly configured servers were seen dropping them. + * Apparently they drop all DHCP packets >576 *ethernet* octets big, + * whereas they may only drop packets >576 *IP* octets big + * (which for typical Ethernet II means 590 octets: 6+6+2 + 576). + * + * In order to work with those buggy servers, + * we truncate packets after end option byte. + */ + padding = DHCP_OPTIONS_BUFSIZE - 1 - udhcp_end_option(packet.data.options); + packet.ip.protocol = IPPROTO_UDP; packet.ip.saddr = source_nip; packet.ip.daddr = dest_nip; packet.udp.source = htons(source_port); packet.udp.dest = htons(dest_port); /* size, excluding IP header: */ - packet.udp.len = htons(UPD_DHCP_SIZE); + packet.udp.len = htons(UPD_DHCP_SIZE - padding); /* for UDP checksumming, ip.len is set to UDP packet len */ packet.ip.tot_len = packet.udp.len; - packet.udp.check = udhcp_checksum(&packet, IP_UPD_DHCP_SIZE); + packet.udp.check = udhcp_checksum(&packet, IP_UPD_DHCP_SIZE - padding); /* but for sending, it is set to IP packet len */ - packet.ip.tot_len = htons(IP_UPD_DHCP_SIZE); + packet.ip.tot_len = htons(IP_UPD_DHCP_SIZE - padding); packet.ip.ihl = sizeof(packet.ip) >> 2; packet.ip.version = IPVERSION; packet.ip.ttl = IPDEFTTL; packet.ip.check = udhcp_checksum(&packet.ip, sizeof(packet.ip)); - /* Currently we send full-sized DHCP packets (zero padded). - * If you need to change this: last byte of the packet is - * packet.data.options[udhcp_end_option(packet.data.options)] - */ udhcp_dump_packet(dhcp_pkt); - result = sendto(fd, &packet, IP_UPD_DHCP_SIZE, 0, + result = sendto(fd, &packet, IP_UPD_DHCP_SIZE - padding, /*flags:*/ 0, (struct sockaddr *) &dest_sll, sizeof(dest_sll)); msg = "sendto"; ret_close: close(fd); - /* FIXME: and if result >= 0 but != IP_UPD_DHCP_SIZE? */ if (result < 0) { ret_msg: bb_perror_msg(msg, "PACKET"); @@ -239,6 +246,7 @@ int FAST_FUNC udhcp_send_kernel_packet(struct dhcp_packet *dhcp_pkt, uint32_t dest_nip, int dest_port) { struct sockaddr_in client; + unsigned padding; int fd; int result = -1; const char *msg; @@ -268,13 +276,13 @@ int FAST_FUNC udhcp_send_kernel_packet(struct dhcp_packet *dhcp_pkt, goto ret_close; } - /* Currently we send full-sized DHCP packets (see above) */ udhcp_dump_packet(dhcp_pkt); - result = safe_write(fd, dhcp_pkt, DHCP_SIZE); + + padding = DHCP_OPTIONS_BUFSIZE - 1 - udhcp_end_option(dhcp_pkt->options); + result = safe_write(fd, dhcp_pkt, DHCP_SIZE - padding); msg = "write"; ret_close: close(fd); - /* FIXME: and if result >= 0 but != DHCP_SIZE? */ if (result < 0) { ret_msg: bb_perror_msg(msg, "UDP"); -- cgit v1.2.3-55-g6feb From 39a04f71ca8ccf81de2cdbd538df519cf34ef2e6 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Mon, 31 May 2010 14:18:57 +0200 Subject: archival/*: shrink by reusing sufficiently similar functions function old new delta append_ext - 16 +16 unxz_main 77 83 +6 unlzma_main 77 83 +6 uncompress_main 42 48 +6 gzip_main 184 190 +6 bzip2_main 114 120 +6 bunzip2_main 61 67 +6 bbunpack 469 475 +6 send_tree 355 360 +5 lzop_main 89 92 +3 gunzip_main 61 64 +3 make_new_name_lzop 84 82 -2 make_new_name_gunzip 114 112 -2 make_new_name_unxz 14 - -14 make_new_name_unlzma 14 - -14 make_new_name_uncompress 14 - -14 make_new_name_bunzip2 14 - -14 make_new_name_gzip 17 - -17 make_new_name_bzip2 17 - -17 ------------------------------------------------------------------------------ (add/remove: 1/6 grow/shrink: 10/2 up/down: 69/-94) Total: -25 bytes Signed-off-by: Denys Vlasenko --- archival/bbunzip.c | 56 ++++++++++++++++++++--------------------------------- archival/bzip2.c | 10 ++-------- archival/gzip.c | 12 +++--------- archival/lzop.c | 6 +++--- include/unarchive.h | 7 +++++-- 5 files changed, 34 insertions(+), 57 deletions(-) diff --git a/archival/bbunzip.c b/archival/bbunzip.c index 86adb6e24..08db2752c 100644 --- a/archival/bbunzip.c +++ b/archival/bbunzip.c @@ -27,9 +27,15 @@ int open_to_or_warn(int to_fd, const char *filename, int flags, int mode) return 0; } +char* FAST_FUNC append_ext(char *filename, const char *expected_ext) +{ + return xasprintf("%s.%s", filename, expected_ext); +} + int FAST_FUNC bbunpack(char **argv, - char* (*make_new_name)(char *filename), - IF_DESKTOP(long long) int (*unpacker)(unpack_info_t *info) + 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 ) { struct stat stat_buf; @@ -68,7 +74,7 @@ int FAST_FUNC bbunpack(char **argv, /* Open dst if we are going to unpack to file */ if (filename) { - new_name = make_new_name(filename); + new_name = make_new_name(filename, expected_ext); if (!new_name) { bb_error_msg("%s: unknown suffix - ignored", filename); goto err; @@ -142,7 +148,7 @@ int FAST_FUNC bbunpack(char **argv, #if ENABLE_UNCOMPRESS || ENABLE_BUNZIP2 || ENABLE_UNLZMA || ENABLE_UNXZ static -char* make_new_name_generic(char *filename, const char *expected_ext) +char* FAST_FUNC make_new_name_generic(char *filename, const char *expected_ext) { char *extension = strrchr(filename, '.'); if (!extension || strcmp(extension + 1, expected_ext) != 0) { @@ -163,12 +169,7 @@ char* make_new_name_generic(char *filename, const char *expected_ext) */ #if ENABLE_UNCOMPRESS static -char* make_new_name_uncompress(char *filename) -{ - return make_new_name_generic(filename, "Z"); -} -static -IF_DESKTOP(long long) int unpack_uncompress(unpack_info_t *info UNUSED_PARAM) +IF_DESKTOP(long long) int FAST_FUNC unpack_uncompress(unpack_info_t *info UNUSED_PARAM) { IF_DESKTOP(long long) int status = -1; @@ -185,7 +186,7 @@ int uncompress_main(int argc UNUSED_PARAM, char **argv) getopt32(argv, "cf"); argv += optind; - return bbunpack(argv, make_new_name_uncompress, unpack_uncompress); + return bbunpack(argv, unpack_uncompress, make_new_name_generic, "Z"); } #endif @@ -219,7 +220,7 @@ int uncompress_main(int argc UNUSED_PARAM, char **argv) */ #if ENABLE_GUNZIP static -char* make_new_name_gunzip(char *filename) +char* FAST_FUNC make_new_name_gunzip(char *filename, const char *expected_ext UNUSED_PARAM) { char *extension = strrchr(filename, '.'); @@ -244,7 +245,7 @@ char* make_new_name_gunzip(char *filename) return filename; } static -IF_DESKTOP(long long) int unpack_gunzip(unpack_info_t *info) +IF_DESKTOP(long long) int FAST_FUNC unpack_gunzip(unpack_info_t *info) { IF_DESKTOP(long long) int status = -1; @@ -292,7 +293,7 @@ int gunzip_main(int argc UNUSED_PARAM, char **argv) if (applet_name[1] == 'c') option_mask32 |= OPT_STDOUT; - return bbunpack(argv, make_new_name_gunzip, unpack_gunzip); + return bbunpack(argv, unpack_gunzip, make_new_name_gunzip, /*unused:*/ NULL); } #endif @@ -305,12 +306,7 @@ int gunzip_main(int argc UNUSED_PARAM, char **argv) */ #if ENABLE_BUNZIP2 static -char* make_new_name_bunzip2(char *filename) -{ - return make_new_name_generic(filename, "bz2"); -} -static -IF_DESKTOP(long long) int unpack_bunzip2(unpack_info_t *info UNUSED_PARAM) +IF_DESKTOP(long long) int FAST_FUNC unpack_bunzip2(unpack_info_t *info UNUSED_PARAM) { return unpack_bz2_stream_prime(STDIN_FILENO, STDOUT_FILENO); } @@ -322,7 +318,7 @@ int bunzip2_main(int argc UNUSED_PARAM, char **argv) if (applet_name[2] == 'c') /* bzcat */ option_mask32 |= OPT_STDOUT; - return bbunpack(argv, make_new_name_bunzip2, unpack_bunzip2); + return bbunpack(argv, unpack_bunzip2, make_new_name_generic, "bz2"); } #endif @@ -337,12 +333,7 @@ int bunzip2_main(int argc UNUSED_PARAM, char **argv) */ #if ENABLE_UNLZMA static -char* make_new_name_unlzma(char *filename) -{ - return make_new_name_generic(filename, "lzma"); -} -static -IF_DESKTOP(long long) int unpack_unlzma(unpack_info_t *info UNUSED_PARAM) +IF_DESKTOP(long long) int FAST_FUNC unpack_unlzma(unpack_info_t *info UNUSED_PARAM) { return unpack_lzma_stream(STDIN_FILENO, STDOUT_FILENO); } @@ -360,19 +351,14 @@ int unlzma_main(int argc UNUSED_PARAM, char **argv) option_mask32 |= OPT_STDOUT; argv += optind; - return bbunpack(argv, make_new_name_unlzma, unpack_unlzma); + return bbunpack(argv, unpack_unlzma, make_new_name_generic, "lzma"); } #endif #if ENABLE_UNXZ static -char* make_new_name_unxz(char *filename) -{ - return make_new_name_generic(filename, "xz"); -} -static -IF_DESKTOP(long long) int unpack_unxz(unpack_info_t *info UNUSED_PARAM) +IF_DESKTOP(long long) int FAST_FUNC unpack_unxz(unpack_info_t *info UNUSED_PARAM) { return unpack_xz_stream(STDIN_FILENO, STDOUT_FILENO); } @@ -390,6 +376,6 @@ int unxz_main(int argc UNUSED_PARAM, char **argv) option_mask32 |= OPT_STDOUT; argv += optind; - return bbunpack(argv, make_new_name_unxz, unpack_unxz); + return bbunpack(argv, unpack_unxz, make_new_name_generic, "xz"); } #endif diff --git a/archival/bzip2.c b/archival/bzip2.c index bbaf56669..f1c84d681 100644 --- a/archival/bzip2.c +++ b/archival/bzip2.c @@ -102,7 +102,7 @@ IF_DESKTOP(long long) int bz_write(bz_stream *strm, void* rbuf, ssize_t rlen, vo } static -IF_DESKTOP(long long) int compressStream(unpack_info_t *info UNUSED_PARAM) +IF_DESKTOP(long long) int FAST_FUNC compressStream(unpack_info_t *info UNUSED_PARAM) { IF_DESKTOP(long long) int total; ssize_t count; @@ -135,12 +135,6 @@ IF_DESKTOP(long long) int compressStream(unpack_info_t *info UNUSED_PARAM) return total; } -static -char* make_new_name_bzip2(char *filename) -{ - return xasprintf("%s.bz2", filename); -} - int bzip2_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int bzip2_main(int argc UNUSED_PARAM, char **argv) { @@ -181,5 +175,5 @@ int bzip2_main(int argc UNUSED_PARAM, char **argv) argv += optind; option_mask32 &= 0x7; /* ignore all except -cfv */ - return bbunpack(argv, make_new_name_bzip2, compressStream); + return bbunpack(argv, compressStream, append_ext, "bz2"); } diff --git a/archival/gzip.c b/archival/gzip.c index a327d5435..5cc553a80 100644 --- a/archival/gzip.c +++ b/archival/gzip.c @@ -1998,13 +1998,7 @@ static void zip(ulg time_stamp) /* ======================================================================== */ static -char* make_new_name_gzip(char *filename) -{ - return xasprintf("%s.gz", filename); -} - -static -IF_DESKTOP(long long) int pack_gzip(unpack_info_t *info UNUSED_PARAM) +IF_DESKTOP(long long) int FAST_FUNC pack_gzip(unpack_info_t *info UNUSED_PARAM) { struct stat s; @@ -2063,7 +2057,7 @@ static const char gzip_longopts[] ALIGN1 = #endif /* - * Linux kernel build uses gzip -d -n. We accept and ignore it. + * Linux kernel build uses gzip -d -n. We accept and ignore -n. * Man page says: * -n --no-name * gzip: do not save the original file name and time stamp. @@ -2113,5 +2107,5 @@ int gzip_main(int argc UNUSED_PARAM, char **argv) /* Initialise the CRC32 table */ G1.crc_32_tab = crc32_filltable(NULL, 0); - return bbunpack(argv, make_new_name_gzip, pack_gzip); + return bbunpack(argv, pack_gzip, append_ext, "gz"); } diff --git a/archival/lzop.c b/archival/lzop.c index ceace0436..ab4d34c88 100644 --- a/archival/lzop.c +++ b/archival/lzop.c @@ -1042,7 +1042,7 @@ static smallint do_lzo_decompress(void) return lzo_decompress(&header); } -static char* make_new_name_lzop(char *filename) +static char* FAST_FUNC make_new_name_lzop(char *filename, const char *expected_ext UNUSED_PARAM) { if (option_mask32 & OPT_DECOMPRESS) { char *extension = strrchr(filename, '.'); @@ -1054,7 +1054,7 @@ static char* make_new_name_lzop(char *filename) return xasprintf("%s.lzo", filename); } -static IF_DESKTOP(long long) int pack_lzop(unpack_info_t *info UNUSED_PARAM) +static IF_DESKTOP(long long) int FAST_FUNC pack_lzop(unpack_info_t *info UNUSED_PARAM) { if (option_mask32 & OPT_DECOMPRESS) return do_lzo_decompress(); @@ -1074,5 +1074,5 @@ int lzop_main(int argc UNUSED_PARAM, char **argv) option_mask32 |= OPT_DECOMPRESS; G.lzo_crc32_table = crc32_filltable(NULL, 0); - return bbunpack(argv, make_new_name_lzop, pack_lzop); + return bbunpack(argv, pack_lzop, make_new_name_lzop, /*unused:*/ NULL); } diff --git a/include/unarchive.h b/include/unarchive.h index 783a943b6..aa7ecec55 100644 --- a/include/unarchive.h +++ b/include/unarchive.h @@ -155,9 +155,12 @@ 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, - char* (*make_new_name)(char *filename), - IF_DESKTOP(long long) int (*unpacker)(unpack_info_t *info)) FAST_FUNC; + 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, -- cgit v1.2.3-55-g6feb From 11bcf4b22449d08b61617183c1951db98457653a Mon Sep 17 00:00:00 2001 From: Tomas Heinrich Date: Tue, 1 Jun 2010 08:33:18 +0200 Subject: lineedit: fix column display for wide and combining chars in TAB completion function old new delta unicode_strwidth - 20 +20 read_line_input 4945 4953 +8 unicode_strlen 31 - -31 ------------------------------------------------------------------------------ (add/remove: 1/1 grow/shrink: 1/0 up/down: 28/-31) Total: -3 bytes Signed-off-by: Tomas Heinrich Signed-off-by: Denys Vlasenko --- include/unicode.h | 6 +++++- libbb/lineedit.c | 9 ++++++--- libbb/unicode.c | 17 ++++++++++++++--- 3 files changed, 25 insertions(+), 7 deletions(-) diff --git a/include/unicode.h b/include/unicode.h index eaf67c833..e9e2bd14a 100644 --- a/include/unicode.h +++ b/include/unicode.h @@ -23,7 +23,8 @@ enum { #if !ENABLE_UNICODE_SUPPORT -# define unicode_strlen(string) strlen(string) +# define unicode_strlen(string) strlen(string) +# define unicode_strwidth(string) strlen(string) # define unicode_status UNICODE_OFF # define init_unicode() ((void)0) @@ -49,7 +50,10 @@ enum { # define ENABLE_UNICODE_BIDI_SUPPORT 0 # endif +/* Number of unicode chars. Falls back to strlen() on invalid unicode */ size_t FAST_FUNC unicode_strlen(const char *string); +/* Width on terminal */ +size_t FAST_FUNC unicode_strwidth(const char *string); enum { UNI_FLAG_PAD = (1 << 0), }; diff --git a/libbb/lineedit.c b/libbb/lineedit.c index 18664b8c1..8a2ea7974 100644 --- a/libbb/lineedit.c +++ b/libbb/lineedit.c @@ -992,7 +992,7 @@ static void showfiles(void) /* find the longest file name - use that as the column width */ for (row = 0; row < nrows; row++) { - l = unicode_strlen(matches[row]); + l = unicode_strwidth(matches[row]); if (column_width < l) column_width = l; } @@ -1012,10 +1012,13 @@ static void showfiles(void) for (nc = 1; nc < ncols && n+nrows < nfiles; n += nrows, nc++) { printf("%s%-*s", matches[n], - (int)(column_width - unicode_strlen(matches[n])), "" + (int)(column_width - unicode_strwidth(matches[n])), "" ); } - puts(matches[n]); + if (ENABLE_UNICODE_SUPPORT) + puts(printable_string(NULL, matches[n])); + else + puts(matches[n]); } } diff --git a/libbb/unicode.c b/libbb/unicode.c index b2c28239b..d6fcf7a43 100644 --- a/libbb/unicode.c +++ b/libbb/unicode.c @@ -25,13 +25,15 @@ uint8_t unicode_status; void FAST_FUNC init_unicode(void) { - /* In unicode, this is a one character string */ static const char unicode_0x394[] = { 0xce, 0x94, 0 }; + size_t width; if (unicode_status != UNICODE_UNKNOWN) return; - - unicode_status = unicode_strlen(unicode_0x394) == 1 ? UNICODE_ON : UNICODE_OFF; + /* In unicode, this is a one character string */ +// can use unicode_strlen(string) too, but otherwise unicode_strlen() is unused + width = mbstowcs(NULL, unicode_0x394, INT_MAX); + unicode_status = (width == 1 ? UNICODE_ON : UNICODE_OFF); } #else @@ -954,6 +956,7 @@ int FAST_FUNC unicode_bidi_is_neutral_wchar(wint_t wc) /* The rest is mostly same for libc and for "homegrown" support */ +#if 0 // UNUSED size_t FAST_FUNC unicode_strlen(const char *string) { size_t width = mbstowcs(NULL, string, INT_MAX); @@ -961,6 +964,14 @@ size_t FAST_FUNC unicode_strlen(const char *string) return strlen(string); return width; } +#endif + +size_t FAST_FUNC unicode_strwidth(const char *string) +{ + uni_stat_t uni_stat; + printable_string(&uni_stat, string); + return uni_stat.unicode_width; +} static char* FAST_FUNC unicode_conv_to_printable2(uni_stat_t *stats, const char *src, unsigned width, int flags) { -- cgit v1.2.3-55-g6feb From 716f3f612e62c55edd052b505a86e4e2e09074a5 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Tue, 1 Jun 2010 14:41:39 +0200 Subject: decompress_unxz: newer version, one which can unpack SHA-256 protected files function old new delta check_sizes - 16 +16 crc32_table - 4 +4 index_update 47 40 -7 crc32_validate 110 93 -17 dec_vli 197 165 -32 unpack_xz_stream 4284 4014 -270 ------------------------------------------------------------------------------ (add/remove: 2/0 grow/shrink: 0/4 up/down: 20/-326) Total: -306 bytes Signed-off-by: Denys Vlasenko --- archival/libunarchive/decompress_unxz.c | 18 +++-- archival/libunarchive/unxz/xz.h | 58 +++++++++------ archival/libunarchive/unxz/xz_config.h | 6 +- archival/libunarchive/unxz/xz_dec_bcj.c | 10 ++- archival/libunarchive/unxz/xz_dec_stream.c | 113 +++++++++++++++++++++-------- archival/libunarchive/unxz/xz_private.h | 2 +- archival/libunarchive/unxz/xz_stream.h | 15 +++- 7 files changed, 154 insertions(+), 68 deletions(-) diff --git a/archival/libunarchive/decompress_unxz.c b/archival/libunarchive/decompress_unxz.c index 924a52513..374b76d66 100644 --- a/archival/libunarchive/decompress_unxz.c +++ b/archival/libunarchive/decompress_unxz.c @@ -16,9 +16,13 @@ #define XZ_FUNC FAST_FUNC #define XZ_EXTERN static -#define xz_crc32_init(table) crc32_filltable(table, /*endian:*/ 0) -static uint32_t xz_crc32(uint32_t *crc32_table, - const uint8_t *buf, size_t size, uint32_t crc) +/* 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 *crc32_table; +static uint32_t xz_crc32(const uint8_t *buf, size_t size, uint32_t crc) { crc = ~crc; @@ -29,8 +33,8 @@ static uint32_t xz_crc32(uint32_t *crc32_table, return ~crc; } -#define xz_crc32 xz_crc32 +/* 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)) @@ -64,8 +68,10 @@ unpack_xz_stream(int src_fd, int dst_fd) iobuf.out = membuf + IN_SIZE; iobuf.out_size = OUT_SIZE; + if (!crc32_table) + crc32_table = crc32_filltable(NULL, /*endian:*/ 0); + state = xz_dec_init(64*1024); /* initial dict of 64k */ - xz_crc32_init(state->crc32_table); while (1) { enum xz_ret r; @@ -102,7 +108,7 @@ unpack_xz_stream(int src_fd, int dst_fd) ) { break; } - if (r != XZ_OK) { + if (r != XZ_OK && r != XZ_UNSUPPORTED_CHECK) { bb_error_msg("corrupted data"); total = -1; break; diff --git a/archival/libunarchive/unxz/xz.h b/archival/libunarchive/unxz/xz.h index dbb9ba92d..eb82706b9 100644 --- a/archival/libunarchive/unxz/xz.h +++ b/archival/libunarchive/unxz/xz.h @@ -31,20 +31,29 @@ /** * enum xz_ret - Return codes - * @XZ_OK: Everything is OK so far. More input or more output - * space is required to continue. - * @XZ_STREAM_END: Operation finished successfully. - * @XZ_MEMLIMIT_ERROR: Not enough memory was preallocated at decoder - * initialization time. - * @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. + * @XZ_OK: Everything is OK so far. More input or more + * output space is required to continue. + * @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_MEMLIMIT_ERROR: Not enough memory was preallocated at decoder + * initialization time. + * @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. @@ -62,6 +71,7 @@ enum xz_ret { XZ_OK, XZ_STREAM_END, + XZ_UNSUPPORTED_CHECK, XZ_MEMLIMIT_ERROR, XZ_FORMAT_ERROR, XZ_OPTIONS_ERROR, @@ -129,7 +139,7 @@ struct xz_dec; * * Because the output buffer is used as the workspace, streams encoded using * a big dictionary are not a problem in single-call. It is enough that the - * output buffer is is big enough to hold the actual uncompressed data; it + * output buffer is big enough to hold the actual uncompressed data; it * can be smaller than the dictionary size stored in the stream headers. * * On success, xz_dec_init() returns a pointer to struct xz_dec, which is @@ -186,23 +196,27 @@ XZ_EXTERN void XZ_FUNC xz_dec_end(struct xz_dec *s); * CRC32 module is used instead, and users of this module don't need to * care about the functions below. */ -#if !defined(__KERNEL__) || defined(XZ_INTERNAL_CRC32) +#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. */ -#ifndef xz_crc32_init -XZ_EXTERN void XZ_FUNC xz_crc32_init(uint32_t *crc32_table); -#endif +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. */ -#ifndef xz_crc32 -XZ_EXTERN uint32_t XZ_FUNC xz_crc32(uint32_t *crc32_table, +XZ_EXTERN uint32_t XZ_FUNC xz_crc32( const uint8_t *buf, size_t size, uint32_t crc); #endif #endif -#endif diff --git a/archival/libunarchive/unxz/xz_config.h b/archival/libunarchive/unxz/xz_config.h index 3259815f0..ff90eff26 100644 --- a/archival/libunarchive/unxz/xz_config.h +++ b/archival/libunarchive/unxz/xz_config.h @@ -43,7 +43,7 @@ * becomes slow. * * NOTE: System headers on GNU/Linux may #define this macro already, - * so if you want to change it, it you need to #undef it first. + * so if you want to change it, you need to #undef it first. */ #ifndef __always_inline # ifdef __GNUC__ @@ -114,6 +114,8 @@ static inline void XZ_FUNC put_unaligned_be32(uint32_t val, uint8_t *buf) * little endian systems, #define get_le32(ptr) (*(const uint32_t *)(ptr)) * could save a few bytes in code size. */ -#define get_le32 get_unaligned_le32 +#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 index d4b6ef751..09162b51f 100644 --- a/archival/libunarchive/unxz/xz_dec_bcj.c +++ b/archival/libunarchive/unxz/xz_dec_bcj.c @@ -10,6 +10,12 @@ #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 { @@ -331,7 +337,6 @@ static noinline_for_stack size_t XZ_FUNC bcj_sparc( } #endif -#ifdef XZ_DEC_BCJ /* * Apply the selected BCJ filter. Update *pos and s->pos to match the amount * of data that got filtered. @@ -388,9 +393,7 @@ static void XZ_FUNC bcj_apply(struct xz_dec_bcj *s, *pos += filtered; s->pos += filtered; } -#endif -#ifdef XZ_DEC_BCJ /* * Flush pending filtered data from temp to the output buffer. * Move the remaining mixture of possibly filtered and unfiltered @@ -557,4 +560,5 @@ XZ_EXTERN enum xz_ret XZ_FUNC xz_dec_bcj_reset( return XZ_OK; } + #endif diff --git a/archival/libunarchive/unxz/xz_dec_stream.c b/archival/libunarchive/unxz/xz_dec_stream.c index 121c3b53a..21db283fb 100644 --- a/archival/libunarchive/unxz/xz_dec_stream.c +++ b/archival/libunarchive/unxz/xz_dec_stream.c @@ -45,8 +45,8 @@ struct xz_dec { /* CRC32 value in Block or Index */ uint32_t crc32; - /* True if CRC32 is calculated from uncompressed data */ - uint8_t crc_type; + /* Type of the integrity check calculated from uncompressed data */ + enum xz_check check_type; /* True if we are operating in single-call mode. */ bool single_call; @@ -134,9 +134,19 @@ struct xz_dec { struct xz_dec_bcj *bcj; bool bcj_active; #endif +}; - uint32_t crc32_table[256]; +#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 @@ -231,9 +241,8 @@ static enum xz_ret XZ_FUNC dec_block(struct xz_dec *s, struct xz_buf *b) > s->block_header.uncompressed) return XZ_DATA_ERROR; - if (s->crc_type == 0x01) - s->crc32 = xz_crc32(s->crc32_table, - b->out + s->out_start, + 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) { @@ -249,15 +258,16 @@ static enum xz_ret XZ_FUNC dec_block(struct xz_dec *s, struct xz_buf *b) s->block.hash.unpadded += s->block_header.size + s->block.compressed; - if (s->crc_type == 0x01) + +#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; - if (s->crc_type == 0x04) /* CRC64 */ - s->block.hash.unpadded += 8; - if (s->crc_type == 0x0A) /* SHA-256 */ - s->block.hash.unpadded += 32; +#endif s->block.hash.uncompressed += s->block.uncompressed; - s->block.hash.crc32 = xz_crc32(s->crc32_table, + s->block.hash.crc32 = xz_crc32( (const uint8_t *)&s->block.hash, sizeof(s->block.hash), s->block.hash.crc32); @@ -272,7 +282,7 @@ 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(s->crc32_table, b->in + s->in_start, in_used, s->crc32); + s->crc32 = xz_crc32(b->in + s->in_start, in_used, s->crc32); } /* @@ -316,7 +326,7 @@ static enum xz_ret XZ_FUNC dec_index(struct xz_dec *s, struct xz_buf *b) case SEQ_INDEX_UNCOMPRESSED: s->index.hash.uncompressed += s->vli; - s->index.hash.crc32 = xz_crc32(s->crc32_table, + s->index.hash.crc32 = xz_crc32( (const uint8_t *)&s->index.hash, sizeof(s->index.hash), s->index.hash.crc32); @@ -352,31 +362,58 @@ static enum xz_ret XZ_FUNC crc32_validate(struct xz_dec *s, struct xz_buf *b) 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->crc32_table, s->temp.buf + HEADER_MAGIC_SIZE, 2, 0) + 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; + /* - * Decode the Stream Flags field. Of integrity checks, we support - * only none (Check ID = 0) and CRC32 (Check ID = 1). - * We also accept CRC64 and SHA-256, but they will not be verified. + * 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. */ - if (s->temp.buf[HEADER_MAGIC_SIZE] != 0 - || (s->temp.buf[HEADER_MAGIC_SIZE + 1] > 1 - && s->temp.buf[HEADER_MAGIC_SIZE + 1] != 0x04 /* CRC64 */ - && s->temp.buf[HEADER_MAGIC_SIZE + 1] != 0x0A /* SHA-256 */ - ) - ) { + 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; - } - s->crc_type = s->temp.buf[HEADER_MAGIC_SIZE + 1]; + 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; } @@ -387,7 +424,7 @@ 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->crc32_table, s->temp.buf + 4, 6, 0) != get_le32(s->temp.buf)) + if (xz_crc32(s->temp.buf + 4, 6, 0) != get_le32(s->temp.buf)) return XZ_DATA_ERROR; /* @@ -398,7 +435,7 @@ static enum xz_ret XZ_FUNC dec_stream_footer(struct xz_dec *s) 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->crc_type) + if (s->temp.buf[8] != 0 || s->temp.buf[9] != s->check_type) return XZ_DATA_ERROR; /* @@ -418,7 +455,7 @@ static enum xz_ret XZ_FUNC dec_block_header(struct xz_dec *s) * eight bytes so this is safe. */ s->temp.size -= 4; - if (xz_crc32(s->crc32_table, s->temp.buf, s->temp.size, 0) + if (xz_crc32(s->temp.buf, s->temp.size, 0) != get_le32(s->temp.buf + s->temp.size)) return XZ_DATA_ERROR; @@ -533,12 +570,19 @@ static enum xz_ret XZ_FUNC dec_main(struct xz_dec *s, struct xz_buf *b) 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; - s->sequence = SEQ_BLOCK_START; - case SEQ_BLOCK_START: /* We need one byte of input to continue. */ if (b->in_pos == b->in_size) @@ -600,11 +644,16 @@ static enum xz_ret XZ_FUNC dec_main(struct xz_dec *s, struct xz_buf *b) s->sequence = SEQ_BLOCK_CHECK; case SEQ_BLOCK_CHECK: - if (s->crc_type == 0x01) { + 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; diff --git a/archival/libunarchive/unxz/xz_private.h b/archival/libunarchive/unxz/xz_private.h index 9da8d7061..f4e0b4010 100644 --- a/archival/libunarchive/unxz/xz_private.h +++ b/archival/libunarchive/unxz/xz_private.h @@ -112,9 +112,9 @@ XZ_EXTERN enum xz_ret XZ_FUNC xz_dec_bcj_reset( */ 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); -#endif /* 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 index efbe75ae3..36f2a7cbf 100644 --- a/archival/libunarchive/unxz/xz_stream.h +++ b/archival/libunarchive/unxz/xz_stream.h @@ -10,10 +10,10 @@ #ifndef XZ_STREAM_H #define XZ_STREAM_H -#if defined(__KERNEL__) && !defined(XZ_INTERNAL_CRC32) +#if defined(__KERNEL__) && !XZ_INTERNAL_CRC32 # include # undef crc32 -# define xz_crc32(crc32_table, buf, size, crc) \ +# define xz_crc32(buf, size, crc) \ (~crc32_le(~(uint32_t)(crc), buf, size)) #endif @@ -43,4 +43,15 @@ typedef uint64_t vli_type; /* 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 -- cgit v1.2.3-55-g6feb From b9542cb2cee6d3b5984a7c82d7aec4a4556d2fe1 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Tue, 1 Jun 2010 23:16:46 +0200 Subject: deinline two big functions function old new delta xz_dec_lzma2_run - 1483 +1483 decode_one_format - 715 +715 decode_format_string 840 98 -742 unpack_xz_stream 4014 2377 -1637 ------------------------------------------------------------------------------ (add/remove: 2/0 grow/shrink: 0/2 up/down: 2198/-2379) Total: -181 bytes Signed-off-by: Denys Vlasenko --- archival/libunarchive/unxz/xz_dec_lzma2.c | 2 +- coreutils/od_bloaty.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/archival/libunarchive/unxz/xz_dec_lzma2.c b/archival/libunarchive/unxz/xz_dec_lzma2.c index c22dc5ba5..37de6fc32 100644 --- a/archival/libunarchive/unxz/xz_dec_lzma2.c +++ b/archival/libunarchive/unxz/xz_dec_lzma2.c @@ -915,7 +915,7 @@ static bool XZ_FUNC lzma2_lzma(struct xz_dec_lzma2 *s, struct xz_buf *b) * 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 enum xz_ret XZ_FUNC xz_dec_lzma2_run( +XZ_EXTERN NOINLINE enum xz_ret XZ_FUNC xz_dec_lzma2_run( struct xz_dec_lzma2 *s, struct xz_buf *b) { uint32_t tmp; diff --git a/coreutils/od_bloaty.c b/coreutils/od_bloaty.c index 6a532fa9d..6aba0f6bb 100644 --- a/coreutils/od_bloaty.c +++ b/coreutils/od_bloaty.c @@ -521,7 +521,7 @@ check_and_close(void) S_ORIG is solely for reporting errors. It should be the full format string argument. */ -static const char * +static NOINLINE const char * decode_one_format(const char *s_orig, const char *s, struct tspec *tspec) { enum size_spec size_spec; -- cgit v1.2.3-55-g6feb From 8376bfae58f1e32325eef934aaea8116995bb96a Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Tue, 1 Jun 2010 23:26:54 +0200 Subject: decompress_unxz: allocate permanent crc32 table _fisrt_ Signed-off-by: Denys Vlasenko --- archival/libunarchive/decompress_unxz.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/archival/libunarchive/decompress_unxz.c b/archival/libunarchive/decompress_unxz.c index 374b76d66..3f9392984 100644 --- a/archival/libunarchive/decompress_unxz.c +++ b/archival/libunarchive/decompress_unxz.c @@ -62,15 +62,15 @@ unpack_xz_stream(int src_fd, int dst_fd) OUT_SIZE = 60 * 1024, }; + if (!crc32_table) + crc32_table = crc32_filltable(NULL, /*endian:*/ 0); + membuf = xmalloc(IN_SIZE + OUT_SIZE); memset(&iobuf, 0, sizeof(iobuf)); iobuf.in = membuf; iobuf.out = membuf + IN_SIZE; iobuf.out_size = OUT_SIZE; - if (!crc32_table) - crc32_table = crc32_filltable(NULL, /*endian:*/ 0); - state = xz_dec_init(64*1024); /* initial dict of 64k */ while (1) { -- cgit v1.2.3-55-g6feb From 8837c5dec402fd6782589c0a676bc7f90dea4061 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Wed, 2 Jun 2010 12:56:18 +0200 Subject: ash: remove one redundant function, improve string sharing, better field names function old new delta var_end - 15 +15 changepath 194 192 -2 setvareq 222 218 -4 lookupvar 57 51 -6 bltinlookup 57 51 -6 evalfun 452 443 -9 varequal 14 - -14 ------------------------------------------------------------------------------ (add/remove: 1/1 grow/shrink: 0/5 up/down: 15/-41) Total: -26 bytes Signed-off-by: Denys Vlasenko --- shell/ash.c | 112 +++++++++++++++++++++++++++++++----------------------------- 1 file changed, 57 insertions(+), 55 deletions(-) diff --git a/shell/ash.c b/shell/ash.c index 9e7da1edd..d77d9d3c2 100644 --- a/shell/ash.c +++ b/shell/ash.c @@ -279,6 +279,14 @@ static int isdigit_str9(const char *str) return (*str == '\0'); } +static const char *var_end(const char *var) +{ + while (*var) + if (*var++ == '=') + break; + return var; +} + /* ============ Interrupts / exceptions */ /* @@ -1712,8 +1720,8 @@ static void FAST_FUNC getoptsreset(const char *value); struct var { struct var *next; /* next entry in hash list */ int flags; /* flags are defined above */ - const char *text; /* name=value */ - void (*func)(const char *) FAST_FUNC; /* function to be called when */ + const char *var_text; /* name=value */ + void (*var_func)(const char *) FAST_FUNC; /* function to be called when */ /* the variable gets set/unset */ }; @@ -1767,13 +1775,13 @@ static void change_random(const char *) FAST_FUNC; static const struct { int flags; - const char *text; - void (*func)(const char *) FAST_FUNC; + const char *var_text; + void (*var_func)(const char *) FAST_FUNC; } varinit_data[] = { { VSTRFIXED|VTEXTFIXED , defifsvar , NULL }, #if ENABLE_ASH_MAIL - { VSTRFIXED|VTEXTFIXED|VUNSET, "MAIL\0" , changemail }, - { VSTRFIXED|VTEXTFIXED|VUNSET, "MAILPATH\0", changemail }, + { VSTRFIXED|VTEXTFIXED|VUNSET, "MAIL" , changemail }, + { VSTRFIXED|VTEXTFIXED|VUNSET, "MAILPATH" , changemail }, #endif { VSTRFIXED|VTEXTFIXED , bb_PATH_root_path, changepath }, { VSTRFIXED|VTEXTFIXED , "PS1=$ " , NULL }, @@ -1783,14 +1791,14 @@ static const struct { { VSTRFIXED|VTEXTFIXED , "OPTIND=1" , getoptsreset }, #endif #if ENABLE_ASH_RANDOM_SUPPORT - { VSTRFIXED|VTEXTFIXED|VUNSET|VDYNAMIC, "RANDOM\0", change_random }, + { VSTRFIXED|VTEXTFIXED|VUNSET|VDYNAMIC, "RANDOM", change_random }, #endif #if ENABLE_LOCALE_SUPPORT - { VSTRFIXED|VTEXTFIXED|VUNSET, "LC_ALL\0" , change_lc_all }, - { VSTRFIXED|VTEXTFIXED|VUNSET, "LC_CTYPE\0", change_lc_ctype }, + { VSTRFIXED|VTEXTFIXED|VUNSET, "LC_ALL" , change_lc_all }, + { VSTRFIXED|VTEXTFIXED|VUNSET, "LC_CTYPE" , change_lc_ctype }, #endif #if ENABLE_FEATURE_EDITING_SAVEHISTORY - { VSTRFIXED|VTEXTFIXED|VUNSET, "HISTFILE\0", NULL }, + { VSTRFIXED|VTEXTFIXED|VUNSET, "HISTFILE" , NULL }, #endif }; @@ -1817,9 +1825,9 @@ extern struct globals_var *const ash_ptr_to_globals_var; (*(struct globals_var**)&ash_ptr_to_globals_var) = xzalloc(sizeof(G_var)); \ barrier(); \ for (i = 0; i < ARRAY_SIZE(varinit_data); i++) { \ - varinit[i].flags = varinit_data[i].flags; \ - varinit[i].text = varinit_data[i].text; \ - varinit[i].func = varinit_data[i].func; \ + varinit[i].flags = varinit_data[i].flags; \ + varinit[i].var_text = varinit_data[i].var_text; \ + varinit[i].var_func = varinit_data[i].var_func; \ } \ } while (0) @@ -1850,19 +1858,19 @@ extern struct globals_var *const ash_ptr_to_globals_var; * They have to skip over the name. They return the null string * for unset variables. */ -#define ifsval() (vifs.text + 4) +#define ifsval() (vifs.var_text + 4) #define ifsset() ((vifs.flags & VUNSET) == 0) #if ENABLE_ASH_MAIL -# define mailval() (vmail.text + 5) -# define mpathval() (vmpath.text + 9) +# define mailval() (vmail.var_text + 5) +# define mpathval() (vmpath.var_text + 9) # define mpathset() ((vmpath.flags & VUNSET) == 0) #endif -#define pathval() (vpath.text + 5) -#define ps1val() (vps1.text + 4) -#define ps2val() (vps2.text + 4) -#define ps4val() (vps4.text + 4) +#define pathval() (vpath.var_text + 5) +#define ps1val() (vps1.var_text + 4) +#define ps2val() (vps2.var_text + 4) +#define ps4val() (vps4.var_text + 4) #if ENABLE_ASH_GETOPTS -# define optindval() (voptind.text + 7) +# define optindval() (voptind.var_text + 7) #endif @@ -1921,12 +1929,6 @@ varcmp(const char *p, const char *q) return c - d; } -static int -varequal(const char *a, const char *b) -{ - return !varcmp(a, b); -} - /* * Find the appropriate entry in the hash table from the name. */ @@ -1961,15 +1963,15 @@ initvar(void) * PS1 depends on uid */ #if ENABLE_FEATURE_EDITING && ENABLE_FEATURE_EDITING_FANCY_PROMPT - vps1.text = "PS1=\\w \\$ "; + vps1.var_text = "PS1=\\w \\$ "; #else if (!geteuid()) - vps1.text = "PS1=# "; + vps1.var_text = "PS1=# "; #endif vp = varinit; end = vp + ARRAY_SIZE(varinit); do { - vpp = hashvar(vp->text); + vpp = hashvar(vp->var_text); vp->next = *vpp; *vpp = vp; } while (++vp < end); @@ -1979,7 +1981,7 @@ static struct var ** findvar(struct var **vpp, const char *name) { for (; *vpp; vpp = &(*vpp)->next) { - if (varequal((*vpp)->text, name)) { + if (varcmp((*vpp)->var_text, name) == 0) { break; } } @@ -2003,11 +2005,11 @@ lookupvar(const char *name) * As soon as they're unset, they're no longer dynamic, and dynamic * lookup will no longer happen at that point. -- PFM. */ - if ((v->flags & VDYNAMIC)) - (*v->func)(NULL); + if (v->flags & VDYNAMIC) + v->var_func(NULL); #endif if (!(v->flags & VUNSET)) - return strchrnul(v->text, '=') + 1; + return var_end(v->var_text); } return NULL; } @@ -2021,8 +2023,8 @@ bltinlookup(const char *name) struct strlist *sp; for (sp = cmdenviron; sp; sp = sp->next) { - if (varequal(sp->text, name)) - return strchrnul(sp->text, '=') + 1; + if (varcmp(sp->text, name) == 0) + return var_end(sp->text); } return lookupvar(name); } @@ -2048,24 +2050,24 @@ setvareq(char *s, int flags) if (flags & VNOSAVE) free(s); - n = vp->text; + n = vp->var_text; ash_msg_and_raise_error("%.*s: is read only", strchrnul(n, '=') - n, n); } if (flags & VNOSET) return; - if (vp->func && (flags & VNOFUNC) == 0) - (*vp->func)(strchrnul(s, '=') + 1); + if (vp->var_func && !(flags & VNOFUNC)) + vp->var_func(var_end(s)); - if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0) - free((char*)vp->text); + if (!(vp->flags & (VTEXTFIXED|VSTACK))) + free((char*)vp->var_text); flags |= vp->flags & ~(VTEXTFIXED|VSTACK|VNOSAVE|VUNSET); } else { + /* variable s is not found */ if (flags & VNOSET) return; - /* not found */ vp = ckzalloc(sizeof(*vp)); vp->next = *vpp; /*vp->func = NULL; - ckzalloc did it */ @@ -2073,7 +2075,7 @@ setvareq(char *s, int flags) } if (!(flags & (VTEXTFIXED|VSTACK|VNOSAVE))) s = ckstrdup(s); - vp->text = s; + vp->var_text = s; vp->flags = flags; } @@ -2171,7 +2173,7 @@ unsetvar(const char *s) if ((flags & VSTRFIXED) == 0) { INT_OFF; if ((flags & (VTEXTFIXED|VSTACK)) == 0) - free((char*)vp->text); + free((char*)vp->var_text); *vpp = vp->next; free(vp); INT_ON; @@ -2223,7 +2225,7 @@ listvars(int on, int off, char ***end) if ((vp->flags & mask) == on) { if (ep == stackstrend()) ep = growstackstr(); - *ep++ = (char *) vp->text; + *ep++ = (char*)vp->var_text; } } } while (++vpp < vartab + VTABSIZE); @@ -6591,7 +6593,7 @@ evalvar(char *p, int flags, struct strlist *var_str_list) var = p; easy = (!quoted || (*var == '@' && shellparam.nparam)); startloc = expdest - (char *)stackblock(); - p = strchr(p, '=') + 1; + p = strchr(p, '=') + 1; //TODO: use var_end(p)? again: varlen = varvalue(var, varflags, flags, var_str_list); @@ -8637,14 +8639,14 @@ poplocalvars(void) free((char*)lvp->text); optschanged(); } else if ((lvp->flags & (VUNSET|VSTRFIXED)) == VUNSET) { - unsetvar(vp->text); + unsetvar(vp->var_text); } else { - if (vp->func) - (*vp->func)(strchrnul(lvp->text, '=') + 1); + if (vp->var_func) + vp->var_func(var_end(lvp->text)); if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0) - free((char*)vp->text); + free((char*)vp->var_text); vp->flags = lvp->flags; - vp->text = lvp->text; + vp->var_text = lvp->text; } free(lvp); } @@ -8763,7 +8765,7 @@ mklocal(char *name) vp = *vpp; /* the new variable */ lvp->flags = VUNSET; } else { - lvp->text = vp->text; + lvp->text = vp->var_text; lvp->flags = vp->flags; vp->flags |= VSTRFIXED|VTEXTFIXED; if (eq) @@ -9073,7 +9075,7 @@ evalcommand(union node *cmd, int flags) expredir(cmd->ncmd.redirect); status = redirectsafe(cmd->ncmd.redirect, REDIR_PUSH | REDIR_SAVEFD2); - path = vpath.text; + path = vpath.var_text; for (argp = cmd->ncmd.assign; argp; argp = argp->narg.next) { struct strlist **spp; char *p; @@ -9086,7 +9088,7 @@ evalcommand(union node *cmd, int flags) * is present */ p = (*spp)->text; - if (varequal(p, path)) + if (varcmp(p, path) == 0) path = p; } @@ -10113,7 +10115,7 @@ change_random(const char *value) /* "get", generate */ t = next_random(&random_gen); /* set without recursion */ - setvar(vrandom.text, utoa(t), VNOFUNC); + setvar(vrandom.var_text, utoa(t), VNOFUNC); vrandom.flags &= ~VNOFUNC; } else { /* set/reset */ -- cgit v1.2.3-55-g6feb