summaryrefslogtreecommitdiff
path: root/src/error.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/error.rs')
-rw-r--r--src/error.rs206
1 files changed, 115 insertions, 91 deletions
diff --git a/src/error.rs b/src/error.rs
index be12eed..e3a3c56 100644
--- a/src/error.rs
+++ b/src/error.rs
@@ -9,17 +9,38 @@ use std::str;
use {raw, Session};
+/// An error code originating from a particular source.
+#[derive(Debug, Copy, Clone, PartialEq, Eq)]
+pub enum ErrorCode {
+ /// Codes for errors that originate in libssh2.
+ /// Can be one of `LIBSSH2_ERROR_*` constants.
+ Session(libc::c_int),
+
+ /// Codes for errors that originate in the SFTP subsystem.
+ /// Can be one of `LIBSSH2_FX_*` constants.
+ //
+ // TODO: This should be `c_ulong` instead of `c_int` because these constants
+ // are only returned by `libssh2_sftp_last_error()` which returns `c_ulong`.
+ SFTP(libc::c_int),
+}
+
+impl fmt::Display for ErrorCode {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "{:?}", self)
+ }
+}
+
/// Representation of an error that can occur within libssh2
#[derive(Debug)]
#[allow(missing_copy_implementations)]
pub struct Error {
- code: libc::c_int,
+ code: ErrorCode,
msg: Cow<'static, str>,
}
impl Error {
#[doc(hidden)]
- pub fn last_error_raw(raw: *mut raw::LIBSSH2_SESSION) -> Option<Error> {
+ pub fn last_session_error_raw(raw: *mut raw::LIBSSH2_SESSION) -> Option<Error> {
unsafe {
let mut msg = null_mut();
let rc = raw::libssh2_session_last_error(raw, &mut msg, null_mut(), 0);
@@ -31,7 +52,7 @@ impl Error {
// LIBSSH2_SESSION, so the error message should be copied before
// it is overwritten by the next API call.
Some(Self {
- code: rc,
+ code: ErrorCode::Session(rc),
msg: make_error_message(msg),
})
}
@@ -53,14 +74,14 @@ impl Error {
let mut msg = null_mut();
let res = raw::libssh2_session_last_error(raw, &mut msg, null_mut(), 0);
if res != rc {
- return Self::from_errno(rc);
+ return Self::from_errno(ErrorCode::Session(rc));
}
// The pointer stored in `msg` points to the internal buffer of
// LIBSSH2_SESSION, so the error message should be copied before
// it is overwritten by the next API call.
Self {
- code: rc,
+ code: ErrorCode::Session(rc),
msg: make_error_message(msg),
}
}
@@ -69,106 +90,109 @@ impl Error {
/// Generate the last error that occurred for a `Session`.
///
/// Returns `None` if there was no last error.
- pub fn last_error(sess: &Session) -> Option<Error> {
- Self::last_error_raw(&mut *sess.raw())
+ pub fn last_session_error(sess: &Session) -> Option<Error> {
+ Self::last_session_error_raw(&mut *sess.raw())
}
/// Create a new error for the given code and message
- pub fn new(code: libc::c_int, msg: &'static str) -> Error {
+ pub fn new(code: ErrorCode, msg: &'static str) -> Error {
Error {
- code: code,
+ code,
msg: Cow::Borrowed(msg),
}
}
/// Generate an error that represents EOF
pub fn eof() -> Error {
- Error::new(raw::LIBSSH2_ERROR_CHANNEL_EOF_SENT, "end of file")
+ Error::new(
+ ErrorCode::Session(raw::LIBSSH2_ERROR_CHANNEL_EOF_SENT),
+ "end of file",
+ )
}
/// Generate an error for unknown failure
pub fn unknown() -> Error {
- Error::new(libc::c_int::min_value(), "no other error listed")
- }
-
- pub(crate) fn rc(rc: libc::c_int) -> Result<(), Error> {
- if rc == 0 {
- Ok(())
- } else {
- Err(Self::from_errno(rc))
- }
+ Error::new(
+ ErrorCode::Session(libc::c_int::min_value()),
+ "no other error listed",
+ )
}
/// Construct an error from an error code from libssh2
- pub fn from_errno(code: libc::c_int) -> Error {
+ pub fn from_errno(code: ErrorCode) -> 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",
- raw::LIBSSH2_FX_EOF => "end of file",
- raw::LIBSSH2_FX_NO_SUCH_FILE => "no such file",
- raw::LIBSSH2_FX_PERMISSION_DENIED => "permission denied",
- raw::LIBSSH2_FX_FAILURE => "failure",
- raw::LIBSSH2_FX_BAD_MESSAGE => "bad message",
- raw::LIBSSH2_FX_NO_CONNECTION => "no connection",
- raw::LIBSSH2_FX_CONNECTION_LOST => "connection lost",
- raw::LIBSSH2_FX_OP_UNSUPPORTED => "operation unsupported",
- raw::LIBSSH2_FX_INVALID_HANDLE => "invalid handle",
- raw::LIBSSH2_FX_NO_SUCH_PATH => "no such path",
- raw::LIBSSH2_FX_FILE_ALREADY_EXISTS => "file already exists",
- raw::LIBSSH2_FX_WRITE_PROTECT => "file is write protected",
- raw::LIBSSH2_FX_NO_MEDIA => "no media available",
- raw::LIBSSH2_FX_NO_SPACE_ON_FILESYSTEM => "no space on filesystem",
- raw::LIBSSH2_FX_QUOTA_EXCEEDED => "quota exceeded",
- raw::LIBSSH2_FX_UNKNOWN_PRINCIPAL => "unknown principal",
- raw::LIBSSH2_FX_LOCK_CONFLICT => "lock conflict",
- raw::LIBSSH2_FX_DIR_NOT_EMPTY => "directory not empty",
- raw::LIBSSH2_FX_NOT_A_DIRECTORY => "not a directory",
- raw::LIBSSH2_FX_INVALID_FILENAME => "invalid filename",
- raw::LIBSSH2_FX_LINK_LOOP => "link loop",
- _ => "unknown error",
+ ErrorCode::Session(code) => 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",
+ },
+ ErrorCode::SFTP(code) => match code {
+ raw::LIBSSH2_FX_EOF => "end of file",
+ raw::LIBSSH2_FX_NO_SUCH_FILE => "no such file",
+ raw::LIBSSH2_FX_PERMISSION_DENIED => "permission denied",
+ raw::LIBSSH2_FX_FAILURE => "failure",
+ raw::LIBSSH2_FX_BAD_MESSAGE => "bad message",
+ raw::LIBSSH2_FX_NO_CONNECTION => "no connection",
+ raw::LIBSSH2_FX_CONNECTION_LOST => "connection lost",
+ raw::LIBSSH2_FX_OP_UNSUPPORTED => "operation unsupported",
+ raw::LIBSSH2_FX_INVALID_HANDLE => "invalid handle",
+ raw::LIBSSH2_FX_NO_SUCH_PATH => "no such path",
+ raw::LIBSSH2_FX_FILE_ALREADY_EXISTS => "file already exists",
+ raw::LIBSSH2_FX_WRITE_PROTECT => "file is write protected",
+ raw::LIBSSH2_FX_NO_MEDIA => "no media available",
+ raw::LIBSSH2_FX_NO_SPACE_ON_FILESYSTEM => "no space on filesystem",
+ raw::LIBSSH2_FX_QUOTA_EXCEEDED => "quota exceeded",
+ raw::LIBSSH2_FX_UNKNOWN_PRINCIPAL => "unknown principal",
+ raw::LIBSSH2_FX_LOCK_CONFLICT => "lock conflict",
+ raw::LIBSSH2_FX_DIR_NOT_EMPTY => "directory not empty",
+ raw::LIBSSH2_FX_NOT_A_DIRECTORY => "not a directory",
+ raw::LIBSSH2_FX_INVALID_FILENAME => "invalid filename",
+ raw::LIBSSH2_FX_LINK_LOOP => "link loop",
+ _ => "unknown error",
+ },
};
Error::new(code, msg)
}
@@ -179,7 +203,7 @@ impl Error {
}
/// Return the code for this error
- pub fn code(&self) -> libc::c_int {
+ pub fn code(&self) -> ErrorCode {
self.code
}
}
@@ -187,8 +211,8 @@ impl Error {
impl From<Error> for io::Error {
fn from(err: Error) -> io::Error {
let kind = match err.code {
- raw::LIBSSH2_ERROR_EAGAIN => io::ErrorKind::WouldBlock,
- raw::LIBSSH2_ERROR_TIMEOUT => io::ErrorKind::TimedOut,
+ ErrorCode::Session(raw::LIBSSH2_ERROR_EAGAIN) => io::ErrorKind::WouldBlock,
+ ErrorCode::Session(raw::LIBSSH2_ERROR_TIMEOUT) => io::ErrorKind::TimedOut,
_ => io::ErrorKind::Other,
};
io::Error::new(kind, err.msg)
@@ -210,7 +234,7 @@ impl error::Error for Error {
impl From<NulError> for Error {
fn from(_: NulError) -> Error {
Error::new(
- raw::LIBSSH2_ERROR_INVAL,
+ ErrorCode::Session(raw::LIBSSH2_ERROR_INVAL),
"provided data contained a nul byte and could not be used \
as as string",
)