summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--archival/libarchive/open_transformer.c44
-rw-r--r--include/bb_archive.h6
-rw-r--r--include/libbb.h1
-rw-r--r--libbb/read_printf.c12
4 files changed, 41 insertions, 22 deletions
diff --git a/archival/libarchive/open_transformer.c b/archival/libarchive/open_transformer.c
index 4a4bf39..97bcc32 100644
--- a/archival/libarchive/open_transformer.c
+++ b/archival/libarchive/open_transformer.c
@@ -159,47 +159,44 @@ void FAST_FUNC fork_transformer(int fd, const char *transform_prog)
*/
static transformer_state_t *setup_transformer_on_fd(int fd, int fail_if_not_compressed)
{
- union {
- uint8_t b[4];
- uint16_t b16[2];
- uint32_t b32[1];
- } magic;
transformer_state_t *xstate;
xstate = xzalloc(sizeof(*xstate));
xstate->src_fd = fd;
- xstate->signature_skipped = 2;
/* .gz and .bz2 both have 2-byte signature, and their
* unpack_XXX_stream wants this header skipped. */
- xread(fd, magic.b16, sizeof(magic.b16[0]));
+ xstate->signature_skipped = 2;
+ xread(fd, xstate->magic.b16, 2);
if (ENABLE_FEATURE_SEAMLESS_GZ
- && magic.b16[0] == GZIP_MAGIC
+ && xstate->magic.b16[0] == GZIP_MAGIC
) {
xstate->xformer = unpack_gz_stream;
USE_FOR_NOMMU(xstate->xformer_prog = "gunzip";)
goto found_magic;
}
if (ENABLE_FEATURE_SEAMLESS_Z
- && magic.b16[0] == COMPRESS_MAGIC
+ && xstate->magic.b16[0] == COMPRESS_MAGIC
) {
xstate->xformer = unpack_Z_stream;
USE_FOR_NOMMU(xstate->xformer_prog = "uncompress";)
goto found_magic;
}
if (ENABLE_FEATURE_SEAMLESS_BZ2
- && magic.b16[0] == BZIP2_MAGIC
+ && xstate->magic.b16[0] == BZIP2_MAGIC
) {
xstate->xformer = unpack_bz2_stream;
USE_FOR_NOMMU(xstate->xformer_prog = "bunzip2";)
goto found_magic;
}
if (ENABLE_FEATURE_SEAMLESS_XZ
- && magic.b16[0] == XZ_MAGIC1
+ && xstate->magic.b16[0] == XZ_MAGIC1
) {
+ uint32_t v32;
xstate->signature_skipped = 6;
- xread(fd, magic.b32, sizeof(magic.b32[0]));
- if (magic.b32[0] == XZ_MAGIC2) {
+ xread(fd, &xstate->magic.b16[1], 4);
+ move_from_unaligned32(v32, &xstate->magic.b16[1]);
+ if (v32 == XZ_MAGIC2) {
xstate->xformer = unpack_xz_stream;
USE_FOR_NOMMU(xstate->xformer_prog = "unxz";)
goto found_magic;
@@ -344,11 +341,24 @@ void* FAST_FUNC xmalloc_open_zipped_read_close(const char *fname, size_t *maxsz_
*maxsz_p = xstate->mem_output_size;
}
} else {
- /* File is not compressed */
-//FIXME: avoid seek
- xlseek(xstate->src_fd, - xstate->signature_skipped, SEEK_CUR);
+ /* File is not compressed.
+ * We already read first few bytes, account for that.
+ * Exmaple where it happens:
+ * "modinfo MODULE.ko" (not compressed)
+ * open("MODULE.ko", O_RDONLY|O_LARGEFILE) = 4
+ * read(4, "\177E", 2) = 2
+ * fstat64(4, ...)
+ * mmap(...)
+ * read(4, "LF\2\1\1\0\0\0\0"...
+ * ...and we avoided seeking on the fd! :)
+ */
xstate->signature_skipped = 0;
- image = xmalloc_read(xstate->src_fd, maxsz_p);
+ image = xmalloc_read_with_initial_buf(
+ xstate->src_fd,
+ maxsz_p,
+ xmemdup(&xstate->magic, xstate->signature_skipped),
+ xstate->signature_skipped
+ );
}
if (!image)
diff --git a/include/bb_archive.h b/include/bb_archive.h
index 561dd0c..9b1db5b 100644
--- a/include/bb_archive.h
+++ b/include/bb_archive.h
@@ -235,6 +235,12 @@ typedef struct transformer_state_t {
off_t bytes_in; /* used in unzip code only: needs to know packed size */
uint32_t crc32;
time_t mtime; /* gunzip code may set this on exit */
+
+ union { /* if we read magic, it's saved here */
+ uint8_t b[8];
+ uint16_t b16[4];
+ uint32_t b32[2];
+ } magic;
} transformer_state_t;
void init_transformer_state(transformer_state_t *xstate) FAST_FUNC;
diff --git a/include/libbb.h b/include/libbb.h
index 57cfce3..33766e9 100644
--- a/include/libbb.h
+++ b/include/libbb.h
@@ -881,6 +881,7 @@ extern ssize_t open_read_close(const char *filename, void *buf, size_t maxsz) FA
extern char *xmalloc_reads(int fd, size_t *maxsz_p) FAST_FUNC;
/* Reads block up to *maxsz_p (default: INT_MAX - 4095) */
extern void *xmalloc_read(int fd, size_t *maxsz_p) FAST_FUNC RETURNS_MALLOC;
+extern void *xmalloc_read_with_initial_buf(int fd, size_t *maxsz_p, char *buf, size_t total) FAST_FUNC;
/* Returns NULL if file can't be opened (default max size: INT_MAX - 4095) */
extern void *xmalloc_open_read_close(const char *filename, size_t *maxsz_p) FAST_FUNC RETURNS_MALLOC;
/* Never returns NULL */
diff --git a/libbb/read_printf.c b/libbb/read_printf.c
index b6a17cc..cb582c0 100644
--- a/libbb/read_printf.c
+++ b/libbb/read_printf.c
@@ -102,10 +102,9 @@ char* FAST_FUNC xmalloc_reads(int fd, size_t *maxsz_p)
// Read (potentially big) files in one go. File size is estimated
// by stat. Extra '\0' byte is appended.
-void* FAST_FUNC xmalloc_read(int fd, size_t *maxsz_p)
+void* FAST_FUNC xmalloc_read_with_initial_buf(int fd, size_t *maxsz_p, char *buf, size_t total)
{
- char *buf;
- size_t size, rd_size, total;
+ size_t size, rd_size;
size_t to_read;
struct stat st;
@@ -118,8 +117,6 @@ void* FAST_FUNC xmalloc_read(int fd, size_t *maxsz_p)
/* In order to make such files readable, we add small const */
size = (st.st_size | 0x3ff) + 1;
- total = 0;
- buf = NULL;
while (1) {
if (to_read < size)
size = to_read;
@@ -148,6 +145,11 @@ void* FAST_FUNC xmalloc_read(int fd, size_t *maxsz_p)
return buf;
}
+void* FAST_FUNC xmalloc_read(int fd, size_t *maxsz_p)
+{
+ return xmalloc_read_with_initial_buf(fd, maxsz_p, NULL, 0);
+}
+
#ifdef USING_LSEEK_TO_GET_SIZE
/* Alternatively, file size can be obtained by lseek to the end.
* The code is slightly bigger. Retained in case fstat approach