rustlibssh2

Libssh2 stop reading large file


I need to read some files via ssh, but when I loop on the file for reading... it stops.
In my Cargo.toml I have this dependency:

[dependencies]
ssh2 = "0.8"

It depends from libssh2.
Code is more complex, but I managed to reproduce the problem with this dirty code:

  use std::fs::File;
  use std::io::Read;
  use std::io::Write;
  #[allow(unused_imports)]
  use std::io::Error;
  use std::net::TcpStream;
  use ssh2::Session;
  use std::path::Path;
  use std::io::prelude::*;

  fn main() {
      println!("Parto!");

      let tcp = TcpStream::connect("myhost:22").unwrap();
      let mut sess = Session::new().unwrap();
      sess.set_tcp_stream(tcp);
      sess.handshake().unwrap();
      sess.userauth_password("user", "password").unwrap();
      assert!(sess.authenticated());

      let (mut remote_file, stat) = sess.scp_recv(Path::new("/home/pi/dbeaver.exe")).unwrap();
      println!("remote file size: {}", stat.size());
      let mut buf: Vec<u8> = vec![0;1000];

      loop {
          let read_bytes = remote_file.read(&mut buf).unwrap();
          println!("Read bytes: {}.", read_bytes);
          if read_bytes < 1000 {
              break;
          }
      } //ending loop
  }

I tested both on Windows 10 and Linux Debian. The problem is always there when the file is more then few KB this read:

let read_bytes = remote_file.read(&mut buf).unwrap();

reads less than buffer size (but the file is not ended).
Tested with both binary or asci files.

No errors, it just stop reading. Odd thing: it sometimes stop at 8 MB, sometimes at 16 KB. With the same file and host involved...

Where do I need to dig or what I need to check?


Solution

  • Quoting from the documentation for the io::Read trait (which ssh2 implements):

    It is not an error if the returned value n is smaller than the buffer size, even when the reader is not at the end of the stream yet. This may happen for example because fewer bytes are actually available right now (e. g. being close to end-of-file) or because read() was interrupted by a signal.

    Since you are reading remotely, this may simply mean that the remaining bytes are still in transit in the network and not yet available on the target computer.

    If you are sure that there are enough incoming data to fill the buffer, you can use read_exact, but note that this will return an error if the available data is shorter than the buffer.

    Edit: or even better, use read_to_end which doesn't require knowing the size beforehand (I don't know why I couldn't see it yesterday when I wrote the original answer).