From 80f8b1b883596f69aa74ecb4839e91f477923c22 Mon Sep 17 00:00:00 2001 From: Ben McClelland Date: Wed, 17 May 2023 16:00:00 -0700 Subject: [PATCH] posix: initial bucket requests --- backend/common.go | 14 +++++- backend/posix/posix.go | 96 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 109 insertions(+), 1 deletion(-) diff --git a/backend/common.go b/backend/common.go index d96432d9..080ee865 100644 --- a/backend/common.go +++ b/backend/common.go @@ -1,6 +1,10 @@ package backend -import "github.com/aws/aws-sdk-go-v2/service/s3/types" +import ( + "time" + + "github.com/aws/aws-sdk-go-v2/service/s3/types" +) func IsValidBucketName(name string) bool { return true } @@ -9,3 +13,11 @@ type ByBucketName []types.Bucket func (d ByBucketName) Len() int { return len(d) } func (d ByBucketName) Swap(i, j int) { d[i], d[j] = d[j], d[i] } func (d ByBucketName) Less(i, j int) bool { return *d[i].Name < *d[j].Name } + +func GetStringPtr(s string) *string { + return &s +} + +func GetTimePtr(t time.Time) *time.Time { + return &t +} diff --git a/backend/posix/posix.go b/backend/posix/posix.go index 55af7df5..d0406a80 100644 --- a/backend/posix/posix.go +++ b/backend/posix/posix.go @@ -1,7 +1,16 @@ package posix import ( + "fmt" + "os" + "path/filepath" + "sort" + "syscall" + + "github.com/aws/aws-sdk-go-v2/service/s3" + "github.com/aws/aws-sdk-go-v2/service/s3/types" "github.com/versity/scoutgw/backend" + "github.com/versity/scoutgw/s3err" ) type Posix struct { @@ -9,3 +18,90 @@ type Posix struct { } var _ backend.Backend = &Posix{} + +const metaTmpDir = ".sgwtmp" + +func (p *Posix) ListBuckets() (*s3.ListBucketsOutput, error) { + entries, err := os.ReadDir(".") + if err != nil { + return nil, fmt.Errorf("readdir buckets: %w", err) + } + + var buckets []types.Bucket + for _, entry := range entries { + if !entry.IsDir() { + // buckets must be a directory + continue + } + + fi, err := entry.Info() + if err != nil { + // skip entries returning errors + continue + } + + buckets = append(buckets, types.Bucket{ + Name: backend.GetStringPtr(entry.Name()), + CreationDate: backend.GetTimePtr(fi.ModTime()), + }) + } + + sort.Sort(backend.ByBucketName(buckets)) + + return &s3.ListBucketsOutput{ + Buckets: buckets, + }, nil +} + +func (p *Posix) HeadBucket(bucket string) (*s3.HeadBucketOutput, error) { + _, err := os.Lstat(bucket) + if err != nil && os.IsNotExist(err) { + return nil, s3err.GetAPIError(s3err.ErrNoSuchBucket) + } + if err != nil { + return nil, fmt.Errorf("stat bucket: %w", err) + } + + return &s3.HeadBucketOutput{}, nil +} + +func (p *Posix) PutBucket(bucket string) error { + err := os.Mkdir(bucket, 0777) + if err != nil && os.IsExist(err) { + return s3err.GetAPIError(s3err.ErrBucketAlreadyExists) + } + if err != nil { + return fmt.Errorf("mkdir bucket: %w", err) + } + + return nil +} + +func (p *Posix) DeleteBucket(bucket string) error { + names, err := os.ReadDir(bucket) + if err != nil && os.IsNotExist(err) { + return s3err.GetAPIError(s3err.ErrNoSuchBucket) + } + if err != nil { + return fmt.Errorf("readdir bucket: %w", err) + } + + if len(names) == 1 && names[0].Name() == metaTmpDir { + // if .sgwtmp is only item in directory + // then clean this up before trying to remove the bucket + err = os.RemoveAll(filepath.Join(bucket, metaTmpDir)) + if err != nil && !os.IsNotExist(err) { + return fmt.Errorf("remove temp dir: %w", err) + } + } + + err = os.Remove(bucket) + if err != nil && err.(*os.PathError).Err == syscall.ENOTEMPTY { + return s3err.GetAPIError(s3err.ErrBucketNotEmpty) + } + if err != nil { + return fmt.Errorf("remove bucket: %w", err) + } + + return nil +}