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.
diff --git a/programs/zstd.1 b/programs/zstd.1
index c7a19db..0e6e016 100644
--- a/programs/zstd.1
+++ b/programs/zstd.1
@@ -217,6 +217,17 @@
.
.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 e343ec0..569ca1a 100644
--- a/programs/zstd.1.md
+++ b/programs/zstd.1.md
@@ -280,6 +280,18 @@
* `--`:
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 29da261..0b9b82a 100644
--- a/programs/zstdcli.c
+++ b/programs/zstdcli.c
@@ -125,6 +125,15 @@
}
+/*! 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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
/* 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 0000000..bb72e05
--- /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