]> git.ipfire.org Git - thirdparty/libarchive.git/commitdiff
Allow setting the original filename for gzip compressed files (#2544)
authorMarcus Tillmanns <maddimax@gmail.com>
Thu, 15 May 2025 12:07:48 +0000 (14:07 +0200)
committerGitHub <noreply@github.com>
Thu, 15 May 2025 12:07:48 +0000 (14:07 +0200)
Co-authored-by: Martin Matuška <martin@matuska.de>
libarchive/archive_write_add_filter_gzip.c
libarchive/test/test_write_filter_gzip.c

index 71d7891261a5db71988ad985990fa62c0d5cb6e3..5ef43c1936ed22bb7d80b21d3da26a18ef954ea3 100644 (file)
@@ -58,6 +58,7 @@ archive_write_set_compression_gzip(struct archive *a)
 struct private_data {
        int              compression_level;
        int              timestamp;
+       char    *original_filename;
 #ifdef HAVE_ZLIB_H
        z_stream         stream;
        int64_t          total_in;
@@ -113,6 +114,8 @@ archive_write_add_filter_gzip(struct archive *_a)
        f->free = &archive_compressor_gzip_free;
        f->code = ARCHIVE_FILTER_GZIP;
        f->name = "gzip";
+
+       data->original_filename = NULL;
 #ifdef HAVE_ZLIB_H
        data->compression_level = Z_DEFAULT_COMPRESSION;
        return (ARCHIVE_OK);
@@ -140,6 +143,7 @@ archive_compressor_gzip_free(struct archive_write_filter *f)
 #else
        __archive_write_program_free(data->pdata);
 #endif
+       free((void*)data->original_filename);
        free(data);
        f->data = NULL;
        return (ARCHIVE_OK);
@@ -165,6 +169,13 @@ archive_compressor_gzip_options(struct archive_write_filter *f, const char *key,
                data->timestamp = (value == NULL)?-1:1;
                return (ARCHIVE_OK);
        }
+       if (strcmp(key, "original-filename") == 0) {
+               free((void*)data->original_filename);
+               data->original_filename = NULL;
+               if (value)
+                       data->original_filename = strdup(value);
+               return (ARCHIVE_OK);
+       }
 
        /* Note: The "warn" return is just to inform the options
         * supervisor that we didn't handle it.  It will generate
@@ -210,7 +221,7 @@ archive_compressor_gzip_open(struct archive_write_filter *f)
        data->compressed[0] = 0x1f; /* GZip signature bytes */
        data->compressed[1] = 0x8b;
        data->compressed[2] = 0x08; /* "Deflate" compression */
-       data->compressed[3] = 0; /* No options */
+       data->compressed[3] = data->original_filename == NULL ? 0 : 0x8;
        if (data->timestamp >= 0) {
                time_t t = time(NULL);
                data->compressed[4] = (uint8_t)(t)&0xff;  /* Timestamp */
@@ -229,6 +240,12 @@ archive_compressor_gzip_open(struct archive_write_filter *f)
        data->stream.next_out += 10;
        data->stream.avail_out -= 10;
 
+       if (data->original_filename != NULL) {
+               strcpy((char*)data->compressed + 10, data->original_filename);
+               data->stream.next_out += strlen(data->original_filename) + 1;
+               data->stream.avail_out -= strlen(data->original_filename) + 1;
+       }
+
        f->write = archive_compressor_gzip_write;
 
        /* Initialize compression library. */
index 14b14ecdd10577eb403cea3fb63e2a717865d491..8fbdbed09744c6a68709888f6ab824fa3f521925 100644 (file)
@@ -145,6 +145,8 @@ DEFINE_TEST(test_write_filter_gzip)
            archive_write_set_filter_option(a, NULL, "compression-level", "99"));
        assertEqualIntA(a, ARCHIVE_OK,
            archive_write_set_options(a, "gzip:compression-level=9"));
+       assertEqualIntA(a, ARCHIVE_OK,
+               archive_write_set_options(a, "gzip:original-filename=testorgfilename"));
        assertEqualIntA(a, ARCHIVE_OK, archive_write_open_memory(a, buff, buffsize, &used2));
        for (i = 0; i < 100; i++) {
                snprintf(path, sizeof(path), "file%03d", i);
@@ -164,8 +166,9 @@ DEFINE_TEST(test_write_filter_gzip)
        assertEqualInt(rbuff[0], 0x1f);
        assertEqualInt(rbuff[1], 0x8b);
        assertEqualInt(rbuff[2], 0x08);
-       assertEqualInt(rbuff[3], 0x00);
+       assertEqualInt(rbuff[3], 0x08);
        assertEqualInt(rbuff[8], 2); /* RFC 1952 flag for compression level 9 */
+       assertEqualString((const char*)rbuff+10, "testorgfilename");
 
        /* Curiously, this test fails; the test data above compresses
         * better at default compression than at level 9. */