aboutsummaryrefslogtreecommitdiff
path: root/src/libutil
diff options
context:
space:
mode:
Diffstat (limited to 'src/libutil')
-rw-r--r--src/libutil/compression.cc64
-rw-r--r--src/libutil/rust-ffi.cc17
-rw-r--r--src/libutil/rust-ffi.hh58
-rw-r--r--src/libutil/tarfile.cc8
4 files changed, 111 insertions, 36 deletions
diff --git a/src/libutil/compression.cc b/src/libutil/compression.cc
index 0dd84e320..860b04adb 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)",
+ zError(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/rust-ffi.cc b/src/libutil/rust-ffi.cc
index accc5e22b..8b8b7b75d 100644
--- a/src/libutil/rust-ffi.cc
+++ b/src/libutil/rust-ffi.cc
@@ -3,10 +3,14 @@
extern "C" std::exception_ptr * make_error(rust::StringSlice s)
{
- // FIXME: leak
return new std::exception_ptr(std::make_exception_ptr(nix::Error(std::string(s.ptr, s.size))));
}
+extern "C" void destroy_error(std::exception_ptr * ex)
+{
+ free(ex);
+}
+
namespace rust {
std::ostream & operator << (std::ostream & str, const String & s)
@@ -15,4 +19,15 @@ std::ostream & operator << (std::ostream & str, const String & s)
return str;
}
+size_t Source::sourceWrapper(void * _this, rust::Slice<uint8_t> data)
+{
+ try {
+ // FIXME: how to propagate exceptions?
+ auto n = ((nix::Source *) _this)->read((unsigned char *) data.ptr, data.size);
+ return n;
+ } catch (...) {
+ abort();
+ }
+}
+
}
diff --git a/src/libutil/rust-ffi.hh b/src/libutil/rust-ffi.hh
index a77f83ac5..3b51661c2 100644
--- a/src/libutil/rust-ffi.hh
+++ b/src/libutil/rust-ffi.hh
@@ -140,64 +140,58 @@ struct Source
: fun(sourceWrapper), _this(&_this)
{}
- // FIXME: how to propagate exceptions?
- static size_t sourceWrapper(void * _this, rust::Slice<uint8_t> data)
- {
- auto n = ((nix::Source *) _this)->read((unsigned char *) data.ptr, data.size);
- return n;
- }
+ static size_t sourceWrapper(void * _this, rust::Slice<uint8_t> data);
};
/* C++ representation of Rust's Result<T, CppException>. */
template<typename T>
struct Result
{
- unsigned int tag;
+ enum { Ok = 0, Err = 1, Uninit = 2 } tag;
union {
T data;
std::exception_ptr * exc;
};
+ Result() : tag(Uninit) { }; // FIXME: remove
+
+ Result(const Result &) = delete;
+
+ Result(Result && other)
+ : tag(other.tag)
+ {
+ other.tag = Uninit;
+ if (tag == Ok)
+ data = std::move(other.data);
+ else if (tag == Err)
+ exc = other.exc;
+ }
+
~Result()
{
- if (tag == 0)
+ if (tag == Ok)
data.~T();
- else if (tag == 1)
- // FIXME: don't leak exc
+ else if (tag == Err)
+ free(exc);
+ else if (tag == Uninit)
;
+ else
+ abort();
}
/* Rethrow the wrapped exception or return the wrapped value. */
T unwrap()
{
- if (tag == 0)
+ if (tag == Ok) {
+ tag = Uninit;
return std::move(data);
- else if (tag == 1)
+ }
+ else if (tag == Err)
std::rethrow_exception(*exc);
else
abort();
}
};
-template<typename T>
-struct CBox
-{
- T * ptr;
-
- T * operator ->()
- {
- return ptr;
- }
-
- CBox(T * ptr) : ptr(ptr) { }
- CBox(const CBox &) = delete;
- CBox(CBox &&) = delete;
-
- ~CBox()
- {
- free(ptr);
- }
-};
-
}
diff --git a/src/libutil/tarfile.cc b/src/libutil/tarfile.cc
index 262bc655f..1be0ba24c 100644
--- a/src/libutil/tarfile.cc
+++ b/src/libutil/tarfile.cc
@@ -3,7 +3,7 @@
extern "C" {
rust::Result<std::tuple<>> *
- unpack_tarfile(rust::Source source, rust::StringSlice dest_dir);
+ unpack_tarfile(rust::Source source, rust::StringSlice dest_dir, rust::Result<std::tuple<>> & out);
}
namespace nix {
@@ -11,7 +11,9 @@ namespace nix {
void unpackTarfile(Source & source, const Path & destDir)
{
rust::Source source2(source);
- rust::CBox(unpack_tarfile(source2, destDir))->unwrap();
+ rust::Result<std::tuple<>> res;
+ unpack_tarfile(source2, destDir, res);
+ res.unwrap();
}
void unpackTarfile(const Path & tarFile, const Path & destDir,
@@ -22,8 +24,8 @@ void unpackTarfile(const Path & tarFile, const Path & destDir,
auto source = sinkToSource([&](Sink & sink) {
// FIXME: look at first few bytes to determine compression type.
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);