~ireas/nitrokey-rs

a2b7e1e05e07302b156ef7515cde17fcd93c443c — Robin Krahl 3 months ago 35be248
Add get_struct utility function

This patch adds the internal get_struct utility function that can be
used for querying a struct with a libnitrokey function that uses an
output parameter.  Instead of this:

    let mut out = R::default();
    get_command_result(op(&mut out))?;
    Ok(out.into())

We can now write this:

    get_struct(|out| op(out))
6 files changed, 25 insertions(+), 20 deletions(-)

M CHANGELOG.md
M src/config.rs
M src/device/mod.rs
M src/device/pro.rs
M src/device/storage.rs
M src/util.rs
M CHANGELOG.md => CHANGELOG.md +2 -0
@@ 18,6 18,8 @@ SPDX-License-Identifier: CC0-1.0
  - Use the `NK_config` struct for configuration handling.
  - Use the derived `Default` implementation for the structs defined by
    `nitrokey-sys`.
- Add `get_struct` utility function for querying structs with libnitrokey
  functions that use an output parameter.

# v0.7.1 (2020-08-30)
- Remove the custom `std::error::Error::source` implementation for

M src/config.rs => src/config.rs +2 -2
@@ 85,8 85,8 @@ impl convert::TryFrom<Config> for nitrokey_sys::NK_config {
    }
}

impl From<&nitrokey_sys::NK_config> for Config {
    fn from(config: &nitrokey_sys::NK_config) -> Config {
impl From<nitrokey_sys::NK_config> for Config {
    fn from(config: nitrokey_sys::NK_config) -> Config {
        Config::from_raw(
            config.numlock,
            config.capslock,

M src/device/mod.rs => src/device/mod.rs +4 -4
@@ 15,7 15,9 @@ use crate::config::Config;
use crate::error::{CommunicationError, Error, LibraryError};
use crate::otp::GenerateOtp;
use crate::pws::GetPasswordSafe;
use crate::util::{get_command_result, get_cstring, owned_str_from_ptr, result_or_error};
use crate::util::{
    get_command_result, get_cstring, get_struct, owned_str_from_ptr, result_or_error,
};

pub use pro::Pro;
pub use storage::{


@@ 469,9 471,7 @@ pub trait Device<'a>: Authenticate<'a> + GetPasswordSafe<'a> + GenerateOtp + fmt
    /// # }
    /// ```
    fn get_config(&self) -> Result<Config, Error> {
        let mut raw_config = nitrokey_sys::NK_config::default();
        get_command_result(unsafe { nitrokey_sys::NK_read_config_struct(&mut raw_config) })?;
        Ok(Config::from(&raw_config))
        get_struct(|out| unsafe { nitrokey_sys::NK_read_config_struct(out) })
    }

    /// Changes the administrator PIN.

M src/device/pro.rs => src/device/pro.rs +2 -4
@@ 4,7 4,7 @@
use crate::device::{Device, Model, Status};
use crate::error::Error;
use crate::otp::GenerateOtp;
use crate::util::get_command_result;
use crate::util::get_struct;

/// A Nitrokey Pro device without user or admin authentication.
///


@@ 76,9 76,7 @@ impl<'a> Device<'a> for Pro<'a> {
    }

    fn get_status(&self) -> Result<Status, Error> {
        let mut raw_status = nitrokey_sys::NK_status::default();
        get_command_result(unsafe { nitrokey_sys::NK_get_status(&mut raw_status) })?;
        Ok(raw_status.into())
        get_struct(|out| unsafe { nitrokey_sys::NK_get_status(out) })
    }
}


M src/device/storage.rs => src/device/storage.rs +4 -10
@@ 8,7 8,7 @@ use std::ops;
use crate::device::{Device, FirmwareVersion, Model, SerialNumber, Status};
use crate::error::{CommandError, Error};
use crate::otp::GenerateOtp;
use crate::util::{get_command_result, get_cstring, get_last_error};
use crate::util::{get_command_result, get_cstring, get_last_error, get_struct};

/// A Nitrokey Storage device without user or admin authentication.
///


@@ 549,9 549,7 @@ impl<'a> Storage<'a> {
    /// # }
    /// ```
    pub fn get_storage_status(&self) -> Result<StorageStatus, Error> {
        let mut raw_status = nitrokey_sys::NK_storage_status::default();
        let raw_result = unsafe { nitrokey_sys::NK_get_status_storage(&mut raw_status) };
        get_command_result(raw_result).map(|_| StorageStatus::from(raw_status))
        get_struct(|out| unsafe { nitrokey_sys::NK_get_status_storage(out) })
    }

    /// Returns the production information for the connected storage device.


@@ 577,9 575,7 @@ impl<'a> Storage<'a> {
    /// # }
    /// ```
    pub fn get_production_info(&self) -> Result<StorageProductionInfo, Error> {
        let mut raw_data = nitrokey_sys::NK_storage_ProductionTest::default();
        let raw_result = unsafe { nitrokey_sys::NK_get_storage_production_info(&mut raw_data) };
        get_command_result(raw_result).map(|_| StorageProductionInfo::from(raw_data))
        get_struct(|out| unsafe { nitrokey_sys::NK_get_storage_production_info(out) })
    }

    /// Clears the warning for a new SD card.


@@ 777,9 773,7 @@ impl<'a> Device<'a> for Storage<'a> {
        // [0] https://github.com/Nitrokey/nitrokey-storage-firmware/issues/96
        // [1] https://github.com/Nitrokey/libnitrokey/issues/166

        let mut raw_status = nitrokey_sys::NK_status::default();
        get_command_result(unsafe { nitrokey_sys::NK_get_status(&mut raw_status) })?;
        let mut status = Status::from(raw_status);
        let mut status: Status = get_struct(|out| unsafe { nitrokey_sys::NK_get_status(out) })?;

        let storage_status = self.get_storage_status()?;
        status.firmware_version = storage_status.firmware_version;

M src/util.rs => src/util.rs +11 -0
@@ 68,6 68,17 @@ pub fn result_or_error<T>(value: T) -> Result<T, Error> {
    get_last_result().and(Ok(value))
}

pub fn get_struct<R, T, F>(f: F) -> Result<R, Error>
where
    R: From<T>,
    T: Default,
    F: Fn(&mut T) -> c_int,
{
    let mut out = T::default();
    get_command_result(f(&mut out))?;
    Ok(out.into())
}

pub fn get_command_result(value: c_int) -> Result<(), Error> {
    if value == 0 {
        Ok(())