- res = rgw_s3_prepare_decrypt(s, attrs, &block_crypt, crypt_http_responses_unused);
- if (res == 0) {
- if (block_crypt != nullptr) {
- auto f = std::unique_ptr<RGWGetObj_BlockDecrypt>(new RGWGetObj_BlockDecrypt(s, s->cct, cb, std::move(block_crypt)));
- //RGWGetObj_BlockDecrypt* f = new RGWGetObj_BlockDecrypt(s->cct, cb, std::move(block_crypt));
- if (f != nullptr) {
- if (manifest_bl != nullptr) {
- res = f->read_manifest(this, *manifest_bl);
- if (res == 0) {
- *filter = std::move(f);
- }
- }
- }
+ int res = rgw_s3_prepare_decrypt(s, attrs, &block_crypt, crypt_http_responses_unused);
+ if (res < 0) {
+ return res;
+ }
+ if (block_crypt == nullptr) {
+ return 0;
+ }
+
+ // in case of a multipart upload, we need to know the part lengths to
+ // correctly decrypt across part boundaries
+ std::vector<size_t> parts_len;
+
+ // for replicated objects, the original part lengths are preserved in an xattr
+ if (auto i = attrs.find(RGW_ATTR_CRYPT_PARTS); i != attrs.end()) {
+ try {
+ auto p = i->second.cbegin();
+ using ceph::decode;
+ decode(parts_len, p);
+ } catch (const buffer::error&) {
+ ldpp_dout(this, 1) << "failed to decode RGW_ATTR_CRYPT_PARTS" << dendl;
+ return -EIO;
+ }
+ } else if (manifest_bl) {
+ // otherwise, we read the part lengths from the manifest
+ res = RGWGetObj_BlockDecrypt::read_manifest_parts(this, *manifest_bl,
+ parts_len);
+ if (res < 0) {
+ return res;