fix: Changes the backend.Walk implementation to return non-truncated result if both delimiter and max-keys are provided

Fixes #816

`ListObjects(V2)` used to return truncated response, if delimiter is provided and the result is limited by max-keys and the number of common prefixes is the same as `max-keys`.
e.g
PUT -> `foo/bar`
PUT -> `foo/quxx`
LIST: `max-keys=1;delim=/` -> foo/

`ListObjects(V2)` should return `foo/` as common prefix and `truncated` should be `false`.

The PR makes this fix to return `non-truncated` response for the above described case.
This commit is contained in:
niksis02
2025-04-09 21:29:58 +04:00
parent eb72905401
commit aaee7afa98
3 changed files with 91 additions and 12 deletions

View File

@@ -44,12 +44,19 @@ func Walk(ctx context.Context, fileSystem fs.FS, prefix, delimiter, marker strin
cpmap := make(map[string]struct{})
var objects []s3response.Object
// if max is 0, it should return empty non-truncated result
if max == 0 {
return WalkResults{
Truncated: false,
}, nil
}
var pastMarker bool
if marker == "" {
pastMarker = true
}
pastMax := max == 0
var pastMax bool
var newMarker string
var truncated bool
@@ -76,14 +83,6 @@ func Walk(ctx context.Context, fileSystem fs.FS, prefix, delimiter, marker strin
return fs.SkipDir
}
if pastMax {
if len(objects) != 0 {
newMarker = *objects[len(objects)-1].Key
truncated = true
}
return fs.SkipAll
}
// After this point, return skipflag instead of nil
// so we can skip a directory without an early return
var skipflag error
@@ -116,7 +115,15 @@ func Walk(ctx context.Context, fileSystem fs.FS, prefix, delimiter, marker strin
if err != nil {
return fmt.Errorf("directory to object %q: %w", path, err)
}
if pastMax {
truncated = true
return fs.SkipAll
}
objects = append(objects, dirobj)
if (len(objects) + len(cpmap)) == int(max) {
newMarker = path
pastMax = true
}
return skipflag
}
@@ -160,9 +167,15 @@ func Walk(ctx context.Context, fileSystem fs.FS, prefix, delimiter, marker strin
if err != nil {
return fmt.Errorf("file to object %q: %w", path, err)
}
if pastMax {
truncated = true
return fs.SkipAll
}
objects = append(objects, obj)
if max > 0 && (len(objects)+len(cpmap)) == int(max) {
if (len(objects) + len(cpmap)) == int(max) {
newMarker = path
pastMax = true
}
@@ -200,8 +213,13 @@ func Walk(ctx context.Context, fileSystem fs.FS, prefix, delimiter, marker strin
if err != nil {
return fmt.Errorf("file to object %q: %w", path, err)
}
if pastMax {
truncated = true
return fs.SkipAll
}
objects = append(objects, obj)
if (len(objects) + len(cpmap)) == int(max) {
newMarker = path
pastMax = true
}
return skipflag
@@ -222,11 +240,14 @@ func Walk(ctx context.Context, fileSystem fs.FS, prefix, delimiter, marker strin
return skipflag
}
if pastMax {
truncated = true
return fs.SkipAll
}
cpmap[cpref] = struct{}{}
if (len(objects) + len(cpmap)) == int(max) {
newMarker = cpref
truncated = true
return fs.SkipAll
pastMax = true
}
return skipflag
@@ -252,6 +273,10 @@ func Walk(ctx context.Context, fileSystem fs.FS, prefix, delimiter, marker strin
})
}
if !truncated {
newMarker = ""
}
return WalkResults{
CommonPrefixes: commonPrefixes,
Objects: objects,