diff --git a/cdoc/Tar.cpp b/cdoc/Tar.cpp index 81283df..32fa4af 100644 --- a/cdoc/Tar.cpp +++ b/cdoc/Tar.cpp @@ -17,22 +17,12 @@ */ #include "Tar.h" +#include "Utils.h" #include -#include +#include -std::vector -split (const std::string &s, char delim) { - std::vector result; - std::stringstream ss (s); - std::string item; - - while (getline (ss, item, delim)) { - result.push_back (item); - } - - return result; -} +using namespace libcdoc; template static int64_t fromOctal(const std::array &data) @@ -59,7 +49,7 @@ static void toOctal(std::array &data, int64_t value) } } -struct Header { +struct libcdoc::Header { std::array name; std::array mode; std::array uid; @@ -89,9 +79,9 @@ struct Header { return {unsignedSum, signedSum}; } - bool isNull() { - Header empty = {}; - return std::memcmp(this, &empty, sizeof(Header)) == 0; + bool isNull() const { + static const Header empty{}; + return *this == empty; } bool verify() { @@ -104,8 +94,7 @@ struct Header { referenceChecksum == checkSum.second; } - static const Header Empty; - static const int Size; + bool operator==(const Header&) const = default; }; static int padding(int64_t size) @@ -113,32 +102,6 @@ static int padding(int64_t size) return sizeof(Header) - size % sizeof(Header); } -bool -libcdoc::TAR::files(libcdoc::DataSource *src, bool &warning, libcdoc::MultiDataConsumer *dst) -{ - TarSource tar(src, false); - std::string name; - int64_t size; - while (tar.next(name, size) == OK) { - dst->open(name, size); - dst->writeAll(tar); - } - warning = !src->isEof(); - return true; -} - -int64_t writePadding(libcdoc::DataConsumer *dst, uint64_t size) { - std::vector pad(padding(size), 0); - return dst->write((const uint8_t *) pad.data(), pad.size()) == pad.size(); -}; - -int64_t writeHeader (libcdoc::DataConsumer *dst, Header &h, uint64_t size) { - h.chksum.fill(' '); - toOctal(h.size, size); - toOctal(h.chksum, h.checksum().first); - return dst->write((const uint8_t *)&h, sizeof(Header)) == sizeof(Header); -}; - std::string toPaxRecord (const std::string &keyword, const std::string &value) { std::string record = ' ' + keyword + '=' + value + '\n'; std::string result; @@ -147,51 +110,6 @@ std::string toPaxRecord (const std::string &keyword, const std::string &value) { return result; }; -bool -libcdoc::TAR::save(libcdoc::DataConsumer& dst, libcdoc::MultiDataSource& src) -{ - std::string name; - int64_t size; - while (src.next(name, size)) { - Header h {}; - std::string filename(name); - std::string filenameTruncated(filename.begin(), filename.begin() + h.name.size()); - std::copy(filenameTruncated.cbegin(), filenameTruncated.cend(), h.name.begin()); - - // TODO: - // write pax record if name contains special symbols - if(filename.size() > 100 || size > 07777777) { - h.typeflag = 'x'; - std::string paxData; - if(filename.size() > 100) - paxData += toPaxRecord("path", filename); - if(size > 07777777) - paxData += toPaxRecord("size", std::to_string(size)); - if(!writeHeader(&dst, h, paxData.size()) || - dst.write((const uint8_t *) paxData.data(), paxData.size()) != paxData.size() || - !writePadding(&dst, paxData.size())) - return false; - } - - h.typeflag = '0'; - if(!writeHeader(&dst, h, size)) - return false; - size_t total_written = 0; - while (!src.isEof()) { - uint8_t buf[256]; - auto n_read = src.read(buf, 256); - if (n_read < 0) return false; - dst.write(buf, n_read); - total_written += n_read; - } - writePadding(&dst, total_written); - - } - Header empty = {}; - return dst.write((const uint8_t *)&empty, sizeof(Header)) == sizeof(Header) && - dst.write((const uint8_t *)&empty, sizeof(Header)) == sizeof(Header); -} - libcdoc::TarConsumer::TarConsumer(DataConsumer *dst, bool take_ownership) : _dst(dst), _owned(take_ownership) { @@ -211,17 +129,44 @@ libcdoc::TarConsumer::write(const uint8_t *src, size_t size) return _dst->write(src, size); } +libcdoc::result_t +libcdoc::TarConsumer::writeHeader(const Header &h) { + if(auto rv = _dst->write((const uint8_t *)&h, sizeof(Header)); rv != sizeof(Header)) + return rv < OK ? rv : OUTPUT_ERROR; + return OK; +} + +libcdoc::result_t +libcdoc::TarConsumer::writeHeader(Header &h, int64_t size) { + h.chksum.fill(' '); + toOctal(h.size, size); + toOctal(h.chksum, h.checksum().first); + return writeHeader(h); +} + +libcdoc::result_t +libcdoc::TarConsumer::writePadding(int64_t size) { + std::array pad {}; + auto padSize = padding(size); + if(auto rv = _dst->write(pad.data(), padSize); rv != padSize) + return rv < OK ? rv : OUTPUT_ERROR; + return OK; +} + libcdoc::result_t libcdoc::TarConsumer::close() { - if (_current_size) { - writePadding(_dst, _current_size); - } - Header empty = {}; - _dst->write((const uint8_t *)&empty, sizeof(Header)); - _dst->write((const uint8_t *)&empty, sizeof(Header)); + if (_current_size > 0) { + if(auto rv = writePadding(_current_size); rv != OK) + return rv; + } + Header empty = {}; + if(auto rv = writeHeader(empty); rv != OK) + return rv; + if(auto rv = writeHeader(empty); rv != OK) + return rv; if (_owned) { - _dst->close(); + return _dst->close(); } return OK; } @@ -235,32 +180,33 @@ libcdoc::TarConsumer::isError() libcdoc::result_t libcdoc::TarConsumer::open(const std::string& name, int64_t size) { - if (_current_size) { - writePadding(_dst, _current_size); - } - _current_size = size; + if (_current_size > 0) { + if(auto rv = writePadding(_current_size); rv != OK) + return rv; + } + + _current_size = size; Header h {}; - std::string filename(name); - size_t len = name.size(); - if (len > h.name.size()) len = h.name.size(); - std::copy(name.cbegin(), name.cbegin() + len, h.name.begin()); + size_t len = std::min(name.size(), h.name.size()); + std::copy_n(name.cbegin(), len, h.name.begin()); // TODO: Create pax record if name contains special symbols - if(filename.size() > 100 || size > 07777777) { + if(name.size() > 100 || size > 07777777) { h.typeflag = 'x'; std::string paxData; - if(filename.size() > 100) - paxData += toPaxRecord("path", filename); + if(name.size() > 100) + paxData += toPaxRecord("path", name); if(size > 07777777) paxData += toPaxRecord("size", std::to_string(size)); - return writeHeader(_dst, h, paxData.size()) && - _dst->write((const uint8_t *) paxData.data(), paxData.size()) == paxData.size() && - writePadding(_dst, paxData.size()) ? OK : OUTPUT_ERROR; - } - + if (auto rv = writeHeader(h, paxData.size()); rv != OK) + return rv; + if (auto rv = _dst->write((const uint8_t *) paxData.data(), paxData.size()); rv != paxData.size()) + return rv < OK ? rv : OUTPUT_ERROR; + if (auto rv = writePadding(paxData.size()); rv != OK) + return rv; + } h.typeflag = '0'; - if(writeHeader(_dst, h, size) < 0) return OUTPUT_ERROR; - return OK; + return writeHeader(h, size); } libcdoc::TarSource::TarSource(DataSource *src, bool take_ownership) diff --git a/cdoc/Tar.h b/cdoc/Tar.h index 8399e1b..9f89186 100644 --- a/cdoc/Tar.h +++ b/cdoc/Tar.h @@ -21,27 +21,25 @@ #include -#include namespace libcdoc { -struct TAR { - explicit TAR() = default; +struct Header; - static bool files(libcdoc::DataSource *src, bool &warning, libcdoc::MultiDataConsumer *dst); - static bool save(libcdoc::DataConsumer& dst, libcdoc::MultiDataSource& src); -}; - -struct TarConsumer : public MultiDataConsumer +struct TarConsumer final : public MultiDataConsumer { public: TarConsumer(DataConsumer *dst, bool take_ownership); ~TarConsumer(); - libcdoc::result_t write(const uint8_t *src, size_t size) override final; - libcdoc::result_t close() override final; - bool isError() override final; - libcdoc::result_t open(const std::string& name, int64_t size) override final; + libcdoc::result_t write(const uint8_t *src, size_t size) final; + libcdoc::result_t close() final; + bool isError() final; + libcdoc::result_t open(const std::string& name, int64_t size) final; private: + result_t writeHeader(const Header &h); + result_t writeHeader(Header &h, int64_t size); + result_t writePadding(int64_t size); + DataConsumer *_dst; bool _owned; int64_t _current_size = 0;