aboutsummaryrefslogtreecommitdiff
path: root/archival
diff options
context:
space:
mode:
authorRon Yorston <rmy@pobox.com>2013-03-19 11:18:39 +0000
committerRon Yorston <rmy@pobox.com>2013-03-19 11:18:39 +0000
commit63d2c5fead323df5f4250ed544d0bc03527c8936 (patch)
tree660979b139a4bc4b143c08843cb7efbc69bdcb4d /archival
parent27fc2d535588728ac3ca69337271471fb6fe3ee9 (diff)
parenta42f530e034b673726a91ea5d8202254e677f066 (diff)
downloadbusybox-w32-63d2c5fead323df5f4250ed544d0bc03527c8936.tar.gz
busybox-w32-63d2c5fead323df5f4250ed544d0bc03527c8936.tar.bz2
busybox-w32-63d2c5fead323df5f4250ed544d0bc03527c8936.zip
Merge branch 'busybox' into merge
Diffstat (limited to 'archival')
-rw-r--r--archival/bbunzip.c77
-rw-r--r--archival/libarchive/data_extract_all.c15
-rw-r--r--archival/libarchive/decompress_unlzma.c29
-rw-r--r--archival/libarchive/decompress_unxz.c47
-rw-r--r--archival/libarchive/open_transformer.c11
-rw-r--r--archival/libarchive/unxz/README6
-rw-r--r--archival/libarchive/unxz/xz.h17
-rw-r--r--archival/libarchive/unxz/xz_dec_bcj.c34
-rw-r--r--archival/libarchive/unxz/xz_dec_lzma2.c7
-rw-r--r--archival/libarchive/unxz/xz_stream.h11
-rw-r--r--archival/lzop.c32
-rw-r--r--archival/rpm.c305
12 files changed, 345 insertions, 246 deletions
diff --git a/archival/bbunzip.c b/archival/bbunzip.c
index 66a046052..f77ac8383 100644
--- a/archival/bbunzip.c
+++ b/archival/bbunzip.c
@@ -7,13 +7,16 @@
7#include "libbb.h" 7#include "libbb.h"
8#include "bb_archive.h" 8#include "bb_archive.h"
9 9
10/* Note: must be kept in sync with archival/lzop.c */
10enum { 11enum {
11 OPT_STDOUT = 1 << 0, 12 OPT_STDOUT = 1 << 0,
12 OPT_FORCE = 1 << 1, 13 OPT_FORCE = 1 << 1,
13 /* only some decompressors: */ 14 /* only some decompressors: */
14 OPT_VERBOSE = 1 << 2, 15 OPT_VERBOSE = 1 << 2,
15 OPT_DECOMPRESS = 1 << 3, 16 OPT_QUIET = 1 << 3,
16 OPT_TEST = 1 << 4, 17 OPT_DECOMPRESS = 1 << 4,
18 OPT_TEST = 1 << 5,
19 SEAMLESS_MAGIC = (1 << 31) * SEAMLESS_COMPRESSION,
17}; 20};
18 21
19static 22static
@@ -39,7 +42,7 @@ int FAST_FUNC bbunpack(char **argv,
39) 42)
40{ 43{
41 struct stat stat_buf; 44 struct stat stat_buf;
42 IF_DESKTOP(long long) int status; 45 IF_DESKTOP(long long) int status = 0;
43 char *filename, *new_name; 46 char *filename, *new_name;
44 smallint exitcode = 0; 47 smallint exitcode = 0;
45 transformer_aux_data_t aux; 48 transformer_aux_data_t aux;
@@ -54,13 +57,27 @@ int FAST_FUNC bbunpack(char **argv,
54 57
55 /* Open src */ 58 /* Open src */
56 if (filename) { 59 if (filename) {
57 if (stat(filename, &stat_buf) != 0) { 60 if (!(option_mask32 & SEAMLESS_MAGIC)) {
58 bb_simple_perror_msg(filename); 61 if (stat(filename, &stat_buf) != 0) {
62 err_name:
63 bb_simple_perror_msg(filename);
59 err: 64 err:
60 exitcode = 1; 65 exitcode = 1;
61 goto free_name; 66 goto free_name;
67 }
68 if (open_to_or_warn(STDIN_FILENO, filename, O_RDONLY, 0))
69 goto err;
70 } else {
71 /* "clever zcat" with FILE */
72 int fd = open_zipped(filename);
73 if (fd < 0)
74 goto err_name;
75 xmove_fd(fd, STDIN_FILENO);
62 } 76 }
63 if (open_to_or_warn(STDIN_FILENO, filename, O_RDONLY, 0)) 77 } else
78 if (option_mask32 & SEAMLESS_MAGIC) {
79 /* "clever zcat" on stdin */
80 if (setup_unzip_on_fd(STDIN_FILENO, /*fail_if_not_detected*/ 0))
64 goto err; 81 goto err;
65 } 82 }
66 83
@@ -68,7 +85,7 @@ int FAST_FUNC bbunpack(char **argv,
68 if (option_mask32 & (OPT_STDOUT|OPT_TEST)) { 85 if (option_mask32 & (OPT_STDOUT|OPT_TEST)) {
69 if (option_mask32 & OPT_TEST) 86 if (option_mask32 & OPT_TEST)
70 if (open_to_or_warn(STDOUT_FILENO, bb_dev_null, O_WRONLY, 0)) 87 if (open_to_or_warn(STDOUT_FILENO, bb_dev_null, O_WRONLY, 0))
71 goto err; 88 xfunc_die();
72 filename = NULL; 89 filename = NULL;
73 } 90 }
74 91
@@ -93,16 +110,22 @@ int FAST_FUNC bbunpack(char **argv,
93 } 110 }
94 111
95 /* Check that the input is sane */ 112 /* Check that the input is sane */
96 if (isatty(STDIN_FILENO) && (option_mask32 & OPT_FORCE) == 0) { 113 if (!(option_mask32 & OPT_FORCE) && isatty(STDIN_FILENO)) {
97 bb_error_msg_and_die("compressed data not read from terminal, " 114 bb_error_msg_and_die("compressed data not read from terminal, "
98 "use -f to force it"); 115 "use -f to force it");
99 } 116 }
100 117
101 init_transformer_aux_data(&aux); 118 if (!(option_mask32 & SEAMLESS_MAGIC)) {
102 aux.check_signature = 1; 119 init_transformer_aux_data(&aux);
103 status = unpacker(&aux); 120 aux.check_signature = 1;
104 if (status < 0) 121 status = unpacker(&aux);
105 exitcode = 1; 122 if (status < 0)
123 exitcode = 1;
124 } else {
125 if (bb_copyfd_eof(STDIN_FILENO, STDOUT_FILENO) < 0)
126 /* Disk full, tty closed, etc. No point in continuing */
127 xfunc_die();
128 }
106 129
107 if (!(option_mask32 & OPT_STDOUT)) 130 if (!(option_mask32 & OPT_STDOUT))
108 xclose(STDOUT_FILENO); /* with error check! */ 131 xclose(STDOUT_FILENO); /* with error check! */
@@ -243,7 +266,7 @@ int uncompress_main(int argc UNUSED_PARAM, char **argv)
243//usage: "-rw-rw-r-- 1 andersen andersen 1761280 Apr 14 17:47 /tmp/BusyBox-0.43.tar\n" 266//usage: "-rw-rw-r-- 1 andersen andersen 1761280 Apr 14 17:47 /tmp/BusyBox-0.43.tar\n"
244//usage: 267//usage:
245//usage:#define zcat_trivial_usage 268//usage:#define zcat_trivial_usage
246//usage: "FILE" 269//usage: "[FILE]..."
247//usage:#define zcat_full_usage "\n\n" 270//usage:#define zcat_full_usage "\n\n"
248//usage: "Decompress to stdout" 271//usage: "Decompress to stdout"
249 272
@@ -294,11 +317,15 @@ IF_DESKTOP(long long) int FAST_FUNC unpack_gunzip(transformer_aux_data_t *aux)
294int gunzip_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 317int gunzip_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
295int gunzip_main(int argc UNUSED_PARAM, char **argv) 318int gunzip_main(int argc UNUSED_PARAM, char **argv)
296{ 319{
297 getopt32(argv, "cfvdtn"); 320 getopt32(argv, "cfvqdtn");
298 argv += optind; 321 argv += optind;
299 /* if called as zcat */ 322
323 /* If called as zcat...
324 * Normally, "zcat" is just "gunzip -c".
325 * But if seamless magic is enabled, then we are much more clever.
326 */
300 if (applet_name[1] == 'c') 327 if (applet_name[1] == 'c')
301 option_mask32 |= OPT_STDOUT; 328 option_mask32 |= OPT_STDOUT | SEAMLESS_MAGIC;
302 329
303 return bbunpack(argv, unpack_gunzip, make_new_name_gunzip, /*unused:*/ NULL); 330 return bbunpack(argv, unpack_gunzip, make_new_name_gunzip, /*unused:*/ NULL);
304} 331}
@@ -318,7 +345,7 @@ int gunzip_main(int argc UNUSED_PARAM, char **argv)
318//usage: "\n -c Write to stdout" 345//usage: "\n -c Write to stdout"
319//usage: "\n -f Force" 346//usage: "\n -f Force"
320//usage:#define bzcat_trivial_usage 347//usage:#define bzcat_trivial_usage
321//usage: "FILE" 348//usage: "[FILE]..."
322//usage:#define bzcat_full_usage "\n\n" 349//usage:#define bzcat_full_usage "\n\n"
323//usage: "Decompress to stdout" 350//usage: "Decompress to stdout"
324//applet:IF_BUNZIP2(APPLET(bunzip2, BB_DIR_USR_BIN, BB_SUID_DROP)) 351//applet:IF_BUNZIP2(APPLET(bunzip2, BB_DIR_USR_BIN, BB_SUID_DROP))
@@ -332,7 +359,7 @@ IF_DESKTOP(long long) int FAST_FUNC unpack_bunzip2(transformer_aux_data_t *aux)
332int bunzip2_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 359int bunzip2_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
333int bunzip2_main(int argc UNUSED_PARAM, char **argv) 360int bunzip2_main(int argc UNUSED_PARAM, char **argv)
334{ 361{
335 getopt32(argv, "cfvdt"); 362 getopt32(argv, "cfvqdt");
336 argv += optind; 363 argv += optind;
337 if (applet_name[2] == 'c') /* bzcat */ 364 if (applet_name[2] == 'c') /* bzcat */
338 option_mask32 |= OPT_STDOUT; 365 option_mask32 |= OPT_STDOUT;
@@ -367,7 +394,7 @@ int bunzip2_main(int argc UNUSED_PARAM, char **argv)
367//usage: "\n -f Force" 394//usage: "\n -f Force"
368//usage: 395//usage:
369//usage:#define lzcat_trivial_usage 396//usage:#define lzcat_trivial_usage
370//usage: "FILE" 397//usage: "[FILE]..."
371//usage:#define lzcat_full_usage "\n\n" 398//usage:#define lzcat_full_usage "\n\n"
372//usage: "Decompress to stdout" 399//usage: "Decompress to stdout"
373//usage: 400//usage:
@@ -387,7 +414,7 @@ int bunzip2_main(int argc UNUSED_PARAM, char **argv)
387//usage: "\n -f Force" 414//usage: "\n -f Force"
388//usage: 415//usage:
389//usage:#define xzcat_trivial_usage 416//usage:#define xzcat_trivial_usage
390//usage: "FILE" 417//usage: "[FILE]..."
391//usage:#define xzcat_full_usage "\n\n" 418//usage:#define xzcat_full_usage "\n\n"
392//usage: "Decompress to stdout" 419//usage: "Decompress to stdout"
393 420
@@ -400,7 +427,7 @@ IF_DESKTOP(long long) int FAST_FUNC unpack_unlzma(transformer_aux_data_t *aux)
400int unlzma_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 427int unlzma_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
401int unlzma_main(int argc UNUSED_PARAM, char **argv) 428int unlzma_main(int argc UNUSED_PARAM, char **argv)
402{ 429{
403 IF_LZMA(int opts =) getopt32(argv, "cfvdt"); 430 IF_LZMA(int opts =) getopt32(argv, "cfvqdt");
404# if ENABLE_LZMA 431# if ENABLE_LZMA
405 /* lzma without -d or -t? */ 432 /* lzma without -d or -t? */
406 if (applet_name[2] == 'm' && !(opts & (OPT_DECOMPRESS|OPT_TEST))) 433 if (applet_name[2] == 'm' && !(opts & (OPT_DECOMPRESS|OPT_TEST)))
@@ -425,7 +452,7 @@ IF_DESKTOP(long long) int FAST_FUNC unpack_unxz(transformer_aux_data_t *aux)
425int unxz_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 452int unxz_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
426int unxz_main(int argc UNUSED_PARAM, char **argv) 453int unxz_main(int argc UNUSED_PARAM, char **argv)
427{ 454{
428 IF_XZ(int opts =) getopt32(argv, "cfvdt"); 455 IF_XZ(int opts =) getopt32(argv, "cfvqdt");
429# if ENABLE_XZ 456# if ENABLE_XZ
430 /* xz without -d or -t? */ 457 /* xz without -d or -t? */
431 if (applet_name[2] == '\0' && !(opts & (OPT_DECOMPRESS|OPT_TEST))) 458 if (applet_name[2] == '\0' && !(opts & (OPT_DECOMPRESS|OPT_TEST)))
diff --git a/archival/libarchive/data_extract_all.c b/archival/libarchive/data_extract_all.c
index 3f67b835f..45776dcbe 100644
--- a/archival/libarchive/data_extract_all.c
+++ b/archival/libarchive/data_extract_all.c
@@ -106,15 +106,28 @@ void FAST_FUNC data_extract_all(archive_handle_t *archive_handle)
106 switch (file_header->mode & S_IFMT) { 106 switch (file_header->mode & S_IFMT) {
107 case S_IFREG: { 107 case S_IFREG: {
108 /* Regular file */ 108 /* Regular file */
109 char *dst_name;
109 int flags = O_WRONLY | O_CREAT | O_EXCL; 110 int flags = O_WRONLY | O_CREAT | O_EXCL;
110 if (archive_handle->ah_flags & ARCHIVE_O_TRUNC) 111 if (archive_handle->ah_flags & ARCHIVE_O_TRUNC)
111 flags = O_WRONLY | O_CREAT | O_TRUNC; 112 flags = O_WRONLY | O_CREAT | O_TRUNC;
112 dst_fd = xopen3(file_header->name, 113 dst_name = file_header->name;
114#ifdef ARCHIVE_REPLACE_VIA_RENAME
115 if (archive_handle->ah_flags & ARCHIVE_REPLACE_VIA_RENAME)
116 /* rpm-style temp file name */
117 dst_name = xasprintf("%s;%x", dst_name, (int)getpid());
118#endif
119 dst_fd = xopen3(dst_name,
113 flags, 120 flags,
114 file_header->mode 121 file_header->mode
115 ); 122 );
116 bb_copyfd_exact_size(archive_handle->src_fd, dst_fd, file_header->size); 123 bb_copyfd_exact_size(archive_handle->src_fd, dst_fd, file_header->size);
117 close(dst_fd); 124 close(dst_fd);
125#ifdef ARCHIVE_REPLACE_VIA_RENAME
126 if (archive_handle->ah_flags & ARCHIVE_REPLACE_VIA_RENAME) {
127 xrename(dst_name, file_header->name);
128 free(dst_name);
129 }
130#endif
118 break; 131 break;
119 } 132 }
120 case S_IFDIR: 133 case S_IFDIR:
diff --git a/archival/libarchive/decompress_unlzma.c b/archival/libarchive/decompress_unlzma.c
index cfde8ea56..ca32bd82c 100644
--- a/archival/libarchive/decompress_unlzma.c
+++ b/archival/libarchive/decompress_unlzma.c
@@ -45,16 +45,16 @@ typedef struct {
45#define RC_MODEL_TOTAL_BITS 11 45#define RC_MODEL_TOTAL_BITS 11
46 46
47 47
48/* Called twice: once at startup (LZMA_FAST only) and once in rc_normalize() */ 48/* Called once in rc_do_normalize() */
49static size_inline void rc_read(rc_t *rc) 49static void rc_read(rc_t *rc)
50{ 50{
51 int buffer_size = safe_read(rc->fd, RC_BUFFER, RC_BUFFER_SIZE); 51 int buffer_size = safe_read(rc->fd, RC_BUFFER, RC_BUFFER_SIZE);
52//TODO: return -1 instead 52//TODO: return -1 instead
53//This will make unlzma delete broken unpacked file on unpack errors 53//This will make unlzma delete broken unpacked file on unpack errors
54 if (buffer_size <= 0) 54 if (buffer_size <= 0)
55 bb_error_msg_and_die("unexpected EOF"); 55 bb_error_msg_and_die("unexpected EOF");
56 rc->ptr = RC_BUFFER;
57 rc->buffer_end = RC_BUFFER + buffer_size; 56 rc->buffer_end = RC_BUFFER + buffer_size;
57 rc->ptr = RC_BUFFER;
58} 58}
59 59
60/* Called twice, but one callsite is in speed_inline'd rc_is_bit_1() */ 60/* Called twice, but one callsite is in speed_inline'd rc_is_bit_1() */
@@ -65,6 +65,12 @@ static void rc_do_normalize(rc_t *rc)
65 rc->range <<= 8; 65 rc->range <<= 8;
66 rc->code = (rc->code << 8) | *rc->ptr++; 66 rc->code = (rc->code << 8) | *rc->ptr++;
67} 67}
68static ALWAYS_INLINE void rc_normalize(rc_t *rc)
69{
70 if (rc->range < (1 << RC_TOP_BITS)) {
71 rc_do_normalize(rc);
72 }
73}
68 74
69/* Called once */ 75/* Called once */
70static ALWAYS_INLINE rc_t* rc_init(int fd) /*, int buffer_size) */ 76static ALWAYS_INLINE rc_t* rc_init(int fd) /*, int buffer_size) */
@@ -78,15 +84,9 @@ static ALWAYS_INLINE rc_t* rc_init(int fd) /*, int buffer_size) */
78 /* rc->ptr = rc->buffer_end; */ 84 /* rc->ptr = rc->buffer_end; */
79 85
80 for (i = 0; i < 5; i++) { 86 for (i = 0; i < 5; i++) {
81#if ENABLE_FEATURE_LZMA_FAST
82 if (rc->ptr >= rc->buffer_end)
83 rc_read(rc);
84 rc->code = (rc->code << 8) | *rc->ptr++;
85#else
86 rc_do_normalize(rc); 87 rc_do_normalize(rc);
87#endif
88 } 88 }
89 rc->range = 0xFFFFFFFF; 89 rc->range = 0xffffffff;
90 return rc; 90 return rc;
91} 91}
92 92
@@ -96,13 +96,6 @@ static ALWAYS_INLINE void rc_free(rc_t *rc)
96 free(rc); 96 free(rc);
97} 97}
98 98
99static ALWAYS_INLINE void rc_normalize(rc_t *rc)
100{
101 if (rc->range < (1 << RC_TOP_BITS)) {
102 rc_do_normalize(rc);
103 }
104}
105
106/* rc_is_bit_1 is called 9 times */ 99/* rc_is_bit_1 is called 9 times */
107static speed_inline int rc_is_bit_1(rc_t *rc, uint16_t *p) 100static speed_inline int rc_is_bit_1(rc_t *rc, uint16_t *p)
108{ 101{
@@ -120,7 +113,7 @@ static speed_inline int rc_is_bit_1(rc_t *rc, uint16_t *p)
120} 113}
121 114
122/* Called 4 times in unlzma loop */ 115/* Called 4 times in unlzma loop */
123static speed_inline int rc_get_bit(rc_t *rc, uint16_t *p, int *symbol) 116static ALWAYS_INLINE int rc_get_bit(rc_t *rc, uint16_t *p, int *symbol)
124{ 117{
125 int ret = rc_is_bit_1(rc, p); 118 int ret = rc_is_bit_1(rc, p);
126 *symbol = *symbol * 2 + ret; 119 *symbol = *symbol * 2 + ret;
diff --git a/archival/libarchive/decompress_unxz.c b/archival/libarchive/decompress_unxz.c
index 79b48a152..986b7b191 100644
--- a/archival/libarchive/decompress_unxz.c
+++ b/archival/libarchive/decompress_unxz.c
@@ -30,8 +30,8 @@ static uint32_t xz_crc32(const uint8_t *buf, size_t size, uint32_t crc)
30/* We use arch-optimized unaligned accessors */ 30/* We use arch-optimized unaligned accessors */
31#define get_unaligned_le32(buf) ({ uint32_t v; move_from_unaligned32(v, buf); SWAP_LE32(v); }) 31#define get_unaligned_le32(buf) ({ uint32_t v; move_from_unaligned32(v, buf); SWAP_LE32(v); })
32#define get_unaligned_be32(buf) ({ uint32_t v; move_from_unaligned32(v, buf); SWAP_BE32(v); }) 32#define get_unaligned_be32(buf) ({ uint32_t v; move_from_unaligned32(v, buf); SWAP_BE32(v); })
33#define put_unaligned_le32(val, buf) move_to_unaligned16(buf, SWAP_LE32(val)) 33#define put_unaligned_le32(val, buf) move_to_unaligned32(buf, SWAP_LE32(val))
34#define put_unaligned_be32(val, buf) move_to_unaligned16(buf, SWAP_BE32(val)) 34#define put_unaligned_be32(val, buf) move_to_unaligned32(buf, SWAP_BE32(val))
35 35
36#include "unxz/xz_dec_bcj.c" 36#include "unxz/xz_dec_bcj.c"
37#include "unxz/xz_dec_lzma2.c" 37#include "unxz/xz_dec_lzma2.c"
@@ -40,6 +40,7 @@ static uint32_t xz_crc32(const uint8_t *buf, size_t size, uint32_t crc)
40IF_DESKTOP(long long) int FAST_FUNC 40IF_DESKTOP(long long) int FAST_FUNC
41unpack_xz_stream(transformer_aux_data_t *aux, int src_fd, int dst_fd) 41unpack_xz_stream(transformer_aux_data_t *aux, int src_fd, int dst_fd)
42{ 42{
43 enum xz_ret xz_result;
43 struct xz_buf iobuf; 44 struct xz_buf iobuf;
44 struct xz_dec *state; 45 struct xz_dec *state;
45 unsigned char *membuf; 46 unsigned char *membuf;
@@ -63,9 +64,8 @@ unpack_xz_stream(transformer_aux_data_t *aux, int src_fd, int dst_fd)
63 /* Limit memory usage to about 64 MiB. */ 64 /* Limit memory usage to about 64 MiB. */
64 state = xz_dec_init(XZ_DYNALLOC, 64*1024*1024); 65 state = xz_dec_init(XZ_DYNALLOC, 64*1024*1024);
65 66
67 xz_result = X_OK;
66 while (1) { 68 while (1) {
67 enum xz_ret r;
68
69 if (iobuf.in_pos == iobuf.in_size) { 69 if (iobuf.in_pos == iobuf.in_size) {
70 int rd = safe_read(src_fd, membuf, BUFSIZ); 70 int rd = safe_read(src_fd, membuf, BUFSIZ);
71 if (rd < 0) { 71 if (rd < 0) {
@@ -73,28 +73,57 @@ unpack_xz_stream(transformer_aux_data_t *aux, int src_fd, int dst_fd)
73 total = -1; 73 total = -1;
74 break; 74 break;
75 } 75 }
76 if (rd == 0 && xz_result == XZ_STREAM_END)
77 break;
76 iobuf.in_size = rd; 78 iobuf.in_size = rd;
77 iobuf.in_pos = 0; 79 iobuf.in_pos = 0;
78 } 80 }
81 if (xz_result == XZ_STREAM_END) {
82 /*
83 * Try to start decoding next concatenated stream.
84 * Stream padding must always be a multiple of four
85 * bytes to preserve four-byte alignment. To keep the
86 * code slightly smaller, we aren't as strict here as
87 * the .xz spec requires. We just skip all zero-bytes
88 * without checking the alignment and thus can accept
89 * files that aren't valid, e.g. the XZ utils test
90 * files bad-0pad-empty.xz and bad-0catpad-empty.xz.
91 */
92 do {
93 if (membuf[iobuf.in_pos] != 0) {
94 xz_dec_reset(state);
95 goto do_run;
96 }
97 iobuf.in_pos++;
98 } while (iobuf.in_pos < iobuf.in_size);
99 }
100 do_run:
79// bb_error_msg(">in pos:%d size:%d out pos:%d size:%d", 101// bb_error_msg(">in pos:%d size:%d out pos:%d size:%d",
80// iobuf.in_pos, iobuf.in_size, iobuf.out_pos, iobuf.out_size); 102// iobuf.in_pos, iobuf.in_size, iobuf.out_pos, iobuf.out_size);
81 r = xz_dec_run(state, &iobuf); 103 xz_result = xz_dec_run(state, &iobuf);
82// bb_error_msg("<in pos:%d size:%d out pos:%d size:%d r:%d", 104// bb_error_msg("<in pos:%d size:%d out pos:%d size:%d r:%d",
83// iobuf.in_pos, iobuf.in_size, iobuf.out_pos, iobuf.out_size, r); 105// iobuf.in_pos, iobuf.in_size, iobuf.out_pos, iobuf.out_size, xz_result);
84 if (iobuf.out_pos) { 106 if (iobuf.out_pos) {
85 xwrite(dst_fd, iobuf.out, iobuf.out_pos); 107 xwrite(dst_fd, iobuf.out, iobuf.out_pos);
86 IF_DESKTOP(total += iobuf.out_pos;) 108 IF_DESKTOP(total += iobuf.out_pos;)
87 iobuf.out_pos = 0; 109 iobuf.out_pos = 0;
88 } 110 }
89 if (r == XZ_STREAM_END) { 111 if (xz_result == XZ_STREAM_END) {
90 break; 112 /*
113 * Can just "break;" here, if not for concatenated
114 * .xz streams.
115 * Checking for padding may require buffer
116 * replenishment. Can't do it here.
117 */
118 continue;
91 } 119 }
92 if (r != XZ_OK && r != XZ_UNSUPPORTED_CHECK) { 120 if (xz_result != XZ_OK && xz_result != XZ_UNSUPPORTED_CHECK) {
93 bb_error_msg("corrupted data"); 121 bb_error_msg("corrupted data");
94 total = -1; 122 total = -1;
95 break; 123 break;
96 } 124 }
97 } 125 }
126
98 xz_dec_end(state); 127 xz_dec_end(state);
99 free(membuf); 128 free(membuf);
100 129
diff --git a/archival/libarchive/open_transformer.c b/archival/libarchive/open_transformer.c
index f2edc2a2b..841e9dce9 100644
--- a/archival/libarchive/open_transformer.c
+++ b/archival/libarchive/open_transformer.c
@@ -35,6 +35,7 @@ void check_errors_in_children(int signo)
35 if (!signo) { 35 if (!signo) {
36 /* block waiting for any child */ 36 /* block waiting for any child */
37 if (wait(&status) < 0) 37 if (wait(&status) < 0)
38//FIXME: check EINTR?
38 return; /* probably there are no children */ 39 return; /* probably there are no children */
39 goto check_status; 40 goto check_status;
40 } 41 }
@@ -42,14 +43,18 @@ void check_errors_in_children(int signo)
42 /* Wait for any child without blocking */ 43 /* Wait for any child without blocking */
43 for (;;) { 44 for (;;) {
44 if (wait_any_nohang(&status) < 0) 45 if (wait_any_nohang(&status) < 0)
46//FIXME: check EINTR?
45 /* wait failed?! I'm confused... */ 47 /* wait failed?! I'm confused... */
46 return; 48 return;
47 check_status: 49 check_status:
48 if (WIFEXITED(status) && WEXITSTATUS(status) == 0) 50 /*if (WIFEXITED(status) && WEXITSTATUS(status) == 0)*/
51 /* On Linux, the above can be checked simply as: */
52 if (status == 0)
49 /* this child exited with 0 */ 53 /* this child exited with 0 */
50 continue; 54 continue;
51 /* Cannot happen? 55 /* Cannot happen:
52 if (!WIFSIGNALED(status) && !WIFEXITED(status)) ???; */ 56 if (!WIFSIGNALED(status) && !WIFEXITED(status)) ???;
57 */
53 bb_got_signal = 1; 58 bb_got_signal = 1;
54 } 59 }
55} 60}
diff --git a/archival/libarchive/unxz/README b/archival/libarchive/unxz/README
index c5972f6b8..a84912035 100644
--- a/archival/libarchive/unxz/README
+++ b/archival/libarchive/unxz/README
@@ -7,7 +7,7 @@ XZ Embedded
7 7
8 XZ Embedded was written for use in the Linux kernel, but the code can 8 XZ Embedded was written for use in the Linux kernel, but the code can
9 be easily used in other environments too, including regular userspace 9 be easily used in other environments too, including regular userspace
10 applications. 10 applications. See userspace/xzminidec.c for an example program.
11 11
12 This README contains information that is useful only when the copy 12 This README contains information that is useful only when the copy
13 of XZ Embedded isn't part of the Linux kernel tree. You should also 13 of XZ Embedded isn't part of the Linux kernel tree. You should also
@@ -55,7 +55,7 @@ Compiler requirements
55 code is modified not to support large files, which needs some more 55 code is modified not to support large files, which needs some more
56 care than just using 32-bit integer instead of 64-bit). 56 care than just using 32-bit integer instead of 64-bit).
57 57
58 If you use GCC, try to use a recent version. For example, on x86, 58 If you use GCC, try to use a recent version. For example, on x86-32,
59 xz_dec_lzma2.c compiled with GCC 3.3.6 is 15-25 % slower than when 59 xz_dec_lzma2.c compiled with GCC 3.3.6 is 15-25 % slower than when
60 compiled with GCC 4.3.3. 60 compiled with GCC 4.3.3.
61 61
@@ -93,7 +93,7 @@ BCJ filter support
93 them always #defined doesn't hurt either. 93 them always #defined doesn't hurt either.
94 94
95 #define Instruction set BCJ filter endianness 95 #define Instruction set BCJ filter endianness
96 XZ_DEC_X86 x86 or x86-64 Little endian only 96 XZ_DEC_X86 x86-32 or x86-64 Little endian only
97 XZ_DEC_POWERPC PowerPC Big endian only 97 XZ_DEC_POWERPC PowerPC Big endian only
98 XZ_DEC_IA64 Itanium (IA-64) Big or little endian 98 XZ_DEC_IA64 Itanium (IA-64) Big or little endian
99 XZ_DEC_ARM ARM Little endian only 99 XZ_DEC_ARM ARM Little endian only
diff --git a/archival/libarchive/unxz/xz.h b/archival/libarchive/unxz/xz.h
index c6c071c4a..e0b22db56 100644
--- a/archival/libarchive/unxz/xz.h
+++ b/archival/libarchive/unxz/xz.h
@@ -19,6 +19,10 @@
19# include <stdint.h> 19# include <stdint.h>
20#endif 20#endif
21 21
22#ifdef __cplusplus
23extern "C" {
24#endif
25
22/* In Linux, this is used to make extern functions static when needed. */ 26/* In Linux, this is used to make extern functions static when needed. */
23#ifndef XZ_EXTERN 27#ifndef XZ_EXTERN
24# define XZ_EXTERN extern 28# define XZ_EXTERN extern
@@ -70,7 +74,7 @@ enum xz_mode {
70 * @XZ_UNSUPPORTED_CHECK: Integrity check type is not supported. Decoding 74 * @XZ_UNSUPPORTED_CHECK: Integrity check type is not supported. Decoding
71 * is still possible in multi-call mode by simply 75 * is still possible in multi-call mode by simply
72 * calling xz_dec_run() again. 76 * calling xz_dec_run() again.
73 * NOTE: This return value is used only if 77 * Note that this return value is used only if
74 * XZ_DEC_ANY_CHECK was defined at build time, 78 * XZ_DEC_ANY_CHECK was defined at build time,
75 * which is not used in the kernel. Unsupported 79 * which is not used in the kernel. Unsupported
76 * check types return XZ_OPTIONS_ERROR if 80 * check types return XZ_OPTIONS_ERROR if
@@ -105,7 +109,7 @@ enum xz_mode {
105 * stream that is truncated or otherwise corrupt. 109 * stream that is truncated or otherwise corrupt.
106 * 110 *
107 * In single-call mode, XZ_BUF_ERROR is returned only when the output buffer 111 * In single-call mode, XZ_BUF_ERROR is returned only when the output buffer
108 * is too small, or the compressed input is corrupt in a way that makes the 112 * is too small or the compressed input is corrupt in a way that makes the
109 * decoder produce more output than the caller expected. When it is 113 * decoder produce more output than the caller expected. When it is
110 * (relatively) clear that the compressed input is truncated, XZ_DATA_ERROR 114 * (relatively) clear that the compressed input is truncated, XZ_DATA_ERROR
111 * is used instead of XZ_BUF_ERROR. 115 * is used instead of XZ_BUF_ERROR.
@@ -207,8 +211,8 @@ XZ_EXTERN struct xz_dec * XZ_FUNC xz_dec_init(
207 * The possible return values depend on build options and operation mode. 211 * The possible return values depend on build options and operation mode.
208 * See enum xz_ret for details. 212 * See enum xz_ret for details.
209 * 213 *
210 * NOTE: If an error occurs in single-call mode (return value is not 214 * Note that if an error occurs in single-call mode (return value is not
211 * XZ_STREAM_END), b->in_pos and b->out_pos are not modified, and the 215 * XZ_STREAM_END), b->in_pos and b->out_pos are not modified and the
212 * contents of the output buffer from b->out[b->out_pos] onward are 216 * contents of the output buffer from b->out[b->out_pos] onward are
213 * undefined. This is true even after XZ_BUF_ERROR, because with some filter 217 * undefined. This is true even after XZ_BUF_ERROR, because with some filter
214 * chains, there may be a second pass over the output buffer, and this pass 218 * chains, there may be a second pass over the output buffer, and this pass
@@ -268,4 +272,9 @@ XZ_EXTERN void XZ_FUNC xz_crc32_init(void);
268XZ_EXTERN uint32_t XZ_FUNC xz_crc32( 272XZ_EXTERN uint32_t XZ_FUNC xz_crc32(
269 const uint8_t *buf, size_t size, uint32_t crc); 273 const uint8_t *buf, size_t size, uint32_t crc);
270#endif 274#endif
275
276#ifdef __cplusplus
277}
278#endif
279
271#endif 280#endif
diff --git a/archival/libarchive/unxz/xz_dec_bcj.c b/archival/libarchive/unxz/xz_dec_bcj.c
index 09162b51f..e0f913a94 100644
--- a/archival/libarchive/unxz/xz_dec_bcj.c
+++ b/archival/libarchive/unxz/xz_dec_bcj.c
@@ -77,10 +77,13 @@ struct xz_dec_bcj {
77 77
78#ifdef XZ_DEC_X86 78#ifdef XZ_DEC_X86
79/* 79/*
80 * This is macro used to test the most significant byte of a memory address 80 * This is used to test the most significant byte of a memory address
81 * in an x86 instruction. 81 * in an x86 instruction.
82 */ 82 */
83#define bcj_x86_test_msbyte(b) ((b) == 0x00 || (b) == 0xFF) 83static inline int bcj_x86_test_msbyte(uint8_t b)
84{
85 return b == 0x00 || b == 0xFF;
86}
84 87
85static noinline_for_stack size_t XZ_FUNC bcj_x86( 88static noinline_for_stack size_t XZ_FUNC bcj_x86(
86 struct xz_dec_bcj *s, uint8_t *buf, size_t size) 89 struct xz_dec_bcj *s, uint8_t *buf, size_t size)
@@ -443,8 +446,12 @@ XZ_EXTERN enum xz_ret XZ_FUNC xz_dec_bcj_run(struct xz_dec_bcj *s,
443 * next filter in the chain. Apply the BCJ filter on the new data 446 * next filter in the chain. Apply the BCJ filter on the new data
444 * in the output buffer. If everything cannot be filtered, copy it 447 * in the output buffer. If everything cannot be filtered, copy it
445 * to temp and rewind the output buffer position accordingly. 448 * to temp and rewind the output buffer position accordingly.
449 *
450 * This needs to be always run when temp.size == 0 to handle a special
451 * case where the output buffer is full and the next filter has no
452 * more output coming but hasn't returned XZ_STREAM_END yet.
446 */ 453 */
447 if (s->temp.size < b->out_size - b->out_pos) { 454 if (s->temp.size < b->out_size - b->out_pos || s->temp.size == 0) {
448 out_start = b->out_pos; 455 out_start = b->out_pos;
449 memcpy(b->out + b->out_pos, s->temp.buf, s->temp.size); 456 memcpy(b->out + b->out_pos, s->temp.buf, s->temp.size);
450 b->out_pos += s->temp.size; 457 b->out_pos += s->temp.size;
@@ -467,16 +474,25 @@ XZ_EXTERN enum xz_ret XZ_FUNC xz_dec_bcj_run(struct xz_dec_bcj *s,
467 s->temp.size = b->out_pos - out_start; 474 s->temp.size = b->out_pos - out_start;
468 b->out_pos -= s->temp.size; 475 b->out_pos -= s->temp.size;
469 memcpy(s->temp.buf, b->out + b->out_pos, s->temp.size); 476 memcpy(s->temp.buf, b->out + b->out_pos, s->temp.size);
477
478 /*
479 * If there wasn't enough input to the next filter to fill
480 * the output buffer with unfiltered data, there's no point
481 * to try decoding more data to temp.
482 */
483 if (b->out_pos + s->temp.size < b->out_size)
484 return XZ_OK;
470 } 485 }
471 486
472 /* 487 /*
473 * If we have unfiltered data in temp, try to fill by decoding more 488 * We have unfiltered data in temp. If the output buffer isn't full
474 * data from the next filter. Apply the BCJ filter on temp. Then we 489 * yet, try to fill the temp buffer by decoding more data from the
475 * hopefully can fill the actual output buffer by copying filtered 490 * next filter. Apply the BCJ filter on temp. Then we hopefully can
476 * data from temp. A mix of filtered and unfiltered data may be left 491 * fill the actual output buffer by copying filtered data from temp.
477 * in temp; it will be taken care on the next call to this function. 492 * A mix of filtered and unfiltered data may be left in temp; it will
493 * be taken care on the next call to this function.
478 */ 494 */
479 if (s->temp.size > 0) { 495 if (b->out_pos < b->out_size) {
480 /* Make b->out{,_pos,_size} temporarily point to s->temp. */ 496 /* Make b->out{,_pos,_size} temporarily point to s->temp. */
481 s->out = b->out; 497 s->out = b->out;
482 s->out_pos = b->out_pos; 498 s->out_pos = b->out_pos;
diff --git a/archival/libarchive/unxz/xz_dec_lzma2.c b/archival/libarchive/unxz/xz_dec_lzma2.c
index da71cb4d4..3c2dc88b7 100644
--- a/archival/libarchive/unxz/xz_dec_lzma2.c
+++ b/archival/libarchive/unxz/xz_dec_lzma2.c
@@ -407,7 +407,6 @@ static void XZ_FUNC dict_uncompressed(
407 407
408 b->out_pos += copy_size; 408 b->out_pos += copy_size;
409 b->in_pos += copy_size; 409 b->in_pos += copy_size;
410
411 } 410 }
412} 411}
413 412
@@ -972,6 +971,9 @@ XZ_EXTERN NOINLINE enum xz_ret XZ_FUNC xz_dec_lzma2_run(
972 */ 971 */
973 tmp = b->in[b->in_pos++]; 972 tmp = b->in[b->in_pos++];
974 973
974 if (tmp == 0x00)
975 return XZ_STREAM_END;
976
975 if (tmp >= 0xE0 || tmp == 0x01) { 977 if (tmp >= 0xE0 || tmp == 0x01) {
976 s->lzma2.need_props = true; 978 s->lzma2.need_props = true;
977 s->lzma2.need_dict_reset = false; 979 s->lzma2.need_dict_reset = false;
@@ -1004,9 +1006,6 @@ XZ_EXTERN NOINLINE enum xz_ret XZ_FUNC xz_dec_lzma2_run(
1004 lzma_reset(s); 1006 lzma_reset(s);
1005 } 1007 }
1006 } else { 1008 } else {
1007 if (tmp == 0x00)
1008 return XZ_STREAM_END;
1009
1010 if (tmp > 0x02) 1009 if (tmp > 0x02)
1011 return XZ_DATA_ERROR; 1010 return XZ_DATA_ERROR;
1012 1011
diff --git a/archival/libarchive/unxz/xz_stream.h b/archival/libarchive/unxz/xz_stream.h
index 36f2a7cbf..66cb5a705 100644
--- a/archival/libarchive/unxz/xz_stream.h
+++ b/archival/libarchive/unxz/xz_stream.h
@@ -25,15 +25,20 @@
25 25
26#define STREAM_HEADER_SIZE 12 26#define STREAM_HEADER_SIZE 12
27 27
28#define HEADER_MAGIC "\3757zXZ\0" 28#define HEADER_MAGIC "\3757zXZ"
29#define HEADER_MAGIC_SIZE 6 29#define HEADER_MAGIC_SIZE 6
30 30
31#define FOOTER_MAGIC "YZ" 31#define FOOTER_MAGIC "YZ"
32#define FOOTER_MAGIC_SIZE 2 32#define FOOTER_MAGIC_SIZE 2
33 33
34/* 34/*
35 * Variable-length integer can hold a 63-bit unsigned integer, or a special 35 * Variable-length integer can hold a 63-bit unsigned integer or a special
36 * value to indicate that the value is unknown. 36 * value indicating that the value is unknown.
37 *
38 * Experimental: vli_type can be defined to uint32_t to save a few bytes
39 * in code size (no effect on speed). Doing so limits the uncompressed and
40 * compressed size of the file to less than 256 MiB and may also weaken
41 * error detection slightly.
37 */ 42 */
38typedef uint64_t vli_type; 43typedef uint64_t vli_type;
39 44
diff --git a/archival/lzop.c b/archival/lzop.c
index 56003d421..9b42e5fd3 100644
--- a/archival/lzop.c
+++ b/archival/lzop.c
@@ -436,25 +436,27 @@ struct globals {
436//#define LZOP_VERSION_STRING "1.01" 436//#define LZOP_VERSION_STRING "1.01"
437//#define LZOP_VERSION_DATE "Apr 27th 2003" 437//#define LZOP_VERSION_DATE "Apr 27th 2003"
438 438
439#define OPTION_STRING "cfvdt123456789CF" 439#define OPTION_STRING "cfvqdt123456789CF"
440 440
441/* Note: must be kept in sync with archival/bbunzip.c */
441enum { 442enum {
442 OPT_STDOUT = (1 << 0), 443 OPT_STDOUT = (1 << 0),
443 OPT_FORCE = (1 << 1), 444 OPT_FORCE = (1 << 1),
444 OPT_VERBOSE = (1 << 2), 445 OPT_VERBOSE = (1 << 2),
445 OPT_DECOMPRESS = (1 << 3), 446 OPT_QUIET = (1 << 3),
446 OPT_TEST = (1 << 4), 447 OPT_DECOMPRESS = (1 << 4),
447 OPT_1 = (1 << 5), 448 OPT_TEST = (1 << 5),
448 OPT_2 = (1 << 6), 449 OPT_1 = (1 << 6),
449 OPT_3 = (1 << 7), 450 OPT_2 = (1 << 7),
450 OPT_4 = (1 << 8), 451 OPT_3 = (1 << 8),
451 OPT_5 = (1 << 9), 452 OPT_4 = (1 << 9),
452 OPT_6 = (1 << 10), 453 OPT_5 = (1 << 10),
453 OPT_789 = (7 << 11), 454 OPT_6 = (1 << 11),
454 OPT_7 = (1 << 11), 455 OPT_789 = (7 << 12),
455 OPT_8 = (1 << 12), 456 OPT_7 = (1 << 13),
456 OPT_C = (1 << 14), 457 OPT_8 = (1 << 14),
457 OPT_F = (1 << 15), 458 OPT_C = (1 << 15),
459 OPT_F = (1 << 16),
458}; 460};
459 461
460/**********************************************************************/ 462/**********************************************************************/
@@ -1093,7 +1095,7 @@ int lzop_main(int argc UNUSED_PARAM, char **argv)
1093 if (applet_name[4] == 'c') 1095 if (applet_name[4] == 'c')
1094 option_mask32 |= (OPT_STDOUT | OPT_DECOMPRESS); 1096 option_mask32 |= (OPT_STDOUT | OPT_DECOMPRESS);
1095 /* unlzop? */ 1097 /* unlzop? */
1096 if (applet_name[0] == 'u') 1098 if (applet_name[4] == 'o')
1097 option_mask32 |= OPT_DECOMPRESS; 1099 option_mask32 |= OPT_DECOMPRESS;
1098 1100
1099 global_crc32_table = crc32_filltable(NULL, 0); 1101 global_crc32_table = crc32_filltable(NULL, 0);
diff --git a/archival/rpm.c b/archival/rpm.c
index 6757a6ceb..86ba4dca4 100644
--- a/archival/rpm.c
+++ b/archival/rpm.c
@@ -14,10 +14,10 @@
14//usage: "\nCommands:" 14//usage: "\nCommands:"
15//usage: "\n -i Install package" 15//usage: "\n -i Install package"
16//usage: "\n -qp Query package" 16//usage: "\n -qp Query package"
17//usage: "\n -i Show information" 17//usage: "\n -qpi Show information"
18//usage: "\n -l List contents" 18//usage: "\n -qpl List contents"
19//usage: "\n -d List documents" 19//usage: "\n -qpd List documents"
20//usage: "\n -c List config files" 20//usage: "\n -qpc List config files"
21 21
22#include "libbb.h" 22#include "libbb.h"
23#include "bb_archive.h" 23#include "bb_archive.h"
@@ -79,136 +79,13 @@ typedef struct {
79 uint32_t count; /* 4 byte count */ 79 uint32_t count; /* 4 byte count */
80} rpm_index; 80} rpm_index;
81 81
82static void *map; 82struct globals {
83static rpm_index **mytags; 83 void *map;
84static int tagcount; 84 rpm_index **mytags;
85 85 int tagcount;
86static void extract_cpio(int fd, const char *source_rpm); 86} FIX_ALIASING;
87static rpm_index **rpm_gettags(int fd, int *num_tags); 87#define G (*(struct globals*)&bb_common_bufsiz1)
88static int bsearch_rpmtag(const void *key, const void *item); 88#define INIT_G() do { } while (0)
89static char *rpm_getstr(int tag, int itemindex);
90static int rpm_getint(int tag, int itemindex);
91static int rpm_getcount(int tag);
92static void fileaction_dobackup(char *filename, int fileref);
93static void fileaction_setowngrp(char *filename, int fileref);
94static void loop_through_files(int filetag, void (*fileaction)(char *filename, int fileref));
95
96int rpm_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
97int rpm_main(int argc, char **argv)
98{
99 int opt = 0, func = 0, rpm_fd, offset;
100 const int pagesize = getpagesize();
101
102 while ((opt = getopt(argc, argv, "iqpldc")) != -1) {
103 switch (opt) {
104 case 'i': /* First arg: Install mode, with q: Information */
105 if (!func) func = rpm_install;
106 else func |= rpm_query_info;
107 break;
108 case 'q': /* First arg: Query mode */
109 if (func) bb_show_usage();
110 func = rpm_query;
111 break;
112 case 'p': /* Query a package */
113 func |= rpm_query_package;
114 break;
115 case 'l': /* List files in a package */
116 func |= rpm_query_list;
117 break;
118 case 'd': /* List doc files in a package (implies list) */
119 func |= rpm_query_list;
120 func |= rpm_query_list_doc;
121 break;
122 case 'c': /* List config files in a package (implies list) */
123 func |= rpm_query_list;
124 func |= rpm_query_list_config;
125 break;
126 default:
127 bb_show_usage();
128 }
129 }
130 argv += optind;
131 //argc -= optind;
132 if (!argv[0]) {
133 bb_show_usage();
134 }
135
136 while (*argv) {
137 const char *source_rpm;
138
139 rpm_fd = xopen(*argv++, O_RDONLY);
140 mytags = rpm_gettags(rpm_fd, &tagcount);
141 if (!mytags)
142 bb_error_msg_and_die("error reading rpm header");
143 offset = xlseek(rpm_fd, 0, SEEK_CUR);
144 /* Mimimum is one page */
145 map = mmap(0, offset > pagesize ? (offset + offset % pagesize) : pagesize, PROT_READ, MAP_PRIVATE, rpm_fd, 0);
146
147 source_rpm = rpm_getstr(TAG_SOURCERPM, 0);
148
149 if (func & rpm_install) {
150 /* Backup any config files */
151 loop_through_files(TAG_BASENAMES, fileaction_dobackup);
152 /* Extact the archive */
153 extract_cpio(rpm_fd, source_rpm);
154 /* Set the correct file uid/gid's */
155 loop_through_files(TAG_BASENAMES, fileaction_setowngrp);
156 }
157 else if ((func & (rpm_query|rpm_query_package)) == (rpm_query|rpm_query_package)) {
158 if (!(func & (rpm_query_info|rpm_query_list))) {
159 /* If just a straight query, just give package name */
160 printf("%s-%s-%s\n", rpm_getstr(TAG_NAME, 0), rpm_getstr(TAG_VERSION, 0), rpm_getstr(TAG_RELEASE, 0));
161 }
162 if (func & rpm_query_info) {
163 /* Do the nice printout */
164 time_t bdate_time;
165 struct tm *bdate_ptm;
166 char bdatestring[50];
167 const char *p;
168
169 p = rpm_getstr(TAG_PREFIXS, 0);
170 if (!p) p = "(not relocateable)";
171 printf("Name : %-29sRelocations: %s\n", rpm_getstr(TAG_NAME, 0), p);
172 p = rpm_getstr(TAG_VENDOR, 0);
173 if (!p) p = "(none)";
174 printf("Version : %-34sVendor: %s\n", rpm_getstr(TAG_VERSION, 0), p);
175 bdate_time = rpm_getint(TAG_BUILDTIME, 0);
176 bdate_ptm = localtime(&bdate_time);
177 strftime(bdatestring, 50, "%a %d %b %Y %T %Z", bdate_ptm);
178 printf("Release : %-30sBuild Date: %s\n", rpm_getstr(TAG_RELEASE, 0), bdatestring);
179 printf("Install date: %-30sBuild Host: %s\n", "(not installed)", rpm_getstr(TAG_BUILDHOST, 0));
180 printf("Group : %-30sSource RPM: %s\n", rpm_getstr(TAG_GROUP, 0), source_rpm);
181 printf("Size : %-33dLicense: %s\n", rpm_getint(TAG_SIZE, 0), rpm_getstr(TAG_LICENSE, 0));
182 printf("URL : %s\n", rpm_getstr(TAG_URL, 0));
183 printf("Summary : %s\n", rpm_getstr(TAG_SUMMARY, 0));
184 printf("Description :\n%s\n", rpm_getstr(TAG_DESCRIPTION, 0));
185 }
186 if (func & rpm_query_list) {
187 int count, it, flags;
188 count = rpm_getcount(TAG_BASENAMES);
189 for (it = 0; it < count; it++) {
190 flags = rpm_getint(TAG_FILEFLAGS, it);
191 switch (func & (rpm_query_list_doc|rpm_query_list_config)) {
192 case rpm_query_list_doc:
193 if (!(flags & RPMFILE_DOC)) continue;
194 break;
195 case rpm_query_list_config:
196 if (!(flags & RPMFILE_CONFIG)) continue;
197 break;
198 case rpm_query_list_doc|rpm_query_list_config:
199 if (!(flags & (RPMFILE_CONFIG|RPMFILE_DOC))) continue;
200 break;
201 }
202 printf("%s%s\n",
203 rpm_getstr(TAG_DIRNAMES, rpm_getint(TAG_DIRINDEXES, it)),
204 rpm_getstr(TAG_BASENAMES, it));
205 }
206 }
207 }
208 free(mytags);
209 }
210 return 0;
211}
212 89
213static void extract_cpio(int fd, const char *source_rpm) 90static void extract_cpio(int fd, const char *source_rpm)
214{ 91{
@@ -231,8 +108,8 @@ static void extract_cpio(int fd, const char *source_rpm)
231 /* compat: overwrite existing files. 108 /* compat: overwrite existing files.
232 * try "rpm -i foo.src.rpm" few times in a row - 109 * try "rpm -i foo.src.rpm" few times in a row -
233 * standard rpm will not complain. 110 * standard rpm will not complain.
234 * (TODO? real rpm creates "file;1234" and then renames it) */ 111 */
235 | ARCHIVE_UNLINK_OLD; 112 | ARCHIVE_REPLACE_VIA_RENAME;
236 archive_handle->src_fd = fd; 113 archive_handle->src_fd = fd;
237 /*archive_handle->offset = 0; - init_handle() did it */ 114 /*archive_handle->offset = 0; - init_handle() did it */
238 115
@@ -294,7 +171,7 @@ static int bsearch_rpmtag(const void *key, const void *item)
294static int rpm_getcount(int tag) 171static int rpm_getcount(int tag)
295{ 172{
296 rpm_index **found; 173 rpm_index **found;
297 found = bsearch(&tag, mytags, tagcount, sizeof(struct rpmtag *), bsearch_rpmtag); 174 found = bsearch(&tag, G.mytags, G.tagcount, sizeof(struct rpmtag *), bsearch_rpmtag);
298 if (!found) 175 if (!found)
299 return 0; 176 return 0;
300 return found[0]->count; 177 return found[0]->count;
@@ -303,7 +180,7 @@ static int rpm_getcount(int tag)
303static char *rpm_getstr(int tag, int itemindex) 180static char *rpm_getstr(int tag, int itemindex)
304{ 181{
305 rpm_index **found; 182 rpm_index **found;
306 found = bsearch(&tag, mytags, tagcount, sizeof(struct rpmtag *), bsearch_rpmtag); 183 found = bsearch(&tag, G.mytags, G.tagcount, sizeof(struct rpmtag *), bsearch_rpmtag);
307 if (!found || itemindex >= found[0]->count) 184 if (!found || itemindex >= found[0]->count)
308 return NULL; 185 return NULL;
309 if (found[0]->type == RPM_STRING_TYPE 186 if (found[0]->type == RPM_STRING_TYPE
@@ -311,7 +188,7 @@ static char *rpm_getstr(int tag, int itemindex)
311 || found[0]->type == RPM_STRING_ARRAY_TYPE 188 || found[0]->type == RPM_STRING_ARRAY_TYPE
312 ) { 189 ) {
313 int n; 190 int n;
314 char *tmpstr = (char *) map + found[0]->offset; 191 char *tmpstr = (char *) G.map + found[0]->offset;
315 for (n = 0; n < itemindex; n++) 192 for (n = 0; n < itemindex; n++)
316 tmpstr = tmpstr + strlen(tmpstr) + 1; 193 tmpstr = tmpstr + strlen(tmpstr) + 1;
317 return tmpstr; 194 return tmpstr;
@@ -322,32 +199,25 @@ static char *rpm_getstr(int tag, int itemindex)
322static int rpm_getint(int tag, int itemindex) 199static int rpm_getint(int tag, int itemindex)
323{ 200{
324 rpm_index **found; 201 rpm_index **found;
325 int *tmpint; /* NB: using int8_t* would be easier to code */ 202 char *tmpint;
326 203
327 /* gcc throws warnings here when sizeof(void*)!=sizeof(int) ... 204 /* gcc throws warnings here when sizeof(void*)!=sizeof(int) ...
328 * it's ok to ignore it because tag won't be used as a pointer */ 205 * it's ok to ignore it because tag won't be used as a pointer */
329 found = bsearch(&tag, mytags, tagcount, sizeof(struct rpmtag *), bsearch_rpmtag); 206 found = bsearch(&tag, G.mytags, G.tagcount, sizeof(struct rpmtag *), bsearch_rpmtag);
330 if (!found || itemindex >= found[0]->count) 207 if (!found || itemindex >= found[0]->count)
331 return -1; 208 return -1;
332 209
333 tmpint = (int *) ((char *) map + found[0]->offset); 210 tmpint = (char *) G.map + found[0]->offset;
334
335 if (found[0]->type == RPM_INT32_TYPE) { 211 if (found[0]->type == RPM_INT32_TYPE) {
336 tmpint = (int *) ((char *) tmpint + itemindex*4); 212 tmpint += itemindex*4;
337 /*return ntohl(*tmpint);*/
338 /* int can be != int32_t */
339 return ntohl(*(int32_t*)tmpint); 213 return ntohl(*(int32_t*)tmpint);
340 } 214 }
341 if (found[0]->type == RPM_INT16_TYPE) { 215 if (found[0]->type == RPM_INT16_TYPE) {
342 tmpint = (int *) ((char *) tmpint + itemindex*2); 216 tmpint += itemindex*2;
343 /* ??? read int, and THEN ntohs() it?? */
344 /*return ntohs(*tmpint);*/
345 return ntohs(*(int16_t*)tmpint); 217 return ntohs(*(int16_t*)tmpint);
346 } 218 }
347 if (found[0]->type == RPM_INT8_TYPE) { 219 if (found[0]->type == RPM_INT8_TYPE) {
348 tmpint = (int *) ((char *) tmpint + itemindex); 220 tmpint += itemindex;
349 /* ??? why we don't read byte here??? */
350 /*return ntohs(*tmpint);*/
351 return *(int8_t*)tmpint; 221 return *(int8_t*)tmpint;
352 } 222 }
353 return -1; 223 return -1;
@@ -392,3 +262,134 @@ static void loop_through_files(int filetag, void (*fileaction)(char *filename, i
392 free(filename); 262 free(filename);
393 } 263 }
394} 264}
265
266int rpm_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
267int rpm_main(int argc, char **argv)
268{
269 int opt, func = 0;
270 const unsigned pagesize = getpagesize();
271
272 while ((opt = getopt(argc, argv, "iqpldc")) != -1) {
273 switch (opt) {
274 case 'i': /* First arg: Install mode, with q: Information */
275 if (!func) func = rpm_install;
276 else func |= rpm_query_info;
277 break;
278 case 'q': /* First arg: Query mode */
279 if (func) bb_show_usage();
280 func = rpm_query;
281 break;
282 case 'p': /* Query a package */
283 func |= rpm_query_package;
284 break;
285 case 'l': /* List files in a package */
286 func |= rpm_query_list;
287 break;
288 case 'd': /* List doc files in a package (implies list) */
289 func |= rpm_query_list;
290 func |= rpm_query_list_doc;
291 break;
292 case 'c': /* List config files in a package (implies list) */
293 func |= rpm_query_list;
294 func |= rpm_query_list_config;
295 break;
296 default:
297 bb_show_usage();
298 }
299 }
300 argv += optind;
301 //argc -= optind;
302 if (!argv[0]) {
303 bb_show_usage();
304 }
305
306 while (*argv) {
307 int rpm_fd;
308 unsigned mapsize;
309 const char *source_rpm;
310
311 rpm_fd = xopen(*argv++, O_RDONLY);
312 G.mytags = rpm_gettags(rpm_fd, &G.tagcount);
313 if (!G.mytags)
314 bb_error_msg_and_die("error reading rpm header");
315 mapsize = xlseek(rpm_fd, 0, SEEK_CUR);
316 mapsize = (mapsize + pagesize) & -(int)pagesize;
317 /* Some NOMMU systems prefer MAP_PRIVATE over MAP_SHARED */
318 G.map = mmap(0, mapsize, PROT_READ, MAP_PRIVATE, rpm_fd, 0);
319//FIXME: error check?
320
321 source_rpm = rpm_getstr(TAG_SOURCERPM, 0);
322
323 if (func & rpm_install) {
324 /* Backup any config files */
325 loop_through_files(TAG_BASENAMES, fileaction_dobackup);
326 /* Extact the archive */
327 extract_cpio(rpm_fd, source_rpm);
328 /* Set the correct file uid/gid's */
329 loop_through_files(TAG_BASENAMES, fileaction_setowngrp);
330 }
331 else if ((func & (rpm_query|rpm_query_package)) == (rpm_query|rpm_query_package)) {
332 if (!(func & (rpm_query_info|rpm_query_list))) {
333 /* If just a straight query, just give package name */
334 printf("%s-%s-%s\n", rpm_getstr(TAG_NAME, 0), rpm_getstr(TAG_VERSION, 0), rpm_getstr(TAG_RELEASE, 0));
335 }
336 if (func & rpm_query_info) {
337 /* Do the nice printout */
338 time_t bdate_time;
339 struct tm *bdate_ptm;
340 char bdatestring[50];
341 const char *p;
342
343 printf("%-12s: %s\n", "Name" , rpm_getstr(TAG_NAME, 0));
344 /* TODO compat: add "Epoch" here */
345 printf("%-12s: %s\n", "Version" , rpm_getstr(TAG_VERSION, 0));
346 printf("%-12s: %s\n", "Release" , rpm_getstr(TAG_RELEASE, 0));
347 /* add "Architecture" */
348 printf("%-12s: %s\n", "Install Date", "(not installed)");
349 printf("%-12s: %s\n", "Group" , rpm_getstr(TAG_GROUP, 0));
350 printf("%-12s: %d\n", "Size" , rpm_getint(TAG_SIZE, 0));
351 printf("%-12s: %s\n", "License" , rpm_getstr(TAG_LICENSE, 0));
352 /* add "Signature" */
353 printf("%-12s: %s\n", "Source RPM" , source_rpm ? source_rpm : "(none)");
354 bdate_time = rpm_getint(TAG_BUILDTIME, 0);
355 bdate_ptm = localtime(&bdate_time);
356 strftime(bdatestring, 50, "%a %d %b %Y %T %Z", bdate_ptm);
357 printf("%-12s: %s\n", "Build Date" , bdatestring);
358 printf("%-12s: %s\n", "Build Host" , rpm_getstr(TAG_BUILDHOST, 0));
359 p = rpm_getstr(TAG_PREFIXS, 0);
360 printf("%-12s: %s\n", "Relocations" , p ? p : "(not relocatable)");
361 /* add "Packager" */
362 p = rpm_getstr(TAG_VENDOR, 0);
363 printf("%-12s: %s\n", "Vendor" , p ? p : "(none)");
364 printf("%-12s: %s\n", "URL" , rpm_getstr(TAG_URL, 0));
365 printf("%-12s: %s\n", "Summary" , rpm_getstr(TAG_SUMMARY, 0));
366 printf("Description :\n%s\n", rpm_getstr(TAG_DESCRIPTION, 0));
367 }
368 if (func & rpm_query_list) {
369 int count, it, flags;
370 count = rpm_getcount(TAG_BASENAMES);
371 for (it = 0; it < count; it++) {
372 flags = rpm_getint(TAG_FILEFLAGS, it);
373 switch (func & (rpm_query_list_doc|rpm_query_list_config)) {
374 case rpm_query_list_doc:
375 if (!(flags & RPMFILE_DOC)) continue;
376 break;
377 case rpm_query_list_config:
378 if (!(flags & RPMFILE_CONFIG)) continue;
379 break;
380 case rpm_query_list_doc|rpm_query_list_config:
381 if (!(flags & (RPMFILE_CONFIG|RPMFILE_DOC))) continue;
382 break;
383 }
384 printf("%s%s\n",
385 rpm_getstr(TAG_DIRNAMES, rpm_getint(TAG_DIRINDEXES, it)),
386 rpm_getstr(TAG_BASENAMES, it));
387 }
388 }
389 }
390 munmap(G.map, mapsize);
391 free(G.mytags);
392 close(rpm_fd);
393 }
394 return 0;
395}