]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/blobdiff - lib/decompress_unlzo.c
Decompressors: fix callback-to-callback mode in decompress_unlzo.c
[mirror_ubuntu-bionic-kernel.git] / lib / decompress_unlzo.c
index 7eb3b80bf02220c1ffc018a6f25dab98726b90f9..5a7a2adf4c4c2aa8d64d881e0ff1739acbe8782c 100644 (file)
@@ -139,8 +139,8 @@ STATIC inline int INIT unlzo(u8 *input, int in_len,
                goto exit_1;
        } else if (input) {
                in_buf = input;
-       } else if (!fill || !posp) {
-               error("NULL input pointer and missing position pointer or fill function");
+       } else if (!fill) {
+               error("NULL input pointer and missing fill function");
                goto exit_1;
        } else {
                in_buf = malloc(lzo1x_worst_compress(LZO_BLOCK_SIZE));
@@ -154,21 +154,40 @@ STATIC inline int INIT unlzo(u8 *input, int in_len,
        if (posp)
                *posp = 0;
 
-       if (fill)
-               fill(in_buf, lzo1x_worst_compress(LZO_BLOCK_SIZE));
+       if (fill) {
+               /*
+                * Start from in_buf + HEADER_SIZE_MAX to make it possible
+                * to use memcpy() to copy the unused data to the beginning
+                * of the buffer. This way memmove() isn't needed which
+                * is missing from pre-boot environments of most archs.
+                */
+               in_buf += HEADER_SIZE_MAX;
+               in_len = fill(in_buf, HEADER_SIZE_MAX);
+       }
 
-       if (!parse_header(input, &skip, in_len)) {
+       if (!parse_header(in_buf, &skip, in_len)) {
                error("invalid header");
                goto exit_2;
        }
        in_buf += skip;
        in_len -= skip;
 
+       if (fill) {
+               /* Move the unused data to the beginning of the buffer. */
+               memcpy(in_buf_save, in_buf, in_len);
+               in_buf = in_buf_save;
+       }
+
        if (posp)
                *posp = skip;
 
        for (;;) {
                /* read uncompressed block size */
+               if (fill && in_len < 4) {
+                       skip = fill(in_buf + in_len, 4 - in_len);
+                       if (skip > 0)
+                               in_len += skip;
+               }
                if (in_len < 4) {
                        error("file corrupted");
                        goto exit_2;
@@ -190,6 +209,11 @@ STATIC inline int INIT unlzo(u8 *input, int in_len,
                }
 
                /* read compressed block size, and skip block checksum info */
+               if (fill && in_len < 8) {
+                       skip = fill(in_buf + in_len, 8 - in_len);
+                       if (skip > 0)
+                               in_len += skip;
+               }
                if (in_len < 8) {
                        error("file corrupted");
                        goto exit_2;
@@ -198,12 +222,21 @@ STATIC inline int INIT unlzo(u8 *input, int in_len,
                in_buf += 8;
                in_len -= 8;
 
-               if (src_len <= 0 || src_len > dst_len || src_len > in_len) {
+               if (src_len <= 0 || src_len > dst_len) {
                        error("file corrupted");
                        goto exit_2;
                }
 
                /* decompress */
+               if (fill && in_len < src_len) {
+                       skip = fill(in_buf + in_len, src_len - in_len);
+                       if (skip > 0)
+                               in_len += skip;
+               }
+               if (in_len < src_len) {
+                       error("file corrupted");
+                       goto exit_2;
+               }
                tmp = dst_len;
 
                /* When the input data is not compressed at all,
@@ -227,12 +260,19 @@ STATIC inline int INIT unlzo(u8 *input, int in_len,
                        out_buf += dst_len;
                if (posp)
                        *posp += src_len + 12;
+
+               in_buf += src_len;
+               in_len -= src_len;
                if (fill) {
+                       /*
+                        * If there happens to still be unused data left in
+                        * in_buf, move it to the beginning of the buffer.
+                        * Use a loop to avoid memmove() dependency.
+                        */
+                       if (in_len > 0)
+                               for (skip = 0; skip < in_len; ++skip)
+                                       in_buf_save[skip] = in_buf[skip];
                        in_buf = in_buf_save;
-                       fill(in_buf, lzo1x_worst_compress(LZO_BLOCK_SIZE));
-               } else {
-                       in_buf += src_len;
-                       in_len -= src_len;
                }
        }