diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/error.rs | 53 | ||||
-rw-r--r-- | src/lib.rs | 2 | ||||
-rw-r--r-- | src/session.rs | 19 | ||||
-rw-r--r-- | src/sftp.rs | 42 |
4 files changed, 115 insertions, 1 deletions
diff --git a/src/error.rs b/src/error.rs index 6d71362..e7d9542 100644 --- a/src/error.rs +++ b/src/error.rs @@ -40,6 +40,59 @@ impl Error { Error::new(raw::LIBSSH2_ERROR_CHANNEL_EOF_SENT, "end of file") } + /// Construct an error from an error code from libssh2 + pub fn from_errno(code: libc::c_int) -> Error { + let msg = match code { + raw::LIBSSH2_ERROR_BANNER_RECV => "banner recv failure", + raw::LIBSSH2_ERROR_BANNER_SEND => "banner send failure", + raw::LIBSSH2_ERROR_INVALID_MAC => "invalid mac", + raw::LIBSSH2_ERROR_KEX_FAILURE => "kex failure", + raw::LIBSSH2_ERROR_ALLOC => "alloc failure", + raw::LIBSSH2_ERROR_SOCKET_SEND => "socket send faiulre", + raw::LIBSSH2_ERROR_KEY_EXCHANGE_FAILURE => "key exchange failure", + raw::LIBSSH2_ERROR_TIMEOUT => "timed out", + raw::LIBSSH2_ERROR_HOSTKEY_INIT => "hostkey init error", + raw::LIBSSH2_ERROR_HOSTKEY_SIGN => "hostkey sign error", + raw::LIBSSH2_ERROR_DECRYPT => "decrypt error", + raw::LIBSSH2_ERROR_SOCKET_DISCONNECT => "socket disconnected", + raw::LIBSSH2_ERROR_PROTO => "protocol error", + raw::LIBSSH2_ERROR_PASSWORD_EXPIRED => "password expired", + raw::LIBSSH2_ERROR_FILE => "file error", + raw::LIBSSH2_ERROR_METHOD_NONE => "bad method name", + raw::LIBSSH2_ERROR_AUTHENTICATION_FAILED => "authentication failed", + raw::LIBSSH2_ERROR_PUBLICKEY_UNVERIFIED => "public key unverified", + raw::LIBSSH2_ERROR_CHANNEL_OUTOFORDER => "channel out of order", + raw::LIBSSH2_ERROR_CHANNEL_FAILURE => "channel failure", + raw::LIBSSH2_ERROR_CHANNEL_REQUEST_DENIED => "request denied", + raw::LIBSSH2_ERROR_CHANNEL_UNKNOWN => "unknown channel error", + raw::LIBSSH2_ERROR_CHANNEL_WINDOW_EXCEEDED => "window exceeded", + raw::LIBSSH2_ERROR_CHANNEL_PACKET_EXCEEDED => "packet exceeded", + raw::LIBSSH2_ERROR_CHANNEL_CLOSED => "closed channel", + raw::LIBSSH2_ERROR_CHANNEL_EOF_SENT => "eof sent", + raw::LIBSSH2_ERROR_SCP_PROTOCOL => "scp protocol error", + raw::LIBSSH2_ERROR_ZLIB => "zlib error", + raw::LIBSSH2_ERROR_SOCKET_TIMEOUT => "socket timeout", + raw::LIBSSH2_ERROR_SFTP_PROTOCOL => "sftp protocol error", + raw::LIBSSH2_ERROR_REQUEST_DENIED => "request denied", + raw::LIBSSH2_ERROR_METHOD_NOT_SUPPORTED => "method not supported", + raw::LIBSSH2_ERROR_INVAL => "invalid", + raw::LIBSSH2_ERROR_INVALID_POLL_TYPE => "invalid poll type", + raw::LIBSSH2_ERROR_PUBLICKEY_PROTOCOL => "public key protocol error", + raw::LIBSSH2_ERROR_EAGAIN => "operation would block", + raw::LIBSSH2_ERROR_BUFFER_TOO_SMALL => "buffer too small", + raw::LIBSSH2_ERROR_BAD_USE => "bad use error", + raw::LIBSSH2_ERROR_COMPRESS => "compression error", + raw::LIBSSH2_ERROR_OUT_OF_BOUNDARY => "out of bounds", + raw::LIBSSH2_ERROR_AGENT_PROTOCOL => "invalid agent protocol", + raw::LIBSSH2_ERROR_SOCKET_RECV => "error receiving on socket", + raw::LIBSSH2_ERROR_ENCRYPT => "bad encrypt", + raw::LIBSSH2_ERROR_BAD_SOCKET => "bad socket", + raw::LIBSSH2_ERROR_KNOWN_HOSTS => "known hosts error", + _ => "unknown error" + }; + Error::new(code, msg) + } + /// Get the message corresponding to this error pub fn message(&self) -> &str { self.msg } } @@ -64,6 +64,7 @@ pub use error::Error; pub use knownhosts::{KnownHosts, Hosts, Host}; pub use listener::Listener; pub use session::Session; +pub use sftp::{Sftp}; mod agent; mod channel; @@ -71,6 +72,7 @@ mod error; mod knownhosts; mod listener; mod session; +mod sftp; /// Initialize the libssh2 library. /// diff --git a/src/session.rs b/src/session.rs index 24f658e..49948f1 100644 --- a/src/session.rs +++ b/src/session.rs @@ -6,7 +6,7 @@ use std::str; use libc::{mod, c_uint, c_int, c_void, c_long}; use {raw, Error, DisconnectCode, ByApplication, SessionFlag, HostKeyType}; -use {MethodType, Agent, Channel, Listener, HashType, KnownHosts}; +use {MethodType, Agent, Channel, Listener, HashType, KnownHosts, Sftp}; pub struct Session { raw: *mut raw::LIBSSH2_SESSION, @@ -529,6 +529,23 @@ impl Session { } } + /// Open a channel and initialize the SFTP subsystem. + /// + /// Although the SFTP subsystem operates over the same type of channel as + /// those exported by the Channel API, the protocol itself implements its + /// own unique binary packet protocol which must be managed with the + /// methods on `Sftp`. + pub fn sftp(&self) -> Result<Sftp, Error> { + unsafe { + let ret = raw::libssh2_sftp_init(self.raw); + if ret.is_null() { + Err(Error::last_error(self).unwrap()) + } else { + Ok(Sftp::from_raw(self, ret)) + } + } + } + /// Gain access to the underlying raw libssh2 session pointer. pub fn raw(&self) -> *mut raw::LIBSSH2_SESSION { self.raw } diff --git a/src/sftp.rs b/src/sftp.rs new file mode 100644 index 0000000..08391fa --- /dev/null +++ b/src/sftp.rs @@ -0,0 +1,42 @@ +use std::kinds::marker; +use libc::c_int; + +use {raw, Session, Error}; + +pub struct Sftp<'a> { + raw: *mut raw::LIBSSH2_SFTP, + marker1: marker::NoSync, + marker2: marker::ContravariantLifetime<'a>, + marker3: marker::NoSend, +} + +impl<'a> Sftp<'a> { + /// Wraps a raw pointer in a new Sftp structure tied to the lifetime of the + /// given session. + /// + /// This consumes ownership of `raw`. + pub unsafe fn from_raw(_sess: &Session, + raw: *mut raw::LIBSSH2_SFTP) -> Sftp { + Sftp { + raw: raw, + marker1: marker::NoSync, + marker2: marker::ContravariantLifetime, + marker3: marker::NoSend, + } + } + + /// Peel off the last error to happen on this SFTP instance. + pub fn last_error(&self) -> Error { + let code = unsafe { raw::libssh2_sftp_last_error(self.raw) }; + Error::from_errno(code as c_int) + } +} + +#[unsafe_destructor] +impl<'a> Drop for Sftp<'a> { + fn drop(&mut self) { + unsafe { assert_eq!(raw::libssh2_sftp_shutdown(self.raw), 0) } + } +} + + |