X-Git-Url: https://gerrit.opnfv.org/gerrit/gitweb?a=blobdiff_plain;f=src%2Fceph%2Fsrc%2Frgw%2Frgw_tar.h;fp=src%2Fceph%2Fsrc%2Frgw%2Frgw_tar.h;h=2e5add6ed13011d4cb8bb663ca724b2bdfca4f1c;hb=812ff6ca9fcd3e629e49d4328905f33eee8ca3f5;hp=0000000000000000000000000000000000000000;hpb=15280273faafb77777eab341909a3f495cf248d9;p=stor4nfv.git diff --git a/src/ceph/src/rgw/rgw_tar.h b/src/ceph/src/rgw/rgw_tar.h new file mode 100644 index 0000000..2e5add6 --- /dev/null +++ b/src/ceph/src/rgw/rgw_tar.h @@ -0,0 +1,156 @@ +// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- +// vim: ts=8 sw=2 smarttab + +#ifndef CEPH_RGW_TAR_H +#define CEPH_RGW_TAR_H + +#include +#include +#include +#include +#include + +#include +#include +#include + +namespace rgw { +namespace tar { + +static constexpr size_t BLOCK_SIZE = 512; + + +static inline std::pair> +interpret_block(const StatusIndicator& status, ceph::bufferlist& bl); + + +class StatusIndicator { + friend std::pair> + interpret_block(const StatusIndicator& status, ceph::bufferlist& bl); + + bool is_empty; + bool is_eof; + + StatusIndicator() + : is_empty(false), + is_eof(false) { + } + + StatusIndicator(const StatusIndicator& prev_status, + const bool is_empty) + : is_empty(is_empty), + is_eof(is_empty && prev_status.empty()) { + } + +public: + bool empty() const { + return is_empty; + } + + bool eof() const { + return is_eof; + } + + static StatusIndicator create() { + return StatusIndicator(); + } +} /* class StatusIndicator */; + + +enum class FileType : char { + UNKNOWN = '\0', + + /* The tar format uses ASCII encoding. */ + NORMAL_FILE = '0', + DIRECTORY = '5' +}; /* enum class FileType */ + +class HeaderView { +protected: + /* Everythng is char here (ASCII encoding), so we don't need to worry about + * the struct padding. */ + const struct header_t { + char filename[100]; + char __filemode[8]; + char __owner_id[8]; + char __group_id[8]; + char filesize[12]; + char lastmod[12]; + char checksum[8]; + char filetype; + char __padding[355]; + } *header; + + static_assert(sizeof(*header) == BLOCK_SIZE, + "The TAR header must be exactly BLOCK_SIZE length"); + + /* The label is far more imporant from what the code really does. */ + static size_t pos2len(const size_t pos) { + return pos + 1; + } + +public: + HeaderView(const char (&header)[BLOCK_SIZE]) + : header(reinterpret_cast(header)) { + } + + FileType get_filetype() const { + switch (header->filetype) { + case static_cast(FileType::NORMAL_FILE): + return FileType::NORMAL_FILE; + case static_cast(FileType::DIRECTORY): + return FileType::DIRECTORY; + default: + return FileType::UNKNOWN; + } + } + + boost::string_ref get_filename() const { + return boost::string_ref(header->filename, + std::min(sizeof(header->filename), + strlen(header->filename))); + } + + size_t get_filesize() const { + /* The string_ref is pretty suitable here because tar encodes its + * metadata in ASCII. */ + const boost::string_ref raw(header->filesize, sizeof(header->filesize)); + + /* We need to find where the padding ends. */ + const auto pad_ends_at = std::min(raw.find_last_not_of('\0'), + raw.find_last_not_of(' ')); + const auto trimmed = raw.substr(0, + pad_ends_at == boost::string_ref::npos ? boost::string_ref::npos + : pos2len(pad_ends_at)); + + size_t sum = 0, mul = 1; + for (const char c : boost::adaptors::reverse(trimmed)) { + sum += (c - '0') * mul; + mul *= 8; + } + + return sum; + } +}; /* class Header */ + + +static inline std::pair> +interpret_block(const StatusIndicator& status, ceph::bufferlist& bl) { + static constexpr std::array zero_block = {0, }; + const char (&block)[BLOCK_SIZE] = \ + reinterpret_cast(*bl.c_str()); + + if (std::memcmp(zero_block.data(), block, BLOCK_SIZE) == 0) { + return std::make_pair(StatusIndicator(status, true), boost::none); + } else { + return std::make_pair(StatusIndicator(status, false), HeaderView(block)); + } +} + +} /* namespace tar */ +} /* namespace rgw */ + +#endif /* CEPH_RGW_TAR_H */