diff --git a/Cargo.toml b/Cargo.toml index 2bf1abf..c70c83b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,7 +2,7 @@ # SPDX-License-Identifier: CC0-1.0 [workspace] -members = ["extensions/chunked", "extensions/hkdf", "extensions/manage", "extensions/wrap-key-to-file"] +members = ["extensions/chunked", "extensions/fs-info", "extensions/hkdf", "extensions/manage", "extensions/wrap-key-to-file"] [workspace.package] authors = ["Nitrokey GmbH "] @@ -40,6 +40,7 @@ trussed-chunked = { version = "0.1.0", optional = true } trussed-hkdf = { version = "0.2.0", optional = true } trussed-manage = { version = "0.1.0", optional = true } trussed-wrap-key-to-file = { version = "0.1.0", optional = true } +trussed-fs-info = { version = "0.1.0", optional = true } [dev-dependencies] hex-literal = "0.3.4" @@ -53,6 +54,7 @@ chunked = ["trussed-chunked", "chacha20poly1305/stream"] hkdf = ["trussed-hkdf", "dep:hkdf", "dep:sha2"] manage = ["trussed-manage"] wrap-key-to-file = ["chacha20poly1305", "trussed-wrap-key-to-file"] +fs-info = ["trussed-fs-info"] virt = ["std", "trussed/virt"] std = [] @@ -73,3 +75,4 @@ trussed-chunked = { path = "extensions/chunked" } trussed-hkdf = { path = "extensions/hkdf" } trussed-manage = { path = "extensions/manage" } trussed-wrap-key-to-file = { path = "extensions/wrap-key-to-file" } +trussed-fs-info= { path = "extensions/fs-info" } diff --git a/extensions/fs-info/Cargo.toml b/extensions/fs-info/Cargo.toml new file mode 100644 index 0000000..6798e6a --- /dev/null +++ b/extensions/fs-info/Cargo.toml @@ -0,0 +1,15 @@ +# Copyright (C) Nitrokey GmbH +# SPDX-License-Identifier: CC0-1.0 + +[package] +name = "trussed-fs-info" +version = "0.1.0" +authors.workspace = true +edition.workspace = true +repository.workspace = true +license.workspace = true + +[dependencies] +serde.workspace = true +serde-byte-array.workspace = true +trussed.workspace = true diff --git a/extensions/fs-info/src/lib.rs b/extensions/fs-info/src/lib.rs new file mode 100644 index 0000000..8a3240a --- /dev/null +++ b/extensions/fs-info/src/lib.rs @@ -0,0 +1,89 @@ +// Copyright (C) Nitrokey GmbH +// SPDX-License-Identifier: CC0-1.0 + +#![no_std] +#![warn(non_ascii_idents, trivial_casts, unused, unused_qualifications)] +#![deny(unsafe_code)] + +use serde::{Deserialize, Serialize}; +use trussed::{ + serde_extensions::{Extension, ExtensionClient, ExtensionResult}, + types::Location, + Error, +}; + +pub struct FsInfoExtension; + +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)] +pub enum FsInfoExtensionRequest { + FsInfo(FsInfoRequest), +} + +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)] +pub struct FsInfoRequest { + pub location: Location, +} + +impl From for FsInfoExtensionRequest { + fn from(value: FsInfoRequest) -> Self { + Self::FsInfo(value) + } +} + +impl TryFrom for FsInfoRequest { + type Error = Error; + + fn try_from(value: FsInfoExtensionRequest) -> Result { + match value { + FsInfoExtensionRequest::FsInfo(v) => Ok(v), + } + } +} + +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)] +pub enum FsInfoExtensionReply { + FsInfo(FsInfoReply), +} + +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)] +pub struct FsInfoReply { + pub block_info: Option, + pub available_space: usize, +} + +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)] +pub struct BlockInfo { + pub size: usize, + pub total: usize, + pub available: usize, +} + +impl From for FsInfoExtensionReply { + fn from(value: FsInfoReply) -> Self { + Self::FsInfo(value) + } +} + +impl TryFrom for FsInfoReply { + type Error = Error; + + fn try_from(value: FsInfoExtensionReply) -> Result { + match value { + FsInfoExtensionReply::FsInfo(v) => Ok(v), + } + } +} + +impl Extension for FsInfoExtension { + type Request = FsInfoExtensionRequest; + type Reply = FsInfoExtensionReply; +} + +pub type FsInfoResult<'a, R, C> = ExtensionResult<'a, FsInfoExtension, R, C>; + +pub trait FsInfoClient: ExtensionClient { + fn fs_info(&mut self, location: Location) -> FsInfoResult<'_, FsInfoReply, Self> { + self.extension(FsInfoRequest { location }) + } +} +impl> FsInfoClient for C {} diff --git a/src/fs_info.rs b/src/fs_info.rs new file mode 100644 index 0000000..82f55dc --- /dev/null +++ b/src/fs_info.rs @@ -0,0 +1,37 @@ +// Copyright (C) Nitrokey GmbH +// SPDX-License-Identifier: CC0-1.0 + +use trussed::{ + platform::Store, serde_extensions::ExtensionImpl, service::ServiceResources, + types::CoreContext, Error, Platform, +}; +use trussed_fs_info::{ + BlockInfo, FsInfoExtension, FsInfoExtensionReply, FsInfoExtensionRequest, FsInfoReply, +}; + +impl ExtensionImpl for super::StagingBackend { + fn extension_request( + &mut self, + _core_ctx: &mut CoreContext, + _backend_ctx: &mut Self::Context, + request: &FsInfoExtensionRequest, + resources: &mut ServiceResources

, + ) -> Result { + match request { + FsInfoExtensionRequest::FsInfo(req) => { + let platform = resources.platform(); + let store = platform.store(); + let fs = store.fs(req.location); + Ok(FsInfoReply { + block_info: Some(BlockInfo { + total: fs.total_blocks(), + available: fs.available_blocks().map_err(|_| Error::InternalError)?, + size: fs.total_space() / fs.total_blocks(), + }), + available_space: fs.available_space().map_err(|_| Error::InternalError)?, + } + .into()) + } + } + } +} diff --git a/src/lib.rs b/src/lib.rs index c6c7ff7..5b197dc 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -15,6 +15,9 @@ pub mod virt; #[cfg(feature = "wrap-key-to-file")] mod wrap_key_to_file; +#[cfg(feature = "fs-info")] +mod fs_info; + #[cfg(feature = "chunked")] mod chunked; diff --git a/src/virt.rs b/src/virt.rs index 57d3d14..61a1941 100644 --- a/src/virt.rs +++ b/src/virt.rs @@ -8,6 +8,8 @@ use trussed::types::{Location, Path}; #[cfg(feature = "chunked")] use trussed_chunked::ChunkedExtension; +#[cfg(feature = "fs-info")] +use trussed_fs_info::FsInfoExtension; #[cfg(feature = "hkdf")] use trussed_hkdf::HkdfExtension; #[cfg(feature = "manage")] @@ -37,6 +39,8 @@ pub enum ExtensionIds { Manage, #[cfg(feature = "wrap-key-to-file")] WrapKeyToFile, + #[cfg(feature = "fs-info")] + FsInfo, } #[cfg(feature = "chunked")] @@ -63,6 +67,12 @@ impl ExtensionId for Dispatcher { const ID: ExtensionIds = ExtensionIds::WrapKeyToFile; } +#[cfg(feature = "fs-info")] +impl ExtensionId for Dispatcher { + type Id = ExtensionIds; + const ID: ExtensionIds = ExtensionIds::FsInfo; +} + impl From for u8 { fn from(value: ExtensionIds) -> Self { match value { @@ -74,6 +84,8 @@ impl From for u8 { ExtensionIds::Manage => 2, #[cfg(feature = "wrap-key-to-file")] ExtensionIds::WrapKeyToFile => 3, + #[cfg(feature = "fs-info")] + ExtensionIds::FsInfo => 4, } } } @@ -90,6 +102,8 @@ impl TryFrom for ExtensionIds { 2 => Ok(Self::Manage), #[cfg(feature = "wrap-key-to-file")] 3 => Ok(Self::WrapKeyToFile), + #[cfg(feature = "fs-info")] + 4 => Ok(Self::FsInfo), _ => Err(Error::FunctionNotSupported), } } @@ -164,6 +178,14 @@ impl ExtensionDispatch for Dispatcher { request, resources, ), + #[cfg(feature = "fs-info")] + ExtensionIds::FsInfo => ExtensionImpl::::extension_request_serialized( + &mut self.backend, + &mut ctx.core, + &mut ctx.backends, + request, + resources, + ), } } }