op_ret = serializer->try_lock(dur, y);
if (op_ret < 0) {
ldpp_dout(this, 0) << "failed to acquire lock" << dendl;
+ if (op_ret == -ENOENT && check_previously_completed(this, parts)) {
+ ldpp_dout(this, 1) << "NOTICE: This multipart completion is already completed" << dendl;
+ op_ret = 0;
+ return;
+ }
op_ret = -ERR_INTERNAL_ERROR;
s->err.message = "This multipart completion is already in progress";
return;
}
}
+bool RGWCompleteMultipart::check_previously_completed(const DoutPrefixProvider* dpp, const RGWMultiCompleteUpload* parts)
+{
+ // re-calculate the etag from the parts and compare to the existing object
+ s->object->set_bucket(s->bucket.get());
+ int ret = s->object->get_obj_attrs(s->obj_ctx, s->yield, this);
+ if (ret < 0) {
+ ldpp_dout(dpp, 0) << __func__ << "() ERROR: get_obj_attrs() returned ret=" << ret << dendl;
+ return false;
+ }
+ rgw::sal::Attrs sattrs = s->object->get_attrs();
+ string oetag = sattrs[RGW_ATTR_ETAG].to_str();
+
+ MD5 hash;
+ for (const auto& [index, part] : parts->parts) {
+ std::string partetag = rgw_string_unquote(part);
+ char petag[CEPH_CRYPTO_MD5_DIGESTSIZE];
+ hex_to_buf(partetag.c_str(), petag, CEPH_CRYPTO_MD5_DIGESTSIZE);
+ hash.Update((const unsigned char *)petag, sizeof(petag));
+ ldpp_dout(dpp, 20) << __func__ << "() re-calculating multipart etag: part: "
+ << index << ", etag: " << partetag << dendl;
+ }
+
+ unsigned char final_etag[CEPH_CRYPTO_MD5_DIGESTSIZE];
+ char final_etag_str[CEPH_CRYPTO_MD5_DIGESTSIZE * 2 + 16];
+ hash.Final(final_etag);
+ buf_to_hex(final_etag, CEPH_CRYPTO_MD5_DIGESTSIZE, final_etag_str);
+ snprintf(&final_etag_str[CEPH_CRYPTO_MD5_DIGESTSIZE * 2], sizeof(final_etag_str) - CEPH_CRYPTO_MD5_DIGESTSIZE * 2,
+ "-%lld", (long long)parts->parts.size());
+
+ if (oetag.compare(final_etag_str) != 0) {
+ ldpp_dout(dpp, 1) << __func__ << "() NOTICE: etag mismatch: object etag:"
+ << oetag << ", re-calculated etag:" << final_etag_str << dendl;
+ return false;
+ }
+ ldpp_dout(dpp, 5) << __func__ << "() object etag and re-calculated etag match, etag: " << oetag << dendl;
+ return true;
+}
+
void RGWCompleteMultipart::complete()
{
/* release exclusive lock iff not already */