diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/libutil/tarfile.cc | 48 |
1 files changed, 23 insertions, 25 deletions
diff --git a/src/libutil/tarfile.cc b/src/libutil/tarfile.cc index 6c3fb4634..8e2f7c8cb 100644 --- a/src/libutil/tarfile.cc +++ b/src/libutil/tarfile.cc @@ -18,6 +18,14 @@ std::shared_ptr<struct archive> archive_read_ptr() { archive_read_free(p); }); } +static void ac(std::shared_ptr<struct archive> a, int r, const char* str = "archive is corrupt (%s)") { + if (r == ARCHIVE_EOF) { + throw EndOfFile("tar ended"); + } + if (r != ARCHIVE_OK) { + throw Error(str, archive_error_string(a.get())); + } +} void archive_read_open_source(std::shared_ptr<struct archive> a, Source& s, unsigned int bufsize = 1024) { std::shared_ptr<unsigned char> buffer((unsigned char*)malloc(bufsize), [](auto p) { free(p); }); typedef struct { @@ -26,7 +34,7 @@ void archive_read_open_source(std::shared_ptr<struct archive> a, Source& s, unsi unsigned int bs; } St; St* state = new St({buffer, s, bufsize}); - if (archive_read_open(a.get(), state, + ac(a, archive_read_open(a.get(), state, NULL /* open */, ([] (struct archive*, void* sptr, const void** buf) -> long int { St& s = *(static_cast<St*>(sptr)); @@ -40,9 +48,7 @@ void archive_read_open_source(std::shared_ptr<struct archive> a, Source& s, unsi }), [] (struct archive*, void* sptr) { delete static_cast<St*>(sptr); return ARCHIVE_OK; - })) { - throw Error("archive is corrupt (%s)", archive_error_string(a.get())); - } + })); } std::shared_ptr<struct archive> archive_write_ptr() { return std::shared_ptr<struct archive>(archive_write_disk_new(), @@ -53,28 +59,27 @@ std::shared_ptr<struct archive> archive_write_ptr() { } static void copy_data(std::shared_ptr<struct archive> ar, std::shared_ptr<struct archive> aw) { - int r; const void *buff; size_t size; la_int64_t offset; for (;;) { - r = archive_read_data_block(ar.get(), &buff, &size, &offset); - if (r == ARCHIVE_EOF) return; - if (r != ARCHIVE_OK) { - throw Error("archive is corrupt (%s)", archive_error_string(ar.get())); - } - r = archive_write_data_block(aw.get(), buff, size, offset); - if (r != ARCHIVE_OK) { - throw Error("could not write archive output (%s)", archive_error_string(aw.get())); + try { + ac(ar, archive_read_data_block(ar.get(), &buff, &size, &offset)); + } catch (EndOfFile &) { + return; } + ac(aw, archive_write_data_block(aw.get(), buff, size, offset), "could not write archive output (%s)"); } } - static void extract_archive(std::shared_ptr<struct archive> a, const Path & destDir) { char * cwd = getcwd(0, 0); if (!cwd) throw SysError("getting current directory"); - Finally freeCwd([&]() { chdir(cwd); free(cwd); }); + Finally backCwd([&]() { + int r = chdir(cwd); + free(cwd); + if (r != 0) throw SysError("resetting directory after archive extraction"); + }); int r = chdir(destDir.c_str()); if (r != 0) throw SysError("setting directory to tar output path"); struct archive_entry *entry; @@ -90,16 +95,12 @@ static void extract_archive(std::shared_ptr<struct archive> a, const Path & dest if (r == ARCHIVE_WARN) { std::cerr << "warning: " << archive_error_string(a.get()); } else if (r < ARCHIVE_WARN) { - throw Error("archive is corrupt (%s)", archive_error_string(a.get())); - } - r = archive_write_header(ext.get(), entry); - if (r != ARCHIVE_OK) { - throw Error("could not write archive output (%s)", archive_error_string(ext.get())); + ac(a, r); } + ac(ext, archive_write_header(ext.get(), entry), "could not write archive output (%s)"); copy_data(a, ext); archive_write_finish_entry(ext.get()); } - //if (r != 0) throw SysError("resetting directory after archive extraction"); } void unpackTarfile(Source & source, const Path & destDir) { @@ -115,10 +116,7 @@ void unpackTarfile(const Path & tarFile, const Path & destDir) auto a = archive_read_ptr(); archive_read_support_filter_all(a.get()); archive_read_support_format_all(a.get()); - int r = archive_read_open_filename(a.get(), tarFile.c_str(), 16384); - if (r != ARCHIVE_OK) { - throw Error("archive is corrupt (%s)", archive_error_string(a.get())); - } + ac(a, archive_read_open_filename(a.get(), tarFile.c_str(), 16384)); createDirs(destDir); extract_archive(a, destDir); } |