From e653e97f77e7e53867e39ed6ce11dbbde6617337 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dirk=20M=C3=BCller?= Date: Tue, 8 Feb 2022 21:32:42 +0100 Subject: [PATCH] Implement more gzip compatibility (#3037) -n --no-name is the current behavior already, so we can implement this as a noop. --best is an alias for -9 in gzip add basic cli tests. --- programs/zstd.1 | 11 ++++++ programs/zstd.1.md | 12 +++++++ programs/zstdcli.c | 41 ++++++++++++++++------ tests/cli-tests/compression/gzip-compat.sh | 15 ++++++++ 4 files changed, 69 insertions(+), 10 deletions(-) create mode 100755 tests/cli-tests/compression/gzip-compat.sh diff --git a/programs/zstd.1 b/programs/zstd.1 index c7a19dbac..0e6e016e9 100644 --- a/programs/zstd.1 +++ b/programs/zstd.1 @@ -217,6 +217,17 @@ If input directory contains "\.\.", the files in this directory will be ignored\ . .IP "" 0 . +.SS "gzip Operation modifiers" +When invoked via a \fBgzip\fR symlink, \fBzstd\fR will support further options that intend to mimic the \fBgzip\fR behavior: +. +.TP +\fB\-n\fR, \fB\-\-no\-name\fR +do not store the original filename and timestamps when compressing a file\. This is the default behavior and hence a no\-op\. +. +.TP +\fB\-\-best\fR +alias to the option \fB\-9\fR\. +. .SS "Restricted usage of Environment Variables" Using environment variables to set parameters has security implications\. Therefore, this avenue is intentionally restricted\. Only \fBZSTD_CLEVEL\fR and \fBZSTD_NBTHREADS\fR are currently supported\. They set the compression level and number of threads to use during compression, respectively\. . diff --git a/programs/zstd.1.md b/programs/zstd.1.md index e343ec044..569ca1aa0 100644 --- a/programs/zstd.1.md +++ b/programs/zstd.1.md @@ -280,6 +280,18 @@ the last one takes effect. * `--`: All arguments after `--` are treated as files + +### gzip Operation modifiers +When invoked via a `gzip` symlink, `zstd` will support further +options that intend to mimic the `gzip` behavior: + +* `-n`, `--no-name`: + do not store the original filename and timestamps when compressing + a file. This is the default behavior and hence a no-op. +* `--best`: + alias to the option `-9`. + + ### Restricted usage of Environment Variables Using environment variables to set parameters has security implications. diff --git a/programs/zstdcli.c b/programs/zstdcli.c index 29da261df..0b9b82a98 100644 --- a/programs/zstdcli.c +++ b/programs/zstdcli.c @@ -125,6 +125,15 @@ static void checkLibVersion(void) } +/*! exeNameMatch() : + @return : a non-zero value if exeName matches test, excluding the extension + */ +static int exeNameMatch(const char* exeName, const char* test) +{ + return !strncmp(exeName, test, strlen(test)) && + (exeName[strlen(test)] == '\0' || exeName[strlen(test)] == '.'); +} + /*-************************************ * Command Line **************************************/ @@ -153,6 +162,11 @@ static void usage(FILE* f, const char* programName) DISPLAY_F(f, " block devices, etc.\n"); DISPLAY_F(f, "--rm : remove source file(s) after successful de/compression \n"); DISPLAY_F(f, " -k : preserve source file(s) (default) \n"); +#ifdef ZSTD_GZCOMPRESS + if (exeNameMatch(programName, ZSTD_GZ)) { /* behave like gzip */ + DISPLAY_F(f, " -n : do not store original filename when compressing \n"); + } +#endif DISPLAY_F(f, " -h/-H : display help/long help and exit \n"); } @@ -208,6 +222,12 @@ static void usage_advanced(const char* programName) DISPLAYOUT( "--ultra : enable levels beyond %i, up to %i (requires more memory) \n", ZSTDCLI_CLEVEL_MAX, ZSTD_maxCLevel()); DISPLAYOUT( "--long[=#]: enable long distance matching with given window log (default: %u) \n", g_defaultMaxWindowLog); DISPLAYOUT( "--fast[=#]: switch to very fast compression levels (default: %u) \n", 1); +#ifdef ZSTD_GZCOMPRESS + if (exeNameMatch(programName, ZSTD_GZ)) { /* behave like gzip */ + DISPLAYOUT( "--best : compatibility alias for -9 \n"); + DISPLAYOUT( "--no-name : do not store original filename when compressing \n"); + } +#endif DISPLAYOUT( "--adapt : dynamically adapt compression level to I/O conditions \n"); DISPLAYOUT( "--[no-]row-match-finder : force enable/disable usage of fast row-based matchfinder for greedy, lazy, and lazy2 strategies \n"); DISPLAYOUT( "--patch-from=FILE : specify the file to be used as a reference point for zstd's diff engine. \n"); @@ -298,15 +318,6 @@ static const char* lastNameFromPath(const char* path) return name; } -/*! exeNameMatch() : - @return : a non-zero value if exeName matches test, excluding the extension - */ -static int exeNameMatch(const char* exeName, const char* test) -{ - return !strncmp(exeName, test, strlen(test)) && - (exeName[strlen(test)] == '\0' || exeName[strlen(test)] == '.'); -} - static void errorOut(const char* msg) { DISPLAY("%s \n", msg); exit(1); @@ -866,7 +877,10 @@ int main(int argCount, const char* argv[]) if (exeNameMatch(programName, ZSTD_UNZSTD)) operation=zom_decompress; if (exeNameMatch(programName, ZSTD_CAT)) { operation=zom_decompress; FIO_overwriteMode(prefs); forceStdout=1; followLinks=1; outFileName=stdoutmark; g_displayLevel=1; } /* supports multiple formats */ if (exeNameMatch(programName, ZSTD_ZCAT)) { operation=zom_decompress; FIO_overwriteMode(prefs); forceStdout=1; followLinks=1; outFileName=stdoutmark; g_displayLevel=1; } /* behave like zcat, also supports multiple formats */ - if (exeNameMatch(programName, ZSTD_GZ)) { suffix = GZ_EXTENSION; FIO_setCompressionType(prefs, FIO_gzipCompression); FIO_setRemoveSrcFile(prefs, 1); } /* behave like gzip */ + if (exeNameMatch(programName, ZSTD_GZ)) { /* behave like gzip */ + suffix = GZ_EXTENSION; FIO_setCompressionType(prefs, FIO_gzipCompression); FIO_setRemoveSrcFile(prefs, 1); + dictCLevel = cLevel = 6; /* gzip default is -6 */ + } if (exeNameMatch(programName, ZSTD_GUNZIP)) { operation=zom_decompress; FIO_setRemoveSrcFile(prefs, 1); } /* behave like gunzip, also supports multiple formats */ if (exeNameMatch(programName, ZSTD_GZCAT)) { operation=zom_decompress; FIO_overwriteMode(prefs); forceStdout=1; followLinks=1; outFileName=stdoutmark; g_displayLevel=1; } /* behave like gzcat, also supports multiple formats */ if (exeNameMatch(programName, ZSTD_LZMA)) { suffix = LZMA_EXTENSION; FIO_setCompressionType(prefs, FIO_lzmaCompression); FIO_setRemoveSrcFile(prefs, 1); } /* behave like lzma */ @@ -936,6 +950,10 @@ int main(int argCount, const char* argv[]) if (!strcmp(argument, "--format=zstd")) { suffix = ZSTD_EXTENSION; FIO_setCompressionType(prefs, FIO_zstdCompression); continue; } #ifdef ZSTD_GZCOMPRESS if (!strcmp(argument, "--format=gzip")) { suffix = GZ_EXTENSION; FIO_setCompressionType(prefs, FIO_gzipCompression); continue; } + if (exeNameMatch(programName, ZSTD_GZ)) { /* behave like gzip */ + if (!strcmp(argument, "--best")) { dictCLevel = cLevel = 9; continue; } + if (!strcmp(argument, "--no-name")) { /* ignore for now */; continue; } + } #endif #ifdef ZSTD_LZMACOMPRESS if (!strcmp(argument, "--format=lzma")) { suffix = LZMA_EXTENSION; FIO_setCompressionType(prefs, FIO_lzmaCompression); continue; } @@ -1098,6 +1116,9 @@ int main(int argCount, const char* argv[]) /* Force stdout, even if stdout==console */ case 'c': forceStdout=1; outFileName=stdoutmark; argument++; break; + /* do not store filename - gzip compatibility - nothing to do */ + case 'n': argument++; break; + /* Use file content as dictionary */ case 'D': argument++; NEXT_FIELD(dictFileName); break; diff --git a/tests/cli-tests/compression/gzip-compat.sh b/tests/cli-tests/compression/gzip-compat.sh new file mode 100755 index 000000000..bb72e05fc --- /dev/null +++ b/tests/cli-tests/compression/gzip-compat.sh @@ -0,0 +1,15 @@ +#!/bin/sh + +set -e + +# Uncomment the set -v line for debugging +# set -v + +# Test gzip specific compression option +$ZSTD_SYMLINK_DIR/gzip --fast file ; $ZSTD_SYMLINK_DIR/gzip -d file.gz +$ZSTD_SYMLINK_DIR/gzip --best file ; $ZSTD_SYMLINK_DIR/gzip -d file.gz + +# Test -n / --no-name: do not embed original filename in archive +$ZSTD_SYMLINK_DIR/gzip -n file ; grep -qv file file.gz ; $ZSTD_SYMLINK_DIR/gzip -d file.gz +$ZSTD_SYMLINK_DIR/gzip --no-name file ; grep -qv file file.gz ; $ZSTD_SYMLINK_DIR/gzip -d file.gz +$ZSTD_SYMLINK_DIR/gzip -c --no-name file | grep -qv file