diff --git a/backend/s3/config_test.go b/backend/s3/config_test.go index d1ecbdf60..29f0509b4 100644 --- a/backend/s3/config_test.go +++ b/backend/s3/config_test.go @@ -11,6 +11,11 @@ var configTests = []struct { Bucket: "bucketname", Prefix: "restic", }}, + {"s3://eu-central-1/bucketname/", Config{ + Endpoint: "eu-central-1", + Bucket: "bucketname", + Prefix: "", + }}, {"s3://eu-central-1/bucketname/prefix/directory", Config{ Endpoint: "eu-central-1", Bucket: "bucketname", @@ -21,6 +26,11 @@ var configTests = []struct { Bucket: "foobar", Prefix: "restic", }}, + {"s3:eu-central-1/foobar/", Config{ + Endpoint: "eu-central-1", + Bucket: "foobar", + Prefix: "", + }}, {"s3:eu-central-1/foobar/prefix/directory", Config{ Endpoint: "eu-central-1", Bucket: "foobar", @@ -31,6 +41,11 @@ var configTests = []struct { Bucket: "foobar", Prefix: "restic", }}, + {"s3:https://hostname:9999/foobar/", Config{ + Endpoint: "hostname:9999", + Bucket: "foobar", + Prefix: "", + }}, {"s3:http://hostname:9999/foobar", Config{ Endpoint: "hostname:9999", Bucket: "foobar", diff --git a/backend/s3/s3.go b/backend/s3/s3.go index 0bdf47894..a6657fd2b 100644 --- a/backend/s3/s3.go +++ b/backend/s3/s3.go @@ -14,13 +14,6 @@ import ( const connLimit = 10 -func s3path(prefix string, t backend.Type, name string) string { - if t == backend.Config { - return prefix + "/" + string(t) - } - return prefix + "/" + string(t) + "/" + name -} - // s3 is a backend which stores the data on an S3 endpoint. type s3 struct { client minio.CloudStorageClient @@ -56,6 +49,20 @@ func Open(cfg Config) (backend.Backend, error) { return be, nil } +func (be *s3) s3path(t backend.Type, name string) string { + var path string + + if be.prefix != "" { + path = be.prefix + "/" + } + path += string(t) + + if t == backend.Config { + return path + } + return path + "/" + name +} + func (be *s3) createConnections() { be.connChan = make(chan struct{}, connLimit) for i := 0; i < connLimit; i++ { @@ -72,7 +79,7 @@ func (be *s3) Location() string { // and saves it in p. Load has the same semantics as io.ReaderAt. func (be s3) Load(h backend.Handle, p []byte, off int64) (int, error) { debug.Log("s3.Load", "%v, offset %v, len %v", h, off, len(p)) - path := s3path(be.prefix, h.Type, h.Name) + path := be.s3path(h.Type, h.Name) obj, err := be.client.GetObject(be.bucketname, path) if err != nil { debug.Log("s3.GetReader", " err %v", err) @@ -101,7 +108,7 @@ func (be s3) Save(h backend.Handle, p []byte) (err error) { debug.Log("s3.Save", "%v bytes at %d", len(p), h) - path := s3path(be.prefix, h.Type, h.Name) + path := be.s3path(h.Type, h.Name) // Check key does not already exist _, err = be.client.StatObject(be.bucketname, path) @@ -126,7 +133,7 @@ func (be s3) Save(h backend.Handle, p []byte) (err error) { // Stat returns information about a blob. func (be s3) Stat(h backend.Handle) (backend.BlobInfo, error) { debug.Log("s3.Stat", "%v") - path := s3path(be.prefix, h.Type, h.Name) + path := be.s3path(h.Type, h.Name) obj, err := be.client.GetObject(be.bucketname, path) if err != nil { debug.Log("s3.Stat", "GetObject() err %v", err) @@ -145,7 +152,7 @@ func (be s3) Stat(h backend.Handle) (backend.BlobInfo, error) { // Test returns true if a blob of the given type and name exists in the backend. func (be *s3) Test(t backend.Type, name string) (bool, error) { found := false - path := s3path(be.prefix, t, name) + path := be.s3path(t, name) _, err := be.client.StatObject(be.bucketname, path) if err == nil { found = true @@ -157,7 +164,7 @@ func (be *s3) Test(t backend.Type, name string) (bool, error) { // Remove removes the blob with the given name and type. func (be *s3) Remove(t backend.Type, name string) error { - path := s3path(be.prefix, t, name) + path := be.s3path(t, name) err := be.client.RemoveObject(be.bucketname, path) debug.Log("s3.Remove", "%v %v -> err %v", t, name, err) return err @@ -170,7 +177,7 @@ func (be *s3) List(t backend.Type, done <-chan struct{}) <-chan string { debug.Log("s3.List", "listing %v", t) ch := make(chan string) - prefix := s3path(be.prefix, t, "") + prefix := be.s3path(t, "") listresp := be.client.ListObjects(be.bucketname, prefix, true, done)