mirror of
https://github.com/kopia/kopia.git
synced 2026-05-19 04:04:56 -04:00
object: fixed Seek() behavior for seeking to end of object
This commit is contained in:
@@ -8,6 +8,7 @@
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"math/rand"
|
||||
"runtime/debug"
|
||||
@@ -349,3 +350,54 @@ func verify(ctx context.Context, t *testing.T, om *Manager, objectID ID, expecte
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// nolint:gocyclo
|
||||
func TestSeek(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
_, om := setupTest(t)
|
||||
|
||||
for _, size := range []int{0, 1, 500000, 15000000} {
|
||||
randomData := make([]byte, size)
|
||||
cryptorand.Read(randomData) //nolint:errcheck
|
||||
|
||||
writer := om.NewWriter(ctx, WriterOptions{})
|
||||
if _, err := writer.Write(randomData); err != nil {
|
||||
t.Errorf("write error: %v", err)
|
||||
}
|
||||
|
||||
objectID, err := writer.Result()
|
||||
if err != nil {
|
||||
t.Fatalf("unable to write: %v", err)
|
||||
}
|
||||
|
||||
r, err := om.Open(ctx, objectID)
|
||||
if err != nil {
|
||||
t.Fatalf("open error: %v", err)
|
||||
}
|
||||
|
||||
if pos, err := r.Seek(0, io.SeekStart); err != nil || pos != 0 {
|
||||
t.Errorf("invalid seek-start result %v %v", pos, err)
|
||||
}
|
||||
|
||||
if pos, err := r.Seek(0, io.SeekCurrent); err != nil || pos != 0 {
|
||||
t.Errorf("invalid seek-current at start result %v %v", pos, err)
|
||||
}
|
||||
|
||||
if pos, err := r.Seek(0, io.SeekEnd); err != nil || pos != int64(size) {
|
||||
t.Errorf("invalid seek-end result %v %v", pos, err)
|
||||
}
|
||||
|
||||
if pos, err := r.Seek(0, io.SeekCurrent); err != nil || pos != int64(size) {
|
||||
t.Errorf("invalid seek-current at end result %v %v, wanted %v", pos, err, size)
|
||||
}
|
||||
|
||||
if pos, err := r.Seek(1, io.SeekCurrent); err != nil || pos != int64(size)+1 {
|
||||
t.Errorf("unexpected result when seeking past end of file: %v, %v, wanted %v", pos, err, size+1)
|
||||
}
|
||||
|
||||
buf := make([]byte, 5)
|
||||
if n, err := r.Read(buf); n != 0 || err != io.EOF {
|
||||
t.Errorf("unexpected read result %v %v", n, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,6 +29,10 @@ func (r *objectReader) Read(buffer []byte) (int, error) {
|
||||
readBytes := 0
|
||||
remaining := len(buffer)
|
||||
|
||||
if r.currentPosition >= r.totalLength {
|
||||
return 0, io.EOF
|
||||
}
|
||||
|
||||
for remaining > 0 {
|
||||
if r.currentChunkData != nil {
|
||||
toCopy := len(r.currentChunkData) - r.currentChunkPosition
|
||||
@@ -114,20 +118,19 @@ func (r *objectReader) findChunkIndexForOffset(offset int64) (int, error) {
|
||||
}
|
||||
|
||||
func (r *objectReader) Seek(offset int64, whence int) (int64, error) {
|
||||
if whence == 1 {
|
||||
if whence == io.SeekCurrent {
|
||||
return r.Seek(r.currentPosition+offset, 0)
|
||||
}
|
||||
|
||||
if whence == 2 {
|
||||
if whence == io.SeekEnd {
|
||||
return r.Seek(r.totalLength+offset, 0)
|
||||
}
|
||||
|
||||
if offset < 0 {
|
||||
return -1, errors.Errorf("invalid seek %v %v", offset, whence)
|
||||
}
|
||||
|
||||
if offset > r.totalLength {
|
||||
offset = r.totalLength
|
||||
if offset >= r.totalLength {
|
||||
r.currentChunkIndex = len(r.seekTable)
|
||||
r.currentChunkData = nil
|
||||
r.currentPosition = offset
|
||||
return offset, nil
|
||||
}
|
||||
|
||||
index, err := r.findChunkIndexForOffset(offset)
|
||||
@@ -136,7 +139,6 @@ func (r *objectReader) Seek(offset int64, whence int) (int64, error) {
|
||||
}
|
||||
|
||||
chunkStartOffset := r.seekTable[index].Start
|
||||
|
||||
if index != r.currentChunkIndex {
|
||||
r.closeCurrentChunk()
|
||||
r.currentChunkIndex = index
|
||||
|
||||
Reference in New Issue
Block a user