bagage/s3/stat.go

129 lines
2.2 KiB
Go

package s3
import (
"errors"
"io/fs"
"path"
"time"
"github.com/minio/minio-go/v7"
)
type S3Stat struct {
fs *S3FS
obj minio.ObjectInfo
path S3Path
}
/*
* Stat a path knowing its ObjectInfo
*/
func NewS3StatFromObjectInfo(fs *S3FS, bucket string, obj minio.ObjectInfo) (*S3Stat, error) {
s := new(S3Stat)
s.path = NewTrustedS3Path(bucket, obj)
s.obj = obj
s.fs = fs
fs.cache[s.path.Path] = s
return s, nil
}
/*
* Stat a path without additional information
*/
func NewS3Stat(fs *S3FS, path string) (*S3Stat, error) {
cache := fs.cache
if entry, ok := cache[path]; ok {
return entry, nil
}
s := new(S3Stat)
s.fs = fs
s.path = NewS3Path(path)
if err := s.Refresh(); err != nil {
return nil, err
}
if s.path.Class&OPAQUE_KEY != 0 {
return nil, errors.New("Failed to precisely determine the key type, this a logic error.")
}
cache[path] = s
cache[s.path.Path] = s
return s, nil
}
func (s *S3Stat) Refresh() error {
if s.path.Class == ROOT || s.path.Class == BUCKET {
return nil
}
mc := s.fs.mc
// Compute the prefix to have the desired behaviour for our stat logic
prefix := s.path.Key
if prefix[len(prefix)-1:] == "/" {
prefix = prefix[:len(prefix)-1]
}
// Get info and check if the key exists
objs_info := mc.ListObjects(s.fs.ctx, s.path.Bucket, minio.ListObjectsOptions{
Prefix: prefix,
Recursive: false,
})
found := false
for object := range objs_info {
if object.Err != nil {
return object.Err
}
if object.Key == prefix || object.Key == prefix+"/" {
s.obj = object
s.path = NewTrustedS3Path(s.path.Bucket, object)
found = true
break
}
}
if !found {
return fs.ErrNotExist
}
return nil
}
func (s *S3Stat) Name() string {
if s.path.Class == ROOT {
return "/"
} else if s.path.Class == BUCKET {
return s.path.Bucket
} else {
return path.Base(s.path.Key)
}
}
func (s *S3Stat) Size() int64 {
return s.obj.Size
}
func (s *S3Stat) Mode() fs.FileMode {
if s.path.Class == OBJECT {
return fs.ModePerm
} else {
return fs.ModeDir | fs.ModePerm
}
}
func (s *S3Stat) ModTime() time.Time {
return s.obj.LastModified
}
func (s *S3Stat) IsDir() bool {
return s.path.Class != OBJECT
}
func (s *S3Stat) Sys() interface{} {
return nil
}