parent
3461e7e300
commit
163a6c35db
@ -0,0 +1,201 @@ |
|||||||
|
package fs |
||||||
|
|
||||||
|
import ( |
||||||
|
"errors" |
||||||
|
"io" |
||||||
|
"io/ioutil" |
||||||
|
"os" |
||||||
|
"path" |
||||||
|
"strings" |
||||||
|
"sync" |
||||||
|
|
||||||
|
mstorage "github.com/minio-io/minio/pkg/storage" |
||||||
|
) |
||||||
|
|
||||||
|
type storage struct { |
||||||
|
root string |
||||||
|
writeLock sync.Mutex |
||||||
|
} |
||||||
|
|
||||||
|
type MkdirFailedError struct{} |
||||||
|
|
||||||
|
func (self MkdirFailedError) Error() string { |
||||||
|
return "Mkdir Failed" |
||||||
|
} |
||||||
|
|
||||||
|
func Start(root string) (chan<- string, <-chan error, *storage) { |
||||||
|
ctrlChannel := make(chan string) |
||||||
|
errorChannel := make(chan error) |
||||||
|
go start(ctrlChannel, errorChannel) |
||||||
|
return ctrlChannel, errorChannel, &storage{root: root} |
||||||
|
} |
||||||
|
|
||||||
|
func start(ctrlChannel <-chan string, errorChannel chan<- error) { |
||||||
|
close(errorChannel) |
||||||
|
} |
||||||
|
|
||||||
|
// Bucket Operaotions
|
||||||
|
|
||||||
|
func (storage *storage) ListBuckets(prefix string) ([]mstorage.BucketMetadata, error) { |
||||||
|
return []mstorage.BucketMetadata{}, errors.New("Not Implemented") |
||||||
|
} |
||||||
|
|
||||||
|
func (storage *storage) StoreBucket(bucket string) error { |
||||||
|
storage.writeLock.Lock() |
||||||
|
defer storage.writeLock.Unlock() |
||||||
|
|
||||||
|
// verify bucket path legal
|
||||||
|
if mstorage.IsValidBucket(bucket) == false { |
||||||
|
return mstorage.BucketNameInvalid{Bucket: bucket} |
||||||
|
} |
||||||
|
|
||||||
|
// get bucket path
|
||||||
|
bucketDir := path.Join(storage.root, bucket) |
||||||
|
|
||||||
|
// check if bucket exists
|
||||||
|
if _, err := os.Stat(bucketDir); err == nil { |
||||||
|
return mstorage.BucketExists{ |
||||||
|
Bucket: bucket, |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// make bucket
|
||||||
|
err := os.Mkdir(bucketDir, 0700) |
||||||
|
if err != nil { |
||||||
|
return mstorage.EmbedError(bucket, "", err) |
||||||
|
} |
||||||
|
return nil |
||||||
|
} |
||||||
|
|
||||||
|
// Object Operations
|
||||||
|
|
||||||
|
func (storage *storage) CopyObjectToWriter(w io.Writer, bucket string, object string) (int64, error) { |
||||||
|
// validate bucket
|
||||||
|
if mstorage.IsValidBucket(bucket) == false { |
||||||
|
return 0, mstorage.BucketNameInvalid{Bucket: bucket} |
||||||
|
} |
||||||
|
|
||||||
|
// validate object
|
||||||
|
if mstorage.IsValidObject(object) == false { |
||||||
|
return 0, mstorage.ObjectNameInvalid{Bucket: bucket, Object: object} |
||||||
|
} |
||||||
|
|
||||||
|
objectPath := path.Join(storage.root, bucket, object) |
||||||
|
|
||||||
|
file, err := os.Open(objectPath) |
||||||
|
if err != nil { |
||||||
|
return 0, mstorage.EmbedError(bucket, object, err) |
||||||
|
} |
||||||
|
count, err := io.Copy(w, file) |
||||||
|
if err != nil { |
||||||
|
return count, mstorage.EmbedError(bucket, object, err) |
||||||
|
} |
||||||
|
return count, nil |
||||||
|
} |
||||||
|
|
||||||
|
func (storage *storage) GetObjectMetadata(bucket string, object string) (mstorage.ObjectMetadata, error) { |
||||||
|
if mstorage.IsValidBucket(bucket) == false { |
||||||
|
return mstorage.ObjectMetadata{}, mstorage.BucketNameInvalid{Bucket: bucket} |
||||||
|
} |
||||||
|
|
||||||
|
if mstorage.IsValidObject(bucket) == false { |
||||||
|
return mstorage.ObjectMetadata{}, mstorage.ObjectNameInvalid{Bucket: bucket, Object: bucket} |
||||||
|
} |
||||||
|
|
||||||
|
objectPath := path.Join(storage.root, bucket, object) |
||||||
|
|
||||||
|
stat, err := os.Stat(objectPath) |
||||||
|
if os.IsNotExist(err) { |
||||||
|
return mstorage.ObjectMetadata{}, mstorage.ObjectNotFound{Bucket: bucket, Object: object} |
||||||
|
} |
||||||
|
|
||||||
|
metadata := mstorage.ObjectMetadata{ |
||||||
|
Bucket: bucket, |
||||||
|
Key: object, |
||||||
|
Created: stat.ModTime(), |
||||||
|
Size: stat.Size(), |
||||||
|
ETag: bucket + "#" + object, |
||||||
|
} |
||||||
|
|
||||||
|
return metadata, nil |
||||||
|
} |
||||||
|
|
||||||
|
func (storage *storage) ListObjects(bucket, prefix string, count int) ([]mstorage.ObjectMetadata, bool, error) { |
||||||
|
if mstorage.IsValidBucket(bucket) == false { |
||||||
|
return []mstorage.ObjectMetadata{}, false, mstorage.BucketNameInvalid{Bucket: bucket} |
||||||
|
} |
||||||
|
if mstorage.IsValidObject(prefix) == false { |
||||||
|
return []mstorage.ObjectMetadata{}, false, mstorage.ObjectNameInvalid{Bucket: bucket, Object: prefix} |
||||||
|
} |
||||||
|
|
||||||
|
rootPrefix := path.Join(storage.root, bucket) |
||||||
|
|
||||||
|
files, err := ioutil.ReadDir(rootPrefix) |
||||||
|
if err != nil { |
||||||
|
return []mstorage.ObjectMetadata{}, false, mstorage.EmbedError("bucket", "", err) |
||||||
|
} |
||||||
|
|
||||||
|
var metadataList []mstorage.ObjectMetadata |
||||||
|
for _, file := range files { |
||||||
|
if len(metadataList) >= count { |
||||||
|
return metadataList, true, nil |
||||||
|
} |
||||||
|
if strings.HasPrefix(file.Name(), prefix) { |
||||||
|
metadata := mstorage.ObjectMetadata{ |
||||||
|
Bucket: bucket, |
||||||
|
Key: file.Name(), |
||||||
|
Created: file.ModTime(), |
||||||
|
Size: file.Size(), |
||||||
|
ETag: bucket + "#" + file.Name(), |
||||||
|
} |
||||||
|
metadataList = append(metadataList, metadata) |
||||||
|
} |
||||||
|
} |
||||||
|
return metadataList, false, nil |
||||||
|
} |
||||||
|
|
||||||
|
func (storage *storage) StoreObject(bucket string, key string, data io.Reader) error { |
||||||
|
// TODO Commits should stage then move instead of writing directly
|
||||||
|
storage.writeLock.Lock() |
||||||
|
defer storage.writeLock.Unlock() |
||||||
|
|
||||||
|
// check bucket name valid
|
||||||
|
if mstorage.IsValidBucket(bucket) == false { |
||||||
|
return mstorage.BucketNameInvalid{Bucket: bucket} |
||||||
|
} |
||||||
|
|
||||||
|
// check bucket exists
|
||||||
|
if _, err := os.Stat(path.Join(storage.root, bucket)); os.IsNotExist(err) { |
||||||
|
return mstorage.BucketNotFound{Bucket: bucket} |
||||||
|
} |
||||||
|
|
||||||
|
// verify object path legal
|
||||||
|
if mstorage.IsValidObject(key) == false { |
||||||
|
return mstorage.ObjectNameInvalid{Bucket: bucket, Object: key} |
||||||
|
} |
||||||
|
|
||||||
|
// get object path
|
||||||
|
objectPath := path.Join(storage.root, bucket, key) |
||||||
|
|
||||||
|
// check if object exists
|
||||||
|
if _, err := os.Stat(objectPath); !os.IsNotExist(err) { |
||||||
|
return mstorage.ObjectExists{ |
||||||
|
Bucket: bucket, |
||||||
|
Key: key, |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// write object
|
||||||
|
file, err := os.OpenFile(objectPath, os.O_WRONLY|os.O_CREATE, 0600) |
||||||
|
defer file.Close() |
||||||
|
if err != nil { |
||||||
|
return mstorage.EmbedError(bucket, key, err) |
||||||
|
} |
||||||
|
|
||||||
|
_, err = io.Copy(file, data) |
||||||
|
if err != nil { |
||||||
|
return mstorage.EmbedError(bucket, key, err) |
||||||
|
} |
||||||
|
|
||||||
|
return nil |
||||||
|
} |
@ -0,0 +1,42 @@ |
|||||||
|
package fs |
||||||
|
|
||||||
|
import ( |
||||||
|
"io/ioutil" |
||||||
|
"log" |
||||||
|
"os" |
||||||
|
"testing" |
||||||
|
|
||||||
|
mstorage "github.com/minio-io/minio/pkg/storage" |
||||||
|
|
||||||
|
. "gopkg.in/check.v1" |
||||||
|
) |
||||||
|
|
||||||
|
func Test(t *testing.T) { TestingT(t) } |
||||||
|
|
||||||
|
type MySuite struct{} |
||||||
|
|
||||||
|
var _ = Suite(&MySuite{}) |
||||||
|
|
||||||
|
func (s *MySuite) TestAPISuite(c *C) { |
||||||
|
var storageList []string |
||||||
|
create := func() mstorage.Storage { |
||||||
|
path, err := ioutil.TempDir(os.TempDir(), "minio-fs-") |
||||||
|
log.Println(path) |
||||||
|
c.Check(err, IsNil) |
||||||
|
storageList = append(storageList, path) |
||||||
|
_, _, store := Start(path) |
||||||
|
return store |
||||||
|
} |
||||||
|
log.Println("FOO") |
||||||
|
mstorage.APITestSuite(c, create) |
||||||
|
log.Println("BAR") |
||||||
|
removeRoots(c, storageList) |
||||||
|
} |
||||||
|
|
||||||
|
func removeRoots(c *C, roots []string) { |
||||||
|
log.Println("REMOVING ROOTS: ", roots) |
||||||
|
for _, root := range roots { |
||||||
|
err := os.RemoveAll(root) |
||||||
|
c.Check(err, IsNil) |
||||||
|
} |
||||||
|
} |
Loading…
Reference in new issue