[git commit] libarchive: treat one "FIXME: avoid seek"

Denys Vlasenko vda.linux at googlemail.com
Fri May 24 15:03:28 UTC 2019


commit: https://git.busybox.net/busybox/commit/?id=dff2bd733fc2dac08d34f2cfad0e68aeb8e7a7a2
branch: https://git.busybox.net/busybox/commit/?id=refs/heads/master

function                                             old     new   delta
xmalloc_read_with_initial_buf                          -     205    +205
setup_transformer_on_fd                              154     150      -4
xmalloc_open_zipped_read_close                       143     135      -8
xmalloc_read                                         201      10    -191
------------------------------------------------------------------------------
(add/remove: 1/0 grow/shrink: 0/3 up/down: 205/-203)            Total: 2 bytes

Signed-off-by: Denys Vlasenko <vda.linux at googlemail.com>
---
 archival/libarchive/open_transformer.c | 44 +++++++++++++++++++++-------------
 include/bb_archive.h                   |  6 +++++
 include/libbb.h                        |  1 +
 libbb/read_printf.c                    | 12 ++++++----
 4 files changed, 41 insertions(+), 22 deletions(-)

diff --git a/archival/libarchive/open_transformer.c b/archival/libarchive/open_transformer.c
index 4a4bf3916..97bcc32f0 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 561dd0c9d..9b1db5b3e 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 57cfce385..33766e989 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 b6a17cc36..cb582c080 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


More information about the busybox-cvs mailing list