From 2132d2b6a274144cbf299269890adabdeec86a6e Mon Sep 17 00:00:00 2001 From: "Gauthier C." Date: Fri, 29 May 2026 14:23:11 +0200 Subject: [PATCH 1/3] [s3] fix metadata lost during backup and restore #1967 --- s3/exporter/exporter.go | 16 +++++++++++++++- s3/importer/importer.go | 13 ++++++++++++- 2 files changed, 27 insertions(+), 2 deletions(-) diff --git a/s3/exporter/exporter.go b/s3/exporter/exporter.go index 108ed7c9..f395fe8d 100644 --- a/s3/exporter/exporter.go +++ b/s3/exporter/exporter.go @@ -19,6 +19,7 @@ package exporter import ( "context" "encoding/base64" + "encoding/json" "fmt" "net/url" "path" @@ -241,8 +242,21 @@ func (p *S3Exporter) Export(ctx context.Context, records <-chan *connectors.Reco g.Go(func() error { objname := strings.TrimLeft(path.Join(p.restoreDir, record.Pathname), "/") + var objectInfo minio.ObjectInfo + if len(record.ExtendedAttributes) > 0 { + if err := json.Unmarshal([]byte(record.ExtendedAttributes[0]), &objectInfo); err != nil { + objectInfo.UserTags = nil + objectInfo.UserMetadata = nil + } + } + _, err := p.minioClient.PutObject(ctx, p.bucket, objname, - record.Reader, record.FileInfo.Lsize, minio.PutObjectOptions{ServerSideEncryption: p.ssec}) + record.Reader, record.FileInfo.Lsize, minio.PutObjectOptions{ + ServerSideEncryption: p.ssec, + ContentType: objectInfo.ContentType, + UserTags: objectInfo.UserTags, + UserMetadata: objectInfo.UserMetadata, + }) results <- record.Error(err) return nil }) diff --git a/s3/importer/importer.go b/s3/importer/importer.go index 9599162c..d6da1134 100644 --- a/s3/importer/importer.go +++ b/s3/importer/importer.go @@ -19,6 +19,7 @@ package importer import ( "context" "encoding/base64" + "encoding/json" "fmt" "io" "net/url" @@ -245,7 +246,17 @@ func (p *S3Importer) Import(ctx context.Context, records chan<- *connectors.Reco Ldev: 1, } - records <- connectors.NewRecord("/"+object.Key, "", fi, nil, func() (io.ReadCloser, error) { + stat, err := p.minioClient.StatObject(ctx, p.bucket, object.Key, minio.GetObjectOptions{ServerSideEncryption: p.ssec}) + if err != nil { + continue + } + var xattr []string + xattrStr, err := json.Marshal(stat) + if err == nil { + xattr = append(xattr, string(xattrStr)) + } + + records <- connectors.NewRecord("/"+object.Key, "", fi, xattr, func() (io.ReadCloser, error) { return p.minioClient.GetObject(ctx, p.bucket, object.Key, minio.GetObjectOptions{ServerSideEncryption: p.ssec}) }) } From 9282b0c30538d744dc026842fea205ad2ac8eb83 Mon Sep 17 00:00:00 2001 From: "Gauthier C." Date: Wed, 24 Jun 2026 10:35:27 +0200 Subject: [PATCH 2/3] [s3] improve performance to fetch metadata --- s3/importer/importer.go | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/s3/importer/importer.go b/s3/importer/importer.go index d6da1134..3e436fc7 100644 --- a/s3/importer/importer.go +++ b/s3/importer/importer.go @@ -246,18 +246,20 @@ func (p *S3Importer) Import(ctx context.Context, records chan<- *connectors.Reco Ldev: 1, } - stat, err := p.minioClient.StatObject(ctx, p.bucket, object.Key, minio.GetObjectOptions{ServerSideEncryption: p.ssec}) + obj, err := p.minioClient.GetObject(ctx, p.bucket, object.Key, minio.GetObjectOptions{ServerSideEncryption: p.ssec}) if err != nil { continue } var xattr []string - xattrStr, err := json.Marshal(stat) - if err == nil { - xattr = append(xattr, string(xattrStr)) + if stat, err := obj.Stat(); err == nil { + xattrStr, err := json.Marshal(stat) + if err == nil { + xattr = append(xattr, string(xattrStr)) + } } records <- connectors.NewRecord("/"+object.Key, "", fi, xattr, func() (io.ReadCloser, error) { - return p.minioClient.GetObject(ctx, p.bucket, object.Key, minio.GetObjectOptions{ServerSideEncryption: p.ssec}) + return obj, nil }) } From 794a63a0f49de6280a2d4ad2902eff288dab6cc7 Mon Sep 17 00:00:00 2001 From: "Gauthier C." Date: Wed, 24 Jun 2026 11:25:03 +0200 Subject: [PATCH 3/3] [s3] error handling when retrieving the object --- s3/importer/importer.go | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/s3/importer/importer.go b/s3/importer/importer.go index 3e436fc7..327ff904 100644 --- a/s3/importer/importer.go +++ b/s3/importer/importer.go @@ -246,20 +246,19 @@ func (p *S3Importer) Import(ctx context.Context, records chan<- *connectors.Reco Ldev: 1, } - obj, err := p.minioClient.GetObject(ctx, p.bucket, object.Key, minio.GetObjectOptions{ServerSideEncryption: p.ssec}) - if err != nil { - continue - } var xattr []string - if stat, err := obj.Stat(); err == nil { - xattrStr, err := json.Marshal(stat) - if err == nil { - xattr = append(xattr, string(xattrStr)) + obj, err := p.minioClient.GetObject(ctx, p.bucket, object.Key, minio.GetObjectOptions{ServerSideEncryption: p.ssec}) + if err == nil { + if stat, err := obj.Stat(); err == nil { + xattrStr, err := json.Marshal(stat) + if err == nil { + xattr = append(xattr, string(xattrStr)) + } } } records <- connectors.NewRecord("/"+object.Key, "", fi, xattr, func() (io.ReadCloser, error) { - return obj, nil + return obj, err }) }