mirror of
https://github.com/minio/minio.git
synced 2025-11-07 04:42:56 -05:00
fix: do not list delete-marked objects (#13864)
delete marked objects should not be considered for listing when listing is delimited, this issue as introduced in PR #13804 which was mainly to address listing of directories in listing when delimited. This PR fixes this properly and adds tests to ensure that we behave in accordance with how an S3 API behaves for ListObjects() without versions.
This commit is contained in:
@@ -1118,15 +1118,12 @@ func (z *erasureServerPools) ListObjects(ctx context.Context, bucket, prefix, ma
|
||||
}
|
||||
|
||||
opts := listPathOptions{
|
||||
Bucket: bucket,
|
||||
Prefix: prefix,
|
||||
Separator: delimiter,
|
||||
Limit: maxKeysPlusOne(maxKeys, marker != ""),
|
||||
Marker: marker,
|
||||
// When delimiter is set make sure to include delete markers
|
||||
// necessary to capture proper CommonPrefixes as expected
|
||||
// in the response as per AWS S3.
|
||||
InclDeleted: delimiter != "",
|
||||
Bucket: bucket,
|
||||
Prefix: prefix,
|
||||
Separator: delimiter,
|
||||
Limit: maxKeysPlusOne(maxKeys, marker != ""),
|
||||
Marker: marker,
|
||||
InclDeleted: false,
|
||||
AskDisks: globalAPIConfig.getListQuorum(),
|
||||
}
|
||||
merged, err := z.listPath(ctx, &opts)
|
||||
|
||||
@@ -53,6 +53,11 @@ func (e metaCacheEntry) isObject() bool {
|
||||
return len(e.metadata) > 0
|
||||
}
|
||||
|
||||
// isObjectDir returns if the entry is representing an object__XL_DIR__
|
||||
func (e metaCacheEntry) isObjectDir() bool {
|
||||
return len(e.metadata) > 0 && strings.HasSuffix(e.name, slashSeparator)
|
||||
}
|
||||
|
||||
// hasPrefix returns whether an entry has a specific prefix
|
||||
func (e metaCacheEntry) hasPrefix(s string) bool {
|
||||
return strings.HasPrefix(e.name, s)
|
||||
|
||||
@@ -156,7 +156,7 @@ func (o *listPathOptions) gatherResults(ctx context.Context, in <-chan metaCache
|
||||
resCh = nil
|
||||
continue
|
||||
}
|
||||
if !o.IncludeDirectories && entry.isDir() {
|
||||
if !o.IncludeDirectories && (entry.isDir() || (entry.isObjectDir() && entry.isLatestDeletemarker())) {
|
||||
continue
|
||||
}
|
||||
if o.Marker != "" && entry.name < o.Marker {
|
||||
@@ -168,7 +168,7 @@ func (o *listPathOptions) gatherResults(ctx context.Context, in <-chan metaCache
|
||||
if !o.Recursive && !entry.isInDir(o.Prefix, o.Separator) {
|
||||
continue
|
||||
}
|
||||
if !o.InclDeleted && entry.isObject() && entry.isLatestDeletemarker() {
|
||||
if !o.InclDeleted && entry.isObject() && entry.isLatestDeletemarker() && !entry.isObjectDir() {
|
||||
continue
|
||||
}
|
||||
if o.Limit > 0 && results.len() >= o.Limit {
|
||||
@@ -324,13 +324,13 @@ func (r *metacacheReader) filter(o listPathOptions) (entries metaCacheEntriesSor
|
||||
pastPrefix = true
|
||||
return false
|
||||
}
|
||||
if !o.IncludeDirectories && entry.isDir() {
|
||||
if !o.IncludeDirectories && (entry.isDir() || (entry.isObjectDir() && entry.isLatestDeletemarker())) {
|
||||
return true
|
||||
}
|
||||
if !entry.isInDir(o.Prefix, o.Separator) {
|
||||
return true
|
||||
}
|
||||
if !o.InclDeleted && entry.isObject() && entry.isLatestDeletemarker() {
|
||||
if !o.InclDeleted && entry.isObject() && entry.isLatestDeletemarker() && !entry.isObjectDir() {
|
||||
return entries.len() < o.Limit
|
||||
}
|
||||
entries.o = append(entries.o, entry)
|
||||
|
||||
@@ -528,10 +528,10 @@ func (r *metacacheReader) readN(n int, inclDeleted, inclDirs bool, prefix string
|
||||
metaDataPoolPut(meta.metadata)
|
||||
meta.metadata = nil
|
||||
}
|
||||
if !inclDirs && meta.isDir() {
|
||||
if !inclDirs && (meta.isDir() || (meta.isObjectDir() && meta.isLatestDeletemarker())) {
|
||||
continue
|
||||
}
|
||||
if !inclDeleted && meta.isLatestDeletemarker() {
|
||||
if !inclDeleted && meta.isLatestDeletemarker() && meta.isObject() && !meta.isObjectDir() {
|
||||
continue
|
||||
}
|
||||
res = append(res, meta)
|
||||
|
||||
@@ -42,6 +42,8 @@ func testListObjectsVersionedFolders(obj ObjectLayer, instanceType string, t1 Te
|
||||
testBuckets := []string{
|
||||
// This bucket is used for testing ListObject operations.
|
||||
"test-bucket-folders",
|
||||
// This bucket has file delete marker.
|
||||
"test-bucket-files",
|
||||
}
|
||||
for _, bucket := range testBuckets {
|
||||
err := obj.MakeBucketWithLocation(context.Background(), bucket, BucketOptions{
|
||||
@@ -62,6 +64,7 @@ func testListObjectsVersionedFolders(obj ObjectLayer, instanceType string, t1 Te
|
||||
}{
|
||||
{testBuckets[0], "unique/folder/", "", nil, true},
|
||||
{testBuckets[0], "unique/folder/1.txt", "content", nil, false},
|
||||
{testBuckets[1], "unique/folder/1.txt", "content", nil, true},
|
||||
}
|
||||
for _, object := range testObjects {
|
||||
md5Bytes := md5.Sum([]byte(object.content))
|
||||
@@ -102,6 +105,10 @@ func testListObjectsVersionedFolders(obj ObjectLayer, instanceType string, t1 Te
|
||||
{Name: "unique/folder/1.txt"},
|
||||
},
|
||||
},
|
||||
{
|
||||
IsTruncated: false,
|
||||
Objects: []ObjectInfo{},
|
||||
},
|
||||
}
|
||||
|
||||
testCases := []struct {
|
||||
@@ -120,6 +127,7 @@ func testListObjectsVersionedFolders(obj ObjectLayer, instanceType string, t1 Te
|
||||
{testBuckets[0], "unique/", "", "/", 1000, resultCases[0], nil, true},
|
||||
{testBuckets[0], "unique/folder", "", "/", 1000, resultCases[0], nil, true},
|
||||
{testBuckets[0], "unique/", "", "", 1000, resultCases[1], nil, true},
|
||||
{testBuckets[1], "unique/folder/", "", "/", 1000, resultCases[2], nil, true},
|
||||
}
|
||||
|
||||
for i, testCase := range testCases {
|
||||
|
||||
Reference in New Issue
Block a user