Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -42,5 +42,5 @@ log-warn = []
log-error = []

[patch.crates-io]
trussed = { git = "https://github.com/trussed-dev/trussed.git", rev = "976372331be2f1b37cab532420cb6c55e0d54473" }
littlefs2 = { git = "https://github.com/trussed-dev/littlefs2.git", rev = "ae57c299312700ca4a3c4437d784a0f4e4f56759" }
trussed = { git = "https://github.com/trussed-dev/trussed.git", rev = "45ed62ba97d994aa6e05e2b61cea013ef131caa4" }
littlefs2 = { git = "https://github.com/trussed-dev/littlefs2.git", rev = "ebd27e49ca321089d01d8c9b169c4aeb58ceeeca" }
78 changes: 24 additions & 54 deletions src/manage.rs
Original file line number Diff line number Diff line change
Expand Up @@ -194,34 +194,19 @@ impl ExtensionImpl<ManageExtension> for StagingBackend {
ManageRequest::FactoryResetDevice(FactoryResetDeviceRequest) => {
let platform = resources.platform();
let store = platform.store();
let ifs = store.ifs();
let efs = store.efs();
let vfs = store.vfs();

ifs.remove_dir_all_where(
path!("/"),
&callback(self.manage.should_preserve_file, Location::Internal),
)
.map_err(|_err| {
debug!("Failed to delete ifs: {_err:?}");
Error::FunctionFailed
})?;
efs.remove_dir_all_where(
path!("/"),
&callback(self.manage.should_preserve_file, Location::External),
)
.map_err(|_err| {
debug!("Failed to delete efs: {_err:?}");
Error::FunctionFailed
})?;
vfs.remove_dir_all_where(
path!("/"),
&callback(self.manage.should_preserve_file, Location::Volatile),
)
.map_err(|_err| {
debug!("Failed to delete vfs: {_err:?}");
Error::FunctionFailed
})?;
for location in [Location::Internal, Location::External, Location::Volatile] {
store
.fs(location)
.remove_dir_all_where(
path!("/"),
&callback(self.manage.should_preserve_file, location),
)
.map_err(|_err| {
debug!("Failed to delete {location:?} fs: {_err:?}");
Error::FunctionFailed
})?;
}
Ok(ManageReply::FactoryResetDevice(FactoryResetDeviceReply))
}
ManageRequest::FactoryResetClient(FactoryResetClientRequest { client }) => {
Expand All @@ -234,33 +219,18 @@ impl ExtensionImpl<ManageExtension> for StagingBackend {

let path = path!("/").join(client);

let ifs = store.ifs();
let efs = store.efs();
let vfs = store.vfs();
ifs.remove_dir_all_where(
&path,
&callback(self.manage.should_preserve_file, Location::Internal),
)
.map_err(|_err| {
debug!("Failed to delete ifs: {_err:?}");
Error::FunctionFailed
})?;
efs.remove_dir_all_where(
&path,
&callback(self.manage.should_preserve_file, Location::External),
)
.map_err(|_err| {
debug!("Failed to delete efs: {_err:?}");
Error::FunctionFailed
})?;
vfs.remove_dir_all_where(
&path,
&callback(self.manage.should_preserve_file, Location::Volatile),
)
.map_err(|_err| {
debug!("Failed to delete vfs: {_err:?}");
Error::FunctionFailed
})?;
for location in [Location::Internal, Location::External, Location::Volatile] {
store
.fs(location)
.remove_dir_all_where(
&path,
&callback(self.manage.should_preserve_file, location),
)
.map_err(|_err| {
debug!("Failed to delete {location:?} fs: {_err:?}");
Error::FunctionFailed
})?;
}
Ok(ManageReply::FactoryResetClient(FactoryResetClientReply))
}
}
Expand Down
178 changes: 57 additions & 121 deletions src/streaming/store.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
// Copyright (C) Nitrokey GmbH
// SPDX-License-Identifier: Apache-2.0 or MIT

use littlefs2::driver::Storage as LfsStorage;
use littlefs2::fs::{File, Filesystem, OpenOptions};
use littlefs2::io::{SeekFrom, Write};
use littlefs2::fs::OpenOptions;
use littlefs2::io::SeekFrom;

use trussed::store::{create_directories, Store};
use trussed::store::{create_directories, DynFile, DynFilesystem, Store};
use trussed::types::{Bytes, Location, Message, Path, PathBuf};
use trussed::Error;

Expand All @@ -29,8 +28,8 @@ impl From<OpenSeekFrom> for SeekFrom {
}
}

pub fn fs_read_chunk<Storage: LfsStorage, const N: usize>(
fs: &Filesystem<Storage>,
pub fn fs_read_chunk<const N: usize>(
fs: &dyn DynFilesystem,
path: &Path,
pos: OpenSeekFrom,
length: usize,
Expand All @@ -40,13 +39,14 @@ pub fn fs_read_chunk<Storage: LfsStorage, const N: usize>(
return Err(Error::FilesystemReadFailure);
}
contents.resize_default(length).unwrap();
let file_len = File::open_and_then(fs, path, |file| {
file.seek(pos.into())?;
let read_n = file.read(&mut contents)?;
contents.truncate(read_n);
file.len()
})
.map_err(|_| Error::FilesystemReadFailure)?;
let file_len = fs
.open_file_and_then(path, &mut |file| {
file.seek(pos.into())?;
let read_n = file.read(&mut contents)?;
contents.truncate(read_n);
file.len()
})
.map_err(|_| Error::FilesystemReadFailure)?;
Ok((contents, file_len))
}

Expand All @@ -59,28 +59,24 @@ pub fn read_chunk<const N: usize>(
pos: OpenSeekFrom,
) -> Result<(Bytes<N>, usize), Error> {
debug_now!("reading chunk {},{:?}", &path, pos);
match location {
Location::Internal => fs_read_chunk(store.ifs(), path, pos, N),
Location::External => fs_read_chunk(store.efs(), path, pos, N),
Location::Volatile => fs_read_chunk(store.vfs(), path, pos, N),
}
fs_read_chunk(store.fs(location), path, pos, N)
}

pub fn fs_write_chunk<Storage: LfsStorage>(
fs: &Filesystem<Storage>,
pub fn fs_write_chunk(
fs: &dyn DynFilesystem,
path: &Path,
contents: &[u8],
pos: OpenSeekFrom,
) -> Result<(), Error> {
File::<Storage>::with_options()
.read(true)
.write(true)
.open_and_then(fs, path, |file| {
fs.open_file_with_options_and_then(
&|options| options.read(true).write(true),
path,
&mut |file| {
file.seek(pos.into())?;
file.write_all(contents)
})
.map_err(|_| Error::FilesystemReadFailure)?;
Ok(())
},
)
.map_err(|_| Error::FilesystemReadFailure)
}

/// Writes contents to path in location of store.
Expand All @@ -93,12 +89,8 @@ pub fn write_chunk(
pos: OpenSeekFrom,
) -> Result<(), Error> {
debug_now!("writing {}", &path);
match location {
Location::Internal => fs_write_chunk(store.ifs(), path, contents, pos),
Location::External => fs_write_chunk(store.efs(), path, contents, pos),
Location::Volatile => fs_write_chunk(store.vfs(), path, contents, pos),
}
.map_err(|_| Error::FilesystemWriteFailure)
fs_write_chunk(store.fs(location), path, contents, pos)
.map_err(|_| Error::FilesystemWriteFailure)
}

pub fn move_file(
Expand All @@ -116,12 +108,7 @@ pub fn move_file(
to_path
);

match to_location {
Location::Internal => create_directories(store.ifs(), to_path),
Location::External => create_directories(store.efs(), to_path),
Location::Volatile => create_directories(store.vfs(), to_path),
}
.map_err(|_err| {
create_directories(store.fs(to_location), to_path).map_err(|_err| {
error!("Failed to create directories chunks: {:?}", _err);
Error::FilesystemWriteFailure
})?;
Expand All @@ -131,67 +118,29 @@ pub fn move_file(
Error::FilesystemWriteFailure
};
// Fast path for same-filesystem
match (from_location, to_location) {
(Location::Internal, Location::Internal) => {
return store.ifs().rename(from_path, to_path).map_err(on_fail)
}
(Location::External, Location::External) => {
return store.efs().rename(from_path, to_path).map_err(on_fail)
}
(Location::Volatile, Location::Volatile) => {
return store.vfs().rename(from_path, to_path).map_err(on_fail)
}
_ => {}
}

match from_location {
Location::Internal => {
move_file_step1(store, &**store.ifs(), from_path, to_location, to_path)
}
Location::External => {
move_file_step1(store, &**store.efs(), from_path, to_location, to_path)
}
Location::Volatile => {
move_file_step1(store, &**store.vfs(), from_path, to_location, to_path)
}
if from_location == to_location {
return store
.fs(from_location)
.rename(from_path, to_path)
.map_err(on_fail);
}
}

// Separate generic function to avoid having 9 times the same code because the filesystem types are not the same.
fn move_file_step1<S: LfsStorage>(
store: impl Store,
from_fs: &Filesystem<S>,
from_path: &Path,
to_location: Location,
to_path: &Path,
) -> Result<(), Error> {
match to_location {
Location::Internal => move_file_step2(from_fs, from_path, &**store.ifs(), to_path),
Location::External => move_file_step2(from_fs, from_path, &**store.efs(), to_path),
Location::Volatile => move_file_step2(from_fs, from_path, &**store.vfs(), to_path),
}
}

// Separate generic function to avoid having 9 times the same code because the filesystem types are not the same.
fn move_file_step2<S1: LfsStorage, S2: LfsStorage>(
from_fs: &Filesystem<S1>,
from_path: &Path,
to_fs: &Filesystem<S2>,
to_path: &Path,
) -> Result<(), Error> {
File::open_and_then(from_fs, from_path, |from_file| {
File::create_and_then(to_fs, to_path, |to_file| copy_file_data(from_file, to_file))
})
.map_err(|_err| {
error!("Failed to flush chunks: {:?}", _err);
Error::FilesystemWriteFailure
})
store
.fs(from_location)
.open_file_and_then(from_path, &mut |from_file| {
let mut options = OpenOptions::new();
options.write(true).create(true).truncate(true);
store
.fs(to_location)
.create_file_and_then(to_path, &mut |to_file| copy_file_data(from_file, to_file))
})
.map_err(|_err| {
error!("Failed to flush chunks: {:?}", _err);
Error::FilesystemWriteFailure
})
}

fn copy_file_data<S1: LfsStorage, S2: LfsStorage>(
from: &File<S1>,
to: &File<S2>,
) -> Result<(), littlefs2::io::Error> {
fn copy_file_data(from: &dyn DynFile, to: &dyn DynFile) -> Result<(), littlefs2::io::Error> {
let mut buf = [0; 1024];
loop {
let read = from.read(&mut buf)?;
Expand Down Expand Up @@ -307,26 +256,7 @@ pub fn partial_read_file(
let path = actual_path(client_id, path)?;
let offset = u32::try_from(offset).map_err(|_| Error::FilesystemReadFailure)?;
let pos = OpenSeekFrom::Start(offset);
match location {
Location::Internal => fs_read_chunk(store.ifs(), &path, pos, length),
Location::External => fs_read_chunk(store.efs(), &path, pos, length),
Location::Volatile => fs_read_chunk(store.vfs(), &path, pos, length),
}
}

fn fs_append_file<Storage: LfsStorage>(
fs: &Filesystem<Storage>,
path: &Path,
data: &[u8],
) -> Result<usize, Error> {
OpenOptions::new()
.write(true)
.append(true)
.open_and_then(fs, path, |file| {
file.write_all(data)?;
file.len()
})
.map_err(|_| Error::FilesystemWriteFailure)
fs_read_chunk(store.fs(location), &path, pos, length)
}

pub fn append_file(
Expand All @@ -337,9 +267,15 @@ pub fn append_file(
data: &[u8],
) -> Result<usize, Error> {
let path = actual_path(client_id, path)?;
match location {
Location::Internal => fs_append_file(store.ifs(), &path, data),
Location::External => fs_append_file(store.efs(), &path, data),
Location::Volatile => fs_append_file(store.vfs(), &path, data),
}
store
.fs(location)
.open_file_with_options_and_then(
&|options| options.write(true).append(true),
&path,
&mut |file| {
file.write_all(data)?;
file.len()
},
)
.map_err(|_| Error::FilesystemWriteFailure)
}