lib/readers: return the cache length when RepeatableReader.Seek goes past it

Seek documents that a position past the cached data returns the maximum
usable offset with an error, but it returned offset - (abs - cacheLen),
which is only the cache length for io.SeekStart. For io.SeekCurrent and
io.SeekEnd it returned an arbitrary, possibly negative, number.
This commit is contained in:
kevin9327 authored and Nick Craig-Wood committed 2026-10-29 18:40:46 +00:00
1 parent 11b681a1f0
commit 337c130c12
2 files changed
+26 -1

No files matched your search

+1 -1
View File
@@ -41,7 +41,7 @@ func (r *RepeatableReader) Seek(offset int64, whence int) (int64, error) {
return 0, errors.New("fs.RepeatableReader.Seek: negative position")
}
if abs > cacheLen {
return offset - (abs - cacheLen), errors.New("fs.RepeatableReader.Seek: offset is unavailable")
return cacheLen, errors.New("fs.RepeatableReader.Seek: offset is unavailable")
}
r.i = abs
return abs, nil
+25
View File
@@ -98,3 +98,28 @@ func TestRepeatableReader(t *testing.T) {
assert.Equal(t, b[2:7], dst)
}
func TestRepeatableReaderSeekUnavailableReturnsCacheLength(t *testing.T) {
r := NewRepeatableReader(bytes.NewBufferString("0123456789abcdef"))
dst := make([]byte, 10)
n, err := r.Read(dst)
require.NoError(t, err)
require.Equal(t, 10, n)
// Past the cache from the current position
_, err = r.Seek(-2, io.SeekCurrent)
require.NoError(t, err)
pos, err := r.Seek(5, io.SeekCurrent)
assert.EqualError(t, err, "fs.RepeatableReader.Seek: offset is unavailable")
assert.Equal(t, int64(10), pos)
// Past the cache from the end
pos, err = r.Seek(5, io.SeekEnd)
assert.EqualError(t, err, "fs.RepeatableReader.Seek: offset is unavailable")
assert.Equal(t, int64(10), pos)
// The read position is unchanged by a failed seek
pos, err = r.Seek(0, io.SeekCurrent)
require.NoError(t, err)
assert.Equal(t, int64(8), pos)
}