put: check the SFTP close status after uploads
ssh2::File's Drop discards the close-handshake error ('too late to
recover'), so a quota or server-side abort surfacing in the final ACKs
was recorded as a successful upload of a truncated file. Close upload
handles explicitly and propagate the error; also applies to the ssh
context driver's write_file and upload_recursive, which had the same
silent-drop issue.
This commit is contained in:
@@ -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(())
|
||||
}
|
||||
|
||||
@@ -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(())
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user