Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix scp_recv ABI issue on Windows #121

Merged
merged 1 commit into from
Jul 31, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
2 changes: 1 addition & 1 deletion libssh2-sys/Cargo.toml
Original file line number Diff line number Diff line change
@@ -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"
Expand Down
26 changes: 26 additions & 0 deletions libssh2-sys/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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,
Expand Down
6 changes: 3 additions & 3 deletions src/session.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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 }))
}
}

Expand Down
11 changes: 10 additions & 1 deletion systest/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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()
}
})
Expand Down