Make isIndexedMetaV2 return errors (#15012)

Indexed streams would be decoded by the legacy loader if there 
was an error loading it. Return an error when the stream is indexed 
and it cannot be loaded.

Fixes "unknown minor metadata version" on corrupted xl.meta files and 
returns an actual error.
This commit is contained in:
Klaus Post 2022-05-31 19:06:57 -07:00 committed by GitHub
parent 7b2198f7e5
commit f7cecf0945
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 23 additions and 17 deletions

View file

@ -168,8 +168,10 @@ func (e *metaCacheEntry) isLatestDeletemarker() bool {
if !isXL2V1Format(e.metadata) {
return false
}
if meta, _ := isIndexedMetaV2(e.metadata); meta != nil {
if meta, _, err := isIndexedMetaV2(e.metadata); meta != nil {
return meta.IsLatestDeleteMarker()
} else if err != nil {
return true
}
// Fall back...
xlMeta, err := e.xlmeta()

View file

@ -50,7 +50,9 @@ func getAllFileInfoVersions(xlMetaBuf []byte, volume, path string) (FileInfoVers
var versions []FileInfo
var err error
if buf, _ := isIndexedMetaV2(xlMetaBuf); buf != nil {
if buf, _, e := isIndexedMetaV2(xlMetaBuf); e != nil {
return FileInfoVersions{}, e
} else if buf != nil {
versions, err = buf.ListVersions(volume, path)
} else {
var xlMeta xlMetaV2
@ -87,7 +89,9 @@ func getFileInfo(xlMetaBuf []byte, volume, path, versionID string, data bool) (F
var fi FileInfo
var err error
var inData xlMetaInlineData
if buf, data := isIndexedMetaV2(xlMetaBuf); buf != nil {
if buf, data, e := isIndexedMetaV2(xlMetaBuf); e != nil {
return FileInfo{}, e
} else if buf != nil {
inData = data
fi, err = buf.ToFileInfo(volume, path, versionID)
if len(buf) != 0 && errors.Is(err, errFileNotFound) {

View file

@ -793,34 +793,32 @@ func decodeVersions(buf []byte, versions int, fn func(idx int, hdr, meta []byte)
}
// isIndexedMetaV2 returns non-nil result if metadata is indexed.
// If data doesn't validate nil is also returned.
func isIndexedMetaV2(buf []byte) (meta xlMetaBuf, data xlMetaInlineData) {
// Returns 3x nil if not XLV2 or not indexed.
// If indexed and unable to parse an error will be returned.
func isIndexedMetaV2(buf []byte) (meta xlMetaBuf, data xlMetaInlineData, err error) {
buf, major, minor, err := checkXL2V1(buf)
if err != nil {
return nil, nil
}
if major != 1 || minor < 3 {
return nil, nil
if err != nil || major != 1 || minor < 3 {
return nil, nil, nil
}
meta, buf, err = msgp.ReadBytesZC(buf)
if err != nil {
return nil, nil
return nil, nil, err
}
if crc, nbuf, err := msgp.ReadUint32Bytes(buf); err == nil {
// Read metadata CRC
buf = nbuf
if got := uint32(xxhash.Sum64(meta)); got != crc {
return nil, nil
return nil, nil, fmt.Errorf("xlMetaV2.Load version(%d), CRC mismatch, want 0x%x, got 0x%x", minor, crc, got)
}
} else {
return nil, nil
return nil, nil, err
}
data = buf
if data.validate() != nil {
data.repair()
}
return meta, data
return meta, data, nil
}
type xlMetaV2ShallowVersion struct {
@ -865,7 +863,9 @@ func (x *xlMetaV2) LoadOrConvert(buf []byte) error {
// Load all versions of the stored data.
// Note that references to the incoming buffer will be kept.
func (x *xlMetaV2) Load(buf []byte) error {
if meta, data := isIndexedMetaV2(buf); meta != nil {
if meta, data, err := isIndexedMetaV2(buf); err != nil {
return err
} else if meta != nil {
return x.loadIndexed(meta, data)
}
// Convert older format.

View file

@ -514,7 +514,7 @@ func BenchmarkXlMetaV2Shallow(b *testing.B) {
b.ResetTimer()
b.ReportAllocs()
for i := 0; i < b.N; i++ {
buf, _ := isIndexedMetaV2(enc)
buf, _, _ := isIndexedMetaV2(enc)
if buf == nil {
b.Fatal("buf == nil")
}
@ -529,7 +529,7 @@ func BenchmarkXlMetaV2Shallow(b *testing.B) {
b.ResetTimer()
b.ReportAllocs()
for i := 0; i < b.N; i++ {
buf, _ := isIndexedMetaV2(enc)
buf, _, _ := isIndexedMetaV2(enc)
if buf == nil {
b.Fatal("buf == nil")
}