]> git.ipfire.org Git - pakfire.git/commitdiff
compress: Add write support for XZ
authorMichael Tremer <michael.tremer@ipfire.org>
Wed, 17 Mar 2021 11:33:12 +0000 (11:33 +0000)
committerMichael Tremer <michael.tremer@ipfire.org>
Wed, 17 Mar 2021 11:33:12 +0000 (11:33 +0000)
Signed-off-by: Michael Tremer <michael.tremer@ipfire.org>
src/libpakfire/compress.c

index 0f0bd2ba21f117b0cc4b0ee3e01c1d1d13dd001b..726b57dd6eb6c06a9e3c28a30c346755eb0419e2 100644 (file)
@@ -32,6 +32,9 @@
 // Compression/Decompression buffer size
 #define BUFFER_SIZE                    64 * 1024
 
+// Settings for XZ
+#define XZ_COMPRESSION_LEVEL   6
+
 const struct compressor {
        char magic[MAX_MAGIC_LENGTH];
        size_t magic_length;
@@ -109,7 +112,6 @@ struct xz_cookie {
        uint8_t buffer[BUFFER_SIZE];
 };
 
-
 static ssize_t xz_read(void* data, char* buffer, size_t size) {
        struct xz_cookie* cookie = (struct xz_cookie*)data;
        if (!cookie)
@@ -169,6 +171,45 @@ static ssize_t xz_read(void* data, char* buffer, size_t size) {
        }
 }
 
+static ssize_t xz_write(void* data, const char* buffer, size_t size) {
+       struct xz_cookie* cookie = (struct xz_cookie*)data;
+       if (!cookie)
+               return -1;
+
+       // Do not write when mode is "r"
+       if (cookie->mode == 'r')
+               return 0;
+
+       // Return nothing when there is no input
+       if (size == 0)
+               return 0;
+
+       // Set input to allocated buffer
+       cookie->stream.next_out  = (uint8_t *)buffer;
+       cookie->stream.avail_out = size;
+
+       while (1) {
+               cookie->stream.next_out  = cookie->buffer;
+               cookie->stream.avail_out = sizeof(cookie->buffer);
+
+               lzma_ret ret = lzma_code(&cookie->stream, LZMA_RUN);
+               if (ret != LZMA_OK)
+                       return -1;
+
+               size_t bytes_to_write = sizeof(cookie->buffer) - cookie->stream.avail_out;
+               if (bytes_to_write) {
+                       size_t bytes_written = fwrite(cookie->buffer, 1, bytes_to_write, cookie->f);
+
+                       if (bytes_written != bytes_to_write)
+                               return -1;
+               }
+
+               // Report that all data has been written
+               if (cookie->stream.avail_in == 0)
+                       return size;
+       }
+}
+
 static int xz_close(void* data) {
        struct xz_cookie* cookie = (struct xz_cookie*)data;
 
@@ -199,14 +240,29 @@ FILE* pakfire_xzfopen(FILE* f, const char* mode) {
                .done = 0,
        };
 
-       // Initialise the decoder
-       lzma_ret ret = lzma_stream_decoder(&cookie.stream, UINT64_MAX, 0);
+       lzma_ret ret;
+
+       // Initialise the encoder/decoder
+       switch (cookie.mode) {
+               case 'r':
+                       ret = lzma_stream_decoder(&cookie.stream, UINT64_MAX, 0);
+                       break;
+
+               case 'w':
+                       ret = lzma_easy_encoder(&cookie.stream, XZ_COMPRESSION_LEVEL, LZMA_CHECK_SHA256);
+                       break;
+
+               default:
+                       errno = ENOTSUP;
+                       return NULL;
+       }
+
        if (ret != LZMA_OK)
                return NULL;
 
        cookie_io_functions_t functions = {
                .read  = xz_read,
-               .write = NULL,
+               .write = xz_write,
                .seek  = NULL,
                .close = xz_close,
        };