diff --git a/backend/common.go b/backend/common.go index 79bb7d20..951d4841 100644 --- a/backend/common.go +++ b/backend/common.go @@ -19,6 +19,7 @@ import ( "encoding/hex" "errors" "fmt" + "hash" "io" "io/fs" "net/url" @@ -391,3 +392,14 @@ func MoveFile(source, destination string, perm os.FileMode) error { return nil } + +// GenerateEtag generates a new quoted etag from the provided hash.Hash +func GenerateEtag(h hash.Hash) string { + dataSum := h.Sum(nil) + return fmt.Sprintf("\"%s\"", hex.EncodeToString(dataSum[:])) +} + +// AreEtagsSame compares 2 etags by ignoring quotes +func AreEtagsSame(e1, e2 string) bool { + return strings.Trim(e1, `"`) == strings.Trim(e2, `"`) +} diff --git a/backend/posix/posix.go b/backend/posix/posix.go index 66d379ee..4c66b45b 100644 --- a/backend/posix/posix.go +++ b/backend/posix/posix.go @@ -18,11 +18,9 @@ import ( "context" "crypto/md5" "crypto/sha256" - "encoding/hex" "encoding/json" "errors" "fmt" - "hash" "io" "io/fs" "net/http" @@ -95,7 +93,7 @@ const ( contentDispHdr = "content-disposition" cacheCtrlHdr = "cache-control" expiresHdr = "expires" - emptyMD5 = "d41d8cd98f00b204e9800998ecf8427e" + emptyMD5 = "\"d41d8cd98f00b204e9800998ecf8427e\"" aclkey = "acl" ownershipkey = "ownership" etagkey = "etag" @@ -1472,7 +1470,7 @@ func (p *Posix) CompleteMultipartUpload(ctx context.Context, input *s3.CompleteM if err != nil { etag = "" } - if parts[i].ETag == nil || !areEtagsSame(etag, *parts[i].ETag) { + if parts[i].ETag == nil || !backend.AreEtagsSame(etag, *parts[i].ETag) { return res, "", s3err.GetAPIError(s3err.ErrInvalidPart) } @@ -2406,7 +2404,7 @@ func (p *Posix) UploadPart(ctx context.Context, input *s3.UploadPartInput) (*s3. return nil, fmt.Errorf("write part data: %w", err) } - etag := generateEtag(hash) + etag := backend.GenerateEtag(hash) err = p.meta.StoreAttribute(f.File(), bucket, partPath, etagkey, []byte(etag)) if err != nil { return nil, fmt.Errorf("set etag attr: %w", err) @@ -2645,8 +2643,7 @@ func (p *Posix) UploadPartCopy(ctx context.Context, upi *s3.UploadPartCopyInput) } } - dataSum := hash.Sum(nil) - etag := hex.EncodeToString(dataSum) + etag := backend.GenerateEtag(hash) err = p.meta.StoreAttribute(f.File(), *upi.Bucket, partPath, etagkey, []byte(etag)) if err != nil { return s3response.CopyPartResult{}, fmt.Errorf("set etag attr: %w", err) @@ -2855,7 +2852,7 @@ func (p *Posix) PutObject(ctx context.Context, po s3response.PutObjectInput) (s3 } } - etag := generateEtag(hash) + etag := backend.GenerateEtag(hash) // if the versioning is enabled, generate a new versionID for the object var versionID string @@ -5006,12 +5003,3 @@ func joinPathWithTrailer(paths ...string) string { } return joined } - -func generateEtag(h hash.Hash) string { - dataSum := h.Sum(nil) - return fmt.Sprintf("\"%s\"", hex.EncodeToString(dataSum[:])) -} - -func areEtagsSame(e1, e2 string) bool { - return strings.Trim(e1, `"`) == strings.Trim(e2, `"`) -} diff --git a/backend/scoutfs/scoutfs.go b/backend/scoutfs/scoutfs.go index a0930914..462cfc3f 100644 --- a/backend/scoutfs/scoutfs.go +++ b/backend/scoutfs/scoutfs.go @@ -287,7 +287,7 @@ func (s *ScoutFS) CompleteMultipartUpload(ctx context.Context, input *s3.Complet if err != nil { etag = "" } - if parts[i].ETag == nil || !areEtagsSame(etag, *parts[i].ETag) { + if parts[i].ETag == nil || !backend.AreEtagsSame(etag, *parts[i].ETag) { return res, "", s3err.GetAPIError(s3err.ErrInvalidPart) } @@ -1033,7 +1033,3 @@ func isNoAttr(err error) bool { } return false } - -func areEtagsSame(e1, e2 string) bool { - return strings.Trim(e1, `"`) == strings.Trim(e2, `"`) -}