128 lines
2.2 KiB
Go
128 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
|
|
}
|