1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
9 #include "include/types.h"
12 #include "rgw_multi.h"
14 #define dout_subsys ceph_subsys_rgw
19 bool RGWMultiPart::xml_end(const char *el
)
21 RGWMultiPartNumber
*num_obj
= static_cast<RGWMultiPartNumber
*>(find_first("PartNumber"));
22 RGWMultiETag
*etag_obj
= static_cast<RGWMultiETag
*>(find_first("ETag"));
24 if (!num_obj
|| !etag_obj
)
27 string s
= num_obj
->get_data();
31 num
= atoi(s
.c_str());
33 s
= etag_obj
->get_data();
39 bool RGWMultiCompleteUpload::xml_end(const char *el
) {
40 XMLObjIter iter
= find("Part");
41 RGWMultiPart
*part
= static_cast<RGWMultiPart
*>(iter
.get_next());
43 int num
= part
->get_num();
44 string etag
= part
->get_etag();
46 part
= static_cast<RGWMultiPart
*>(iter
.get_next());
52 XMLObj
*RGWMultiXMLParser::alloc_obj(const char *el
) {
54 if (strcmp(el
, "CompleteMultipartUpload") == 0 ||
55 strcmp(el
, "MultipartUpload") == 0) {
56 obj
= new RGWMultiCompleteUpload();
57 } else if (strcmp(el
, "Part") == 0) {
58 obj
= new RGWMultiPart();
59 } else if (strcmp(el
, "PartNumber") == 0) {
60 obj
= new RGWMultiPartNumber();
61 } else if (strcmp(el
, "ETag") == 0) {
62 obj
= new RGWMultiETag();
68 bool is_v2_upload_id(const string
& upload_id
)
70 const char *uid
= upload_id
.c_str();
72 return (strncmp(uid
, MULTIPART_UPLOAD_ID_PREFIX
, sizeof(MULTIPART_UPLOAD_ID_PREFIX
) - 1) == 0) ||
73 (strncmp(uid
, MULTIPART_UPLOAD_ID_PREFIX_LEGACY
, sizeof(MULTIPART_UPLOAD_ID_PREFIX_LEGACY
) - 1) == 0);
76 int list_multipart_parts(RGWRados
*store
, RGWBucketInfo
& bucket_info
, CephContext
*cct
,
77 const string
& upload_id
,
78 string
& meta_oid
, int num_parts
,
79 int marker
, map
<uint32_t, RGWUploadPartInfo
>& parts
,
80 int *next_marker
, bool *truncated
,
83 map
<string
, bufferlist
> parts_map
;
84 map
<string
, bufferlist
>::iterator iter
;
88 obj
.init_ns(bucket_info
.bucket
, meta_oid
, RGW_OBJ_NS_MULTIPART
);
89 obj
.set_in_extra_data(true);
92 store
->obj_to_raw(bucket_info
.placement_rule
, obj
, &raw_obj
);
94 bool sorted_omap
= is_v2_upload_id(upload_id
) && !assume_unsorted
;
105 snprintf(buf
, sizeof(buf
), "%08d", marker
);
108 ret
= store
->omap_get_vals(raw_obj
, header
, p
, num_parts
+ 1, parts_map
);
110 ret
= store
->omap_get_all(raw_obj
, header
, parts_map
);
118 uint32_t expected_next
= marker
+ 1;
120 for (i
= 0, iter
= parts_map
.begin(); (i
< num_parts
|| !sorted_omap
) && iter
!= parts_map
.end(); ++iter
, ++i
) {
121 bufferlist
& bl
= iter
->second
;
122 bufferlist::iterator bli
= bl
.begin();
123 RGWUploadPartInfo info
;
126 } catch (buffer::error
& err
) {
127 ldout(cct
, 0) << "ERROR: could not part info, caught buffer::error" << dendl
;
131 if (info
.num
!= expected_next
) {
132 /* ouch, we expected a specific part num here, but we got a different one. Either
133 * a part is missing, or it could be a case of mixed rgw versions working on the same
134 * upload, where one gateway doesn't support correctly sorted omap keys for multipart
135 * upload just assume data is unsorted.
137 return list_multipart_parts(store
, bucket_info
, cct
, upload_id
, meta_oid
, num_parts
, marker
, parts
, next_marker
, truncated
, true);
142 (int)info
.num
> marker
) {
143 parts
[info
.num
] = info
;
150 *truncated
= (iter
!= parts_map
.end());
152 /* rebuild a map with only num_parts entries */
154 map
<uint32_t, RGWUploadPartInfo
> new_parts
;
155 map
<uint32_t, RGWUploadPartInfo
>::iterator piter
;
157 for (i
= 0, piter
= parts
.begin(); i
< num_parts
&& piter
!= parts
.end(); ++i
, ++piter
) {
158 new_parts
[piter
->first
] = piter
->second
;
159 last_num
= piter
->first
;
163 *truncated
= (piter
!= parts
.end());
165 parts
.swap(new_parts
);
169 *next_marker
= last_num
;
175 int list_multipart_parts(RGWRados
*store
, struct req_state
*s
,
176 const string
& upload_id
,
177 string
& meta_oid
, int num_parts
,
178 int marker
, map
<uint32_t, RGWUploadPartInfo
>& parts
,
179 int *next_marker
, bool *truncated
,
180 bool assume_unsorted
)
182 return list_multipart_parts(store
, s
->bucket_info
, s
->cct
, upload_id
, meta_oid
, num_parts
, marker
, parts
, next_marker
, truncated
, assume_unsorted
);
185 int abort_multipart_upload(RGWRados
*store
, CephContext
*cct
, RGWObjectCtx
*obj_ctx
, RGWBucketInfo
& bucket_info
, RGWMPObj
& mp_obj
)
188 meta_obj
.init_ns(bucket_info
.bucket
, mp_obj
.get_meta(), RGW_OBJ_NS_MULTIPART
);
189 meta_obj
.set_in_extra_data(true);
190 meta_obj
.index_hash_source
= mp_obj
.get_key();
191 cls_rgw_obj_chain chain
;
192 list
<rgw_obj_index_key
> remove_objs
;
193 map
<uint32_t, RGWUploadPartInfo
> obj_parts
;
199 ret
= list_multipart_parts(store
, bucket_info
, cct
, mp_obj
.get_upload_id(), mp_obj
.get_meta(), 1000,
200 marker
, obj_parts
, &marker
, &truncated
);
203 for (auto obj_iter
= obj_parts
.begin(); obj_iter
!= obj_parts
.end(); ++obj_iter
) {
204 RGWUploadPartInfo
& obj_part
= obj_iter
->second
;
206 if (obj_part
.manifest
.empty()) {
207 string oid
= mp_obj
.get_part(obj_iter
->second
.num
);
208 obj
.init_ns(bucket_info
.bucket
, oid
, RGW_OBJ_NS_MULTIPART
);
209 obj
.index_hash_source
= mp_obj
.get_key();
210 ret
= store
->delete_obj(*obj_ctx
, bucket_info
, obj
, 0);
211 if (ret
< 0 && ret
!= -ENOENT
)
214 store
->update_gc_chain(meta_obj
, obj_part
.manifest
, &chain
);
215 RGWObjManifest::obj_iterator oiter
= obj_part
.manifest
.obj_begin();
216 if (oiter
!= obj_part
.manifest
.obj_end()) {
218 rgw_raw_obj raw_head
= oiter
.get_location().get_raw_obj(store
);
219 rgw_raw_obj_to_obj(bucket_info
.bucket
, raw_head
, &head
);
221 rgw_obj_index_key key
;
222 head
.key
.get_index_key(&key
);
223 remove_objs
.push_back(key
);
228 /* use upload id as tag */
229 ret
= store
->send_chain_to_gc(chain
, mp_obj
.get_upload_id() , false); // do it async
231 ldout(cct
, 5) << "gc->send_chain() returned " << ret
<< dendl
;
234 RGWRados::Object
del_target(store
, bucket_info
, *obj_ctx
, meta_obj
);
235 RGWRados::Object::Delete
del_op(&del_target
);
237 del_op
.params
.bucket_owner
= bucket_info
.owner
;
238 del_op
.params
.versioning_status
= 0;
239 if (!remove_objs
.empty()) {
240 del_op
.params
.remove_objs
= &remove_objs
;
243 // and also remove the metadata obj
244 ret
= del_op
.delete_obj();
245 return ret
== -ENOENT
?-ERR_NO_SUCH_UPLOAD
:ret
;