aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorTom Bereknyei <tom@rebelliondefense.com>2019-12-13 03:29:33 -0500
committerTom Bereknyei <tom@rebelliondefense.com>2019-12-13 03:34:15 -0500
commitc6295a3afd87a605f30f1de8b09d7885eb08fedb (patch)
tree17b611f1cdf0e6491cdc1c52b1046bdb614758bf /src
parentf800d450b78091835ab7ca67847d76e75d877a24 (diff)
Initial gzip support
Closes #3256
Diffstat (limited to 'src')
-rw-r--r--src/libutil/compression.cc64
-rw-r--r--src/libutil/tarfile.cc1
2 files changed, 65 insertions, 0 deletions
diff --git a/src/libutil/compression.cc b/src/libutil/compression.cc
index 0dd84e320..17b506d5d 100644
--- a/src/libutil/compression.cc
+++ b/src/libutil/compression.cc
@@ -11,6 +11,8 @@
#include <brotli/decode.h>
#include <brotli/encode.h>
+#include <zlib.h>
+
#include <iostream>
namespace nix {
@@ -42,6 +44,66 @@ struct NoneSink : CompressionSink
void write(const unsigned char * data, size_t len) override { nextSink(data, len); }
};
+struct GzipDecompressionSink : CompressionSink
+{
+ Sink & nextSink;
+ z_stream strm;
+ bool finished = false;
+ uint8_t outbuf[BUFSIZ];
+
+ GzipDecompressionSink(Sink & nextSink) : nextSink(nextSink)
+ {
+ strm.zalloc = Z_NULL;
+ strm.zfree = Z_NULL;
+ strm.opaque = Z_NULL;
+ strm.avail_in = 0;
+ strm.next_in = Z_NULL;
+ strm.next_out = outbuf;
+ strm.avail_out = sizeof(outbuf);
+
+ // Enable gzip and zlib decoding (+32) with 15 windowBits
+ int ret = inflateInit2(&strm,15+32);
+ if (ret != Z_OK)
+ throw CompressionError("unable to initialise gzip encoder");
+ }
+
+ ~GzipDecompressionSink()
+ {
+ inflateEnd(&strm);
+ }
+
+ void finish() override
+ {
+ CompressionSink::flush();
+ write(nullptr, 0);
+ }
+
+ void write(const unsigned char * data, size_t len) override
+ {
+ assert(len <= std::numeric_limits<decltype(strm.avail_in)>::max());
+
+ strm.next_in = (Bytef *) data;
+ strm.avail_in = len;
+
+ while (!finished && (!data || strm.avail_in)) {
+ checkInterrupt();
+
+ int ret = inflate(&strm,Z_SYNC_FLUSH);
+ if (ret != Z_OK && ret != Z_STREAM_END)
+ throw CompressionError("error while decompressing gzip file: %d: %d: %d",ret, len, strm.avail_in);
+
+
+ finished = ret == Z_STREAM_END;
+
+ if (strm.avail_out < sizeof(outbuf) || strm.avail_in == 0) {
+ nextSink(outbuf, sizeof(outbuf) - strm.avail_out);
+ strm.next_out = (Bytef *) outbuf;
+ strm.avail_out = sizeof(outbuf);
+ }
+ }
+ }
+};
+
struct XzDecompressionSink : CompressionSink
{
Sink & nextSink;
@@ -215,6 +277,8 @@ ref<CompressionSink> makeDecompressionSink(const std::string & method, Sink & ne
return make_ref<XzDecompressionSink>(nextSink);
else if (method == "bzip2")
return make_ref<BzipDecompressionSink>(nextSink);
+ else if (method == "gzip")
+ return make_ref<GzipDecompressionSink>(nextSink);
else if (method == "br")
return make_ref<BrotliDecompressionSink>(nextSink);
else
diff --git a/src/libutil/tarfile.cc b/src/libutil/tarfile.cc
index 262bc655f..c00673182 100644
--- a/src/libutil/tarfile.cc
+++ b/src/libutil/tarfile.cc
@@ -24,6 +24,7 @@ void unpackTarfile(const Path & tarFile, const Path & destDir,
auto decompressor =
// FIXME: add .gz support
hasSuffix(*baseName, ".bz2") ? makeDecompressionSink("bzip2", sink) :
+ hasSuffix(*baseName, ".gz") ? makeDecompressionSink("gzip", sink) :
hasSuffix(*baseName, ".xz") ? makeDecompressionSink("xz", sink) :
makeDecompressionSink("none", sink);
readFile(tarFile, *decompressor);