From 72daccd46860db26bd3daeb12bbac484edda3802 Mon Sep 17 00:00:00 2001 From: Harshavardhana Date: Fri, 10 Feb 2023 06:53:03 -0800 Subject: [PATCH] fix: scanner in healing cycle must use actual size (#16589) --- cmd/erasure-healing.go | 11 +++++---- cmd/erasure-metadata.go | 49 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 54 insertions(+), 6 deletions(-) diff --git a/cmd/erasure-healing.go b/cmd/erasure-healing.go index e39ded11a..ef0f1b593 100644 --- a/cmd/erasure-healing.go +++ b/cmd/erasure-healing.go @@ -411,6 +411,11 @@ func (er *erasureObjects) healObject(ctx context.Context, bucket string, object erasure.ShardFileSize(latestMeta.Parts[0].ActualSize) < smallFileThreshold) } + result.ObjectSize, err = latestMeta.GetActualSize() + if err != nil { + return result, err + } + // Loop to find number of disks with valid data, per-drive // data state and a list of outdated disks on which data needs // to be healed. @@ -421,9 +426,6 @@ func (er *erasureObjects) healObject(ctx context.Context, bucket string, object switch { case v != nil: driveState = madmin.DriveStateOk - // If data is sane on any one disk, we can - // extract the correct object size. - result.ObjectSize = partsMetadata[i].Size case errs[i] == errDiskNotFound, dataErrs[i] == errDiskNotFound: driveState = madmin.DriveStateOffline case errs[i] == errFileNotFound, errs[i] == errFileVersionNotFound, errs[i] == errVolumeNotFound: @@ -673,9 +675,6 @@ func (er *erasureObjects) healObject(ctx context.Context, bucket string, object }) } - // Set the size of the object in the heal result - result.ObjectSize = latestMeta.Size - return result, nil } diff --git a/cmd/erasure-metadata.go b/cmd/erasure-metadata.go index 3ca18fafe..623971c17 100644 --- a/cmd/erasure-metadata.go +++ b/cmd/erasure-metadata.go @@ -23,15 +23,18 @@ import ( "fmt" "net/http" "sort" + "strconv" "strings" "time" "github.com/minio/minio/internal/amztime" "github.com/minio/minio/internal/bucket/replication" + "github.com/minio/minio/internal/crypto" "github.com/minio/minio/internal/hash/sha256" xhttp "github.com/minio/minio/internal/http" "github.com/minio/minio/internal/logger" "github.com/minio/minio/internal/sync/errgroup" + "github.com/minio/sio" ) // Object was stored with additional erasure codes due to degraded system at upload time @@ -104,6 +107,52 @@ func (fi FileInfo) IsValid() bool { correctIndexes) } +func (fi FileInfo) checkMultipart() (int64, bool) { + if len(fi.Parts) == 0 { + return 0, false + } + if !crypto.IsMultiPart(fi.Metadata) { + return 0, false + } + var size int64 + for _, part := range fi.Parts { + psize, err := sio.DecryptedSize(uint64(part.Size)) + if err != nil { + return 0, false + } + size += int64(psize) + } + + return size, len(extractETag(fi.Metadata)) != 32 +} + +// GetActualSize - returns the actual size of the stored object +func (fi FileInfo) GetActualSize() (int64, error) { + if _, ok := fi.Metadata[ReservedMetadataPrefix+"compression"]; ok { + sizeStr, ok := fi.Metadata[ReservedMetadataPrefix+"actual-size"] + if !ok { + return -1, errInvalidDecompressedSize + } + size, err := strconv.ParseInt(sizeStr, 10, 64) + if err != nil { + return -1, errInvalidDecompressedSize + } + return size, nil + } + if _, ok := crypto.IsEncrypted(fi.Metadata); ok { + size, ok := fi.checkMultipart() + if !ok { + size, err := sio.DecryptedSize(uint64(fi.Size)) + if err != nil { + err = errObjectTampered // assign correct error type + } + return int64(size), err + } + return size, nil + } + return fi.Size, nil +} + // ToObjectInfo - Converts metadata to object info. func (fi FileInfo) ToObjectInfo(bucket, object string, versioned bool) ObjectInfo { object = decodeDirObject(object)