aboutsummaryrefslogblamecommitdiff
path: root/s3_stat.go
blob: 65b6faa849fdfbecd3b01aaa4b7062ae5ee000b9 (plain) (tree)































































































































                                                                                                         
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
}