From 0a24261afb5fb3fec8ba3384866197eea94b1dde Mon Sep 17 00:00:00 2001 From: Alexander Neumann Date: Sat, 23 Jan 2016 14:12:12 +0100 Subject: [PATCH] Add Load() for all existing backends --- backend/interface.go | 4 ++++ backend/local/local.go | 25 +++++++++++++++++++++++++ backend/mock_backend.go | 9 +++++++++ backend/s3/s3.go | 21 +++++++++++++++++++++ backend/sftp/sftp.go | 25 +++++++++++++++++++++++++ 5 files changed, 84 insertions(+) diff --git a/backend/interface.go b/backend/interface.go index eccd58fde..73c3e82b6 100644 --- a/backend/interface.go +++ b/backend/interface.go @@ -56,6 +56,10 @@ type Backend interface { Close() error Lister + + // Load returns the data stored in the backend for h at the given offset + // and saves it in p. Load has the same semantics as io.ReaderAt. + Load(h Handle, p []byte, off int64) (int, error) } // Lister implements listing data items stored in a backend. diff --git a/backend/local/local.go b/backend/local/local.go index 80c4eefbc..9946ddc4a 100644 --- a/backend/local/local.go +++ b/backend/local/local.go @@ -223,6 +223,31 @@ func (b *Local) GetReader(t backend.Type, name string, offset, length uint) (io. return backend.LimitReadCloser(f, int64(length)), nil } +// Load returns the data stored in the backend for h at the given offset +// and saves it in p. Load has the same semantics as io.ReaderAt. +func (b *Local) Load(h backend.Handle, p []byte, off int64) (n int, err error) { + f, err := os.Open(filename(b.p, h.Type, h.Name)) + if err != nil { + return 0, err + } + + defer func() { + e := f.Close() + if err == nil && e != nil { + err = e + } + }() + + if off > 0 { + _, err = f.Seek(off, 0) + if err != nil { + return 0, err + } + } + + return io.ReadFull(f, p) +} + // Test returns true if a blob of the given type and name exists in the backend. func (b *Local) Test(t backend.Type, name string) (bool, error) { _, err := os.Stat(filename(b.p, t, name)) diff --git a/backend/mock_backend.go b/backend/mock_backend.go index 0d24a3bbf..a5e21b8a4 100644 --- a/backend/mock_backend.go +++ b/backend/mock_backend.go @@ -10,6 +10,7 @@ import ( type MockBackend struct { CloseFn func() error CreateFn func() (Blob, error) + LoadFn func(h Handle, p []byte, off int64) (int, error) GetReaderFn func(Type, string, uint, uint) (io.ReadCloser, error) ListFn func(Type, <-chan struct{}) <-chan string RemoveFn func(Type, string) error @@ -42,6 +43,14 @@ func (m *MockBackend) Create() (Blob, error) { return m.CreateFn() } +func (m *MockBackend) Load(h Handle, p []byte, off int64) (int, error) { + if m.LoadFn == nil { + return 0, errors.New("not implemented") + } + + return m.Load(h, p, off) +} + func (m *MockBackend) GetReader(t Type, name string, offset, len uint) (io.ReadCloser, error) { if m.GetReaderFn == nil { return nil, errors.New("not implemented") diff --git a/backend/s3/s3.go b/backend/s3/s3.go index 619d41546..2d3f89606 100644 --- a/backend/s3/s3.go +++ b/backend/s3/s3.go @@ -170,6 +170,27 @@ func (be *S3Backend) GetReader(t backend.Type, name string, offset, length uint) return backend.LimitReadCloser(obj, int64(length)), nil } +// Load returns the data stored in the backend for h at the given offset +// and saves it in p. Load has the same semantics as io.ReaderAt. +func (be S3Backend) 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(h.Type, h.Name) + obj, err := be.client.GetObject(be.bucketname, path) + if err != nil { + debug.Log("s3.GetReader", " err %v", err) + return 0, err + } + + if off > 0 { + _, err = obj.Seek(off, 0) + if err != nil { + return 0, err + } + } + + return io.ReadFull(obj, p) +} + // Test returns true if a blob of the given type and name exists in the backend. func (be *S3Backend) Test(t backend.Type, name string) (bool, error) { found := false diff --git a/backend/sftp/sftp.go b/backend/sftp/sftp.go index 2fd57b83c..007e2088a 100644 --- a/backend/sftp/sftp.go +++ b/backend/sftp/sftp.go @@ -366,6 +366,31 @@ func (r *SFTP) GetReader(t backend.Type, name string, offset, length uint) (io.R return backend.LimitReadCloser(f, int64(length)), nil } +// Load returns the data stored in the backend for h at the given offset +// and saves it in p. Load has the same semantics as io.ReaderAt. +func (r *SFTP) Load(h backend.Handle, p []byte, off int64) (n int, err error) { + f, err := r.c.Open(r.filename(h.Type, h.Name)) + if err != nil { + return 0, err + } + + defer func() { + e := f.Close() + if err == nil && e != nil { + err = e + } + }() + + if off > 0 { + _, err = f.Seek(off, 0) + if err != nil { + return 0, err + } + } + + return io.ReadFull(f, p) +} + // Test returns true if a blob of the given type and name exists in the backend. func (r *SFTP) Test(t backend.Type, name string) (bool, error) { _, err := r.c.Lstat(r.filename(t, name))