libarchive: treat one "FIXME: avoid seek"
authorDenys Vlasenko <vda.linux@googlemail.com>
Fri, 24 May 2019 15:03:28 +0000 (17:03 +0200)
committerDenys Vlasenko <vda.linux@googlemail.com>
Fri, 24 May 2019 15:03:28 +0000 (17:03 +0200)
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@googlemail.com>
archival/libarchive/open_transformer.c
include/bb_archive.h
include/libbb.h
libbb/read_printf.c

index 4a4bf391683ec904152e9219c52152d5b18ee39e..97bcc32f09e7ae3b71fe83e74ca16926a2ae8dbc 100644 (file)
@@ -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)
index 561dd0c9dc4709288b2ce833aa23510042803385..9b1db5b3e751ecbf575a0026d6c5a2b7729b9336 100644 (file)
@@ -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;
index 57cfce385336efafb6b089a47c6850ece2d2c110..33766e989c07fe330e10e5006f1b8006dda7f20f 100644 (file)
@@ -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 */
index b6a17cc364a45a713366843ffaf1e3609379a344..cb582c0807abeeb2a826957b8ad328aafae3f94a 100644 (file)
@@ -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