forked from TrueCloudLab/restic
s3: add getRemainingSize
This commit is contained in:
parent
9452f416bf
commit
246ccf09b9
2 changed files with 99 additions and 6 deletions
|
@ -3,6 +3,7 @@ package s3
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
"os"
|
||||||
"path"
|
"path"
|
||||||
"restic"
|
"restic"
|
||||||
"strings"
|
"strings"
|
||||||
|
@ -84,6 +85,35 @@ type Sizer interface {
|
||||||
Size() int64
|
Size() int64
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type Lenner interface {
|
||||||
|
Len() int
|
||||||
|
}
|
||||||
|
|
||||||
|
// getRemainingSize returns number of bytes remaining. If it is not possible to
|
||||||
|
// determine the size, panic() is called.
|
||||||
|
func getRemainingSize(rd io.Reader) (size int64, err error) {
|
||||||
|
if r, ok := rd.(Lenner); ok {
|
||||||
|
size = int64(r.Len())
|
||||||
|
} else if r, ok := rd.(Sizer); ok {
|
||||||
|
size = r.Size()
|
||||||
|
} else if f, ok := rd.(*os.File); ok {
|
||||||
|
fi, err := f.Stat()
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
pos, err := f.Seek(0, io.SeekCurrent)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
size = fi.Size() - pos
|
||||||
|
} else {
|
||||||
|
panic(fmt.Sprintf("Save() got passed a reader without a method to determine the data size, type is %T", rd))
|
||||||
|
}
|
||||||
|
return size, nil
|
||||||
|
}
|
||||||
|
|
||||||
// Save stores data in the backend at the handle.
|
// Save stores data in the backend at the handle.
|
||||||
func (be *s3) Save(h restic.Handle, rd io.Reader) (err error) {
|
func (be *s3) Save(h restic.Handle, rd io.Reader) (err error) {
|
||||||
if err := h.Valid(); err != nil {
|
if err := h.Valid(); err != nil {
|
||||||
|
@ -91,12 +121,9 @@ func (be *s3) Save(h restic.Handle, rd io.Reader) (err error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
objName := be.Filename(h)
|
objName := be.Filename(h)
|
||||||
|
size, err := getRemainingSize(rd)
|
||||||
var size int64
|
if err != nil {
|
||||||
if r, ok := rd.(Sizer); ok {
|
return err
|
||||||
size = r.Size()
|
|
||||||
} else {
|
|
||||||
panic("Save() got passed a reader without a method to determine the data size")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
debug.Log("Save %v at %v", h, objName)
|
debug.Log("Save %v at %v", h, objName)
|
||||||
|
|
66
src/restic/backend/s3/s3_internal_test.go
Normal file
66
src/restic/backend/s3/s3_internal_test.go
Normal file
|
@ -0,0 +1,66 @@
|
||||||
|
package s3
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"io"
|
||||||
|
"io/ioutil"
|
||||||
|
"os"
|
||||||
|
"restic/test"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func writeFile(t testing.TB, data []byte, offset int64) *os.File {
|
||||||
|
tempfile, err := ioutil.TempFile("", "restic-test-")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = os.Remove(tempfile.Name()); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, err = tempfile.Write(data); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, err = tempfile.Seek(offset, io.SeekStart); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return tempfile
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGetRemainingSize(t *testing.T) {
|
||||||
|
length := 18 * 1123
|
||||||
|
partialRead := 1005
|
||||||
|
|
||||||
|
data := test.Random(23, length)
|
||||||
|
|
||||||
|
partReader := bytes.NewReader(data)
|
||||||
|
buf := make([]byte, partialRead)
|
||||||
|
_, _ = io.ReadFull(partReader, buf)
|
||||||
|
|
||||||
|
partFileReader := writeFile(t, data, int64(partialRead))
|
||||||
|
|
||||||
|
var tests = []struct {
|
||||||
|
io.Reader
|
||||||
|
size int64
|
||||||
|
}{
|
||||||
|
{bytes.NewReader([]byte("foobar test")), 11},
|
||||||
|
{partReader, int64(length - partialRead)},
|
||||||
|
{partFileReader, int64(length - partialRead)},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, test := range tests {
|
||||||
|
t.Run("", func(t *testing.T) {
|
||||||
|
size, err := getRemainingSize(test.Reader)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if size != test.size {
|
||||||
|
t.Fatalf("invalid size returned, want %v, got %v", test.size, size)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue