package main 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 }