mirror of
https://github.com/minio/minio.git
synced 2025-02-09 20:58:08 -05:00
Fix incorrect merging of slash-suffixed objects (#19699)
If two objects share everything but one object has a slash prefix, those would be merged in listings, with secondary properties used for a tiebreak. Example: An object with the key `prefix/obj` would be merged with an object named `prefix/obj/`. While this violates the [no object can be a prefix of another](https://min.io/docs/minio/linux/operations/concepts/thresholds.html#conflicting-objects), let's resolve these. If we have an object with 'name' and a directory named 'name/' discard the directory only - but allow objects of 'name' and 'name/' (xldir) to be uniquely returned. Regression from #15772
This commit is contained in:
parent
b534dc69ab
commit
2f7a10ab31
@ -736,17 +736,36 @@ func mergeEntryChannels(ctx context.Context, in []chan metaCacheEntry, out chan<
|
|||||||
bestIdx = otherIdx
|
bestIdx = otherIdx
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
// We should make sure to avoid objects and directories
|
|
||||||
// of this fashion such as
|
|
||||||
// - foo-1
|
|
||||||
// - foo-1/
|
|
||||||
// we should avoid this situation by making sure that
|
|
||||||
// we compare the `foo-1/` after path.Clean() to
|
|
||||||
// de-dup the entries.
|
|
||||||
if path.Clean(best.name) == path.Clean(other.name) {
|
if path.Clean(best.name) == path.Clean(other.name) {
|
||||||
|
// We may be in a situation where we have a directory and an object with the same name.
|
||||||
|
// In that case we will drop the directory entry.
|
||||||
|
// This should however not be confused with an object with a trailing slash.
|
||||||
|
dirMatches := best.isDir() == other.isDir()
|
||||||
|
suffixMatches := strings.HasSuffix(best.name, slashSeparator) == strings.HasSuffix(other.name, slashSeparator)
|
||||||
|
|
||||||
|
// Simple case. Both are same type with same suffix.
|
||||||
|
if dirMatches && suffixMatches {
|
||||||
toMerge = append(toMerge, otherIdx)
|
toMerge = append(toMerge, otherIdx)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if !dirMatches && !suffixMatches {
|
||||||
|
// We have an object `name` and a directory `name/`.
|
||||||
|
if other.isDir() {
|
||||||
|
// Discard the directory.
|
||||||
|
if err := selectFrom(otherIdx); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
// Replace directory with object.
|
||||||
|
toMerge = toMerge[:0]
|
||||||
|
best = other
|
||||||
|
bestIdx = otherIdx
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
// Return as separate entries.
|
||||||
|
}
|
||||||
if best.name > other.name {
|
if best.name > other.name {
|
||||||
toMerge = toMerge[:0]
|
toMerge = toMerge[:0]
|
||||||
best = other
|
best = other
|
||||||
|
Loading…
x
Reference in New Issue
Block a user