summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorWez Furlong <wez@wezfurlong.org>2019-07-29 14:03:34 -0700
committerWez Furlong <wez@wezfurlong.org>2019-07-31 14:21:50 -0700
commit3aa8096bc4e1c6c762f8553c516b5ce099ba5f71 (patch)
tree87daf4fefb6814697e8ac7309e5892456cfc7e6b
parentff790796728ed74ff29cded408622117ebf0e64f (diff)
downloadssh2-rs-3aa8096bc4e1c6c762f8553c516b5ce099ba5f71.zip
Fix scp_recv ABI issue on Windows
* Adopt scp_recv2 instead, which uses compatible 64-bit stat types * Mark scp_recv as deprecated * small version bump Fixes https://github.com/alexcrichton/ssh2-rs/issues/109 Refs https://github.com/alexcrichton/ssh2-rs/pull/117 Co-authored-by: Joyce Babu <joyce@ennexa.com>
-rw-r--r--Cargo.toml2
-rw-r--r--libssh2-sys/Cargo.toml2
-rw-r--r--libssh2-sys/lib.rs26
-rw-r--r--src/session.rs6
-rw-r--r--systest/build.rs11
5 files changed, 41 insertions, 6 deletions
diff --git a/Cargo.toml b/Cargo.toml
index 5f93fcc..731ebb1 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -19,7 +19,7 @@ vendored-openssl = ["libssh2-sys/vendored-openssl"]
[dependencies]
bitflags = "1.0.4"
libc = "0.2"
-libssh2-sys = { path = "libssh2-sys", version = "0.2.4" }
+libssh2-sys = { path = "libssh2-sys", version = "0.2.12" }
[dev-dependencies]
tempdir = "0.3"
diff --git a/libssh2-sys/Cargo.toml b/libssh2-sys/Cargo.toml
index 4dc882a..06a7caa 100644
--- a/libssh2-sys/Cargo.toml
+++ b/libssh2-sys/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "libssh2-sys"
-version = "0.2.11"
+version = "0.2.12"
authors = ["Alex Crichton <alex@alexcrichton.com>"]
links = "ssh2"
build = "build.rs"
diff --git a/libssh2-sys/lib.rs b/libssh2-sys/lib.rs
index e57864f..5ce1dc2 100644
--- a/libssh2-sys/lib.rs
+++ b/libssh2-sys/lib.rs
@@ -192,6 +192,24 @@ pub enum LIBSSH2_SFTP_HANDLE {}
pub type libssh2_int64_t = i64;
pub type libssh2_uint64_t = u64;
+// libssh2_struct_stat is a typedef for libc::stat on all platforms, however,
+// Windows has a bunch of legacy around struct stat that makes things more
+// complicated to validate with systest.
+// The most reasonable looking solution to this is a newtype that derefs
+// to libc::stat.
+// We cannot use `pub struct libssh2_struct_stat(pub libc::stat)` because
+// that triggers a `no tuple structs in FFI` error.
+#[repr(C)]
+pub struct libssh2_struct_stat(libc::stat);
+
+impl std::ops::Deref for libssh2_struct_stat {
+ type Target = libc::stat;
+
+ fn deref(&self) -> &Self::Target {
+ &self.0
+ }
+}
+
#[repr(C)]
pub struct libssh2_agent_publickey {
pub magic: c_uint,
@@ -548,11 +566,19 @@ extern "C" {
pub fn libssh2_knownhost_init(sess: *mut LIBSSH2_SESSION) -> *mut LIBSSH2_KNOWNHOSTS;
// scp
+ #[deprecated(note = "dangerously unsafe on windows, use libssh2_scp_recv2 instead")]
pub fn libssh2_scp_recv(
sess: *mut LIBSSH2_SESSION,
path: *const c_char,
sb: *mut libc::stat,
) -> *mut LIBSSH2_CHANNEL;
+
+ pub fn libssh2_scp_recv2(
+ sess: *mut LIBSSH2_SESSION,
+ path: *const c_char,
+ sb: *mut libssh2_struct_stat,
+ ) -> *mut LIBSSH2_CHANNEL;
+
pub fn libssh2_scp_send64(
sess: *mut LIBSSH2_SESSION,
path: *const c_char,
diff --git a/src/session.rs b/src/session.rs
index 3ae3473..bce81ad 100644
--- a/src/session.rs
+++ b/src/session.rs
@@ -533,8 +533,8 @@ impl Session {
pub fn scp_recv(&self, path: &Path) -> Result<(Channel, ScpFileStat), Error> {
let path = try!(CString::new(try!(util::path2bytes(path))));
unsafe {
- let mut sb: libc::stat = mem::zeroed();
- let ret = raw::libssh2_scp_recv(self.inner.raw, path.as_ptr(), &mut sb);
+ let mut sb: raw::libssh2_struct_stat = mem::zeroed();
+ let ret = raw::libssh2_scp_recv2(self.inner.raw, path.as_ptr(), &mut sb);
let mut c = Channel::from_raw_opt(ret, &self.inner)?;
// Hm, apparently when we scp_recv() a file the actual channel
@@ -543,7 +543,7 @@ impl Session {
// artificially limit the channel to a certain amount of bytes that
// can be read.
c.limit_read(sb.st_size as u64);
- Ok((c, ScpFileStat { stat: sb }))
+ Ok((c, ScpFileStat { stat: *sb }))
}
}
diff --git a/systest/build.rs b/systest/build.rs
index 6131643..7d5c281 100644
--- a/systest/build.rs
+++ b/systest/build.rs
@@ -9,9 +9,18 @@ fn main() {
.header("libssh2_sftp.h")
.include(env::var("DEP_SSH2_INCLUDE").unwrap())
.type_name(|s, is_struct| {
- if (is_struct || s == "stat") && !s.starts_with("LIB") {
+ if s == "stat" {
+ // Ensure that we emit `struct stat` rather than just a `stat` typedef.
+ format!("struct stat")
+ } else if s == "libssh2_struct_stat" {
+ // libssh2_struct_stat is a typedef so ensure that we don't emit
+ // `struct libssh2_struct_stat` in the C code we generate
+ s.to_string()
+ } else if is_struct && !s.starts_with("LIB") {
+ // Otherwise we prefer to emit `struct foo` unless the type is `LIB_XXX`
format!("struct {}", s)
} else {
+ // All other cases: just emit the type name
s.to_string()
}
})