/******************************************************************************* * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. * Licensed under the Apache License, Version 2.0 (the "License"). You may not use * this file except in compliance with the License. A copy of the License is located at * * http://aws.amazon.com/apache2.0 * * or in the "license" file accompanying this file. * This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR * CONDITIONS OF ANY KIND, either express or implied. See the License for the * specific language governing permissions and limitations under the License. * ***************************************************************************** * __ _ _ ___ * ( )( \/\/ )/ __) * /__\ \ / \__ \ * (_)(_) \/\/ (___/ * * AWS SDK for .NET * API Version: 2006-03-01 * */ using System; using System.Collections.Generic; using System.Collections.Specialized; using System.Globalization; using System.IO; using System.Net; using System.Text; using System.Text.RegularExpressions; using System.Threading; using Amazon.Runtime.Internal; using Amazon.Runtime.Internal.Auth; using Amazon.S3.Model; using Amazon.Util; using System.Threading.Tasks; namespace Amazon.S3.Util { /// /// Provides utilities used by the Amazon S3 client implementation. /// These utilities might be useful to consumers of the Amazon S3 /// library. /// public static partial class AmazonS3Util { /// /// Deletes an S3 bucket which contains objects. /// An S3 bucket which contains objects cannot be deleted until all the objects /// in it are deleted. This method deletes all the objects in the specified /// bucket and then deletes the bucket itself. /// /// The bucket to be deleted. /// The Amazon S3 Client to use for S3 specific operations. public static Task DeleteS3BucketWithObjectsAsync(IAmazonS3 s3Client, string bucketName) { var cancelSource = new CancellationTokenSource(); return DeleteS3BucketWithObjectsAsync(s3Client, bucketName, cancelSource.Token); } /// /// Deletes an S3 bucket which contains objects. /// An S3 bucket which contains objects cannot be deleted until all the objects /// in it are deleted. This method deletes all the objects in the specified /// bucket and then deletes the bucket itself. /// /// The bucket to be deleted. /// The Amazon S3 Client to use for S3 specific operations. /// Options to control the behavior of the delete operation. public static Task DeleteS3BucketWithObjectsAsync(IAmazonS3 s3Client, string bucketName, S3DeleteBucketWithObjectsOptions deleteOptions) { var cancelSource = new CancellationTokenSource(); return DeleteS3BucketWithObjectsAsync(s3Client, bucketName, deleteOptions, cancelSource.Token); } /// /// Initiates the asynchronous execution of the DeleteS3BucketWithObjects operation. /// DeleteS3BucketWithObjects deletes an S3 bucket which contains objects. /// An S3 bucket which contains objects cannot be deleted until all the objects /// in it are deleted. This method deletes all the objects in the specified /// bucket and then deletes the bucket itself. /// /// The bucket to be deleted. /// The Amazon S3 Client to use for S3 specific operations. /// token to check if the operation has been request to cancel. /// An IAsyncCancelableResult that can be used to poll or wait for results, or both; /// this value is also needed when invoking EndDeleteS3BucketWithObjects. IAsyncCancelableResult can also /// be used to cancel the operation while it's in progress. public static Task DeleteS3BucketWithObjectsAsync(IAmazonS3 s3Client, string bucketName, CancellationToken token) { return DeleteS3BucketWithObjectsAsync(s3Client, bucketName, new S3DeleteBucketWithObjectsOptions { ContinueOnError = false, QuietMode = true, }, token); } /// /// Initiates the asynchronous execution of the DeleteS3BucketWithObjects operation. /// DeleteS3BucketWithObjects deletes an S3 bucket which contains objects. /// An S3 bucket which contains objects cannot be deleted until all the objects /// in it are deleted. This method deletes all the objects in the specified /// bucket and then deletes the bucket itself. /// /// The bucket to be deleted. /// The Amazon S3 Client to use for S3 specific operations. /// Options to control the behavior of the delete operation. /// token to check if the operation has been request to cancel. /// An IAsyncCancelableResult that can be used to poll or wait for results, or both; /// this value is also needed when invoking EndDeleteS3BucketWithObjects. IAsyncCancelableResult can also /// be used to cancel the operation while it's in progress. public static Task DeleteS3BucketWithObjectsAsync(IAmazonS3 s3Client, string bucketName, S3DeleteBucketWithObjectsOptions deleteOptions, CancellationToken token) { return DeleteS3BucketWithObjectsAsync(s3Client, bucketName, deleteOptions, null, token); } /// /// Initiates the asynchronous execution of the DeleteS3BucketWithObjects operation. /// DeleteS3BucketWithObjects deletes an S3 bucket which contains objects. /// An S3 bucket which contains objects cannot be deleted until all the objects /// in it are deleted. This method deletes all the objects in the specified /// bucket and then deletes the bucket itself. /// /// The bucket to be deleted. /// The Amazon S3 Client to use for S3 specific operations. /// >Options to control the behavior of the delete operation. /// An callback that is invoked to send updates while delete operation is in progress. /// token to check if the operation has been request to cancel. /// An IAsyncCancelableResult that can be used to poll or wait for results, or both; /// this value is also needed when invoking EndDeleteS3BucketWithObjects. IAsyncCancelableResult can also /// be used to cancel the operation while it's in progress. public static Task DeleteS3BucketWithObjectsAsync(IAmazonS3 s3Client, string bucketName, S3DeleteBucketWithObjectsOptions deleteOptions, Action updateCallback, CancellationToken token) { var request = new S3DeleteBucketWithObjectsRequest { BucketName = bucketName, DeleteOptions = deleteOptions, UpdateCallback = updateCallback, S3Client = s3Client }; return InvokeDeleteS3BucketWithObjects(request, token); } /// /// Invokes the DeleteS3BucketWithObjectsInternal method. /// /// The Request object that has all the data to complete the operation. /// token to request the operation to be cancelled. private static Task InvokeDeleteS3BucketWithObjects(object state,CancellationToken token) { var request = (S3DeleteBucketWithObjectsRequest)state; return DeleteS3BucketWithObjectsInternalAsync( request.S3Client, request.BucketName, request.DeleteOptions, request.UpdateCallback, token ); } /// /// Deletes an S3 bucket which contains objects. /// An S3 bucket which contains objects cannot be deleted until all the objects /// in it are deleted. The function deletes all the objects in the specified /// bucket and then deletes the bucket itself. /// /// The bucket to be deleted. /// The Amazon S3 Client to use for S3 specific operations. /// Options to control the behavior of the delete operation. /// The callback which is used to send updates about the delete operation. /// token to check if the operation has been request to cancel. private static async Task DeleteS3BucketWithObjectsInternalAsync(IAmazonS3 s3Client, string bucketName, S3DeleteBucketWithObjectsOptions deleteOptions, Action updateCallback, CancellationToken token) { // Validations. if (s3Client == null) { throw new ArgumentNullException("s3Client", "The s3Client cannot be null!"); } if (string.IsNullOrEmpty(bucketName)) { throw new ArgumentNullException("bucketName", "The bucketName cannot be null or empty string!"); } var listVersionsRequest = new ListVersionsRequest { BucketName = bucketName }; ListVersionsResponse listVersionsResponse; // Iterate through the objects in the bucket and delete them. do { // Check if the operation has been canceled. if (token.IsCancellationRequested) { // Signal that the operation is canceled. return; } // List all the versions of all the objects in the bucket. listVersionsResponse = await s3Client.ListVersionsAsync(listVersionsRequest,token).ConfigureAwait(false); if (listVersionsResponse.Versions.Count == 0) { // If the bucket has no objects break the loop. break; } var keyVersionList = new List(listVersionsResponse.Versions.Count); for (int index = 0; index < listVersionsResponse.Versions.Count; index++) { keyVersionList.Add(new KeyVersion { Key = listVersionsResponse.Versions[index].Key, VersionId = listVersionsResponse.Versions[index].VersionId }); } try { // Delete the current set of objects. var deleteObjectsResponse = await s3Client.DeleteObjectsAsync(new DeleteObjectsRequest { BucketName = bucketName, Objects = keyVersionList, Quiet = deleteOptions.QuietMode },token).ConfigureAwait(false); if (!deleteOptions.QuietMode) { // If quiet mode is not set, update the client with list of deleted objects. InvokeS3DeleteBucketWithObjectsUpdateCallback( updateCallback, new S3DeleteBucketWithObjectsUpdate { DeletedObjects = deleteObjectsResponse.DeletedObjects } ); } } catch (DeleteObjectsException deleteObjectsException) { if (deleteOptions.ContinueOnError) { // Continue the delete operation if an error was encountered. // Update the client with the list of objects that were deleted and the // list of objects on which the delete failed. InvokeS3DeleteBucketWithObjectsUpdateCallback( updateCallback, new S3DeleteBucketWithObjectsUpdate { DeletedObjects = deleteObjectsException.Response.DeletedObjects, DeleteErrors = deleteObjectsException.Response.DeleteErrors } ); } else { // Re-throw the exception if an error was encountered. throw; } } // Set the markers to get next set of objects from the bucket. listVersionsRequest.KeyMarker = listVersionsResponse.NextKeyMarker; listVersionsRequest.VersionIdMarker = listVersionsResponse.NextVersionIdMarker; } // Continue listing objects and deleting them until the bucket is empty. while (listVersionsResponse.IsTruncated); const int maxRetries = 10; for (int retries = 1; retries <= maxRetries; retries++) { try { // Bucket is empty, delete the bucket. await s3Client.DeleteBucketAsync(new DeleteBucketRequest { BucketName = bucketName },token).ConfigureAwait(false); break; } catch (AmazonS3Exception e) { if (e.StatusCode != HttpStatusCode.Conflict || retries == maxRetries) throw; else DefaultRetryPolicy.WaitBeforeRetry(retries, 5000); } } } /// /// Invokes the callback which provides updated about the delete operation. /// /// The callback to be invoked. /// The data being passed to the callback. /// 8 private static void InvokeS3DeleteBucketWithObjectsUpdateCallback( Action updateCallback, S3DeleteBucketWithObjectsUpdate update) { if (updateCallback != null) { updateCallback(update); } } } }