From 0ba49356185269fa26b2a9599ce48dcbf71c4532 Mon Sep 17 00:00:00 2001 From: cw Date: Fri, 28 Aug 2020 10:55:52 +0800 Subject: [PATCH 1/3] Add config writing capability https://git.m-labs.hk/M-Labs/artiq-zynq/issues/63 --- src/runtime/src/config.rs | 39 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 38 insertions(+), 1 deletion(-) diff --git a/src/runtime/src/config.rs b/src/runtime/src/config.rs index b8e3672..91c3136 100644 --- a/src/runtime/src/config.rs +++ b/src/runtime/src/config.rs @@ -1,7 +1,7 @@ use crate::sd_reader; use core::fmt; use alloc::{string::FromUtf8Error, string::String, vec::Vec}; -use core_io::{self as io, BufRead, BufReader, Read}; +use core_io::{self as io, BufRead, BufReader, Read, Write}; use libboard_zynq::sdio; @@ -103,4 +103,41 @@ 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 mut file; + + let isascii_and_short = data.is_ascii() & (data.len() <= 100); + let file_path; + let config_key_bin = &["/CONFIG/", key, ".BIN"].concat(); + + if isascii_and_short { + file_path = "/CONFIG.TXT"; + } else { + file_path = config_key_bin; + } + + file = match root_dir.create_file(file_path) { + Ok(f) => f, + Err(_) => root_dir.open_file("/CONFIG.TXT")? + }; + + file.truncate()?; + file.write_all(&[key,"="].concat().as_bytes())?; + file.write_all(data.as_bytes())?; + + if isascii_and_short { + match root_dir.remove(config_key_bin) { + Ok(_) => {}, + Err(_) => {} + }; + } + + Ok(()) + } else { + Err(Error::NoConfig) + } + } } -- 2.47.2 From 22db44fdb989b7f341aefdd544f9ff74b6d8bce3 Mon Sep 17 00:00:00 2001 From: cw Date: Fri, 28 Aug 2020 12:02:26 +0800 Subject: [PATCH 2/3] Improve error handling and rename variables --- src/runtime/src/config.rs | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/src/runtime/src/config.rs b/src/runtime/src/config.rs index 91c3136..18c1898 100644 --- a/src/runtime/src/config.rs +++ b/src/runtime/src/config.rs @@ -1,7 +1,7 @@ use crate::sd_reader; use core::fmt; use alloc::{string::FromUtf8Error, string::String, vec::Vec}; -use core_io::{self as io, BufRead, BufReader, Read, Write}; +use core_io::{self as io, BufRead, BufReader, Read, Write, ErrorKind}; use libboard_zynq::sdio; @@ -107,19 +107,18 @@ impl Config { 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 mut file; - let isascii_and_short = data.is_ascii() & (data.len() <= 100); + let use_config_txt = data.is_ascii() & (data.len() <= 100); let file_path; let config_key_bin = &["/CONFIG/", key, ".BIN"].concat(); - if isascii_and_short { + if use_config_txt { file_path = "/CONFIG.TXT"; } else { file_path = config_key_bin; } - file = match root_dir.create_file(file_path) { + let mut file = match root_dir.create_file(file_path) { Ok(f) => f, Err(_) => root_dir.open_file("/CONFIG.TXT")? }; @@ -128,10 +127,15 @@ impl Config { file.write_all(&[key,"="].concat().as_bytes())?; file.write_all(data.as_bytes())?; - if isascii_and_short { + if use_config_txt { match root_dir.remove(config_key_bin) { Ok(_) => {}, - Err(_) => {} + Err(e) => match e.kind() { + ErrorKind::NotFound => {}, + _ => { + return Err(Error::IoError(e)); + } + } }; } -- 2.47.2 From 6bd4881cc5802cbc6bf9b76b865ebb84bea6c829 Mon Sep 17 00:00:00 2001 From: cw Date: Fri, 11 Sep 2020 16:12:19 +0800 Subject: [PATCH 3/3] Rewrite config writing Tested with short and long data strings --- src/runtime/src/config.rs | 96 ++++++++++++++++++++++++++++++++------- 1 file changed, 80 insertions(+), 16 deletions(-) diff --git a/src/runtime/src/config.rs b/src/runtime/src/config.rs index 18c1898..d9278c7 100644 --- a/src/runtime/src/config.rs +++ b/src/runtime/src/config.rs @@ -1,7 +1,7 @@ use crate::sd_reader; use core::fmt; use alloc::{string::FromUtf8Error, string::String, vec::Vec}; -use core_io::{self as io, BufRead, BufReader, Read, Write, ErrorKind}; +use core_io::{self as io, BufRead, BufReader, Read, Write, Seek, ErrorKind, SeekFrom}; use libboard_zynq::sdio; @@ -61,6 +61,39 @@ 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>, @@ -108,26 +141,27 @@ impl Config { if let Some(fs) = &self.fs { let root_dir = fs.root_dir(); - let use_config_txt = data.is_ascii() & (data.len() <= 100); - let file_path; let config_key_bin = &["/CONFIG/", key, ".BIN"].concat(); + let config_txt_tmp = "/CONFIG.TMP"; - if use_config_txt { - file_path = "/CONFIG.TXT"; - } else { - file_path = config_key_bin; - } + 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)); + } + }; - let mut file = match root_dir.create_file(file_path) { - Ok(f) => f, - Err(_) => root_dir.open_file("/CONFIG.TXT")? - }; + rename_file(&root_dir, config_txt_tmp, "/CONFIG.TXT")?; - file.truncate()?; - file.write_all(&[key,"="].concat().as_bytes())?; - file.write_all(data.as_bytes())?; + let mut file = root_dir.open_file("/CONFIG.TXT")?; + file.seek(SeekFrom::End(0))?; + file.write_all(&["\n", key, "=", data, "\n"].concat().as_bytes())?; - if use_config_txt { match root_dir.remove(config_key_bin) { Ok(_) => {}, Err(e) => match e.kind() { @@ -137,6 +171,36 @@ impl Config { } } }; + } 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(()) -- 2.47.2