]> git.ipfire.org Git - thirdparty/systemd.git/blobdiff - src/journal/compress.c
Merge pull request #2495 from heftig/master
[thirdparty/systemd.git] / src / journal / compress.c
index e1ca0a8818edd6cbc6394e2ac1e8735b58f366cb..1933b87b009dce16578d4094e036f9df77ab25b7 100644 (file)
@@ -1,5 +1,3 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
 /***
   This file is part of systemd.
 
@@ -58,7 +56,8 @@ static const char* const object_compressed_table[_OBJECT_COMPRESSED_MAX] = {
 
 DEFINE_STRING_TABLE_LOOKUP(object_compressed, int);
 
-int compress_blob_xz(const void *src, uint64_t src_size, void *dst, size_t *dst_size) {
+int compress_blob_xz(const void *src, uint64_t src_size,
+                     void *dst, size_t dst_alloc_size, size_t *dst_size) {
 #ifdef HAVE_XZ
         static const lzma_options_lzma opt = {
                 1u << 20u, NULL, 0, LZMA_LC_DEFAULT, LZMA_LP_DEFAULT,
@@ -74,6 +73,7 @@ int compress_blob_xz(const void *src, uint64_t src_size, void *dst, size_t *dst_
         assert(src);
         assert(src_size > 0);
         assert(dst);
+        assert(dst_alloc_size > 0);
         assert(dst_size);
 
         /* Returns < 0 if we couldn't compress the data or the
@@ -83,7 +83,7 @@ int compress_blob_xz(const void *src, uint64_t src_size, void *dst, size_t *dst_
                 return -ENOBUFS;
 
         ret = lzma_stream_buffer_encode((lzma_filter*) filters, LZMA_CHECK_NONE, NULL,
-                                        src, src_size, dst, &out_pos, src_size - 1);
+                                        src, src_size, dst, &out_pos, dst_alloc_size);
         if (ret != LZMA_OK)
                 return -ENOBUFS;
 
@@ -94,13 +94,15 @@ int compress_blob_xz(const void *src, uint64_t src_size, void *dst, size_t *dst_
 #endif
 }
 
-int compress_blob_lz4(const void *src, uint64_t src_size, void *dst, size_t *dst_size) {
+int compress_blob_lz4(const void *src, uint64_t src_size,
+                      void *dst, size_t dst_alloc_size, size_t *dst_size) {
 #ifdef HAVE_LZ4
         int r;
 
         assert(src);
         assert(src_size > 0);
         assert(dst);
+        assert(dst_alloc_size > 0);
         assert(dst_size);
 
         /* Returns < 0 if we couldn't compress the data or the
@@ -109,7 +111,7 @@ int compress_blob_lz4(const void *src, uint64_t src_size, void *dst, size_t *dst
         if (src_size < 9)
                 return -ENOBUFS;
 
-        r = LZ4_compress_limitedOutput(src, dst + 8, src_size, src_size - 8 - 1);
+        r = LZ4_compress_limitedOutput(src, dst + 8, src_size, (int) dst_alloc_size - 8);
         if (r <= 0)
                 return -ENOBUFS;
 
@@ -201,7 +203,7 @@ int decompress_blob_lz4(const void *src, uint64_t src_size,
                 return -EBADMSG;
 
         size = le64toh( *(le64_t*)src );
-        if (size < 0 || (le64_t) size != *(le64_t*)src)
+        if (size < 0 || (unsigned) size != le64toh(*(le64_t*)src))
                 return -EFBIG;
         if ((size_t) size > *dst_alloc_size) {
                 out = realloc(*dst, size);
@@ -306,6 +308,7 @@ int decompress_startswith_lz4(const void *src, uint64_t src_size,
          * prefix */
 
         int r;
+        size_t size;
 
         assert(src);
         assert(src_size > 0);
@@ -322,10 +325,18 @@ int decompress_startswith_lz4(const void *src, uint64_t src_size,
 
         r = LZ4_decompress_safe_partial(src + 8, *buffer, src_size - 8,
                                         prefix_len + 1, *buffer_size);
+        if (r >= 0)
+                size = (unsigned) r;
+        else {
+                /* lz4 always tries to decode full "sequence", so in
+                 * pathological cases might need to decompress the
+                 * full field. */
+                r = decompress_blob_lz4(src, src_size, buffer, buffer_size, &size, 0);
+                if (r < 0)
+                        return r;
+        }
 
-        if (r < 0)
-                return -EBADMSG;
-        if ((unsigned) r >= prefix_len + 1)
+        if (size >= prefix_len + 1)
                 return memcmp(*buffer, prefix, prefix_len) == 0 &&
                         ((const uint8_t*) *buffer)[prefix_len] == extra;
         else
@@ -438,7 +449,7 @@ int compress_stream_lz4(int fdf, int fdt, uint64_t max_bytes) {
         _cleanup_(LZ4F_freeCompressionContextp) LZ4F_compressionContext_t ctx = NULL;
         _cleanup_free_ char *buf = NULL;
         char *src = NULL;
-        size_t size, n, total_in = 0, total_out = 0, offset = 0, frame_size;
+        size_t size, n, total_in = 0, total_out, offset = 0, frame_size;
         struct stat st;
         int r;
         static const LZ4F_compressOptions_t options = {
@@ -461,7 +472,7 @@ int compress_stream_lz4(int fdf, int fdt, uint64_t max_bytes) {
         if (!buf)
                 return -ENOMEM;
 
-        n = offset = LZ4F_compressBegin(ctx, buf, size, &preferences);
+        n = offset = total_out = LZ4F_compressBegin(ctx, buf, size, &preferences);
         if (LZ4F_isError(n))
                 return -EINVAL;
 
@@ -599,80 +610,8 @@ int decompress_stream_xz(int fdf, int fdt, uint64_t max_bytes) {
 #endif
 }
 
+int decompress_stream_lz4(int in, int out, uint64_t max_bytes) {
 #ifdef HAVE_LZ4
-static int decompress_stream_lz4_v1(int fdf, int fdt, uint64_t max_bytes) {
-
-        _cleanup_free_ char *buf = NULL, *out = NULL;
-        size_t buf_size = 0;
-        LZ4_streamDecode_t lz4_data = {};
-        le32_t header;
-        size_t total_in = sizeof(header), total_out = 0;
-
-        assert(fdf >= 0);
-        assert(fdt >= 0);
-
-        out = malloc(4*LZ4_BUFSIZE);
-        if (!out)
-                return -ENOMEM;
-
-        for (;;) {
-                ssize_t m;
-                int r;
-
-                r = loop_read_exact(fdf, &header, sizeof(header), false);
-                if (r < 0)
-                        return r;
-
-                m = le32toh(header);
-                if (m == 0)
-                        break;
-
-                /* We refuse to use a bigger decompression buffer than
-                 * the one used for compression by 4 times. This means
-                 * that compression buffer size can be enlarged 4
-                 * times. This can be changed, but old binaries might
-                 * not accept buffers compressed by newer binaries then.
-                 */
-                if (m > LZ4_COMPRESSBOUND(LZ4_BUFSIZE * 4)) {
-                        log_debug("Compressed stream block too big: %zd bytes", m);
-                        return -ENOBUFS;
-                }
-
-                total_in += sizeof(header) + m;
-
-                if (!GREEDY_REALLOC(buf, buf_size, m))
-                        return -ENOMEM;
-
-                r = loop_read_exact(fdf, buf, m, false);
-                if (r < 0)
-                        return r;
-
-                r = LZ4_decompress_safe_continue(&lz4_data, buf, out, m, 4*LZ4_BUFSIZE);
-                if (r <= 0) {
-                        log_debug("LZ4 decompression failed (legacy format).");
-                        return -EBADMSG;
-                }
-
-                total_out += r;
-
-                if (max_bytes != (uint64_t) -1 && (uint64_t) total_out > max_bytes) {
-                        log_debug("Decompressed stream longer than %" PRIu64 " bytes", max_bytes);
-                        return -EFBIG;
-                }
-
-                r = loop_write(fdt, out, r, false);
-                if (r < 0)
-                        return r;
-        }
-
-        log_debug("LZ4 decompression finished (legacy format, %zu -> %zu bytes, %.1f%%)",
-                  total_in, total_out,
-                  (double) total_out / total_in * 100);
-
-        return 0;
-}
-
-static int decompress_stream_lz4_v2(int in, int out, uint64_t max_bytes) {
         size_t c;
         _cleanup_(LZ4F_freeDecompressionContextp) LZ4F_decompressionContext_t ctx = NULL;
         _cleanup_free_ char *buf = NULL;
@@ -726,17 +665,6 @@ static int decompress_stream_lz4_v2(int in, int out, uint64_t max_bytes) {
  cleanup:
         munmap(src, st.st_size);
         return r;
-}
-#endif
-
-int decompress_stream_lz4(int fdf, int fdt, uint64_t max_bytes) {
-#ifdef HAVE_LZ4
-        int r;
-
-        r = decompress_stream_lz4_v2(fdf, fdt, max_bytes);
-        if (r == -EBADMSG)
-                r = decompress_stream_lz4_v1(fdf, fdt, max_bytes);
-        return r;
 #else
         log_debug("Cannot decompress file. Compiled without LZ4 support.");
         return -EPROTONOSUPPORT;