From c99f55c4204c81f1a8c368e24b434e02a676a96d Mon Sep 17 00:00:00 2001 From: Alex Auvolat Date: Tue, 25 Jan 2022 12:25:29 +0100 Subject: [PATCH] Add restriction on part ordering in CompleteMultipartUpload --- script/test-smoke.sh | 14 +++++++------- src/api/s3_put.rs | 11 +++++++++++ 2 files changed, 18 insertions(+), 7 deletions(-) diff --git a/script/test-smoke.sh b/script/test-smoke.sh index 0adf322a..e6f1c6ea 100755 --- a/script/test-smoke.sh +++ b/script/test-smoke.sh @@ -257,15 +257,15 @@ if [ -z "$SKIP_AWS" ]; then aws s3api list-parts --bucket eprouvette --key list-parts --upload-id $UPLOAD_ID >$CMDOUT [ $(jq '.Parts | length' $CMDOUT) == 0 ] [ $(jq -r '.StorageClass' $CMDOUT) == 'STANDARD' ] # check that the result is not empty - ETAG1=$(aws s3api upload-part --bucket eprouvette --key list-parts --upload-id $UPLOAD_ID --part-number 10 --body /tmp/garage.2.rnd | jq .ETag) + ETAG1=$(aws s3api upload-part --bucket eprouvette --key list-parts --upload-id $UPLOAD_ID --part-number 1 --body /tmp/garage.2.rnd | jq .ETag) aws s3api list-parts --bucket eprouvette --key list-parts --upload-id $UPLOAD_ID >$CMDOUT [ $(jq '.Parts | length' $CMDOUT) == 1 ] - [ $(jq '.Parts[0].PartNumber' $CMDOUT) == 10 ] + [ $(jq '.Parts[0].PartNumber' $CMDOUT) == 1 ] [ $(jq '.Parts[0].Size' $CMDOUT) == 5242880 ] [ $(jq '.Parts[0].ETag' $CMDOUT) == $ETAG1 ] - ETAG2=$(aws s3api upload-part --bucket eprouvette --key list-parts --upload-id $UPLOAD_ID --part-number 9999 --body /tmp/garage.3.rnd | jq .ETag) - ETAG3=$(aws s3api upload-part --bucket eprouvette --key list-parts --upload-id $UPLOAD_ID --part-number 30 --body /tmp/garage.2.rnd | jq .ETag) + ETAG2=$(aws s3api upload-part --bucket eprouvette --key list-parts --upload-id $UPLOAD_ID --part-number 3 --body /tmp/garage.3.rnd | jq .ETag) + ETAG3=$(aws s3api upload-part --bucket eprouvette --key list-parts --upload-id $UPLOAD_ID --part-number 2 --body /tmp/garage.2.rnd | jq .ETag) aws s3api list-parts --bucket eprouvette --key list-parts --upload-id $UPLOAD_ID >$CMDOUT [ $(jq '.Parts | length' $CMDOUT) == 3 ] [ $(jq '.Parts[1].ETag' $CMDOUT) == $ETAG3 ] @@ -279,15 +279,15 @@ if [ -z "$SKIP_AWS" ]; then "Parts": [ { "ETag": $ETAG1, - "PartNumber": 10 + "PartNumber": 1 }, { "ETag": $ETAG3, - "PartNumber": 30 + "PartNumber": 2 }, { "ETag": $ETAG2, - "PartNumber": 9999 + "PartNumber": 3 } ] } diff --git a/src/api/s3_put.rs b/src/api/s3_put.rs index f52080a6..a6863cd3 100644 --- a/src/api/s3_put.rs +++ b/src/api/s3_put.rs @@ -559,6 +559,17 @@ pub async fn handle_complete_multipart_upload( return Err(Error::InvalidPartOrder); } + // Garage-specific restriction, see #204: part numbers must be + // consecutive starting at 1 + if body_list_of_parts[0].part_number != 1 + || !body_list_of_parts + .iter() + .zip(body_list_of_parts.iter().skip(1)) + .all(|(p1, p2)| p1.part_number + 1 == p2.part_number) + { + return Err(Error::NotImplemented("Garage does not support completing a Multipart upload with non-consecutive part numbers. This is a restriction of Garage's data model, which might be fixed in a future release. See issue #204 for more information on this topic.".into())); + } + // Check that the list of parts they gave us corresponds to the parts we have here debug!("Expected parts from request: {:?}", body_list_of_parts); debug!("Parts stored in version: {:?}", version.parts_etags.items());