From da8727996efacec4280696caefee3feecea4eae7 Mon Sep 17 00:00:00 2001 From: Robin Krahl Date: Tue, 28 Jan 2020 10:07:23 +0100 Subject: Add String value to the Error::UnexpectedError variant To make debugging of unexpected errors easier, this patch adds an associated String value with a description of the unexpected behavior to the UnexpectedError variant of the Error enum. --- src/util.rs | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) (limited to 'src/util.rs') diff --git a/src/util.rs b/src/util.rs index 5a56c55..1b52c3d 100644 --- a/src/util.rs +++ b/src/util.rs @@ -39,7 +39,9 @@ pub fn owned_str_from_ptr(ptr: *const c_char) -> Result { pub fn result_from_string(ptr: *const c_char) -> Result { if ptr.is_null() { - return Err(Error::UnexpectedError); + return Err(Error::UnexpectedError( + "libnitrokey returned a null pointer".to_owned(), + )); } let s = owned_str_from_ptr(ptr)?; unsafe { free(ptr as *mut c_void) }; @@ -69,10 +71,9 @@ pub fn get_last_result() -> Result<(), Error> { } pub fn get_last_error() -> Error { - match get_last_result() { - Ok(()) => Error::UnexpectedError, - Err(err) => err, - } + get_last_result().err().unwrap_or_else(|| { + Error::UnexpectedError("Expected an error, but command status is zero".to_owned()) + }) } pub fn generate_password(length: usize) -> Result, Error> { -- cgit v1.2.1 From d905aafe208536203dd319e5dc48bd250180a8ef Mon Sep 17 00:00:00 2001 From: Robin Krahl Date: Tue, 28 Jan 2020 17:56:53 +0100 Subject: Refactor string handling in util The util module provides helper methods to deal with the C strings returned by libnitrokey. The current implementation has to problems: - It causes unnecessary allocations if we only want to look at the string, for example in get_serial_number. - If the conversion from a CStr to a String fails, the string pointer is not freed. Therefore this patch introduces the run_with_str function that executes a function with the string returned by libnitrokey and then makes sure that the pointer is freed correctly. --- src/util.rs | 36 +++++++++++++++++++++++------------- 1 file changed, 23 insertions(+), 13 deletions(-) (limited to 'src/util.rs') diff --git a/src/util.rs b/src/util.rs index 08946d6..b17b071 100644 --- a/src/util.rs +++ b/src/util.rs @@ -30,28 +30,38 @@ pub enum LogLevel { DebugL2, } +pub fn str_from_ptr<'a>(ptr: *const c_char) -> Result<&'a str, Error> { + unsafe { CStr::from_ptr(ptr) }.to_str().map_err(Error::from) +} + pub fn owned_str_from_ptr(ptr: *const c_char) -> Result { - unsafe { CStr::from_ptr(ptr) } - .to_str() - .map(String::from) - .map_err(Error::from) + str_from_ptr(ptr).map(ToOwned::to_owned) } -pub fn result_from_string(ptr: *const c_char) -> Result { +pub fn run_with_string(ptr: *const c_char, op: F) -> Result +where + F: FnOnce(&str) -> Result, +{ if ptr.is_null() { return Err(Error::UnexpectedError( "libnitrokey returned a null pointer".to_owned(), )); } - let s = owned_str_from_ptr(ptr)?; + let result = str_from_ptr(ptr).and_then(op); unsafe { free(ptr as *mut c_void) }; - // An empty string can both indicate an error or be a valid return value. In this case, we - // have to check the last command status to decide what to return. - if s.is_empty() { - get_last_result().map(|_| s) - } else { - Ok(s) - } + result +} + +pub fn result_from_string(ptr: *const c_char) -> Result { + run_with_string(ptr, |s| { + // An empty string can both indicate an error or be a valid return value. In this case, we + // have to check the last command status to decide what to return. + if s.is_empty() { + get_last_result().map(|_| s.to_owned()) + } else { + Ok(s.to_owned()) + } + }) } pub fn result_or_error(value: T) -> Result { -- cgit v1.2.1