aboutsummaryrefslogtreecommitdiff
path: root/s3/stat.go
diff options
context:
space:
mode:
Diffstat (limited to 's3/stat.go')
-rw-r--r--s3/stat.go128
1 files changed, 128 insertions, 0 deletions
diff --git a/s3/stat.go b/s3/stat.go
new file mode 100644
index 0000000..96b0c24
--- /dev/null
+++ b/s3/stat.go
@@ -0,0 +1,128 @@
+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
+}