Skip to content

Commit

Permalink
Initial gzip support
Browse files Browse the repository at this point in the history
Closes NixOS#3256
  • Loading branch information
Tom Bereknyei committed Dec 13, 2019
1 parent f800d45 commit 1707a2b
Show file tree
Hide file tree
Showing 5 changed files with 88 additions and 1 deletion.
5 changes: 5 additions & 0 deletions configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,11 @@ PKG_CHECK_MODULES([LIBLZMA], [liblzma], [CXXFLAGS="$LIBLZMA_CFLAGS $CXXFLAGS"])
AC_CHECK_LIB([lzma], [lzma_stream_encoder_mt],
[AC_DEFINE([HAVE_LZMA_MT], [1], [xz multithreaded compression support])])

# Look for zlib, a required dependency.
PKG_CHECK_MODULES([ZLIB], [zlib], [CXXFLAGS="$ZLIB_CFLAGS $CXXFLAGS"])
AC_CHECK_HEADER([zlib.h],[:],[AC_MSG_ERROR([could not find the zlib.h header])])
LDFLAGS="-lz $LDFLAGS"

# Look for libbrotli{enc,dec}.
PKG_CHECK_MODULES([LIBBROTLI], [libbrotlienc libbrotlidec], [CXXFLAGS="$LIBBROTLI_CFLAGS $CXXFLAGS"])

Expand Down
2 changes: 1 addition & 1 deletion release-common.nix
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ rec {

buildDeps =
[ curl
bzip2 xz brotli editline
bzip2 xz brotli zlib editline
openssl pkgconfig sqlite boehmgc
boost
nlohmann_json
Expand Down
64 changes: 64 additions & 0 deletions src/libutil/compression.cc
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
#include <brotli/decode.h>
#include <brotli/encode.h>

#include <zlib.h>

#include <iostream>

namespace nix {
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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
Expand Down
1 change: 1 addition & 0 deletions src/libutil/tarfile.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
17 changes: 17 additions & 0 deletions tests/tarball.sh
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,20 @@ nix-instantiate --eval -E 'with <fnord/xyzzy>; 1 + 2' -I fnord=file://no-such-ta
(! nix-instantiate --eval -E '<fnord/xyzzy> 1' -I fnord=file://no-such-tarball.tar.xz)

nix-instantiate --eval -E '<fnord/config.nix>' -I fnord=file://no-such-tarball.tar.xz -I fnord=.

tarball=$TEST_ROOT/tarball.tar.gz
(cd $TEST_ROOT && tar c tarball) | gzip > $tarball

nix-env -f file://$tarball -qa --out-path | grep -q dependencies

nix-build -o $TEST_ROOT/result file://$tarball

nix-build -o $TEST_ROOT/result '<foo>' -I foo=file://$tarball

nix-build -o $TEST_ROOT/result -E "import (fetchTarball file://$tarball)"

nix-instantiate --eval -E '1 + 2' -I fnord=file://no-such-tarball.tar.gz
nix-instantiate --eval -E 'with <fnord/xyzzy>; 1 + 2' -I fnord=file://no-such-tarball.tar.gz
(! nix-instantiate --eval -E '<fnord/xyzzy> 1' -I fnord=file://no-such-tarball.tar.gz)

nix-instantiate --eval -E '<fnord/config.nix>' -I fnord=file://no-such-tarball.tar.gz -I fnord=.

0 comments on commit 1707a2b

Please sign in to comment.