summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorAlex Crichton <alex@alexcrichton.com>2015-02-23 18:18:06 -0800
committerAlex Crichton <alex@alexcrichton.com>2015-02-23 18:18:06 -0800
commita062f8704731821b591887f27e7ce9fb7515b29f (patch)
tree21219352b1dee6f425780b0a476d961c30127a7b /src
parentc4c46c2d68dd207371c0565e2de2439bac583edc (diff)
downloadssh2-rs-a062f8704731821b591887f27e7ce9fb7515b29f.zip
Update to std::io
Diffstat (limited to 'src')
-rw-r--r--src/channel.rs52
-rw-r--r--src/knownhosts.rs13
-rw-r--r--src/lib.rs36
-rw-r--r--src/session.rs140
-rw-r--r--src/sftp.rs157
-rw-r--r--src/util.rs28
6 files changed, 237 insertions, 189 deletions
diff --git a/src/channel.rs b/src/channel.rs
index e415af7..a27afa1 100644
--- a/src/channel.rs
+++ b/src/channel.rs
@@ -1,5 +1,6 @@
+use std::io::prelude::*;
+use std::io::{self, ErrorKind};
use std::cmp;
-use std::old_io;
use libc::{c_uint, c_int, size_t, c_char, c_void, c_uchar};
use {raw, Session, Error};
@@ -119,11 +120,14 @@ impl<'sess> Channel<'sess> {
/// # Example
///
/// ```no_run
+ /// # use std::io::prelude::*;
/// # use ssh2::Session;
/// # let session: Session = panic!();
/// let mut channel = session.channel_session().unwrap();
/// channel.exec("ls").unwrap();
- /// println!("{}", channel.read_to_string().unwrap());
+ /// let mut s = String::new();
+ /// channel.read_to_string(&mut s).unwrap();
+ /// println!("{}", s);
/// ```
pub fn exec(&mut self, command: &str) -> Result<(), Error> {
self.process_startup("exec", Some(command))
@@ -181,7 +185,7 @@ impl<'sess> Channel<'sess> {
}
/// Write data to the channel stderr stream.
- pub fn write_stderr(&mut self, data: &[u8]) -> Result<(), Error> {
+ pub fn write_stderr(&mut self, data: &[u8]) -> Result<usize, Error> {
self.write_stream(::EXTENDED_DATA_STDERR, data)
}
@@ -192,13 +196,13 @@ impl<'sess> Channel<'sess> {
/// selected stream_id. The SSH2 protocol currently defines a stream ID of 1
/// to be the stderr substream.
pub fn write_stream(&mut self, stream_id: i32, data: &[u8])
- -> Result<(), Error> {
+ -> Result<usize, Error> {
unsafe {
let rc = raw::libssh2_channel_write_ex(self.raw,
stream_id as c_int,
data.as_ptr() as *mut _,
data.len() as size_t);
- self.sess.rc(rc)
+ self.sess.rc(rc).map(|()| rc as usize)
}
}
@@ -215,7 +219,7 @@ impl<'sess> Channel<'sess> {
/// to be the stderr substream.
pub fn read_stream(&mut self, stream_id: i32, data: &mut [u8])
-> Result<usize, Error> {
- if self.eof() { return Err(Error::eof()) }
+ if self.eof() { return Ok(0) }
let data = match self.read_limit {
Some(amt) => {
@@ -230,7 +234,6 @@ impl<'sess> Channel<'sess> {
data.as_mut_ptr() as *mut _,
data.len() as size_t);
if rc < 0 { try!(self.sess.rc(rc)); }
- if rc == 0 && self.eof() { return Err(Error::eof()) }
match self.read_limit {
Some(ref mut amt) => *amt -= rc as u64,
None => {}
@@ -397,40 +400,27 @@ impl<'sess> SessionBinding<'sess> for Channel<'sess> {
fn raw(&self) -> *mut raw::LIBSSH2_CHANNEL { self.raw }
}
-impl<'sess> Writer for Channel<'sess> {
- fn write_all(&mut self, buf: &[u8]) -> old_io::IoResult<()> {
+impl<'sess> Write for Channel<'sess> {
+ fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
self.write_stream(0, buf).map_err(|e| {
- old_io::IoError {
- kind: old_io::OtherIoError,
- desc: "ssh write error",
- detail: Some(e.to_string()),
- }
+ io::Error::new(ErrorKind::Other, "ssh write error",
+ Some(e.to_string()))
})
}
- fn flush(&mut self) -> old_io::IoResult<()> {
+ fn flush(&mut self) -> io::Result<()> {
self.flush_stream(0).map_err(|e| {
- old_io::IoError {
- kind: old_io::OtherIoError,
- desc: "ssh write error",
- detail: Some(e.to_string()),
- }
+ io::Error::new(ErrorKind::Other, "ssh write error",
+ Some(e.to_string()))
})
}
}
-impl<'sess> Reader for Channel<'sess> {
- fn read(&mut self, buf: &mut [u8]) -> old_io::IoResult<usize> {
+impl<'sess> Read for Channel<'sess> {
+ fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
self.read_stream(0, buf).map_err(|e| {
- if self.eof() {
- old_io::standard_error(old_io::EndOfFile)
- } else {
- old_io::IoError {
- kind: old_io::OtherIoError,
- desc: "ssh read error",
- detail: Some(e.to_string()),
- }
- }
+ io::Error::new(ErrorKind::Other, "ssh read error",
+ Some(e.to_string()))
})
}
}
diff --git a/src/knownhosts.rs b/src/knownhosts.rs
index 171c758..20d18a1 100644
--- a/src/knownhosts.rs
+++ b/src/knownhosts.rs
@@ -1,10 +1,11 @@
use std::ffi::CString;
use std::marker;
+use std::path::Path;
use std::str;
use libc::{c_int, size_t};
use {raw, Session, Error, KnownHostFileKind, CheckResult};
-use util::{Binding, SessionBinding};
+use util::{self, Binding, SessionBinding};
/// A set of known hosts which can be used to verify the identity of a remote
/// server.
@@ -12,8 +13,8 @@ use util::{Binding, SessionBinding};
/// # Example
///
/// ```no_run
-/// # #![allow(unstable)]
-/// use std::os;
+/// use std::env;
+/// use std::path::Path;
/// use ssh2::{self, CheckResult, HostKeyType, KnownHostKeyFormat};
/// use ssh2::KnownHostFileKind;
///
@@ -21,7 +22,7 @@ use util::{Binding, SessionBinding};
/// let mut known_hosts = session.known_hosts().unwrap();
///
/// // Initialize the known hosts with a global known hosts file
-/// let file = Path::new(os::getenv("HOME").unwrap()).join(".ssh/known_hosts");
+/// let file = Path::new(&env::var("HOME").unwrap()).join(".ssh/known_hosts");
/// known_hosts.read_file(&file, KnownHostFileKind::OpenSSH).unwrap();
///
/// // Now check to see if the seesion's host key is anywhere in the known
@@ -68,7 +69,7 @@ impl<'sess> KnownHosts<'sess> {
/// the collection of known hosts.
pub fn read_file(&mut self, file: &Path, kind: KnownHostFileKind)
-> Result<u32, Error> {
- let file = try!(CString::new(file.as_vec()));
+ let file = try!(CString::new(try!(util::path2bytes(file))));
let n = unsafe {
raw::libssh2_knownhost_readfile(self.raw, file.as_ptr(),
kind as c_int)
@@ -92,7 +93,7 @@ impl<'sess> KnownHosts<'sess> {
/// file format.
pub fn write_file(&self, file: &Path, kind: KnownHostFileKind)
-> Result<(), Error> {
- let file = try!(CString::new(file.as_vec()));
+ let file = try!(CString::new(try!(util::path2bytes(file))));
let n = unsafe {
raw::libssh2_knownhost_writefile(self.raw, file.as_ptr(),
kind as c_int)
diff --git a/src/lib.rs b/src/lib.rs
index d53c641..640a640 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -32,7 +32,7 @@
//! ## Authenticating with ssh-agent
//!
//! ```no_run
-//! use std::old_io::TcpStream;
+//! use std::net::TcpStream;
//! use ssh2::Session;
//!
//! // Connect to the local SSH server
@@ -50,7 +50,7 @@
//! ## Authenticating with a password
//!
//! ```no_run
-//! use std::old_io::TcpStream;
+//! use std::net::TcpStream;
//! use ssh2::Session;
//!
//! // Connect to the local SSH server
@@ -65,7 +65,8 @@
//! ## Run a command
//!
//! ```no_run
-//! use std::old_io::{self, TcpStream};
+//! use std::io::prelude::*;
+//! use std::net::{TcpStream};
//! use ssh2::Session;
//!
//! // Connect to the local SSH server
@@ -76,14 +77,18 @@
//!
//! let mut channel = sess.channel_session().unwrap();
//! channel.exec("ls").unwrap();
-//! println!("{}", channel.read_to_string().unwrap());
+//! let mut s = String::new();
+//! channel.read_to_string(&mut s).unwrap();
+//! println!("{}", s);
//! println!("{}", channel.exit_status().unwrap());
//! ```
//!
//! ## Upload a file
//!
//! ```no_run
-//! use std::old_io::{self, TcpStream};
+//! use std::io::prelude::*;
+//! use std::net::TcpStream;
+//! use std::path::Path;
//! use ssh2::Session;
//!
//! // Connect to the local SSH server
@@ -92,15 +97,17 @@
//! sess.handshake(&tcp).unwrap();
//! sess.userauth_agent("username").unwrap();
//!
-//! let mut remote_file = sess.scp_send(&Path::new("remote"),
-//! old_io::USER_FILE, 10, None).unwrap();
+//! let mut remote_file = sess.scp_send(Path::new("remote"),
+//! 0o644, 10, None).unwrap();
//! remote_file.write(b"1234567890").unwrap();
//! ```
//!
//! ## Download a file
//!
//! ```no_run
-//! use std::old_io::TcpStream;
+//! use std::io::prelude::*;
+//! use std::net::TcpStream;
+//! use std::path::Path;
//! use ssh2::Session;
//!
//! // Connect to the local SSH server
@@ -109,13 +116,14 @@
//! sess.handshake(&tcp).unwrap();
//! sess.userauth_agent("username").unwrap();
//!
-//! let (mut remote_file, stat) = sess.scp_recv(&Path::new("remote")).unwrap();
-//! println!("remote file size: {}", stat.size);
-//! let contents = remote_file.read_to_end();
+//! let (mut remote_file, stat) = sess.scp_recv(Path::new("remote")).unwrap();
+//! println!("remote file size: {}", stat.size());
+//! let mut contents = Vec::new();
+//! remote_file.read_to_end(&mut contents).unwrap();
+//! // ...
//! ```
-#![feature(unsafe_destructor, std_misc, collections, old_io, core, old_path)]
-#![feature(io)]
+#![feature(unsafe_destructor, std_misc, collections, io, core, path, os, net)]
#![deny(missing_docs, unused_results)]
#![cfg_attr(test, deny(warnings))]
@@ -131,7 +139,7 @@ pub use channel::{Channel, ExitSignal, ReadWindow, WriteWindow};
pub use error::Error;
pub use knownhosts::{KnownHosts, Hosts, Host};
pub use listener::Listener;
-pub use session::Session;
+pub use session::{Session, ScpFileStat};
pub use sftp::{Sftp, OpenFlags, READ, WRITE, APPEND, CREATE, TRUNCATE};
pub use sftp::{EXCLUSIVE, OpenType, File, FileStat};
pub use sftp::{RenameFlags, ATOMIC, OVERWRITE, NATIVE};
diff --git a/src/session.rs b/src/session.rs
index 81ed002..c2dfc03 100644
--- a/src/session.rs
+++ b/src/session.rs
@@ -1,13 +1,14 @@
use std::ffi::CString;
-use std::old_io::{self, TcpStream};
use std::mem;
+use std::net::TcpStream;
+use std::path::Path;
use std::slice;
use std::str;
use libc::{self, c_uint, c_int, c_void, c_long};
use {raw, Error, DisconnectCode, ByApplication, HostKeyType};
use {MethodType, Agent, Channel, Listener, HashType, KnownHosts, Sftp};
-use util::{Binding, SessionBinding};
+use util::{self, Binding, SessionBinding};
/// An SSH session, typically representing one TCP connection.
///
@@ -20,6 +21,11 @@ pub struct Session {
unsafe impl Send for Session {}
+/// Metadata returned about a remote file when received via `scp`.
+pub struct ScpFileStat {
+ stat: libc::stat,
+}
+
impl Session {
/// Initializes an SSH session object.
///
@@ -193,10 +199,10 @@ impl Session {
privatekey: &Path,
passphrase: Option<&str>) -> Result<(), Error> {
let pubkey = match pubkey {
- Some(s) => Some(try!(CString::new(s.as_vec()))),
+ Some(s) => Some(try!(CString::new(try!(util::path2bytes(s))))),
None => None,
};
- let privatekey = try!(CString::new(privatekey.as_vec()));
+ let privatekey = try!(CString::new(try!(util::path2bytes(privatekey))));
let passphrase = match passphrase {
Some(s) => Some(try!(CString::new(s))),
None => None,
@@ -222,8 +228,8 @@ impl Session {
hostname: &str,
local_username: Option<&str>)
-> Result<(), Error> {
- let publickey = try!(CString::new(publickey.as_vec()));
- let privatekey = try!(CString::new(privatekey.as_vec()));
+ let publickey = try!(CString::new(try!(util::path2bytes(publickey))));
+ let privatekey = try!(CString::new(try!(util::path2bytes(privatekey))));
let passphrase = match passphrase {
Some(s) => Some(try!(CString::new(s))),
None => None,
@@ -415,8 +421,8 @@ impl Session {
/// sent over the returned channel. Some stat information is also returned
/// about the remote file to prepare for receiving the file.
pub fn scp_recv(&self, path: &Path)
- -> Result<(Channel, old_io::FileStat), Error> {
- let path = try!(CString::new(path.as_vec()));
+ -> 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.raw, path.as_ptr(), &mut sb);
@@ -428,7 +434,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, mkstat(&sb)))
+ Ok((c, ScpFileStat { stat: sb }))
}
}
@@ -440,15 +446,15 @@ impl Session {
///
/// The size of the file, `size`, must be known ahead of time before
/// transmission.
- pub fn scp_send(&self, remote_path: &Path, mode: old_io::FilePermission,
+ pub fn scp_send(&self, remote_path: &Path, mode: i32,
size: u64, times: Option<(u64, u64)>)
-> Result<Channel, Error> {
- let path = try!(CString::new(remote_path.as_vec()));
+ let path = try!(CString::new(try!(util::path2bytes(remote_path))));
let (mtime, atime) = times.unwrap_or((0, 0));
unsafe {
let ret = raw::libssh2_scp_send64(self.raw,
path.as_ptr(),
- mode.bits() as c_int,
+ mode as c_int,
size,
mtime as libc::time_t,
atime as libc::time_t);
@@ -618,57 +624,69 @@ impl Binding for Session {
fn raw(&self) -> *mut raw::LIBSSH2_SESSION { self.raw }
}
-// Sure do wish this was exported in libnative!
-fn mkstat(stat: &libc::stat) -> old_io::FileStat {
- #[cfg(windows)] type Mode = libc::c_int;
- #[cfg(unix)] type Mode = libc::mode_t;
-
- // FileStat times are in milliseconds
- fn mktime(secs: u64, nsecs: u64) -> u64 { secs * 1000 + nsecs / 1000000 }
-
- #[cfg(all(not(target_os = "linux"), not(target_os = "android")))]
- fn flags(stat: &libc::stat) -> u64 { stat.st_flags as u64 }
- #[cfg(any(target_os = "linux", target_os = "android"))]
- fn flags(_stat: &libc::stat) -> u64 { 0 }
-
- #[cfg(all(not(target_os = "linux"), not(target_os = "android")))]
- fn gen(stat: &libc::stat) -> u64 { stat.st_gen as u64 }
- #[cfg(any(target_os = "linux", target_os = "android"))]
- fn gen(_stat: &libc::stat) -> u64 { 0 }
-
- old_io::FileStat {
- size: stat.st_size as u64,
- kind: match (stat.st_mode as Mode) & libc::S_IFMT {
- libc::S_IFREG => old_io::FileType::RegularFile,
- libc::S_IFDIR => old_io::FileType::Directory,
- libc::S_IFIFO => old_io::FileType::NamedPipe,
- libc::S_IFBLK => old_io::FileType::BlockSpecial,
- libc::S_IFLNK => old_io::FileType::Symlink,
- _ => old_io::FileType::Unknown,
- },
- perm: old_io::FilePermission::from_bits_truncate(stat.st_mode as u32),
- created: mktime(stat.st_ctime as u64, stat.st_ctime_nsec as u64),
- modified: mktime(stat.st_mtime as u64, stat.st_mtime_nsec as u64),
- accessed: mktime(stat.st_atime as u64, stat.st_atime_nsec as u64),
- unstable: old_io::UnstableFileStat {
- device: stat.st_dev as u64,
- inode: stat.st_ino as u64,
- rdev: stat.st_rdev as u64,
- nlink: stat.st_nlink as u64,
- uid: stat.st_uid as u64,
- gid: stat.st_gid as u64,
- blksize: stat.st_blksize as u64,
- blocks: stat.st_blocks as u64,
- flags: flags(stat),
- gen: gen(stat),
- }
+impl Drop for Session {
+ fn drop(&mut self) {
+ unsafe { assert_eq!(raw::libssh2_session_free(self.raw), 0); }
}
}
-impl Drop for Session {
- fn drop(&mut self) {
- unsafe {
- assert_eq!(raw::libssh2_session_free(self.raw), 0);
- }
+impl ScpFileStat {
+ /// Returns the size of the remote file.
+ pub fn size(&self) -> u64 { self.stat.st_size as u64 }
+ /// Returns the listed mode of the remote file.
+ pub fn mode(&self) -> i32 { self.stat.st_mode as i32 }
+ /// Returns whether the remote file is a directory.
+ pub fn is_dir(&self) -> bool {
+ self.mode() & (libc::S_IFMT as i32) == (libc::S_IFDIR as i32)
+ }
+ /// Returns whether the remote file is a regular file.
+ pub fn is_file(&self) -> bool {
+ self.mode() & (libc::S_IFMT as i32) == (libc::S_IFREG as i32)
}
}
+
+// fn mkstat(stat: &libc::stat) -> old_io::FileStat {
+// #[cfg(windows)] type Mode = libc::c_int;
+// #[cfg(unix)] type Mode = libc::mode_t;
+//
+// // FileStat times are in milliseconds
+// fn mktime(secs: u64, nsecs: u64) -> u64 { secs * 1000 + nsecs / 1000000 }
+//
+// #[cfg(all(not(target_os = "linux"), not(target_os = "android")))]
+// fn flags(stat: &libc::stat) -> u64 { stat.st_flags as u64 }
+// #[cfg(any(target_os = "linux", target_os = "android"))]
+// fn flags(_stat: &libc::stat) -> u64 { 0 }
+//
+// #[cfg(all(not(target_os = "linux"), not(target_os = "android")))]
+// fn gen(stat: &libc::stat) -> u64 { stat.st_gen as u64 }
+// #[cfg(any(target_os = "linux", target_os = "android"))]
+// fn gen(_stat: &libc::stat) -> u64 { 0 }
+//
+// old_io::FileStat {
+// size: stat.st_size as u64,
+// kind: match (stat.st_mode as Mode) & libc::S_IFMT {
+// libc::S_IFREG => old_io::FileType::RegularFile,
+// libc::S_IFDIR => old_io::FileType::Directory,
+// libc::S_IFIFO => old_io::FileType::NamedPipe,
+// libc::S_IFBLK => old_io::FileType::BlockSpecial,
+// libc::S_IFLNK => old_io::FileType::Symlink,
+// _ => old_io::FileType::Unknown,
+// },
+// perm: old_io::FilePermission::from_bits_truncate(stat.st_mode as u32),
+// created: mktime(stat.st_ctime as u64, stat.st_ctime_nsec as u64),
+// modified: mktime(stat.st_mtime as u64, stat.st_mtime_nsec as u64),
+// accessed: mktime(stat.st_atime as u64, stat.st_atime_nsec as u64),
+// unstable: old_io::UnstableFileStat {
+// device: stat.st_dev as u64,
+// inode: stat.st_ino as u64,
+// rdev: stat.st_rdev as u64,
+// nlink: stat.st_nlink as u64,
+// uid: stat.st_uid as u64,
+// gid: stat.st_gid as u64,
+// blksize: stat.st_blksize as u64,
+// blocks: stat.st_blocks as u64,
+// flags: flags(stat),
+// gen: gen(stat),
+// }
+// }
+// }
diff --git a/src/sftp.rs b/src/sftp.rs
index d39fc33..009f7cf 100644
--- a/src/sftp.rs
+++ b/src/sftp.rs
@@ -1,10 +1,12 @@
+use std::io::prelude::*;
+use std::io::{self, ErrorKind, Seek, SeekFrom};
use std::marker;
use std::mem;
-use std::old_io;
+use std::path::{Path, PathBuf};
use libc::{c_int, c_ulong, c_long, c_uint, size_t};
use {raw, Session, Error, Channel};
-use util::SessionBinding;
+use util::{self, SessionBinding};
/// A handle to a remote filesystem over SFTP.
///
@@ -98,15 +100,14 @@ pub enum OpenType {
impl<'sess> Sftp<'sess> {
/// Open a handle to a file.
pub fn open_mode(&self, filename: &Path, flags: OpenFlags,
- mode: old_io::FilePermission,
- open_type: OpenType) -> Result<File, Error> {
- let filename = filename.as_vec();
+ mode: i32, open_type: OpenType) -> Result<File, Error> {
+ let filename = try!(util::path2bytes(filename));
unsafe {
let ret = raw::libssh2_sftp_open_ex(self.raw,
filename.as_ptr() as *const _,
filename.len() as c_uint,
flags.bits() as c_ulong,
- mode.bits() as c_long,
+ mode as c_long,
open_type as c_int);
if ret.is_null() {
Err(self.last_error())
@@ -118,17 +119,17 @@ impl<'sess> Sftp<'sess> {
/// Helper to open a file in the `Read` mode.
pub fn open(&self, filename: &Path) -> Result<File, Error> {
- self.open_mode(filename, READ, old_io::USER_FILE, OpenType::File)
+ self.open_mode(filename, READ, 0o644, OpenType::File)
}
/// Helper to create a file in write-only mode with truncation.
pub fn create(&self, filename: &Path) -> Result<File, Error> {
- self.open_mode(filename, WRITE | TRUNCATE, old_io::USER_FILE, OpenType::File)
+ self.open_mode(filename, WRITE | TRUNCATE, 0o644, OpenType::File)
}
/// Helper to open a directory for reading its contents.
pub fn opendir(&self, dirname: &Path) -> Result<File, Error> {
- self.open_mode(dirname, READ, old_io::USER_FILE, OpenType::Dir)
+ self.open_mode(dirname, READ, 0, OpenType::Dir)
}
/// Convenience function to read the files in a directory.
@@ -136,16 +137,16 @@ impl<'sess> Sftp<'sess> {
/// The returned paths are all joined with `dirname` when returned, and the
/// paths `.` and `..` are filtered out of the returned list.
pub fn readdir(&self, dirname: &Path)
- -> Result<Vec<(Path, FileStat)>, Error> {
+ -> Result<Vec<(PathBuf, FileStat)>, Error> {
let mut dir = try!(self.opendir(dirname));
let mut ret = Vec::new();
loop {
match dir.readdir() {
Ok((filename, stat)) => {
- if filename.as_vec() == b"." ||
- filename.as_vec() == b".." { continue }
+ if &*filename == Path::new(".") ||
+ &*filename == Path::new("..") { continue }
- ret.push((dirname.join(filename), stat))
+ ret.push((dirname.join(&filename), stat))
}
Err(ref e) if e.code() == raw::LIBSSH2_ERROR_FILE => break,
Err(e) => return Err(e),
@@ -155,20 +156,20 @@ impl<'sess> Sftp<'sess> {
}
/// Create a directory on the remote file system.
- pub fn mkdir(&self, filename: &Path, mode: old_io::FilePermission)
+ pub fn mkdir(&self, filename: &Path, mode: i32)
-> Result<(), Error> {
- let filename = filename.as_vec();
+ let filename = try!(util::path2bytes(filename));
self.rc(unsafe {
raw::libssh2_sftp_mkdir_ex(self.raw,
filename.as_ptr() as *const _,
filename.len() as c_uint,
- mode.bits() as c_long)
+ mode as c_long)
})
}
/// Remove a directory from the remote file system.
pub fn rmdir(&self, filename: &Path) -> Result<(), Error> {
- let filename = filename.as_vec();
+ let filename = try!(util::path2bytes(filename));
self.rc(unsafe {
raw::libssh2_sftp_rmdir_ex(self.raw,
filename.as_ptr() as *const _,
@@ -178,7 +179,7 @@ impl<'sess> Sftp<'sess> {
/// Get the metadata for a file, performed by stat(2)
pub fn stat(&self, filename: &Path) -> Result<FileStat, Error> {
- let filename = filename.as_vec();
+ let filename = try!(util::path2bytes(filename));
unsafe {
let mut ret = mem::zeroed();
let rc = raw::libssh2_sftp_stat_ex(self.raw,
@@ -193,7 +194,7 @@ impl<'sess> Sftp<'sess> {
/// Get the metadata for a file, performed by lstat(2)
pub fn lstat(&self, filename: &Path) -> Result<FileStat, Error> {
- let filename = filename.as_vec();
+ let filename = try!(util::path2bytes(filename));
unsafe {
let mut ret = mem::zeroed();
let rc = raw::libssh2_sftp_stat_ex(self.raw,
@@ -208,7 +209,7 @@ impl<'sess> Sftp<'sess> {
/// Set the metadata for a file.
pub fn setstat(&self, filename: &Path, stat: FileStat) -> Result<(), Error> {
- let filename = filename.as_vec();
+ let filename = try!(util::path2bytes(filename));
self.rc(unsafe {
let mut raw = stat.raw();
raw::libssh2_sftp_stat_ex(self.raw,
@@ -221,8 +222,8 @@ impl<'sess> Sftp<'sess> {
/// Create a symlink at `target` pointing at `path`.
pub fn symlink(&self, path: &Path, target: &Path) -> Result<(), Error> {
- let path = path.as_vec();
- let target = target.as_vec();
+ let path = try!(util::path2bytes(path));
+ let target = try!(util::path2bytes(target));
self.rc(unsafe {
raw::libssh2_sftp_symlink_ex(self.raw,
path.as_ptr() as *const _,
@@ -234,17 +235,17 @@ impl<'sess> Sftp<'sess> {
}
/// Read a symlink at `path`.
- pub fn readlink(&self, path: &Path) -> Result<Path, Error> {
+ pub fn readlink(&self, path: &Path) -> Result<PathBuf, Error> {
self.readlink_op(path, raw::LIBSSH2_SFTP_READLINK)
}
/// Resolve the real path for `path`.
- pub fn realpath(&self, path: &Path) -> Result<Path, Error> {
+ pub fn realpath(&self, path: &Path) -> Result<PathBuf, Error> {
self.readlink_op(path, raw::LIBSSH2_SFTP_REALPATH)
}
- fn readlink_op(&self, path: &Path, op: c_int) -> Result<Path, Error> {
- let path = path.as_vec();
+ fn readlink_op(&self, path: &Path, op: c_int) -> Result<PathBuf, Error> {
+ let path = try!(util::path2bytes(path));
let mut ret = Vec::<u8>::with_capacity(128);
let mut rc;
loop {
@@ -267,7 +268,7 @@ impl<'sess> Sftp<'sess> {
Err(self.last_error())
} else {
unsafe { ret.set_len(rc as usize) }
- Ok(Path::new(ret))
+ Ok(mkpath(ret))
}
}
@@ -286,8 +287,8 @@ impl<'sess> Sftp<'sess> {
pub fn rename(&self, src: &Path, dst: &Path, flags: Option<RenameFlags>)
-> Result<(), Error> {
let flags = flags.unwrap_or(ATOMIC | OVERWRITE | NATIVE);
- let src = src.as_vec();
- let dst = dst.as_vec();
+ let src = try!(util::path2bytes(src));
+ let dst = try!(util::path2bytes(dst));
self.rc(unsafe {
raw::libssh2_sftp_rename_ex(self.raw,
src.as_ptr() as *const _,
@@ -377,7 +378,7 @@ impl<'sftp> File<'sftp> {
///
/// Also note that the return paths will not be absolute paths, they are
/// the filenames of the files in this directory.
- pub fn readdir(&mut self) -> Result<(Path, FileStat), Error> {
+ pub fn readdir(&mut self) -> Result<(PathBuf, FileStat), Error> {
let mut buf = Vec::<u8>::with_capacity(128);
let mut stat = unsafe { mem::zeroed() };
let mut rc;
@@ -403,7 +404,7 @@ impl<'sftp> File<'sftp> {
} else {
unsafe { buf.set_len(rc as usize); }
}
- Ok((Path::new(buf), FileStat::from_raw(&stat)))
+ Ok((mkpath(buf), FileStat::from_raw(&stat)))
}
/// This function causes the remote server to synchronize the file data and
@@ -415,51 +416,40 @@ impl<'sftp> File<'sftp> {
}
}
-impl<'sftp> Reader for File<'sftp> {
- fn read(&mut self, buf: &mut [u8]) -> old_io::IoResult<usize> {
+impl<'sftp> Read for File<'sftp> {
+ fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
unsafe {
let rc = raw::libssh2_sftp_read(self.raw,
buf.as_mut_ptr() as *mut _,
buf.len() as size_t);
match rc {
- 0 => Err(old_io::standard_error(old_io::EndOfFile)),
- n if n < 0 => Err(old_io::IoError {
- kind: old_io::OtherIoError,
- desc: "read error",
- detail: Some(self.sftp.last_error().to_string()),
- }),
+ n if n < 0 => Err(io::Error::new(ErrorKind::Other, "read error",
+ Some(self.sftp.last_error()
+ .to_string()))),
n => Ok(n as usize)
}
}
}
}
-impl<'sftp> Writer for File<'sftp> {
- fn write_all(&mut self, mut buf: &[u8]) -> old_io::IoResult<()> {
- while buf.len() > 0 {
- let rc = unsafe {
- raw::libssh2_sftp_write(self.raw,
- buf.as_ptr() as *const _,
- buf.len() as size_t)
- };
- if rc < 0 {
- return Err(old_io::IoError {
- kind: old_io::OtherIoError,
- desc: "write error",
- detail: Some(self.sftp.last_error().to_string()),
- })
- }
- buf = &buf[rc as usize..];
+impl<'sftp> Write for File<'sftp> {
+ fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
+ let rc = unsafe {
+ raw::libssh2_sftp_write(self.raw,
+ buf.as_ptr() as *const _,
+ buf.len() as size_t)
+ };
+ if rc < 0 {
+ Err(io::Error::new(ErrorKind::Other, "write error",
+ Some(self.sftp.last_error().to_string())))
+ } else {
+ Ok(rc as usize)
}
- Ok(())
}
+ fn flush(&mut self) -> io::Result<()> { Ok(()) }
}
impl<'sftp> Seek for File<'sftp> {
- fn tell(&self) -> old_io::IoResult<u64> {
- Ok(unsafe { raw::libssh2_sftp_tell64(self.raw) })
- }
-
/// Move the file handle's internal pointer to an arbitrary location.
///
/// libssh2 implements file pointers as a localized concept to make file
@@ -470,28 +460,31 @@ impl<'sftp> Seek for File<'sftp> {
/// You MUST NOT seek during writing or reading a file with SFTP, as the
/// internals use outstanding packets and changing the "file position"
/// during transit will results in badness.
- fn seek(&mut self, offset: i64, whence: old_io::SeekStyle) -> old_io::IoResult<()> {
- let next = match whence {
- old_io::SeekSet => offset as u64,
- old_io::SeekCur => (self.tell().unwrap() as i64 + offset) as u64,
- old_io::SeekEnd => match self.stat() {
+ fn seek(&mut self, how: SeekFrom) -> io::Result<u64> {
+ let next = match how {
+ SeekFrom::Start(pos) => pos,
+ SeekFrom::Current(offset) => {
+ let cur = unsafe { raw::libssh2_sftp_tell64(self.raw) };
+ (cur as i64 + offset) as u64
+ }
+ SeekFrom::End(offset) => match self.stat() {
Ok(s) => match s.size {
Some(size) => (size as i64 + offset) as u64,
- None => return Err(old_io::IoError {
- kind: old_io::OtherIoError,
- desc: "no file size available",
- detail: None,
- })
+ None => {
+ return Err(io::Error::new(ErrorKind::Other,
+ "no file size available",
+ None))
+ }
},
- Err(e) => return Err(old_io::IoError {
- kind: old_io::OtherIoError,
- desc: "failed to stat remote file",
- detail: Some(e.to_string()),
- }),
+ Err(e) => {
+ return Err(io::Error::new(ErrorKind::Other,
+ "failed to stat remote file",
+ Some(e.to_string())))
+ }
}
};
unsafe { raw::libssh2_sftp_seek64(self.raw, next) }
- Ok(())
+ Ok(next)
}
}
@@ -547,3 +540,15 @@ impl FileStat {
}
}
}
+
+#[cfg(unix)]
+fn mkpath(v: Vec<u8>) -> PathBuf {
+ use std::os::unix::prelude::*;
+ use std::ffi::OsStr;
+ PathBuf::new(<OsStr as OsStrExt>::from_bytes(&v))
+}
+#[cfg(windows)]
+fn mkpath(v: Vec<u8>) -> PathBuf {
+ use std::str;
+ PathBuf::new(str::from_utf8(&v).unwrap())
+}
diff --git a/src/util.rs b/src/util.rs
index 11b7ffb..357cdce 100644
--- a/src/util.rs
+++ b/src/util.rs
@@ -1,4 +1,6 @@
-use {Session, Error};
+use std::path::Path;
+
+use {raw, Session, Error};
#[doc(hidden)]
pub trait Binding: Sized {
@@ -24,3 +26,27 @@ pub trait SessionBinding<'sess>: Sized {
}
}
}
+
+#[cfg(unix)]
+pub fn path2bytes(p: &Path) -> Result<&[u8], Error> {
+ use std::os::unix::prelude::*;
+ use std::ffi::AsOsStr;
+ check(p.as_os_str().as_bytes())
+}
+#[cfg(windows)]
+pub fn path2bytes(p: &Path) -> Result<&[u8], Error> {
+ match p.to_str() {
+ Some(s) => check(s),
+ None => Error::new(raw::LIBSSH2_ERROR_INVAL,
+ "only unicode paths on windows may be used"),
+ }
+}
+
+fn check(b: &[u8]) -> Result<&[u8], Error> {
+ if b.iter().any(|b| *b == 0) {
+ Err(Error::new(raw::LIBSSH2_ERROR_INVAL,
+ "path provided contains a 0 byte"))
+ } else {
+ Ok(b)
+ }
+}