From 03f9eb3a18bb57bb0041c11f1f6c2835d06b6ac2 Mon Sep 17 00:00:00 2001 From: Collin Shoop Date: Wed, 11 Aug 2021 12:17:24 -0400 Subject: [PATCH] storagedriver/s3: Fixed a Delete noop edgecase Delete was not working when the subpath immediately followed the given path started with an ascii lower than "/" such as dash "-" and underscore "_" and requests no files to be deleted. (cherry picked from commit 5d8fa0ce94b68cce70237805db92cdd8d40de282) Signed-off-by: Collin Shoop --- registry/storage/driver/s3-aws/s3.go | 28 +++++++++++++++++++++------- 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/registry/storage/driver/s3-aws/s3.go b/registry/storage/driver/s3-aws/s3.go index 6ced69fcc..0fb895f68 100644 --- a/registry/storage/driver/s3-aws/s3.go +++ b/registry/storage/driver/s3-aws/s3.go @@ -806,7 +806,21 @@ func min(a, b int) int { // We must be careful since S3 does not guarantee read after delete consistency func (d *driver) Delete(ctx context.Context, path string) error { s3Objects := make([]*s3.ObjectIdentifier, 0, listMax) - s3Path := d.s3Path(path) + + // manually add the given path if it's a file + stat, err := d.Stat(ctx, path) + if err != nil { + return err + } + if stat != nil && !stat.IsDir() { + path := d.s3Path(path) + s3Objects = append(s3Objects, &s3.ObjectIdentifier{ + Key: &path, + }) + } + + // list objects under the given path as a subpath (suffix with slash "/") + s3Path := d.s3Path(path) + "/" listObjectsInput := &s3.ListObjectsInput{ Bucket: aws.String(d.Bucket), Prefix: aws.String(s3Path), @@ -820,14 +834,10 @@ ListLoop: // if there were no more results to return after the first call, resp.IsTruncated would have been false // and the loop would be exited without recalling ListObjects if err != nil || len(resp.Contents) == 0 { - return storagedriver.PathNotFoundError{Path: path} + break ListLoop } for _, key := range resp.Contents { - // Stop if we encounter a key that is not a subpath (so that deleting "/a" does not delete "/ab"). - if len(*key.Key) > len(s3Path) && (*key.Key)[len(s3Path)] != '/' { - break ListLoop - } s3Objects = append(s3Objects, &s3.ObjectIdentifier{ Key: key.Key, }) @@ -843,8 +853,12 @@ ListLoop: } } - // need to chunk objects into groups of 1000 per s3 restrictions total := len(s3Objects) + if total == 0 { + return storagedriver.PathNotFoundError{Path: path} + } + + // need to chunk objects into groups of 1000 per s3 restrictions for i := 0; i < total; i += 1000 { _, err := d.S3.DeleteObjects(&s3.DeleteObjectsInput{ Bucket: aws.String(d.Bucket),