From eaa3f81d6b1a5d5abf520e0afa9db9d050ea56c3 Mon Sep 17 00:00:00 2001 From: Michael Eischer Date: Sat, 11 May 2024 22:08:12 +0200 Subject: [PATCH] sftp: check for truncated files without an extra backend request --- internal/backend/sftp/sftp.go | 31 ++++++++++++++++++------------- 1 file changed, 18 insertions(+), 13 deletions(-) diff --git a/internal/backend/sftp/sftp.go b/internal/backend/sftp/sftp.go index dd95b3cf8..7bab25bed 100644 --- a/internal/backend/sftp/sftp.go +++ b/internal/backend/sftp/sftp.go @@ -425,7 +425,24 @@ func (r *SFTP) checkNoSpace(dir string, size int64, origErr error) error { // Load runs fn with a reader that yields the contents of the file at h at the // given offset. func (r *SFTP) Load(ctx context.Context, h backend.Handle, length int, offset int64, fn func(rd io.Reader) error) error { - return util.DefaultLoad(ctx, h, length, offset, r.openReader, fn) + return util.DefaultLoad(ctx, h, length, offset, r.openReader, func(rd io.Reader) error { + if length == 0 { + return fn(rd) + } + + // there is no direct way to efficiently check whether the file is too short + // rd is already a LimitedReader which can be used to track the number of bytes read + err := fn(rd) + + // check the underlying reader to be agnostic to however fn() handles the returned error + _, rderr := rd.Read([]byte{0}) + if rderr == io.EOF && rd.(*backend.LimitedReadCloser).N != 0 { + // file is too short + return fmt.Errorf("%w: %v", errTooShort, err) + } + + return err + }) } func (r *SFTP) openReader(_ context.Context, h backend.Handle, length int, offset int64) (io.ReadCloser, error) { @@ -434,18 +451,6 @@ func (r *SFTP) openReader(_ context.Context, h backend.Handle, length int, offse return nil, err } - fi, err := f.Stat() - if err != nil { - _ = f.Close() - return nil, err - } - - size := fi.Size() - if size < offset+int64(length) { - _ = f.Close() - return nil, errTooShort - } - if offset > 0 { _, err = f.Seek(offset, 0) if err != nil {