int part_num, int* parts_count, bool prefetch,
RGWObjState** pstate, RGWObjManifest** pmanifest)
{
+ if (!manifest) {
+ return -ERR_INVALID_PART;
+ }
// navigate to the requested part in the manifest
RGWObjManifest::obj_iterator end = manifest->obj_end(dpp);
if (end.get_cur_part_id() == 0) { // not multipart
RGWBucketInfo& bucket_info = source->get_bucket_info();
if (params.part_num) {
+ int parts_count = 0;
// use the manifest to redirect to the requested part number
- if (!manifest) {
- return -ERR_INVALID_PART;
- }
r = get_part_obj_state(dpp, y, store, bucket_info, &source->get_ctx(),
- manifest, *params.part_num, params.parts_count,
+ manifest, *params.part_num, &parts_count,
part_prefetch, &astate, &manifest);
- if (r < 0) {
+ if (r == -ERR_INVALID_PART && *params.part_num == 1) {
+ // for non-multipart uploads, treat requests for the first part as a
+ // request for the entire range. this behavior is expected by the java
+ // sdk's TransferManager.download()
+ ldpp_dout(dpp, 4) << "requested part #" << *params.part_num
+ << ": " << cpp_strerror(r) << dendl;
+ } else if (r < 0) {
ldpp_dout(dpp, 4) << "failed to read part #" << *params.part_num
<< ": " << cpp_strerror(r) << dendl;
return -ERR_INVALID_PART;
- }
- if (!astate->exists) {
+ } else if (!astate->exists) {
ldpp_dout(dpp, 4) << "part #" << *params.part_num
<< " does not exist" << dendl;
return -ERR_INVALID_PART;
+ } else {
+ params.parts_count = parts_count;
}
}
parent_op.params.lastmod = params.lastmod;
parent_op.params.target_obj = params.target_obj;
parent_op.params.part_num = params.part_num;
- parent_op.params.parts_count = params.parts_count;
parent_op.params.obj_size = &obj_size;
parent_op.params.attrs = &source->get_attrs();
source->set_instance(parent_op.state.obj.key.instance);
source->set_obj_size(obj_size);
+ params.parts_count = parent_op.params.parts_count;
return ret;
}
read_op->params.lastmod = &lastmod;
if (multipart_part_num) {
read_op->params.part_num = &*multipart_part_num;
- multipart_parts_count.emplace(0);
- read_op->params.parts_count = &*multipart_parts_count;
}
op_ret = read_op->prepare(s->yield, this);
version_id = s->object->get_instance();
s->obj_size = s->object->get_obj_size();
attrs = s->object->get_attrs();
+ multipart_parts_count = read_op->params.parts_count;
/* STAT ops don't need data, and do no i/o */
if (get_type() == RGW_OP_STAT_OBJ) {
/// If non-null, read data/attributes from the given multipart part.
int* part_num{nullptr};
- /// If part_num is specified, the total number of multipart parts is
- /// written to this output parameter.
- int* parts_count{nullptr};
+ /// If part_num is specified and the object is multipart, the total
+ /// number of multipart parts is assigned to this output parameter.
+ std::optional<int> parts_count;
} params;
virtual ~ReadOp() = default;