]> git-server-git.apps.pok.os.sepia.ceph.com Git - ceph.git/commitdiff
rgw/torrent: add a PutObj filter for torrent info
authorCasey Bodley <cbodley@redhat.com>
Sun, 19 Feb 2023 05:46:42 +0000 (00:46 -0500)
committerCasey Bodley <cbodley@redhat.com>
Thu, 2 Mar 2023 12:48:03 +0000 (07:48 -0500)
Signed-off-by: Casey Bodley <cbodley@redhat.com>
src/rgw/rgw_torrent.cc
src/rgw/rgw_torrent.h

index e1a1417a5a6fdc08beb383167bd5866ee2d01ba3..96b56d980ddfcc301dc11922452c48e3916e2ec9 100644 (file)
@@ -4,7 +4,7 @@
 #include <errno.h>
 #include <stdlib.h>
 
-#include <sstream>
+#include <ctime>
 
 #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<unsigned char*>(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<const unsigned char*>(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<unsigned char*>(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;
+}
index d79b6d0b22e2f0bd94dac4fc2936ec381044391a..08d7cc2bcbea01b6b1f5a68e8942d77387d0cee0 100644 (file)
@@ -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;
+};