LCOV - code coverage report
Current view: top level - journal - compress.c (source / functions) Hit Total Coverage
Test: systemd test coverage Lines: 130 184 70.7 %
Date: 2015-07-29 18:47:03 Functions: 8 15 53.3 %

          Line data    Source code
       1             : /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
       2             : 
       3             : /***
       4             :   This file is part of systemd.
       5             : 
       6             :   Copyright 2011 Lennart Poettering
       7             : 
       8             :   systemd is free software; you can redistribute it and/or modify it
       9             :   under the terms of the GNU Lesser General Public License as published by
      10             :   the Free Software Foundation; either version 2.1 of the License, or
      11             :   (at your option) any later version.
      12             : 
      13             :   systemd is distributed in the hope that it will be useful, but
      14             :   WITHOUT ANY WARRANTY; without even the implied warranty of
      15             :   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
      16             :   Lesser General Public License for more details.
      17             : 
      18             :   You should have received a copy of the GNU Lesser General Public License
      19             :   along with systemd; If not, see <http://www.gnu.org/licenses/>.
      20             : ***/
      21             : 
      22             : #include <stdlib.h>
      23             : #include <string.h>
      24             : #include <unistd.h>
      25             : 
      26             : #ifdef HAVE_XZ
      27             : #  include <lzma.h>
      28             : #endif
      29             : 
      30             : #ifdef HAVE_LZ4
      31             : #  include <lz4.h>
      32             : #endif
      33             : 
      34             : #include "compress.h"
      35             : #include "macro.h"
      36             : #include "util.h"
      37             : #include "sparse-endian.h"
      38             : #include "journal-def.h"
      39             : 
      40             : #define ALIGN_8(l) ALIGN_TO(l, sizeof(size_t))
      41             : 
      42             : static const char* const object_compressed_table[_OBJECT_COMPRESSED_MAX] = {
      43             :         [OBJECT_COMPRESSED_XZ] = "XZ",
      44             :         [OBJECT_COMPRESSED_LZ4] = "LZ4",
      45             : };
      46             : 
      47          15 : DEFINE_STRING_TABLE_LOOKUP(object_compressed, int);
      48             : 
      49        6874 : int compress_blob_xz(const void *src, uint64_t src_size, void *dst, size_t *dst_size) {
      50             : #ifdef HAVE_XZ
      51             :         static const lzma_options_lzma opt = {
      52             :                 1u << 20u, NULL, 0, LZMA_LC_DEFAULT, LZMA_LP_DEFAULT,
      53             :                 LZMA_PB_DEFAULT, LZMA_MODE_FAST, 128, LZMA_MF_HC3, 4};
      54             :         static const lzma_filter filters[2] = {
      55             :                 {LZMA_FILTER_LZMA2, (lzma_options_lzma*) &opt},
      56             :                 {LZMA_VLI_UNKNOWN, NULL}
      57             :         };
      58             :         lzma_ret ret;
      59        6874 :         size_t out_pos = 0;
      60             : 
      61        6874 :         assert(src);
      62        6874 :         assert(src_size > 0);
      63        6874 :         assert(dst);
      64        6874 :         assert(dst_size);
      65             : 
      66             :         /* Returns < 0 if we couldn't compress the data or the
      67             :          * compressed result is longer than the original */
      68             : 
      69        6874 :         if (src_size < 80)
      70          79 :                 return -ENOBUFS;
      71             : 
      72        6795 :         ret = lzma_stream_buffer_encode((lzma_filter*) filters, LZMA_CHECK_NONE, NULL,
      73             :                                         src, src_size, dst, &out_pos, src_size - 1);
      74        6795 :         if (ret != LZMA_OK)
      75           7 :                 return -ENOBUFS;
      76             : 
      77        6788 :         *dst_size = out_pos;
      78        6788 :         return 0;
      79             : #else
      80             :         return -EPROTONOSUPPORT;
      81             : #endif
      82             : }
      83             : 
      84           0 : int compress_blob_lz4(const void *src, uint64_t src_size, void *dst, size_t *dst_size) {
      85             : #ifdef HAVE_LZ4
      86             :         int r;
      87             : 
      88             :         assert(src);
      89             :         assert(src_size > 0);
      90             :         assert(dst);
      91             :         assert(dst_size);
      92             : 
      93             :         /* Returns < 0 if we couldn't compress the data or the
      94             :          * compressed result is longer than the original */
      95             : 
      96             :         if (src_size < 9)
      97             :                 return -ENOBUFS;
      98             : 
      99             :         r = LZ4_compress_limitedOutput(src, dst + 8, src_size, src_size - 8 - 1);
     100             :         if (r <= 0)
     101             :                 return -ENOBUFS;
     102             : 
     103             :         *(le64_t*) dst = htole64(src_size);
     104             :         *dst_size = r + 8;
     105             : 
     106             :         return 0;
     107             : #else
     108           0 :         return -EPROTONOSUPPORT;
     109             : #endif
     110             : }
     111             : 
     112             : 
     113        6794 : int decompress_blob_xz(const void *src, uint64_t src_size,
     114             :                        void **dst, size_t *dst_alloc_size, size_t* dst_size, size_t dst_max) {
     115             : 
     116             : #ifdef HAVE_XZ
     117       13588 :         _cleanup_(lzma_end) lzma_stream s = LZMA_STREAM_INIT;
     118             :         lzma_ret ret;
     119             :         size_t space;
     120             : 
     121        6794 :         assert(src);
     122        6794 :         assert(src_size > 0);
     123        6794 :         assert(dst);
     124        6794 :         assert(dst_alloc_size);
     125        6794 :         assert(dst_size);
     126        6794 :         assert(*dst_alloc_size == 0 || *dst);
     127             : 
     128        6794 :         ret = lzma_stream_decoder(&s, UINT64_MAX, 0);
     129        6794 :         if (ret != LZMA_OK)
     130           0 :                 return -ENOMEM;
     131             : 
     132        6794 :         space = MIN(src_size * 2, dst_max ?: (size_t) -1);
     133        6794 :         if (!greedy_realloc(dst, dst_alloc_size, space, 1))
     134           0 :                 return -ENOMEM;
     135             : 
     136        6794 :         s.next_in = src;
     137        6794 :         s.avail_in = src_size;
     138             : 
     139        6794 :         s.next_out = *dst;
     140        6794 :         s.avail_out = space;
     141             : 
     142             :         for (;;) {
     143             :                 size_t used;
     144             : 
     145       61520 :                 ret = lzma_code(&s, LZMA_FINISH);
     146             : 
     147       61520 :                 if (ret == LZMA_STREAM_END)
     148        6788 :                         break;
     149       54732 :                 else if (ret != LZMA_OK)
     150           6 :                         return -ENOMEM;
     151             : 
     152       54726 :                 if (dst_max > 0 && (space - s.avail_out) >= dst_max)
     153             :                         break;
     154       54726 :                 else if (dst_max > 0 && space == dst_max)
     155           0 :                         return -ENOBUFS;
     156             : 
     157       54726 :                 used = space - s.avail_out;
     158       54726 :                 space = MIN(2 * space, dst_max ?: (size_t) -1);
     159       54726 :                 if (!greedy_realloc(dst, dst_alloc_size, space, 1))
     160           0 :                         return -ENOMEM;
     161             : 
     162       54726 :                 s.avail_out = space - used;
     163       54726 :                 s.next_out = *dst + used;
     164       54726 :         }
     165             : 
     166        6788 :         *dst_size = space - s.avail_out;
     167        6788 :         return 0;
     168             : #else
     169             :         return -EPROTONOSUPPORT;
     170             : #endif
     171             : }
     172             : 
     173           0 : int decompress_blob_lz4(const void *src, uint64_t src_size,
     174             :                         void **dst, size_t *dst_alloc_size, size_t* dst_size, size_t dst_max) {
     175             : 
     176             : #ifdef HAVE_LZ4
     177             :         char* out;
     178             :         int r, size; /* LZ4 uses int for size */
     179             : 
     180             :         assert(src);
     181             :         assert(src_size > 0);
     182             :         assert(dst);
     183             :         assert(dst_alloc_size);
     184             :         assert(dst_size);
     185             :         assert(*dst_alloc_size == 0 || *dst);
     186             : 
     187             :         if (src_size <= 8)
     188             :                 return -EBADMSG;
     189             : 
     190             :         size = le64toh( *(le64_t*)src );
     191             :         if (size < 0 || (le64_t) size != *(le64_t*)src)
     192             :                 return -EFBIG;
     193             :         if ((size_t) size > *dst_alloc_size) {
     194             :                 out = realloc(*dst, size);
     195             :                 if (!out)
     196             :                         return -ENOMEM;
     197             :                 *dst = out;
     198             :                 *dst_alloc_size = size;
     199             :         } else
     200             :                 out = *dst;
     201             : 
     202             :         r = LZ4_decompress_safe(src + 8, out, src_size - 8, size);
     203             :         if (r < 0 || r != size)
     204             :                 return -EBADMSG;
     205             : 
     206             :         *dst_size = size;
     207             :         return 0;
     208             : #else
     209           0 :         return -EPROTONOSUPPORT;
     210             : #endif
     211             : }
     212             : 
     213           1 : int decompress_blob(int compression,
     214             :                     const void *src, uint64_t src_size,
     215             :                     void **dst, size_t *dst_alloc_size, size_t* dst_size, size_t dst_max) {
     216           1 :         if (compression == OBJECT_COMPRESSED_XZ)
     217           1 :                 return decompress_blob_xz(src, src_size,
     218             :                                           dst, dst_alloc_size, dst_size, dst_max);
     219           0 :         else if (compression == OBJECT_COMPRESSED_LZ4)
     220           0 :                 return decompress_blob_lz4(src, src_size,
     221             :                                            dst, dst_alloc_size, dst_size, dst_max);
     222             :         else
     223           0 :                 return -EBADMSG;
     224             : }
     225             : 
     226             : 
     227           4 : int decompress_startswith_xz(const void *src, uint64_t src_size,
     228             :                              void **buffer, size_t *buffer_size,
     229             :                              const void *prefix, size_t prefix_len,
     230             :                              uint8_t extra) {
     231             : 
     232             : #ifdef HAVE_XZ
     233           8 :         _cleanup_(lzma_end) lzma_stream s = LZMA_STREAM_INIT;
     234             :         lzma_ret ret;
     235             : 
     236             :         /* Checks whether the decompressed blob starts with the
     237             :          * mentioned prefix. The byte extra needs to follow the
     238             :          * prefix */
     239             : 
     240           4 :         assert(src);
     241           4 :         assert(src_size > 0);
     242           4 :         assert(buffer);
     243           4 :         assert(buffer_size);
     244           4 :         assert(prefix);
     245           4 :         assert(*buffer_size == 0 || *buffer);
     246             : 
     247           4 :         ret = lzma_stream_decoder(&s, UINT64_MAX, 0);
     248           4 :         if (ret != LZMA_OK)
     249           0 :                 return -EBADMSG;
     250             : 
     251           4 :         if (!(greedy_realloc(buffer, buffer_size, ALIGN_8(prefix_len + 1), 1)))
     252           0 :                 return -ENOMEM;
     253             : 
     254           4 :         s.next_in = src;
     255           4 :         s.avail_in = src_size;
     256             : 
     257           4 :         s.next_out = *buffer;
     258           4 :         s.avail_out = *buffer_size;
     259             : 
     260             :         for (;;) {
     261           4 :                 ret = lzma_code(&s, LZMA_FINISH);
     262             : 
     263           4 :                 if (ret != LZMA_STREAM_END && ret != LZMA_OK)
     264           0 :                         return -EBADMSG;
     265             : 
     266           4 :                 if (*buffer_size - s.avail_out >= prefix_len + 1)
     267           7 :                         return memcmp(*buffer, prefix, prefix_len) == 0 &&
     268           3 :                                 ((const uint8_t*) *buffer)[prefix_len] == extra;
     269             : 
     270           0 :                 if (ret == LZMA_STREAM_END)
     271           0 :                         return 0;
     272             : 
     273           0 :                 s.avail_out += *buffer_size;
     274             : 
     275           0 :                 if (!(greedy_realloc(buffer, buffer_size, *buffer_size * 2, 1)))
     276           0 :                         return -ENOMEM;
     277             : 
     278           0 :                 s.next_out = *buffer + *buffer_size - s.avail_out;
     279           0 :         }
     280             : 
     281             : #else
     282             :         return -EPROTONOSUPPORT;
     283             : #endif
     284             : }
     285             : 
     286           0 : int decompress_startswith_lz4(const void *src, uint64_t src_size,
     287             :                               void **buffer, size_t *buffer_size,
     288             :                               const void *prefix, size_t prefix_len,
     289             :                               uint8_t extra) {
     290             : #ifdef HAVE_LZ4
     291             :         /* Checks whether the decompressed blob starts with the
     292             :          * mentioned prefix. The byte extra needs to follow the
     293             :          * prefix */
     294             : 
     295             :         int r;
     296             : 
     297             :         assert(src);
     298             :         assert(src_size > 0);
     299             :         assert(buffer);
     300             :         assert(buffer_size);
     301             :         assert(prefix);
     302             :         assert(*buffer_size == 0 || *buffer);
     303             : 
     304             :         if (src_size <= 8)
     305             :                 return -EBADMSG;
     306             : 
     307             :         if (!(greedy_realloc(buffer, buffer_size, ALIGN_8(prefix_len + 1), 1)))
     308             :                 return -ENOMEM;
     309             : 
     310             :         r = LZ4_decompress_safe_partial(src + 8, *buffer, src_size - 8,
     311             :                                         prefix_len + 1, *buffer_size);
     312             : 
     313             :         if (r < 0)
     314             :                 return -EBADMSG;
     315             :         if ((unsigned) r >= prefix_len + 1)
     316             :                 return memcmp(*buffer, prefix, prefix_len) == 0 &&
     317             :                         ((const uint8_t*) *buffer)[prefix_len] == extra;
     318             :         else
     319             :                 return 0;
     320             : 
     321             : #else
     322           0 :         return -EPROTONOSUPPORT;
     323             : #endif
     324             : }
     325             : 
     326           0 : int decompress_startswith(int compression,
     327             :                           const void *src, uint64_t src_size,
     328             :                           void **buffer, size_t *buffer_size,
     329             :                           const void *prefix, size_t prefix_len,
     330             :                           uint8_t extra) {
     331           0 :         if (compression == OBJECT_COMPRESSED_XZ)
     332           0 :                 return decompress_startswith_xz(src, src_size,
     333             :                                                 buffer, buffer_size,
     334             :                                                 prefix, prefix_len,
     335             :                                                 extra);
     336           0 :         else if (compression == OBJECT_COMPRESSED_LZ4)
     337           0 :                 return decompress_startswith_lz4(src, src_size,
     338             :                                                  buffer, buffer_size,
     339             :                                                  prefix, prefix_len,
     340             :                                                  extra);
     341             :         else
     342           0 :                 return -EBADMSG;
     343             : }
     344             : 
     345           1 : int compress_stream_xz(int fdf, int fdt, off_t max_bytes) {
     346             : #ifdef HAVE_XZ
     347           2 :         _cleanup_(lzma_end) lzma_stream s = LZMA_STREAM_INIT;
     348             :         lzma_ret ret;
     349             : 
     350             :         uint8_t buf[BUFSIZ], out[BUFSIZ];
     351           1 :         lzma_action action = LZMA_RUN;
     352             : 
     353           1 :         assert(fdf >= 0);
     354           1 :         assert(fdt >= 0);
     355             : 
     356           1 :         ret = lzma_easy_encoder(&s, LZMA_PRESET_DEFAULT, LZMA_CHECK_CRC64);
     357           1 :         if (ret != LZMA_OK) {
     358           0 :                 log_error("Failed to initialize XZ encoder: code %u", ret);
     359           0 :                 return -EINVAL;
     360             :         }
     361             : 
     362             :         for (;;) {
     363         142 :                 if (s.avail_in == 0 && action == LZMA_RUN) {
     364         116 :                         size_t m = sizeof(buf);
     365             :                         ssize_t n;
     366             : 
     367         116 :                         if (max_bytes != -1 && m > (size_t) max_bytes)
     368           0 :                                 m = max_bytes;
     369             : 
     370         116 :                         n = read(fdf, buf, m);
     371         116 :                         if (n < 0)
     372           0 :                                 return -errno;
     373         116 :                         if (n == 0)
     374           1 :                                 action = LZMA_FINISH;
     375             :                         else {
     376         115 :                                 s.next_in = buf;
     377         115 :                                 s.avail_in = n;
     378             : 
     379         115 :                                 if (max_bytes != -1) {
     380           0 :                                         assert(max_bytes >= n);
     381           0 :                                         max_bytes -= n;
     382             :                                 }
     383             :                         }
     384             :                 }
     385             : 
     386         142 :                 if (s.avail_out == 0) {
     387          31 :                         s.next_out = out;
     388          31 :                         s.avail_out = sizeof(out);
     389             :                 }
     390             : 
     391         142 :                 ret = lzma_code(&s, action);
     392         142 :                 if (ret != LZMA_OK && ret != LZMA_STREAM_END) {
     393           0 :                         log_error("Compression failed: code %u", ret);
     394           0 :                         return -EBADMSG;
     395             :                 }
     396             : 
     397         142 :                 if (s.avail_out == 0 || ret == LZMA_STREAM_END) {
     398             :                         ssize_t n, k;
     399             : 
     400          31 :                         n = sizeof(out) - s.avail_out;
     401             : 
     402          31 :                         k = loop_write(fdt, out, n, false);
     403          31 :                         if (k < 0)
     404           0 :                                 return k;
     405             : 
     406          31 :                         if (ret == LZMA_STREAM_END) {
     407           1 :                                 log_debug("XZ compression finished (%"PRIu64" -> %"PRIu64" bytes, %.1f%%)",
     408             :                                           s.total_in, s.total_out,
     409             :                                           (double) s.total_out / s.total_in * 100);
     410             : 
     411           1 :                                 return 0;
     412             :                         }
     413             :                 }
     414         141 :         }
     415             : #else
     416             :         return -EPROTONOSUPPORT;
     417             : #endif
     418             : }
     419             : 
     420             : #define LZ4_BUFSIZE (512*1024)
     421             : 
     422           0 : int compress_stream_lz4(int fdf, int fdt, off_t max_bytes) {
     423             : 
     424             : #ifdef HAVE_LZ4
     425             : 
     426             :         _cleanup_free_ char *buf1 = NULL, *buf2 = NULL, *out = NULL;
     427             :         char *buf;
     428             :         LZ4_stream_t lz4_data = {};
     429             :         le32_t header;
     430             :         size_t total_in = 0, total_out = sizeof(header);
     431             :         ssize_t n;
     432             : 
     433             :         assert(fdf >= 0);
     434             :         assert(fdt >= 0);
     435             : 
     436             :         buf1 = malloc(LZ4_BUFSIZE);
     437             :         buf2 = malloc(LZ4_BUFSIZE);
     438             :         out = malloc(LZ4_COMPRESSBOUND(LZ4_BUFSIZE));
     439             :         if (!buf1 || !buf2 || !out)
     440             :                 return log_oom();
     441             : 
     442             :         buf = buf1;
     443             :         for (;;) {
     444             :                 size_t m;
     445             :                 int r;
     446             : 
     447             :                 m = LZ4_BUFSIZE;
     448             :                 if (max_bytes != -1 && m > (size_t) max_bytes - total_in)
     449             :                         m = max_bytes - total_in;
     450             : 
     451             :                 n = read(fdf, buf, m);
     452             :                 if (n < 0)
     453             :                         return -errno;
     454             :                 if (n == 0)
     455             :                         break;
     456             : 
     457             :                 total_in += n;
     458             : 
     459             :                 r = LZ4_compress_continue(&lz4_data, buf, out, n);
     460             :                 if (r == 0) {
     461             :                         log_error("LZ4 compression failed.");
     462             :                         return -EBADMSG;
     463             :                 }
     464             : 
     465             :                 header = htole32(r);
     466             :                 errno = 0;
     467             : 
     468             :                 n = write(fdt, &header, sizeof(header));
     469             :                 if (n < 0)
     470             :                         return -errno;
     471             :                 if (n != sizeof(header))
     472             :                         return errno ? -errno : -EIO;
     473             : 
     474             :                 n = loop_write(fdt, out, r, false);
     475             :                 if (n < 0)
     476             :                         return n;
     477             : 
     478             :                 total_out += sizeof(header) + r;
     479             : 
     480             :                 buf = buf == buf1 ? buf2 : buf1;
     481             :         }
     482             : 
     483             :         header = htole32(0);
     484             :         n = write(fdt, &header, sizeof(header));
     485             :         if (n < 0)
     486             :                 return -errno;
     487             :         if (n != sizeof(header))
     488             :                 return errno ? -errno : -EIO;
     489             : 
     490             :         log_debug("LZ4 compression finished (%zu -> %zu bytes, %.1f%%)",
     491             :                   total_in, total_out,
     492             :                   (double) total_out / total_in * 100);
     493             : 
     494             :         return 0;
     495             : #else
     496           0 :         return -EPROTONOSUPPORT;
     497             : #endif
     498             : }
     499             : 
     500           3 : int decompress_stream_xz(int fdf, int fdt, off_t max_bytes) {
     501             : 
     502             : #ifdef HAVE_XZ
     503           6 :         _cleanup_(lzma_end) lzma_stream s = LZMA_STREAM_INIT;
     504             :         lzma_ret ret;
     505             : 
     506             :         uint8_t buf[BUFSIZ], out[BUFSIZ];
     507           3 :         lzma_action action = LZMA_RUN;
     508             : 
     509           3 :         assert(fdf >= 0);
     510           3 :         assert(fdt >= 0);
     511             : 
     512           3 :         ret = lzma_stream_decoder(&s, UINT64_MAX, 0);
     513           3 :         if (ret != LZMA_OK) {
     514           0 :                 log_error("Failed to initialize XZ decoder: code %u", ret);
     515           0 :                 return -ENOMEM;
     516             :         }
     517             : 
     518             :         for (;;) {
     519         291 :                 if (s.avail_in == 0 && action == LZMA_RUN) {
     520             :                         ssize_t n;
     521             : 
     522          63 :                         n = read(fdf, buf, sizeof(buf));
     523          63 :                         if (n < 0)
     524           0 :                                 return -errno;
     525          63 :                         if (n == 0)
     526           0 :                                 action = LZMA_FINISH;
     527             :                         else {
     528          63 :                                 s.next_in = buf;
     529          63 :                                 s.avail_in = n;
     530             :                         }
     531             :                 }
     532             : 
     533         291 :                 if (s.avail_out == 0) {
     534         231 :                         s.next_out = out;
     535         231 :                         s.avail_out = sizeof(out);
     536             :                 }
     537             : 
     538         291 :                 ret = lzma_code(&s, action);
     539         291 :                 if (ret != LZMA_OK && ret != LZMA_STREAM_END) {
     540           1 :                         log_error("Decompression failed: code %u", ret);
     541           1 :                         return -EBADMSG;
     542             :                 }
     543             : 
     544         290 :                 if (s.avail_out == 0 || ret == LZMA_STREAM_END) {
     545             :                         ssize_t n, k;
     546             : 
     547         230 :                         n = sizeof(out) - s.avail_out;
     548             : 
     549         230 :                         if (max_bytes != -1) {
     550         230 :                                 if (max_bytes < n)
     551           1 :                                         return -EFBIG;
     552             : 
     553         229 :                                 max_bytes -= n;
     554             :                         }
     555             : 
     556         229 :                         k = loop_write(fdt, out, n, false);
     557         229 :                         if (k < 0)
     558           0 :                                 return k;
     559             : 
     560         229 :                         if (ret == LZMA_STREAM_END) {
     561           1 :                                 log_debug("XZ decompression finished (%"PRIu64" -> %"PRIu64" bytes, %.1f%%)",
     562             :                                           s.total_in, s.total_out,
     563             :                                           (double) s.total_out / s.total_in * 100);
     564             : 
     565           1 :                                 return 0;
     566             :                         }
     567             :                 }
     568         288 :         }
     569             : #else
     570             :         log_error("Cannot decompress file. Compiled without XZ support.");
     571             :         return -EPROTONOSUPPORT;
     572             : #endif
     573             : }
     574             : 
     575           0 : int decompress_stream_lz4(int fdf, int fdt, off_t max_bytes) {
     576             : 
     577             : #ifdef HAVE_LZ4
     578             :         _cleanup_free_ char *buf = NULL, *out = NULL;
     579             :         size_t buf_size = 0;
     580             :         LZ4_streamDecode_t lz4_data = {};
     581             :         le32_t header;
     582             :         size_t total_in = sizeof(header), total_out = 0;
     583             : 
     584             :         assert(fdf >= 0);
     585             :         assert(fdt >= 0);
     586             : 
     587             :         out = malloc(4*LZ4_BUFSIZE);
     588             :         if (!out)
     589             :                 return log_oom();
     590             : 
     591             :         for (;;) {
     592             :                 ssize_t m;
     593             :                 int r;
     594             : 
     595             :                 r = loop_read_exact(fdf, &header, sizeof(header), false);
     596             :                 if (r < 0)
     597             :                         return r;
     598             : 
     599             :                 m = le32toh(header);
     600             :                 if (m == 0)
     601             :                         break;
     602             : 
     603             :                 /* We refuse to use a bigger decompression buffer than
     604             :                  * the one used for compression by 4 times. This means
     605             :                  * that compression buffer size can be enlarged 4
     606             :                  * times. This can be changed, but old binaries might
     607             :                  * not accept buffers compressed by newer binaries then.
     608             :                  */
     609             :                 if (m > LZ4_COMPRESSBOUND(LZ4_BUFSIZE * 4)) {
     610             :                         log_error("Compressed stream block too big: %zd bytes", m);
     611             :                         return -EBADMSG;
     612             :                 }
     613             : 
     614             :                 total_in += sizeof(header) + m;
     615             : 
     616             :                 if (!GREEDY_REALLOC(buf, buf_size, m))
     617             :                         return log_oom();
     618             : 
     619             :                 r = loop_read_exact(fdf, buf, m, false);
     620             :                 if (r < 0)
     621             :                         return r;
     622             : 
     623             :                 r = LZ4_decompress_safe_continue(&lz4_data, buf, out, m, 4*LZ4_BUFSIZE);
     624             :                 if (r <= 0)
     625             :                         log_error("LZ4 decompression failed.");
     626             : 
     627             :                 total_out += r;
     628             : 
     629             :                 if (max_bytes != -1 && total_out > (size_t) max_bytes) {
     630             :                         log_debug("Decompressed stream longer than %zd bytes", max_bytes);
     631             :                         return -EFBIG;
     632             :                 }
     633             : 
     634             :                 r = loop_write(fdt, out, r, false);
     635             :                 if (r < 0)
     636             :                         return r;
     637             :         }
     638             : 
     639             :         log_debug("LZ4 decompression finished (%zu -> %zu bytes, %.1f%%)",
     640             :                   total_in, total_out,
     641             :                   (double) total_out / total_in * 100);
     642             : 
     643             :         return 0;
     644             : #else
     645           0 :         log_error("Cannot decompress file. Compiled without LZ4 support.");
     646           0 :         return -EPROTONOSUPPORT;
     647             : #endif
     648             : }
     649             : 
     650           0 : int decompress_stream(const char *filename, int fdf, int fdt, off_t max_bytes) {
     651             : 
     652           0 :         if (endswith(filename, ".lz4"))
     653           0 :                 return decompress_stream_lz4(fdf, fdt, max_bytes);
     654           0 :         else if (endswith(filename, ".xz"))
     655           0 :                 return decompress_stream_xz(fdf, fdt, max_bytes);
     656             :         else
     657           0 :                 return -EPROTONOSUPPORT;
     658             : }

Generated by: LCOV version 1.11