/// <summary> /// Make a multi part copy upload for objects larger than 5GB or if CopyCondition specifies a byte range. /// </summary> /// <param name="bucketName"> source bucket name</param> /// <param name="objectName"> source object name</param> /// <param name="destBucketName"> destination bucket name</param> /// <param name="destObjectName"> destiantion object name</param> /// <param name="copyConditions"> copyconditions </param> /// <param name="copySize"> size of copy upload</param> /// <param name="cancellationToken"> optional cancellation token</param> /// <returns></returns> private async Task MultipartCopyUploadAsync(string bucketName, string objectName, string destBucketName, string destObjectName, CopyConditions copyConditions, long copySize, CancellationToken cancellationToken) { // For all sizes greater than 5GB or if Copy byte range specified in conditions and byte range larger // than minimum part size (5 MB) do multipart. dynamic multiPartInfo = utils.CalculateMultiPartSize(copySize); double partSize = multiPartInfo.partSize; double partCount = multiPartInfo.partCount; double lastPartSize = multiPartInfo.lastPartSize; Part[] totalParts = new Part[(int)partCount]; // No need to resume upload since this is a server side copy. Just initiate a new upload. string uploadId = await this.NewMultipartUploadAsync(destBucketName, destObjectName, null, cancellationToken); // Upload each part double expectedReadSize = partSize; int partNumber; for (partNumber = 1; partNumber <= partCount; partNumber++) { CopyConditions partCondition = copyConditions.Clone(); partCondition.byteRangeStart = (long)partSize * (partNumber - 1) + partCondition.byteRangeStart; if (partNumber < partCount) { partCondition.byteRangeEnd = partCondition.byteRangeStart + (long)partSize - 1; } else { partCondition.byteRangeEnd = partCondition.byteRangeStart + (long)lastPartSize - 1; } var resource = ""; if (!string.IsNullOrEmpty(uploadId) && partNumber > 0) { resource += "?uploadId=" + uploadId + "&partNumber=" + partNumber; } Dictionary <string, string> customHeader = new Dictionary <string, string>(); customHeader.Add("x-amz-copy-source-range", "bytes=" + partCondition.byteRangeStart.ToString() + "-" + partCondition.byteRangeEnd.ToString()); CopyPartResult cpPartResult = (CopyPartResult)await this.CopyObjectRequestAsync(bucketName, objectName, destBucketName, destObjectName, copyConditions, customHeader, resource, cancellationToken, typeof(CopyPartResult)); totalParts[partNumber - 1] = new Part() { PartNumber = partNumber, ETag = cpPartResult.ETag, size = (long)expectedReadSize }; } Dictionary <int, string> etags = new Dictionary <int, string>(); for (partNumber = 1; partNumber <= partCount; partNumber++) { etags[partNumber] = totalParts[partNumber - 1].ETag; } // Complete multi part upload await this.CompleteMultipartUploadAsync(destBucketName, destObjectName, uploadId, etags, cancellationToken); }
public CopyObjectResponse(HttpStatusCode statusCode, string content, Type reqType) : base(statusCode, content) { using (var stream = new MemoryStream(System.Text.Encoding.UTF8.GetBytes(content))) { if (reqType == typeof(CopyObjectResult)) { this.CopyObjectRequestResult = (CopyObjectResult) new XmlSerializer(typeof(CopyObjectResult)).Deserialize(stream); } else { this.CopyPartRequestResult = (CopyPartResult) new XmlSerializer(typeof(CopyPartResult)).Deserialize(stream); } } }