From a1564c5218752f8e20cfdd68b3b554716bc8b6b2 Mon Sep 17 00:00:00 2001 From: cw Date: Fri, 11 Sep 2020 16:30:43 +0800 Subject: [PATCH] Add config writing capability Tested with short (less than 100 characters) and long data strings --- libconfig/src/lib.rs | 106 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 105 insertions(+), 1 deletion(-) diff --git a/libconfig/src/lib.rs b/libconfig/src/lib.rs index 4e5ff30..f07fb8f 100644 --- a/libconfig/src/lib.rs +++ b/libconfig/src/lib.rs @@ -3,7 +3,7 @@ extern crate alloc; use core::fmt; use alloc::{string::FromUtf8Error, string::String, vec::Vec, rc::Rc}; -use core_io::{self as io, BufRead, BufReader, Read}; +use core_io::{self as io, BufRead, BufReader, Read, Write, Seek, ErrorKind, SeekFrom}; use libboard_zynq::sdio; pub mod sd_reader; @@ -66,6 +66,38 @@ fn parse_config<'a>( } Err(Error::KeyNotFoundError(key)) } +fn delete_old_entry<'a>( + key: &str, + file: fatfs::File, + mut file_tmp: fatfs::File, +) -> Result<'a, ()> { + let prefix = [key, "="].concat(); + let buf_reader = BufReader::new(file); + + for line in buf_reader.lines() { + let line = line?; + if !line.starts_with(&prefix) { + file_tmp.write_all(&[line.as_str(), "\n"].concat().as_bytes())?; + } + } + Ok(()) +} +fn rename_file<'a>(dir: &fatfs::Dir, old_file_name: &str, new_file_name: &str) -> Result<'a, ()>{ + { + let old_file = dir.open_file(old_file_name)?; + let mut new_file = dir.create_file(new_file_name)?; + new_file.truncate()?; + + for line in BufReader::new(old_file).lines() { + let line = line?; + new_file.write_all(&[line.as_str(), "\n"].concat().as_bytes())?; + } + } + + dir.remove(old_file_name)?; + + Ok(()) +} pub struct Config { fs: Option>>, @@ -112,4 +144,76 @@ impl Config { pub fn read_str<'b>(&self, key: &'b str) -> Result<'b, String> { Ok(String::from_utf8(self.read(key)?)?) } + + pub fn write_str<'b>(&mut self, key: &str, data: &str) -> Result<'b, ()>{ + if let Some(fs) = &self.fs { + let root_dir = fs.root_dir(); + + let config_key_bin = &["/CONFIG/", key, ".BIN"].concat(); + let config_txt_tmp = "/CONFIG.TMP"; + + if data.is_ascii() & (data.len() <= 100) { + match root_dir.create_file("/CONFIG.TXT") { + Ok(file) => { + let mut file_tmp = root_dir.create_file(config_txt_tmp)?; + file_tmp.truncate()?; + delete_old_entry(key, file, file_tmp)?; + }, + Err(e) => { + return Err(Error::IoError(e)); + } + }; + + rename_file(&root_dir, config_txt_tmp, "/CONFIG.TXT")?; + + let mut file = root_dir.open_file("/CONFIG.TXT")?; + file.seek(SeekFrom::End(0))?; + file.write_all(&["\n", key, "=", data, "\n"].concat().as_bytes())?; + + match root_dir.remove(config_key_bin) { + Ok(_) => {}, + Err(e) => match e.kind() { + ErrorKind::NotFound => {}, + _ => { + return Err(Error::IoError(e)); + } + } + }; + } else { + root_dir.create_dir("/CONFIG")?; + match root_dir.create_file(config_key_bin) { + Ok(mut file) => { + file.truncate()?; + file.write_all(&[data, "\n"].concat().as_bytes())?; + }, + Err(e) => { + return Err(Error::IoError(e)); + } + }; + + let mut need_to_rename = false; + match root_dir.open_file("/CONFIG.TXT") { + Ok(file) => { + need_to_rename = true; + let mut file_tmp = root_dir.create_file(config_txt_tmp)?; + file_tmp.truncate()?; + delete_old_entry(key, file, file_tmp)?; + }, + Err(e) => match e.kind() { + ErrorKind::NotFound => {}, + _ => { + return Err(Error::IoError(e)); + } + } + }; + if need_to_rename { // docs: ensure no ref to files + rename_file(&root_dir, config_txt_tmp, "/CONFIG.TXT")?; + } + } + + Ok(()) + } else { + Err(Error::NoConfig) + } + } }