diff --git a/extensions/manage/src/lib.rs b/extensions/manage/src/lib.rs index 527dae1..0dab704 100644 --- a/extensions/manage/src/lib.rs +++ b/extensions/manage/src/lib.rs @@ -5,7 +5,7 @@ #![warn(non_ascii_idents, trivial_casts, unused, unused_qualifications)] #![deny(unsafe_code)] -use littlefs2_core::{Path, PathBuf}; +use littlefs2_core::{path, Path, PathBuf}; use serde::{Deserialize, Serialize}; use trussed_core::{ serde_extensions::{Extension, ExtensionClient, ExtensionResult}, @@ -145,3 +145,9 @@ pub trait ManageClient: ExtensionClient { } impl> ManageClient for C {} + +/// Empty file written to mark that a file system should be reformatted +/// +/// When booting, if this file is written to a filesystem, it means that the previous +/// power cycle was caused by a factory reset and the storage should be reformatted +pub const FACTORY_RESET_MARKER_FILE: &Path = path!("/factory-reset-must-reformat"); diff --git a/src/manage.rs b/src/manage.rs index 1e1e437..323a104 100644 --- a/src/manage.rs +++ b/src/manage.rs @@ -11,6 +11,7 @@ use trussed::{ use trussed_manage::{ FactoryResetClientReply, FactoryResetClientRequest, FactoryResetDeviceReply, FactoryResetDeviceRequest, ManageExtension, ManageReply, ManageRequest, + FACTORY_RESET_MARKER_FILE, }; use crate::StagingBackend; @@ -61,16 +62,34 @@ impl ExtensionImpl for StagingBackend { let store = platform.store(); 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 - })?; + let fs = store.fs(location); + fs.remove_dir_all_where( + path!("/"), + &callback(self.manage.should_preserve_file, location), + ) + .map_err(|_err| { + debug!("Failed to delete {location:?} fs: {_err:?}"); + Error::FunctionFailed + })?; + if location == Location::External { + let is_empty = fs + .read_dir_and_then(path!("/"), &mut |dir| match dir.next() { + Some(Ok(_)) => Ok(false), + Some(Err(err)) => Err(err), + None => Ok(true), + }) + .map_err(|_err| { + debug!("Failed to check emptyness {location:?} fs: {_err:?}"); + Error::FunctionFailed + })?; + if is_empty { + fs.write(FACTORY_RESET_MARKER_FILE, &[]) + .map_err(|_err| { + debug!("Failed to write reformat instruction for {location:?} fs: {_err:?}"); + Error::FunctionFailed + })?; + } + } } Ok(ManageReply::FactoryResetDevice(FactoryResetDeviceReply)) }