Fix proto read and write

This commit is contained in:
topjohnwu 2023-09-06 20:45:59 -07:00
parent 35b3c8ba5c
commit 4fff2aa7d8
2 changed files with 115 additions and 104 deletions

View File

@ -97,8 +97,8 @@ macro_rules! cstr {
#[macro_export] #[macro_export]
macro_rules! raw_cstr { macro_rules! raw_cstr {
($s:literal) => {{ ($($str:tt)*) => {{
cstr!($s).as_ptr() cstr!($($str)*).as_ptr()
}}; }};
} }

View File

@ -1,17 +1,18 @@
use core::ffi::c_char; use core::ffi::c_char;
use std::pin::Pin;
use std::{ use std::{
fs::{read_to_string, remove_file, rename, File}, fs::{read_to_string, remove_file, rename, File},
io::{BufWriter, Write}, io::{BufWriter, Write},
ops::{Deref, DerefMut},
os::fd::FromRawFd, os::fd::FromRawFd,
path::{Path, PathBuf}, path::{Path, PathBuf},
pin::Pin,
}; };
use quick_protobuf::{BytesReader, MessageRead, MessageWrite, Writer}; use quick_protobuf::{BytesReader, MessageRead, MessageWrite, Writer};
use base::{ use base::{
cstr, debug, libc::mkstemp, Directory, LoggedResult, MappedFile, StringExt, Utf8CStr, cstr, debug, libc::mkstemp, raw_cstr, Directory, LoggedError, LoggedResult, MappedFile,
WalkResult, StringExt, Utf8CStr, WalkResult,
}; };
use crate::ffi::{clone_attr, prop_cb_exec, PropCb}; use crate::ffi::{clone_attr, prop_cb_exec, PropCb};
@ -31,17 +32,6 @@ macro_rules! PERSIST_PROP {
}; };
} }
struct MatchNameCb<'a> {
cb: Pin<&'a mut PropCb>,
name: &'a Utf8CStr,
}
struct PropCollectCb<'a> {
props: &'a mut PersistentProperties,
replace_name: Option<&'a Utf8CStr>,
replace_value: Option<&'a Utf8CStr>,
}
trait PropCbExec { trait PropCbExec {
fn exec(&mut self, name: &Utf8CStr, value: &Utf8CStr); fn exec(&mut self, name: &Utf8CStr, value: &Utf8CStr);
} }
@ -52,54 +42,43 @@ impl PropCbExec for Pin<&mut PropCb> {
} }
} }
impl PropCbExec for MatchNameCb<'_> { impl Deref for PersistentProperties {
fn exec(&mut self, name: &Utf8CStr, value: &Utf8CStr) { type Target = Vec<PersistentPropertyRecord>;
if name == self.name {
self.cb.exec(name, value); fn deref(&self) -> &Self::Target {
debug!("resetprop: found prop [{}] = [{}]", name, value); &self.properties
}
}
impl DerefMut for PersistentProperties {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.properties
}
}
trait PropExt {
fn find_index(&self, name: &Utf8CStr) -> Result<usize, usize>;
fn find(&mut self, name: &Utf8CStr) -> LoggedResult<&mut PersistentPropertyRecord>;
}
impl PropExt for PersistentProperties {
fn find_index(&self, name: &Utf8CStr) -> Result<usize, usize> {
self.binary_search_by(|p| p.name.as_deref().cmp(&Some(name.deref())))
}
fn find(&mut self, name: &Utf8CStr) -> LoggedResult<&mut PersistentPropertyRecord> {
if let Ok(idx) = self.find_index(name) {
Ok(&mut self[idx])
} else {
Err(LoggedError::default())
} }
} }
} }
impl PropCbExec for PropCollectCb<'_> { fn check_proto() -> bool {
fn exec(&mut self, name: &Utf8CStr, value: &Utf8CStr) {
let replace_value = self.replace_value.unwrap_or(value);
let value = self.replace_name.map_or(value, |replace_name| {
if name.as_bytes() == replace_name.as_bytes() {
replace_value
} else {
value
}
});
self.props.properties.push(PersistentPropertyRecord {
name: Some(name.to_string()),
value: Some(value.to_string()),
})
}
}
fn check_pb() -> bool {
Path::new(PERSIST_PROP!()).exists() Path::new(PERSIST_PROP!()).exists()
} }
fn pb_get_prop(cb: &mut dyn PropCbExec) -> LoggedResult<()> {
debug!("resetprop: decode with protobuf [{}]", PERSIST_PROP!());
let m = MappedFile::open(cstr!(PERSIST_PROP!()))?;
let m = m.as_ref();
let mut r = BytesReader::from_bytes(m);
let mut pp = PersistentProperties::from_reader(&mut r, m)?;
pp.properties.iter_mut().for_each(|p| {
if let PersistentPropertyRecord {
name: Some(ref mut n),
value: Some(ref mut v),
} = p
{
cb.exec(Utf8CStr::from_string(n), Utf8CStr::from_string(v));
}
});
Ok(())
}
fn file_get_prop(name: &Utf8CStr) -> LoggedResult<String> { fn file_get_prop(name: &Utf8CStr) -> LoggedResult<String> {
let path = PathBuf::new().join(PERSIST_PROP_DIR!()).join(name); let path = PathBuf::new().join(PERSIST_PROP_DIR!()).join(name);
let path = path.as_path(); let path = path.as_path();
@ -107,27 +86,6 @@ fn file_get_prop(name: &Utf8CStr) -> LoggedResult<String> {
Ok(read_to_string(path)?) Ok(read_to_string(path)?)
} }
fn pb_write_props(props: &PersistentProperties) -> LoggedResult<()> {
let mut tmp = String::from(concat!(PERSIST_PROP!(), ".XXXXXX"));
tmp.nul_terminate();
{
let f = unsafe {
let fd = mkstemp(tmp.as_mut_ptr().cast());
if fd < 0 {
return Err(Default::default());
}
File::from_raw_fd(fd)
};
debug!("resetprop: encode with protobuf [{}]", tmp);
props.write_message(&mut Writer::new(BufWriter::new(f)))?;
}
unsafe {
clone_attr(cstr!(PERSIST_PROP!()).as_ptr(), tmp.as_ptr().cast());
}
rename(tmp, PERSIST_PROP!())?;
Ok(())
}
fn file_set_prop(name: &Utf8CStr, value: Option<&Utf8CStr>) -> LoggedResult<()> { fn file_set_prop(name: &Utf8CStr, value: Option<&Utf8CStr>) -> LoggedResult<()> {
let path = PathBuf::new().join(PERSIST_PROP_DIR!()).join(name); let path = PathBuf::new().join(PERSIST_PROP_DIR!()).join(name);
let path = path.as_path(); let path = path.as_path();
@ -152,25 +110,73 @@ fn file_set_prop(name: &Utf8CStr, value: Option<&Utf8CStr>) -> LoggedResult<()>
Ok(()) Ok(())
} }
fn proto_read_props() -> LoggedResult<PersistentProperties> {
debug!("resetprop: decode with protobuf [{}]", PERSIST_PROP!());
let m = MappedFile::open(cstr!(PERSIST_PROP!()))?;
let m = m.as_ref();
let mut r = BytesReader::from_bytes(m);
let mut props = PersistentProperties::from_reader(&mut r, m)?;
// Keep the list sorted for binary search
props.sort_unstable_by(|a, b| a.name.cmp(&b.name));
Ok(props)
}
fn proto_write_props(props: &PersistentProperties) -> LoggedResult<()> {
let mut tmp = String::from(concat!(PERSIST_PROP!(), ".XXXXXX"));
tmp.nul_terminate();
{
let f = unsafe {
let fd = mkstemp(tmp.as_mut_ptr().cast());
if fd < 0 {
return Err(Default::default());
}
File::from_raw_fd(fd)
};
debug!("resetprop: encode with protobuf [{}]", tmp);
props.write_message(&mut Writer::new(BufWriter::new(f)))?;
}
unsafe {
clone_attr(raw_cstr!(PERSIST_PROP!()), tmp.as_ptr().cast());
}
rename(tmp, PERSIST_PROP!())?;
Ok(())
}
pub unsafe fn persist_get_prop(name: *const c_char, prop_cb: Pin<&mut PropCb>) { pub unsafe fn persist_get_prop(name: *const c_char, prop_cb: Pin<&mut PropCb>) {
unsafe fn inner(name: *const c_char, mut prop_cb: Pin<&mut PropCb>) -> LoggedResult<()> { fn inner(name: *const c_char, mut prop_cb: Pin<&mut PropCb>) -> LoggedResult<()> {
let name = Utf8CStr::from_ptr(name)?; let name = unsafe { Utf8CStr::from_ptr(name)? };
if check_pb() { if check_proto() {
pb_get_prop(&mut MatchNameCb { cb: prop_cb, name }) let mut props = proto_read_props()?;
if let Ok(PersistentPropertyRecord {
name: Some(ref mut n),
value: Some(ref mut v),
}) = props.find(name)
{
prop_cb.exec(Utf8CStr::from_string(n), Utf8CStr::from_string(v));
}
} else { } else {
let mut value = file_get_prop(name)?; let mut value = file_get_prop(name)?;
prop_cb.exec(name, Utf8CStr::from_string(&mut value)); prop_cb.exec(name, Utf8CStr::from_string(&mut value));
debug!("resetprop: found prop [{}] = [{}]", name, value); debug!("resetprop: found prop [{}] = [{}]", name, value);
Ok(())
} }
Ok(())
} }
inner(name, prop_cb).ok(); inner(name, prop_cb).ok();
} }
pub unsafe fn persist_get_props(prop_cb: Pin<&mut PropCb>) { pub unsafe fn persist_get_props(prop_cb: Pin<&mut PropCb>) {
fn inner(mut prop_cb: Pin<&mut PropCb>) -> LoggedResult<()> { fn inner(mut prop_cb: Pin<&mut PropCb>) -> LoggedResult<()> {
if check_pb() { if check_proto() {
pb_get_prop(&mut prop_cb) let mut props = proto_read_props()?;
props.iter_mut().for_each(|p| {
if let PersistentPropertyRecord {
name: Some(ref mut n),
value: Some(ref mut v),
} = p
{
prop_cb.exec(Utf8CStr::from_string(n), Utf8CStr::from_string(v));
}
});
} else { } else {
let mut dir = Directory::open(cstr!(PERSIST_PROP_DIR!()))?; let mut dir = Directory::open(cstr!(PERSIST_PROP_DIR!()))?;
dir.for_all_file(|f| { dir.for_all_file(|f| {
@ -181,23 +187,23 @@ pub unsafe fn persist_get_props(prop_cb: Pin<&mut PropCb>) {
} }
Ok(WalkResult::Continue) Ok(WalkResult::Continue)
})?; })?;
Ok(())
} }
Ok(())
} }
inner(prop_cb).ok(); inner(prop_cb).ok();
} }
pub unsafe fn persist_delete_prop(name: *const c_char) -> bool { pub unsafe fn persist_delete_prop(name: *const c_char) -> bool {
unsafe fn inner(name: *const c_char) -> LoggedResult<()> { fn inner(name: *const c_char) -> LoggedResult<()> {
let name = Utf8CStr::from_ptr(name)?; let name = unsafe { Utf8CStr::from_ptr(name)? };
if check_pb() { if check_proto() {
let mut pp = PersistentProperties { properties: vec![] }; let mut props = proto_read_props()?;
pb_get_prop(&mut PropCollectCb { if let Ok(idx) = props.find_index(name) {
props: &mut pp, props.remove(idx);
replace_name: Some(name), proto_write_props(&props)
replace_value: None, } else {
})?; Err(LoggedError::default())
pb_write_props(&pp) }
} else { } else {
file_set_prop(name, None) file_set_prop(name, None)
} }
@ -208,14 +214,19 @@ pub unsafe fn persist_set_prop(name: *const c_char, value: *const c_char) -> boo
unsafe fn inner(name: *const c_char, value: *const c_char) -> LoggedResult<()> { unsafe fn inner(name: *const c_char, value: *const c_char) -> LoggedResult<()> {
let name = Utf8CStr::from_ptr(name)?; let name = Utf8CStr::from_ptr(name)?;
let value = Utf8CStr::from_ptr(value)?; let value = Utf8CStr::from_ptr(value)?;
if check_pb() { if check_proto() {
let mut pp = PersistentProperties { properties: vec![] }; let mut props = proto_read_props()?;
pb_get_prop(&mut PropCollectCb { match props.find_index(name) {
props: &mut pp, Ok(idx) => props[idx].value = Some(value.to_string()),
replace_name: Some(name), Err(idx) => props.insert(
replace_value: Some(value), idx,
})?; PersistentPropertyRecord {
pb_write_props(&pp) name: Some(name.to_string()),
value: Some(value.to_string()),
},
),
}
proto_write_props(&props)
} else { } else {
file_set_prop(name, Some(value)) file_set_prop(name, Some(value))
} }