diff --git a/backend/interface.go b/backend/interface.go index 3836daa7b..b671609c7 100644 --- a/backend/interface.go +++ b/backend/interface.go @@ -38,9 +38,7 @@ type Getter interface { } type Creater interface { - Create(Type, []byte) (ID, error) - CreateFrom(Type, io.Reader) (ID, error) - CreateBlob(Type) (Blob, error) + Create(Type) (Blob, error) } type Tester interface { diff --git a/backend/local.go b/backend/local.go index 338149de6..5509e034c 100644 --- a/backend/local.go +++ b/backend/local.go @@ -10,8 +10,6 @@ import ( "path/filepath" "strconv" "strings" - - "github.com/juju/arrar" ) const ( @@ -183,96 +181,6 @@ func (b *Local) dirname(t Type, id ID) string { return filepath.Join(b.p, n) } -// Create stores new content of type t and data and returns the ID. If the blob -// is already present, returns ErrAlreadyPresent and the blob's ID. -func (b *Local) Create(t Type, data []byte) (ID, error) { - // TODO: make sure that tempfile is removed upon error - - // check if blob is already present in backend - id := IDFromData(data) - res, err := b.Test(t, id) - if err != nil { - return nil, arrar.Annotate(err, "test for presence") - } - - if res { - return id, ErrAlreadyPresent - } - - // create tempfile in backend - file, err := b.tempFile() - if err != nil { - return nil, err - } - - // write data to tempfile - _, err = file.Write(data) - if err != nil { - return nil, err - } - - err = file.Close() - if err != nil { - return nil, err - } - - // return id - err = b.renameFile(file, t, id) - if err != nil { - return nil, err - } - - return id, nil -} - -// CreateFrom reads content from rd and stores it as type t. Returned is the -// storage ID. If the blob is already present, returns ErrAlreadyPresent and -// the blob's ID. -func (b *Local) CreateFrom(t Type, rd io.Reader) (ID, error) { - // TODO: make sure that tempfile is removed upon error - - // check hash while writing - hr := NewHashingReader(rd, newHash()) - - // create tempfile in backend - file, err := b.tempFile() - if err != nil { - return nil, err - } - - // write data to tempfile - _, err = io.Copy(file, hr) - if err != nil { - return nil, err - } - - err = file.Close() - if err != nil { - return nil, err - } - - // get ID - id := ID(hr.Sum(nil)) - - // check for duplicate ID - res, err := b.Test(t, id) - if err != nil { - return nil, arrar.Annotate(err, "test for presence") - } - - if res { - return id, ErrAlreadyPresent - } - - // rename file - err = b.renameFile(file, t, id) - if err != nil { - return nil, err - } - - return id, nil -} - type localBlob struct { f *os.File h hash.Hash @@ -325,7 +233,7 @@ func (lb *localBlob) ID() (ID, error) { // Create creates a new blob of type t. Blob implements io.WriteCloser. Once // Close() has been called, ID() can be used to retrieve the ID. If the blob is // already present, Close() returns ErrAlreadyPresent. -func (b *Local) CreateBlob(t Type) (Blob, error) { +func (b *Local) Create(t Type) (Blob, error) { // TODO: make sure that tempfile is removed upon error // create tempfile in backend diff --git a/backend/local_test.go b/backend/local_test.go index 1179f1462..397bd1fee 100644 --- a/backend/local_test.go +++ b/backend/local_test.go @@ -4,6 +4,7 @@ import ( "bytes" "flag" "fmt" + "io" "io/ioutil" "sort" "testing" @@ -69,7 +70,7 @@ func testBackend(b backend.Backend, t *testing.T) { // add files for _, test := range TestStrings { // store string in backend - blob, err := b.CreateBlob(tpe) + blob, err := b.Create(tpe) ok(t, err) _, err = blob.Write([]byte(test.data)) @@ -97,24 +98,43 @@ func testBackend(b backend.Backend, t *testing.T) { equals(t, test.data, string(buf)) } - // test stream functions with first file + // test adding the first file again test := TestStrings[0] id, err := backend.ParseID(test.id) ok(t, err) - // create with reader, should return error - _, err = b.CreateFrom(tpe, bytes.NewReader([]byte(test.data))) + // create blob + blob, err := b.Create(tpe) + ok(t, err) + + _, err = io.Copy(blob, bytes.NewReader([]byte(test.data))) + ok(t, err) + err = blob.Close() assert(t, err == backend.ErrAlreadyPresent, - "expected ErrAlreadyPresent, got %v", err) + "wrong error returned: expected %v, got %v", + backend.ErrAlreadyPresent, err) + + id2, err := blob.ID() + ok(t, err) + + assert(t, id.Equal(id2), "IDs do not match: expected %v, got %v", id, id2) // remove and recreate err = b.Remove(tpe, id) ok(t, err) - id2, err := b.CreateFrom(tpe, bytes.NewReader([]byte(test.data))) + // create blob + blob, err = b.Create(tpe) ok(t, err) - assert(t, id.Equal(id2), - "expected id %v, got %v", id, id2) + + _, err = io.Copy(blob, bytes.NewReader([]byte(test.data))) + ok(t, err) + err = blob.Close() + ok(t, err) + + id2, err = blob.ID() + ok(t, err) + assert(t, id.Equal(id2), "IDs do not match: expected %v, got %v", id, id2) // list items IDs := backend.IDs{} diff --git a/backend/sftp.go b/backend/sftp.go index 2c73ae393..c98eff480 100644 --- a/backend/sftp.go +++ b/backend/sftp.go @@ -15,7 +15,6 @@ import ( "strconv" "strings" - "github.com/juju/arrar" "github.com/pkg/sftp" ) @@ -291,96 +290,6 @@ func (r *SFTP) dirname(t Type, id ID) string { return filepath.Join(r.p, n) } -// Create stores new content of type t and data and returns the ID. If the blob -// is already present, returns ErrAlreadyPresent and the blob's ID. -func (r *SFTP) Create(t Type, data []byte) (ID, error) { - // TODO: make sure that tempfile is removed upon error - - // check if blob is already present in backend - id := IDFromData(data) - res, err := r.Test(t, id) - if err != nil { - return nil, arrar.Annotate(err, "test for presence") - } - - if res { - return id, ErrAlreadyPresent - } - - // create tempfile in backend - filename, file, err := r.tempFile() - if err != nil { - return nil, arrar.Annotate(err, "create tempfile") - } - - // write data to tempfile - _, err = file.Write(data) - if err != nil { - return nil, arrar.Annotate(err, "writing data to tempfile") - } - - err = file.Close() - if err != nil { - return nil, arrar.Annotate(err, "close tempfile") - } - - // return id - err = r.renameFile(filename, t, id) - if err != nil { - return nil, arrar.Annotate(err, "rename file") - } - - return id, nil -} - -// CreateFrom reads content from rd and stores it as type t. Returned is the -// storage ID. If the blob is already present, returns ErrAlreadyPresent and -// the blob's ID. -func (r *SFTP) CreateFrom(t Type, rd io.Reader) (ID, error) { - // TODO: make sure that tempfile is removed upon error - - // check hash while writing - hr := NewHashingReader(rd, newHash()) - - // create tempfile in backend - filename, file, err := r.tempFile() - if err != nil { - return nil, err - } - - // write data to tempfile - _, err = io.Copy(file, hr) - if err != nil { - return nil, err - } - - err = file.Close() - if err != nil { - return nil, err - } - - // get ID - id := ID(hr.Sum(nil)) - - // check for duplicate ID - res, err := r.Test(t, id) - if err != nil { - return nil, arrar.Annotate(err, "test for presence") - } - - if res { - return id, ErrAlreadyPresent - } - - // rename file - err = r.renameFile(filename, t, id) - if err != nil { - return nil, err - } - - return id, nil -} - type sftpBlob struct { f *sftp.File name string @@ -434,7 +343,7 @@ func (sb *sftpBlob) ID() (ID, error) { // Create creates a new blob of type t. Blob implements io.WriteCloser. Once // Close() has been called, ID() can be used to retrieve the ID. If the blob is // already present, Close() returns ErrAlreadyPresent. -func (r *SFTP) CreateBlob(t Type) (Blob, error) { +func (r *SFTP) Create(t Type) (Blob, error) { // TODO: make sure that tempfile is removed upon error // create tempfile in backend diff --git a/key.go b/key.go index fcc5fba17..e306ec1bc 100644 --- a/key.go +++ b/key.go @@ -209,10 +209,26 @@ func AddKey(s Server, password string, template *Key) (*Key, error) { } // store in repository and return - id, err := s.Create(backend.Key, buf) + blob, err := s.Create(backend.Key) if err != nil { return nil, err } + + _, err = blob.Write(buf) + if err != nil { + return nil, err + } + + err = blob.Close() + if err != nil { + return nil, err + } + + id, err := blob.ID() + if err != nil { + return nil, err + } + newkey.id = id FreeChunkBuf("key", newkey.Data) diff --git a/server.go b/server.go index e09e9ff5c..7c0093caf 100644 --- a/server.go +++ b/server.go @@ -169,7 +169,22 @@ func (s Server) Save(t backend.Type, data []byte, id backend.ID) (Blob, error) { ciphertext = ciphertext[:n] // save blob - sid, err := s.Create(t, ciphertext) + backendBlob, err := s.Create(t) + if err != nil { + return Blob{}, err + } + + _, err = backendBlob.Write(ciphertext) + if err != nil { + return Blob{}, err + } + + err = backendBlob.Close() + if err != nil { + return Blob{}, err + } + + sid, err := backendBlob.ID() if err != nil { return Blob{}, err } @@ -225,8 +240,22 @@ func (s Server) SaveFrom(t backend.Type, id backend.ID, length uint, rd io.Reade ciphertext = ciphertext[:n] - // save blob - sid, err := s.Create(t, ciphertext) + backendBlob, err := s.Create(t) + if err != nil { + return Blob{}, err + } + + _, err = backendBlob.Write(ciphertext) + if err != nil { + return Blob{}, err + } + + err = backendBlob.Close() + if err != nil { + return Blob{}, err + } + + sid, err := backendBlob.ID() if err != nil { return Blob{}, err } @@ -322,16 +351,8 @@ func (s Server) GetReader(t backend.Type, id backend.ID) (io.ReadCloser, error) return s.be.GetReader(t, id) } -func (s Server) Create(t backend.Type, data []byte) (backend.ID, error) { - return s.be.Create(t, data) -} - -func (s Server) CreateFrom(t backend.Type, r io.Reader) (backend.ID, error) { - return s.be.CreateFrom(t, r) -} - -func (s Server) CreateBlob(t backend.Type) (backend.Blob, error) { - return s.be.CreateBlob(t) +func (s Server) Create(t backend.Type) (backend.Blob, error) { + return s.be.Create(t) } func (s Server) Test(t backend.Type, id backend.ID) (bool, error) {