From f4bd49aa69d002e632ced99cbcd57b52481ff70a Mon Sep 17 00:00:00 2001 From: Casey Bodley Date: Sun, 19 Feb 2023 00:46:42 -0500 Subject: [PATCH] rgw/torrent: add a PutObj filter for torrent info Signed-off-by: Casey Bodley --- src/rgw/rgw_torrent.cc | 79 +++++++++++++++++++++++++++++++++++++++++- src/rgw/rgw_torrent.h | 20 +++++++++++ 2 files changed, 98 insertions(+), 1 deletion(-) diff --git a/src/rgw/rgw_torrent.cc b/src/rgw/rgw_torrent.cc index e1a1417a5a6fd..96b56d980ddfc 100644 --- a/src/rgw/rgw_torrent.cc +++ b/src/rgw/rgw_torrent.cc @@ -4,7 +4,7 @@ #include #include -#include +#include #include "rgw_torrent.h" #include "rgw_sal.h" @@ -259,3 +259,80 @@ int seed::save_torrent_file(optional_yield y) return op_ret; } + +RGWPutObj_Torrent::RGWPutObj_Torrent(rgw::sal::DataProcessor* next, + size_t max_len, size_t piece_len) + : Pipe(next), max_len(max_len), piece_len(piece_len) +{ +} + +int RGWPutObj_Torrent::process(bufferlist&& data, uint64_t logical_offset) +{ + if (!data.length()) { // done + if (piece_offset) { // hash the remainder + char out[SHA1::digest_size]; + digest.Final(reinterpret_cast(out)); + piece_hashes.append(out, sizeof(out)); + piece_count++; + } + return Pipe::process(std::move(data), logical_offset); + } + + len += data.length(); + if (len >= max_len) { + // enforce the maximum object size; stop calculating and buffering hashes + piece_hashes.clear(); + piece_offset = 0; + piece_count = 0; + return Pipe::process(std::move(data), logical_offset); + } + + auto p = data.begin(); + while (!p.end()) { + // feed each buffer segment through sha1 + uint32_t want = piece_len - piece_offset; + const char* buf = nullptr; + size_t bytes = p.get_ptr_and_advance(want, &buf); + digest.Update(reinterpret_cast(buf), bytes); + piece_offset += bytes; + + // record the hash digest at each piece boundary + if (bytes == want) { + char out[SHA1::digest_size]; + digest.Final(reinterpret_cast(out)); + digest.Restart(); + piece_hashes.append(out, sizeof(out)); + piece_count++; + piece_offset = 0; + } + } + + return Pipe::process(std::move(data), logical_offset); +} + +bufferlist RGWPutObj_Torrent::bencode_torrent(std::string_view filename) const +{ + bufferlist bl; + if (len >= max_len) { + return bl; + } + + /*Only encode create_date and sha1 info*/ + /*Other field will be added if config is set when run get torrent*/ + TorrentBencode benc; + benc.bencode(CREATION_DATE, std::time(nullptr), bl); + + benc.bencode_key(INFO_PIECES, bl); + benc.bencode_dict(bl); + benc.bencode(LENGTH, len, bl); + benc.bencode(NAME, filename, bl); + benc.bencode(PIECE_LENGTH, piece_len, bl); + + benc.bencode_key(PIECES, bl); + bl.append(std::to_string(piece_count)); + bl.append(':'); + bl.append(piece_hashes); + benc.bencode_end(bl); + + return bl; +} diff --git a/src/rgw/rgw_torrent.h b/src/rgw/rgw_torrent.h index d79b6d0b22e2f..08d7cc2bcbea0 100644 --- a/src/rgw/rgw_torrent.h +++ b/src/rgw/rgw_torrent.h @@ -13,6 +13,7 @@ #include "common/ceph_time.h" #include "rgw_common.h" +#include "rgw_putobj.h" struct req_state; @@ -131,3 +132,22 @@ private: void sha1(ceph::crypto::SHA1 *h, bufferlist &bl, off_t bl_len); int save_torrent_file(optional_yield y); }; + +class RGWPutObj_Torrent : public rgw::putobj::Pipe { + size_t max_len = 0; + size_t piece_len = 0; + bufferlist piece_hashes; + size_t len = 0; + size_t piece_offset = 0; + uint32_t piece_count = 0; + ceph::crypto::SHA1 digest; + + public: + RGWPutObj_Torrent(rgw::sal::DataProcessor* next, + size_t max_len, size_t piece_len); + + int process(bufferlist&& data, uint64_t logical_offset) override; + + // after processing is complete, return the bencoded torrent info + bufferlist bencode_torrent(std::string_view filename) const; +}; -- 2.39.5