diff --git a/src/context/ssh.rs b/src/context/ssh.rs index 8c3f6c6..2ea4b9a 100644 --- a/src/context/ssh.rs +++ b/src/context/ssh.rs @@ -288,6 +288,13 @@ impl ContextDriver for SshDriver { } let mut remote_file = sftp.create(path).map_err(io::Error::other)?; remote_file.write_all(content.as_bytes())?; + // Close explicitly: the `Drop` impl of `ssh2::File` discards a + // close-time error ("too late to recover"), silently truncating the + // remote file. Writes are unbuffered (`Write::flush` is a no-op), so + // no flush is needed before closing. + remote_file.close().map_err(|e| { + io::Error::other(format!("Failed to close remote file {:?}: {}", path, e)) + })?; Ok(()) } @@ -327,6 +334,18 @@ impl SshDriver { io::Error::other(format!("Failed to create remote file {:?}: {}", dest, e)) })?; io::copy(&mut file, &mut remote_file)?; + // Close explicitly: quota-exceeded and similar failures only + // surface in the final ACKs and the close handshake, and the + // `Drop` impl of `ssh2::File` discards that error ("too late to + // recover"), leaving a truncated remote file behind. Writes are + // unbuffered (`ssh2::File`'s `Write::flush` is a no-op), so no + // flush is needed before closing. + remote_file.close().map_err(|e| { + io::Error::other(format!( + "Failed to close remote file {:?} after upload: {}", + dest, e + )) + })?; } Ok(()) } diff --git a/src/put/ssh.rs b/src/put/ssh.rs index 7f97b66..3bac629 100644 --- a/src/put/ssh.rs +++ b/src/put/ssh.rs @@ -433,6 +433,16 @@ pub fn upload_file( bar.inc(n as u64); } + // Close explicitly: quota-exceeded and similar failures only surface in + // the final ACKs and the close handshake, and the `Drop` impl of + // `ssh2::File` discards that error ("too late to recover"), recording a + // truncated remote file as a successful upload. `ssh2::File::write` is + // unbuffered (`Write::flush` is a documented no-op) and `close` + // finalizes the pending writes server-side, so no flush is needed. + remote_file + .close() + .map_err(|e| format!("failed to close remote file '{remote}' after upload: {e}"))?; + Ok(()) }