From c755ba4a9540aacac77a5fce2817ec47d15ddc94 Mon Sep 17 00:00:00 2001 From: Felicitas Pojtinger Date: Sat, 18 Dec 2021 17:37:13 +0100 Subject: [PATCH] feat: Enable seeking form start without `close`ing files --- internal/fs/file.go | 41 ++++++++++++++++++++++++++------------- internal/ioext/counter.go | 18 +++++++++++++++++ 2 files changed, 46 insertions(+), 13 deletions(-) diff --git a/internal/fs/file.go b/internal/fs/file.go index 91b0a5b..1b4fade 100644 --- a/internal/fs/file.go +++ b/internal/fs/file.go @@ -9,6 +9,7 @@ import ( "sync" models "github.com/pojntfx/stfs/internal/db/sqlite/models/metadata" + "github.com/pojntfx/stfs/internal/ioext" "github.com/pojntfx/stfs/pkg/config" "github.com/pojntfx/stfs/pkg/inventory" "github.com/pojntfx/stfs/pkg/operations" @@ -28,8 +29,8 @@ type File struct { info os.FileInfo ioLock sync.Mutex - reader *io.PipeReader - writer *io.PipeWriter + reader *ioext.CounterReadCloser + writer io.WriteCloser onHeader func(hdr *models.Header) } @@ -119,11 +120,8 @@ func (f *File) WriteString(s string) (ret int, err error) { return -1, ErrNotImplemented } -func (f *File) Close() error { - log.Println("File.Close", f.name) - - f.ioLock.Lock() - defer f.ioLock.Unlock() +func (f *File) closeWithoutLocking() error { + log.Println("File.closeWithoutLocking", f.name) if f.reader != nil { if err := f.reader.Close(); err != nil { @@ -143,6 +141,15 @@ func (f *File) Close() error { return nil } +func (f *File) Close() error { + log.Println("File.Close", f.name) + + f.ioLock.Lock() + defer f.ioLock.Unlock() + + return f.closeWithoutLocking() +} + func (f *File) Read(p []byte) (n int, err error) { log.Println("File.Read", f.name, len(p)) @@ -150,7 +157,11 @@ func (f *File) Read(p []byte) (n int, err error) { defer f.ioLock.Unlock() if f.reader == nil || f.writer == nil { - reader, writer := io.Pipe() + r, writer := io.Pipe() + reader := &ioext.CounterReadCloser{ + Reader: r, + BytesRead: 0, + } go func() { if err := f.ops.Restore( @@ -201,13 +212,17 @@ func (f *File) Seek(offset int64, whence int) (int64, error) { return -1, ErrNotImplemented } - _ = f.Close() // Ignore errors here as it might not be opened - f.ioLock.Lock() defer f.ioLock.Unlock() - if f.reader == nil || f.writer == nil { - reader, writer := io.Pipe() + if f.reader == nil || f.writer == nil || offset < int64(f.reader.BytesRead) { // We have to re-open as we can't seek backwards + _ = f.closeWithoutLocking() // Ignore errors here as it might not be opened + + r, writer := io.Pipe() + reader := &ioext.CounterReadCloser{ + Reader: r, + BytesRead: 0, + } go func() { if err := f.ops.Restore( @@ -236,7 +251,7 @@ func (f *File) Seek(offset int64, whence int) (int64, error) { f.writer = writer } - written, err := io.CopyN(io.Discard, f.reader, offset) + written, err := io.CopyN(io.Discard, f.reader, offset-int64(f.reader.BytesRead)) if err != nil { return -1, err } diff --git a/internal/ioext/counter.go b/internal/ioext/counter.go index d00536f..1dea264 100644 --- a/internal/ioext/counter.go +++ b/internal/ioext/counter.go @@ -16,6 +16,24 @@ func (r *CounterReader) Read(p []byte) (n int, err error) { return n, err } +type CounterReadCloser struct { + Reader io.ReadCloser + + BytesRead int +} + +func (r *CounterReadCloser) Read(p []byte) (n int, err error) { + n, err = r.Reader.Read(p) + + r.BytesRead += n + + return n, err +} + +func (r *CounterReadCloser) Close() error { + return r.Reader.Close() +} + type CounterWriter struct { Writer io.Writer