Guard against accidental io.EOFs
diff --git a/client.go b/client.go
index afa1978..c0100fa 100644
--- a/client.go
+++ b/client.go
@@ -944,7 +944,7 @@
// readChunkAt attempts to read the whole entire length of the buffer from the file starting at the offset.
// It will continue progressively reading into the buffer until it fills the whole buffer, or an error occurs.
func (f *File) readChunkAt(ch chan result, b []byte, off int64) (n int, err error) {
- for err == nil && n < len(b) {
+ for n < len(b) {
id := f.c.nextID()
typ, data, err := f.c.sendPacket(ch, &sshFxpReadPacket{
ID: id,
@@ -953,6 +953,12 @@
Len: uint32(len(b) - n),
})
if err != nil {
+ if errors.Is(err, io.EOF) {
+ // sendPacket should never return io.EOF.
+ // Proper client EOFs are always from SSH_FX_EOF packets handled below.
+ return n, ErrSSHFxConnectionLost
+ }
+
return n, err
}
@@ -974,7 +980,7 @@
}
}
- return
+ return len(b), nil
}
func (f *File) readAtSequential(b []byte, off int64) (read int, err error) {
@@ -1782,7 +1788,13 @@
default:
return err
}
+
default:
+ // io.EOF should only ever come from an SSH_FX_EOF packet as handled above.
+ if errors.Is(err, io.EOF) {
+ return ErrSSHFxConnectionLost
+ }
+
return err
}
}
diff --git a/conn.go b/conn.go
index dcca260..0c2c779 100644
--- a/conn.go
+++ b/conn.go
@@ -142,6 +142,13 @@
c.dispatchRequest(ch, p)
s := <-ch
+
+ if errors.Is(s.err, io.EOF) {
+ // This function should never return io.EOF.
+ // Proper client EOFs are always from SSH_FX_EOF packets.
+ return s.typ, s.data, ErrSSHFxConnectionLost
+ }
+
return s.typ, s.data, s.err
}