aboutsummaryrefslogblamecommitdiff
path: root/s3/stat.go
blob: 96b0c249141f09d2af4e75d1e8ff7df069910953 (plain) (tree)
1
          
























                                                                                              
                                 


















                                                        
                                         



                                                                                                         
                              



                                  
                                                           





                                                                              
                            




                                               
                                                                                      











                                                                     
                                                                        












                                     
                                 
                          

                                          
                
                                            







                                     
                                   










                                               
                                     




                                    
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
}