diff --git a/backend/posix/posix.go b/backend/posix/posix.go index a77adf7..c20c228 100644 --- a/backend/posix/posix.go +++ b/backend/posix/posix.go @@ -1563,7 +1563,7 @@ func (p *Posix) CompleteMultipartUpload(ctx context.Context, input *s3.CompleteM upiddir := filepath.Join(objdir, uploadID) userMetaData := make(map[string]string) - objMeta := p.loadObjectMetaData(bucket, upiddir, nil, userMetaData) + objMeta := p.loadObjectMetaData(nil, bucket, upiddir, nil, userMetaData) err = p.storeObjectMetadata(f.File(), bucket, object, objMeta) if err != nil { return res, "", err @@ -1859,7 +1859,7 @@ type objectMetadata struct { // fill out the user metadata map with the metadata for the object // and return object meta properties as `ObjectMetadata` -func (p *Posix) loadObjectMetaData(bucket, object string, fi *os.FileInfo, m map[string]string) objectMetadata { +func (p *Posix) loadObjectMetaData(f *os.File, bucket, object string, fi *os.FileInfo, m map[string]string) objectMetadata { ents, err := p.meta.ListAttributes(bucket, object) if err != nil || len(ents) == 0 { return objectMetadata{} @@ -1870,7 +1870,7 @@ func (p *Posix) loadObjectMetaData(bucket, object string, fi *os.FileInfo, m map if !isValidMeta(e) { continue } - b, err := p.meta.RetrieveAttribute(nil, bucket, object, e) + b, err := p.meta.RetrieveAttribute(f, bucket, object, e) if err != nil { continue } @@ -1884,7 +1884,7 @@ func (p *Posix) loadObjectMetaData(bucket, object string, fi *os.FileInfo, m map var result objectMetadata - b, err := p.meta.RetrieveAttribute(nil, bucket, object, contentTypeHdr) + b, err := p.meta.RetrieveAttribute(f, bucket, object, contentTypeHdr) if err == nil { result.ContentType = backend.GetPtrFromString(string(b)) } @@ -1896,27 +1896,27 @@ func (p *Posix) loadObjectMetaData(bucket, object string, fi *os.FileInfo, m map } } - b, err = p.meta.RetrieveAttribute(nil, bucket, object, contentEncHdr) + b, err = p.meta.RetrieveAttribute(f, bucket, object, contentEncHdr) if err == nil { result.ContentEncoding = backend.GetPtrFromString(string(b)) } - b, err = p.meta.RetrieveAttribute(nil, bucket, object, contentDispHdr) + b, err = p.meta.RetrieveAttribute(f, bucket, object, contentDispHdr) if err == nil { result.ContentDisposition = backend.GetPtrFromString(string(b)) } - b, err = p.meta.RetrieveAttribute(nil, bucket, object, contentLangHdr) + b, err = p.meta.RetrieveAttribute(f, bucket, object, contentLangHdr) if err == nil { result.ContentLanguage = backend.GetPtrFromString(string(b)) } - b, err = p.meta.RetrieveAttribute(nil, bucket, object, cacheCtrlHdr) + b, err = p.meta.RetrieveAttribute(f, bucket, object, cacheCtrlHdr) if err == nil { result.CacheControl = backend.GetPtrFromString(string(b)) } - b, err = p.meta.RetrieveAttribute(nil, bucket, object, expiresHdr) + b, err = p.meta.RetrieveAttribute(f, bucket, object, expiresHdr) if err == nil { result.Expires = backend.GetPtrFromString(string(b)) } @@ -2286,7 +2286,7 @@ func (p *Posix) ListParts(ctx context.Context, input *s3.ListPartsInput) (s3resp userMetaData := make(map[string]string) upiddir := filepath.Join(objdir, uploadID) - p.loadObjectMetaData(bucket, upiddir, nil, userMetaData) + p.loadObjectMetaData(nil, bucket, upiddir, nil, userMetaData) return s3response.ListPartsResult{ Bucket: bucket, @@ -3428,7 +3428,7 @@ func (p *Posix) GetObject(_ context.Context, input *s3.GetObjectInput) (*s3.GetO objPath := filepath.Join(bucket, object) - fi, err := os.Stat(objPath) + fid, err := os.Stat(objPath) if errors.Is(err, fs.ErrNotExist) || errors.Is(err, syscall.ENOTDIR) { if versionId != "" { return nil, s3err.GetAPIError(s3err.ErrInvalidVersionId) @@ -3442,10 +3442,10 @@ func (p *Posix) GetObject(_ context.Context, input *s3.GetObjectInput) (*s3.GetO return nil, fmt.Errorf("stat object: %w", err) } - if strings.HasSuffix(object, "/") && !fi.IsDir() { + if strings.HasSuffix(object, "/") && !fid.IsDir() { return nil, s3err.GetAPIError(s3err.ErrNoSuchKey) } - if !strings.HasSuffix(object, "/") && fi.IsDir() { + if !strings.HasSuffix(object, "/") && fid.IsDir() { return nil, s3err.GetAPIError(s3err.ErrNoSuchKey) } @@ -3464,33 +3464,15 @@ func (p *Posix) GetObject(_ context.Context, input *s3.GetObjectInput) (*s3.GetO } return &s3.GetObjectOutput{ DeleteMarker: getBoolPtr(true), - LastModified: backend.GetTimePtr(fi.ModTime()), + LastModified: backend.GetTimePtr(fid.ModTime()), }, err } } - objSize := fi.Size() - startOffset, length, isValid, err := backend.ParseObjectRange(objSize, *input.Range) - if err != nil { - return nil, err - } - - if fi.IsDir() { - // directory objects are always 0 len - objSize = 0 - length = 0 - } - - var contentRange string - if isValid { - contentRange = fmt.Sprintf("bytes %v-%v/%v", - startOffset, startOffset+length-1, objSize) - } - - if fi.IsDir() { + if fid.IsDir() { userMetaData := make(map[string]string) - objMeta := p.loadObjectMetaData(bucket, object, &fi, userMetaData) + objMeta := p.loadObjectMetaData(nil, bucket, object, &fid, userMetaData) b, err := p.meta.RetrieveAttribute(nil, bucket, object, etagkey) etag := string(b) if err != nil { @@ -3507,6 +3489,7 @@ func (p *Posix) GetObject(_ context.Context, input *s3.GetObjectInput) (*s3.GetO tagCount = &tgCount } + var length int64 = 0 return &s3.GetObjectOutput{ AcceptRanges: backend.GetPtrFromString("bytes"), ContentLength: &length, @@ -3517,10 +3500,10 @@ func (p *Posix) GetObject(_ context.Context, input *s3.GetObjectInput) (*s3.GetO CacheControl: objMeta.CacheControl, ExpiresString: objMeta.Expires, ETag: &etag, - LastModified: backend.GetTimePtr(fi.ModTime()), + LastModified: backend.GetTimePtr(fid.ModTime()), Metadata: userMetaData, TagCount: tagCount, - ContentRange: &contentRange, + ContentRange: nil, StorageClass: types.StorageClassStandard, VersionId: &versionId, }, nil @@ -3538,11 +3521,45 @@ func (p *Posix) GetObject(_ context.Context, input *s3.GetObjectInput) (*s3.GetO versionId = string(vId) } + f, err := os.Open(objPath) + if errors.Is(err, fs.ErrNotExist) { + return nil, s3err.GetAPIError(s3err.ErrNoSuchKey) + } + if err != nil { + return nil, fmt.Errorf("open object: %w", err) + } + + fi, err := f.Stat() + if errors.Is(err, fs.ErrNotExist) || errors.Is(err, syscall.ENOTDIR) { + if versionId != "" { + return nil, s3err.GetAPIError(s3err.ErrInvalidVersionId) + } + return nil, s3err.GetAPIError(s3err.ErrNoSuchKey) + } + if errors.Is(err, syscall.ENAMETOOLONG) { + return nil, s3err.GetAPIError(s3err.ErrKeyTooLong) + } + if err != nil { + return nil, fmt.Errorf("stat object: %w", err) + } + + objSize := fi.Size() + startOffset, length, isValid, err := backend.ParseObjectRange(objSize, *input.Range) + if err != nil { + return nil, err + } + + var contentRange string + if isValid { + contentRange = fmt.Sprintf("bytes %v-%v/%v", + startOffset, startOffset+length-1, objSize) + } + userMetaData := make(map[string]string) - objMeta := p.loadObjectMetaData(bucket, object, &fi, userMetaData) + objMeta := p.loadObjectMetaData(f, bucket, object, &fi, userMetaData) - b, err := p.meta.RetrieveAttribute(nil, bucket, object, etagkey) + b, err := p.meta.RetrieveAttribute(f, bucket, object, etagkey) etag := string(b) if err != nil { etag = "" @@ -3558,14 +3575,6 @@ func (p *Posix) GetObject(_ context.Context, input *s3.GetObjectInput) (*s3.GetO tagCount = &tgCount } - f, err := os.Open(objPath) - if errors.Is(err, fs.ErrNotExist) { - return nil, s3err.GetAPIError(s3err.ErrNoSuchKey) - } - if err != nil { - return nil, fmt.Errorf("open object: %w", err) - } - var checksums s3response.Checksum var cType types.ChecksumType // Skip the checksums retreival if object isn't requested fully @@ -3762,7 +3771,7 @@ func (p *Posix) HeadObject(ctx context.Context, input *s3.HeadObjectInput) (*s3. } userMetaData := make(map[string]string) - objMeta := p.loadObjectMetaData(bucket, object, &fi, userMetaData) + objMeta := p.loadObjectMetaData(nil, bucket, object, &fi, userMetaData) b, err := p.meta.RetrieveAttribute(nil, bucket, object, etagkey) etag := string(b) @@ -3965,7 +3974,7 @@ func (p *Posix) CopyObject(ctx context.Context, input s3response.CopyObjectInput } mdmap := make(map[string]string) - p.loadObjectMetaData(srcBucket, srcObject, &fi, mdmap) + p.loadObjectMetaData(nil, srcBucket, srcObject, &fi, mdmap) var etag string var version *string @@ -4125,7 +4134,7 @@ func (p *Posix) CopyObject(ctx context.Context, input s3response.CopyObjectInput // load and pass the source object meta properties, if metadata directive is "COPY" if input.MetadataDirective != types.MetadataDirectiveReplace { - metaProps := p.loadObjectMetaData(srcBucket, srcObject, &fi, nil) + metaProps := p.loadObjectMetaData(nil, srcBucket, srcObject, &fi, nil) putObjectInput.ContentEncoding = metaProps.ContentEncoding putObjectInput.ContentDisposition = metaProps.ContentDisposition putObjectInput.ContentLanguage = metaProps.ContentLanguage