From: Michihiro NAKAJIMA Date: Mon, 22 Oct 2012 21:22:23 +0000 (+0900) Subject: Introduce gzip:timestamp option into gzip write filter to X-Git-Tag: v3.1.0~40^2~18 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=3549d5aef73b93ae622fd4e00de4a761228ab838;p=thirdparty%2Flibarchive.git Introduce gzip:timestamp option into gzip write filter to control recording timestamp. --- diff --git a/Makefile.am b/Makefile.am index b37b7b8de..e7ddddd3d 100644 --- a/Makefile.am +++ b/Makefile.am @@ -426,6 +426,7 @@ libarchive_test_SOURCES= \ libarchive/test/test_write_filter_bzip2.c \ libarchive/test/test_write_filter_compress.c \ libarchive/test/test_write_filter_gzip.c \ + libarchive/test/test_write_filter_gzip_timestamp.c \ libarchive/test/test_write_filter_lrzip.c \ libarchive/test/test_write_filter_lzip.c \ libarchive/test/test_write_filter_lzma.c \ diff --git a/libarchive/archive_write_add_filter_gzip.c b/libarchive/archive_write_add_filter_gzip.c index 7e119b98f..28fd8ebc9 100644 --- a/libarchive/archive_write_add_filter_gzip.c +++ b/libarchive/archive_write_add_filter_gzip.c @@ -59,6 +59,7 @@ archive_write_set_compression_gzip(struct archive *a) struct private_data { int compression_level; + int timestamp; #ifdef HAVE_ZLIB_H z_stream stream; int64_t total_in; @@ -162,6 +163,10 @@ archive_compressor_gzip_options(struct archive_write_filter *f, const char *key, data->compression_level = value[0] - '0'; return (ARCHIVE_OK); } + if (strcmp(key, "timestamp") == 0) { + data->timestamp = (value == NULL)?-1:1; + return (ARCHIVE_OK); + } /* Note: The "warn" return is just to inform the options * supervisor that we didn't handle it. It will generate @@ -178,7 +183,6 @@ archive_compressor_gzip_open(struct archive_write_filter *f) { struct private_data *data = (struct private_data *)f->data; int ret; - time_t t; ret = __archive_write_open_filter(f->next_filter); if (ret != ARCHIVE_OK) @@ -210,15 +214,18 @@ archive_compressor_gzip_open(struct archive_write_filter *f) data->stream.avail_out = data->compressed_buffer_size; /* Prime output buffer with a gzip header. */ - t = time(NULL); 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[4] = (uint8_t)(t)&0xff; /* Timestamp */ - data->compressed[5] = (uint8_t)(t>>8)&0xff; - data->compressed[6] = (uint8_t)(t>>16)&0xff; - data->compressed[7] = (uint8_t)(t>>24)&0xff; + if (data->timestamp >= 0) { + time_t t = time(NULL); + data->compressed[4] = (uint8_t)(t)&0xff; /* Timestamp */ + data->compressed[5] = (uint8_t)(t>>8)&0xff; + data->compressed[6] = (uint8_t)(t>>16)&0xff; + data->compressed[7] = (uint8_t)(t>>24)&0xff; + } else + memset(&data->compressed[4], 0, 4); data->compressed[8] = 0; /* No deflate options */ data->compressed[9] = 3; /* OS=Unix */ data->stream.next_out += 10; @@ -401,6 +408,31 @@ archive_compressor_gzip_open(struct archive_write_filter *f) archive_strcat(&as, " -"); archive_strappend_char(&as, '0' + data->compression_level); } + if (data->timestamp < 0) + /* Do not save timestamp. */ + archive_strcat(&as, " -n"); + else if (data->timestamp > 0) + /* Save timestamp. */ + archive_strcat(&as, " -N"); + + f->write = archive_compressor_gzip_write; + r = __archive_write_program_open(f, data->pdata, as.s); + archive_string_free(&as); + return (r); +} + +static int +archive_compressor_gzip_write(struct archive_write_filter *f, const void *buff, + size_t length) +{ + struct private_data *data = (struct private_data *)f->data; + + return __archive_write_program_write(f, data->pdata, buff, length); +} + +static int +archive_compressor_gzip_close(struct archive_write_filter *f) +{ f->write = archive_compressor_gzip_write; r = __archive_write_program_open(f, data->pdata, as.s); diff --git a/libarchive/test/CMakeLists.txt b/libarchive/test/CMakeLists.txt index efbe7b089..346eaf4b2 100644 --- a/libarchive/test/CMakeLists.txt +++ b/libarchive/test/CMakeLists.txt @@ -161,6 +161,7 @@ IF(ENABLE_TEST) test_write_filter_bzip2.c test_write_filter_compress.c test_write_filter_gzip.c + test_write_filter_gzip_timestamp.c test_write_filter_lrzip.c test_write_filter_lzip.c test_write_filter_lzma.c diff --git a/libarchive/test/test_write_filter_gzip_timestamp.c b/libarchive/test/test_write_filter_gzip_timestamp.c new file mode 100644 index 000000000..ce5ebb9f8 --- /dev/null +++ b/libarchive/test/test_write_filter_gzip_timestamp.c @@ -0,0 +1,110 @@ +/*- + * Copyright (c) 2007 Tim Kientzle + * Copyright (c) 2012 Michihiro NAKAJIMA + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer + * in this position and unchanged. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "test.h" +__FBSDID("$FreeBSD$"); + +DEFINE_TEST(test_write_filter_gzip_timestamp) +{ + struct archive_entry *ae; + struct archive* a; + char *buff, *data; + size_t buffsize, datasize; + size_t used1; + int r, use_prog = 0; + + buffsize = 10000; + assert(NULL != (buff = (char *)malloc(buffsize))); + + datasize = 10000; + assert(NULL != (data = (char *)malloc(datasize))); + memset(data, 0, datasize); + + /* Test1: set "gzip:timestamp" option. */ + assert((a = archive_write_new()) != NULL); + assertEqualIntA(a, ARCHIVE_OK, archive_write_set_format_ustar(a)); + r = archive_write_add_filter_gzip(a); + if (r != ARCHIVE_OK) { + if (canGzip() && r == ARCHIVE_WARN) + use_prog = 1; + else { + skipping("gzip writing not supported on this platform"); + assertEqualInt(ARCHIVE_OK, archive_write_free(a)); + return; + } + } + assertEqualIntA(a, ARCHIVE_OK, + archive_write_set_options(a, "gzip:timestamp")); + assertEqualIntA(a, ARCHIVE_OK, + archive_write_set_bytes_per_block(a, 10)); + assertEqualInt(ARCHIVE_FILTER_GZIP, archive_filter_code(a, 0)); + assertEqualString("gzip", archive_filter_name(a, 0)); + assertEqualIntA(a, (use_prog)?ARCHIVE_WARN:ARCHIVE_OK, + archive_write_open_memory(a, buff, buffsize, &used1)); + assert((ae = archive_entry_new()) != NULL); + archive_entry_set_filetype(ae, AE_IFREG); + archive_entry_set_size(ae, datasize); + archive_entry_copy_pathname(ae, "file"); + assertEqualIntA(a, ARCHIVE_OK, archive_write_header(a, ae)); + assertEqualIntA(a, datasize, archive_write_data(a, data, datasize)); + archive_entry_free(ae); + assertEqualIntA(a, ARCHIVE_OK, archive_write_close(a)); + assertEqualInt(ARCHIVE_OK, archive_write_free(a)); + failure("Timestamp should be recorded"); + assert(memcmp(buff + 4, "\x00\x00\x00\x00", 4) != 0); + + /* Test2: set "gzip:!timestamp" option. */ + assert((a = archive_write_new()) != NULL); + assertEqualIntA(a, ARCHIVE_OK, archive_write_set_format_ustar(a)); + assertEqualIntA(a, (use_prog)?ARCHIVE_WARN:ARCHIVE_OK, + archive_write_add_filter_gzip(a)); + assertEqualIntA(a, ARCHIVE_OK, + archive_write_set_options(a, "gzip:!timestamp")); + assertEqualIntA(a, ARCHIVE_OK, + archive_write_set_bytes_per_block(a, 10)); + assertEqualInt(ARCHIVE_FILTER_GZIP, archive_filter_code(a, 0)); + assertEqualString("gzip", archive_filter_name(a, 0)); + assertEqualIntA(a, (use_prog)?ARCHIVE_WARN:ARCHIVE_OK, + archive_write_open_memory(a, buff, buffsize, &used1)); + assert((ae = archive_entry_new()) != NULL); + archive_entry_set_filetype(ae, AE_IFREG); + archive_entry_set_size(ae, datasize); + archive_entry_copy_pathname(ae, "file"); + assertEqualIntA(a, ARCHIVE_OK, archive_write_header(a, ae)); + assertEqualIntA(a, datasize, archive_write_data(a, data, datasize)); + archive_entry_free(ae); + assertEqualIntA(a, ARCHIVE_OK, archive_write_close(a)); + assertEqualInt(ARCHIVE_OK, archive_write_free(a)); + failure("Timestamp should not be recorded"); + assertEqualMem(buff + 4, "\x00\x00\x00\x00", 4); + + /* + * Clean up. + */ + free(data); + free(buff); +} diff --git a/tar/bsdtar.1 b/tar/bsdtar.1 index 2297c3506..3fd2d9b3e 100644 --- a/tar/bsdtar.1 +++ b/tar/bsdtar.1 @@ -24,7 +24,7 @@ .\" .\" $FreeBSD$ .\" -.Dd October 22, 2012 +.Dd October 23, 2012 .Dt TAR 1 .Os .Sh NAME @@ -472,6 +472,12 @@ or to disable. .It Cm gzip:compression-level A decimal integer from 0 to 9 specifying the gzip compression level. +.It Cm gzip:timestamp +Store timestamp. This is enabled by default, use +.Cm !timestamp +or +.Cm gzip:!timestamp +to disable. .It Cm xz:compression-level A decimal integer from 0 to 9 specifying the xz compression level. .It Cm mtree: Ns Ar keyword