s3: change metadata storage to normal map with lowercase keys

This commit is contained in:
Nick Craig-Wood 2022-06-22 15:40:30 +01:00
parent 776a083892
commit a692bd2cd4

View File

@ -2072,14 +2072,14 @@ type Object struct {
// //
// List will read everything but meta & mimeType - to fill // List will read everything but meta & mimeType - to fill
// that in you need to call readMetaData // that in you need to call readMetaData
fs *Fs // what this object is part of fs *Fs // what this object is part of
remote string // The remote path remote string // The remote path
md5 string // md5sum of the object md5 string // md5sum of the object
bytes int64 // size of the object bytes int64 // size of the object
lastModified time.Time // Last modified lastModified time.Time // Last modified
meta map[string]*string // The object metadata if known - may be nil meta map[string]string // The object metadata if known - may be nil - with lower case keys
mimeType string // MimeType of object - may be "" mimeType string // MimeType of object - may be ""
storageClass string // e.g. GLACIER storageClass string // e.g. GLACIER
} }
// ------------------------------------------------------------ // ------------------------------------------------------------
@ -3753,6 +3753,27 @@ func (o *Object) readMetaData(ctx context.Context) (err error) {
return nil return nil
} }
// Convert S3 metadata with pointers into a map[string]string
// while lowercasing the keys
func s3MetadataToMap(s3Meta map[string]*string) map[string]string {
meta := make(map[string]string, len(s3Meta))
for k, v := range s3Meta {
if v != nil {
meta[strings.ToLower(k)] = *v
}
}
return meta
}
// Convert our metadata back into S3 metadata
func mapToS3Metadata(meta map[string]string) map[string]*string {
s3Meta := make(map[string]*string, len(meta))
for k, v := range meta {
s3Meta[k] = aws.String(v)
}
return s3Meta
}
func (o *Object) setMetaData(etag *string, contentLength *int64, lastModified *time.Time, meta map[string]*string, mimeType *string, storageClass *string) { func (o *Object) setMetaData(etag *string, contentLength *int64, lastModified *time.Time, meta map[string]*string, mimeType *string, storageClass *string) {
// Ignore missing Content-Length assuming it is 0 // Ignore missing Content-Length assuming it is 0
// Some versions of ceph do this due their apache proxies // Some versions of ceph do this due their apache proxies
@ -3760,17 +3781,14 @@ func (o *Object) setMetaData(etag *string, contentLength *int64, lastModified *t
o.bytes = *contentLength o.bytes = *contentLength
} }
o.setMD5FromEtag(aws.StringValue(etag)) o.setMD5FromEtag(aws.StringValue(etag))
o.meta = meta o.meta = s3MetadataToMap(meta)
if o.meta == nil {
o.meta = map[string]*string{}
}
// Read MD5 from metadata if present // Read MD5 from metadata if present
if md5sumBase64, ok := o.meta[metaMD5Hash]; ok { if md5sumBase64, ok := o.meta[metaMD5Hash]; ok {
md5sumBytes, err := base64.StdEncoding.DecodeString(*md5sumBase64) md5sumBytes, err := base64.StdEncoding.DecodeString(md5sumBase64)
if err != nil { if err != nil {
fs.Debugf(o, "Failed to read md5sum from metadata %q: %v", *md5sumBase64, err) fs.Debugf(o, "Failed to read md5sum from metadata %q: %v", md5sumBase64, err)
} else if len(md5sumBytes) != 16 { } else if len(md5sumBytes) != 16 {
fs.Debugf(o, "Failed to read md5sum from metadata %q: wrong length", *md5sumBase64) fs.Debugf(o, "Failed to read md5sum from metadata %q: wrong length", md5sumBase64)
} else { } else {
o.md5 = hex.EncodeToString(md5sumBytes) o.md5 = hex.EncodeToString(md5sumBytes)
} }
@ -3800,11 +3818,11 @@ func (o *Object) ModTime(ctx context.Context) time.Time {
} }
// read mtime out of metadata if available // read mtime out of metadata if available
d, ok := o.meta[metaMtime] d, ok := o.meta[metaMtime]
if !ok || d == nil { if !ok {
// fs.Debugf(o, "No metadata") // fs.Debugf(o, "No metadata")
return o.lastModified return o.lastModified
} }
modTime, err := swift.FloatStringToTime(*d) modTime, err := swift.FloatStringToTime(d)
if err != nil { if err != nil {
fs.Logf(o, "Failed to read mtime from object: %v", err) fs.Logf(o, "Failed to read mtime from object: %v", err)
return o.lastModified return o.lastModified
@ -3818,7 +3836,7 @@ func (o *Object) SetModTime(ctx context.Context, modTime time.Time) error {
if err != nil { if err != nil {
return err return err
} }
o.meta[metaMtime] = aws.String(swift.TimeToFloatString(modTime)) o.meta[metaMtime] = swift.TimeToFloatString(modTime)
// Can't update metadata here, so return this error to force a recopy // Can't update metadata here, so return this error to force a recopy
if o.storageClass == "GLACIER" || o.storageClass == "DEEP_ARCHIVE" { if o.storageClass == "GLACIER" || o.storageClass == "DEEP_ARCHIVE" {
@ -3829,7 +3847,7 @@ func (o *Object) SetModTime(ctx context.Context, modTime time.Time) error {
bucket, bucketPath := o.split() bucket, bucketPath := o.split()
req := s3.CopyObjectInput{ req := s3.CopyObjectInput{
ContentType: aws.String(fs.MimeType(ctx, o)), // Guess the content type ContentType: aws.String(fs.MimeType(ctx, o)), // Guess the content type
Metadata: o.meta, Metadata: mapToS3Metadata(o.meta),
MetadataDirective: aws.String(s3.MetadataDirectiveReplace), // replace metadata with that passed in MetadataDirective: aws.String(s3.MetadataDirectiveReplace), // replace metadata with that passed in
} }
if o.fs.opt.RequesterPays { if o.fs.opt.RequesterPays {
@ -4423,7 +4441,7 @@ func (o *Object) Update(ctx context.Context, in io.Reader, src fs.ObjectInfo, op
o.md5 = md5sumHex o.md5 = md5sumHex
o.bytes = size o.bytes = size
o.lastModified = time.Now() o.lastModified = time.Now()
o.meta = req.Metadata o.meta = s3MetadataToMap(req.Metadata)
o.mimeType = aws.StringValue(req.ContentType) o.mimeType = aws.StringValue(req.ContentType)
o.storageClass = aws.StringValue(req.StorageClass) o.storageClass = aws.StringValue(req.StorageClass)
// If we have done a single part PUT request then we can read these // If we have done a single part PUT request then we can read these