diff options
Diffstat (limited to 'src/libutil/tarfile.cc')
-rw-r--r-- | src/libutil/tarfile.cc | 130 |
1 files changed, 63 insertions, 67 deletions
diff --git a/src/libutil/tarfile.cc b/src/libutil/tarfile.cc index 2da169ba7..50e691a3d 100644 --- a/src/libutil/tarfile.cc +++ b/src/libutil/tarfile.cc @@ -2,83 +2,76 @@ #include <archive_entry.h> #include "serialise.hh" +#include "tarfile.hh" namespace nix { -struct TarArchive { - struct archive * archive; - Source * source; - std::vector<unsigned char> buffer; - - void check(int err, const char * reason = "failed to extract archive: %s") - { - if (err == ARCHIVE_EOF) - throw EndOfFile("reached end of archive"); - else if (err != ARCHIVE_OK) - throw Error(reason, archive_error_string(this->archive)); - } - - TarArchive(Source & source) : buffer(4096) - { - this->archive = archive_read_new(); - this->source = &source; - - archive_read_support_filter_all(archive); - archive_read_support_format_all(archive); - check(archive_read_open(archive, - (void *)this, - TarArchive::callback_open, - TarArchive::callback_read, - TarArchive::callback_close), - "failed to open archive: %s"); - } - - TarArchive(const Path & path) - { - this->archive = archive_read_new(); +static int callback_open(struct archive *, void * self) +{ + return ARCHIVE_OK; +} - archive_read_support_filter_all(archive); - archive_read_support_format_all(archive); - check(archive_read_open_filename(archive, path.c_str(), 16384), "failed to open archive: %s"); +static ssize_t callback_read(struct archive * archive, void * _self, const void * * buffer) +{ + auto self = (TarArchive *) _self; + *buffer = self->buffer.data(); + + try { + return self->source->read((char *) self->buffer.data(), 4096); + } catch (EndOfFile &) { + return 0; + } catch (std::exception & err) { + archive_set_error(archive, EIO, "Source threw exception: %s", err.what()); + return -1; } +} - TarArchive(const TarArchive &) = delete; +static int callback_close(struct archive *, void * self) +{ + return ARCHIVE_OK; +} - void close() - { - check(archive_read_close(archive), "failed to close archive: %s"); - } +void TarArchive::check(int err, const std::string & reason) +{ + if (err == ARCHIVE_EOF) + throw EndOfFile("reached end of archive"); + else if (err != ARCHIVE_OK) + throw Error(reason, archive_error_string(this->archive)); +} - ~TarArchive() - { - if (this->archive) archive_read_free(this->archive); - } +TarArchive::TarArchive(Source & source, bool raw) + : source(&source), buffer(4096) +{ + init(); + if (!raw) + archive_read_support_format_all(archive); + else + archive_read_support_format_raw(archive); + check(archive_read_open(archive, (void *)this, callback_open, callback_read, callback_close), "Failed to open archive (%s)"); +} -private: +TarArchive::TarArchive(const Path & path) +{ + init(); + archive_read_support_format_all(archive); + check(archive_read_open_filename(archive, path.c_str(), 16384), "failed to open archive: %s"); +} - static int callback_open(struct archive *, void * self) { - return ARCHIVE_OK; - } +void TarArchive::init() +{ + archive = archive_read_new(); + archive_read_support_filter_all(archive); +} - static ssize_t callback_read(struct archive * archive, void * _self, const void * * buffer) - { - auto self = (TarArchive *)_self; - *buffer = self->buffer.data(); - - try { - return self->source->read((char *) self->buffer.data(), 4096); - } catch (EndOfFile &) { - return 0; - } catch (std::exception & err) { - archive_set_error(archive, EIO, "source threw exception: %s", err.what()); - return -1; - } - } +void TarArchive::close() +{ + check(archive_read_close(this->archive), "Failed to close archive (%s)"); +} - static int callback_close(struct archive *, void * self) { - return ARCHIVE_OK; - } -}; +TarArchive::~TarArchive() +{ + if (this->archive) archive_read_free(this->archive); +} static void extract_archive(TarArchive & archive, const Path & destDir) { @@ -92,13 +85,16 @@ static void extract_archive(TarArchive & archive, const Path & destDir) struct archive_entry * entry; int r = archive_read_next_header(archive.archive, &entry); if (r == ARCHIVE_EOF) break; - else if (r == ARCHIVE_WARN) + auto name = archive_entry_pathname(entry); + if (!name) + throw Error("cannot get archive member name: %s", archive_error_string(archive.archive)); + if (r == ARCHIVE_WARN) warn(archive_error_string(archive.archive)); else archive.check(r); archive_entry_set_pathname(entry, - (destDir + "/" + archive_entry_pathname(entry)).c_str()); + (destDir + "/" + name).c_str()); archive.check(archive_read_extract(archive.archive, entry, flags)); } |