From: Marcus Tillmanns Date: Thu, 15 May 2025 12:07:48 +0000 (+0200) Subject: Allow setting the original filename for gzip compressed files (#2544) X-Git-Tag: v3.8.0~21 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=84ac71335fd7bc151be763dd525353c182b280b5;p=thirdparty%2Flibarchive.git Allow setting the original filename for gzip compressed files (#2544) Co-authored-by: Martin Matuška --- diff --git a/libarchive/archive_write_add_filter_gzip.c b/libarchive/archive_write_add_filter_gzip.c index 71d789126..5ef43c193 100644 --- a/libarchive/archive_write_add_filter_gzip.c +++ b/libarchive/archive_write_add_filter_gzip.c @@ -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. */ diff --git a/libarchive/test/test_write_filter_gzip.c b/libarchive/test/test_write_filter_gzip.c index 14b14ecdd..8fbdbed09 100644 --- a/libarchive/test/test_write_filter_gzip.c +++ b/libarchive/test/test_write_filter_gzip.c @@ -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. */