mirror of
https://github.com/topjohnwu/Magisk.git
synced 2025-01-05 12:37:39 +00:00
233 lines
7.2 KiB
Rust
233 lines
7.2 KiB
Rust
use std::io::Read;
|
|
use std::{
|
|
fs::File,
|
|
io::{BufWriter, Write},
|
|
ops::{Deref, DerefMut},
|
|
os::fd::FromRawFd,
|
|
pin::Pin,
|
|
};
|
|
|
|
use quick_protobuf::{BytesReader, MessageRead, MessageWrite, Writer};
|
|
|
|
use base::libc::{O_CLOEXEC, O_RDONLY};
|
|
use base::{
|
|
clone_attr, cstr, debug, libc::mkstemp, Directory, FsPath, FsPathBuf, LibcReturn, LoggedResult,
|
|
MappedFile, SilentResultExt, Utf8CStr, Utf8CStrBufArr, WalkResult,
|
|
};
|
|
|
|
use crate::ffi::{prop_cb_exec, PropCb};
|
|
use crate::resetprop::proto::persistent_properties::{
|
|
mod_PersistentProperties::PersistentPropertyRecord, PersistentProperties,
|
|
};
|
|
|
|
macro_rules! PERSIST_PROP_DIR {
|
|
() => {
|
|
"/data/property"
|
|
};
|
|
}
|
|
|
|
macro_rules! PERSIST_PROP {
|
|
() => {
|
|
concat!(PERSIST_PROP_DIR!(), "/persistent_properties")
|
|
};
|
|
}
|
|
|
|
trait PropCbExec {
|
|
fn exec(&mut self, name: &Utf8CStr, value: &Utf8CStr);
|
|
}
|
|
|
|
impl PropCbExec for Pin<&mut PropCb> {
|
|
fn exec(&mut self, name: &Utf8CStr, value: &Utf8CStr) {
|
|
unsafe { prop_cb_exec(self.as_mut(), name.as_ptr(), value.as_ptr(), u32::MAX) }
|
|
}
|
|
}
|
|
|
|
impl Deref for PersistentProperties {
|
|
type Target = Vec<PersistentPropertyRecord>;
|
|
|
|
fn deref(&self) -> &Self::Target {
|
|
&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> {
|
|
let idx = self.find_index(name).silent()?;
|
|
Ok(&mut self[idx])
|
|
}
|
|
}
|
|
|
|
fn check_proto() -> bool {
|
|
FsPath::from(cstr!(PERSIST_PROP!())).exists()
|
|
}
|
|
|
|
fn file_get_prop(name: &Utf8CStr) -> LoggedResult<String> {
|
|
let mut buf = Utf8CStrBufArr::default();
|
|
let path = FsPathBuf::new(&mut buf)
|
|
.join(PERSIST_PROP_DIR!())
|
|
.join(name);
|
|
let mut file = path.open(O_RDONLY | O_CLOEXEC).silent()?;
|
|
debug!("resetprop: read prop from [{}]", path);
|
|
let mut s = String::new();
|
|
file.read_to_string(&mut s)?;
|
|
Ok(s)
|
|
}
|
|
|
|
fn file_set_prop(name: &Utf8CStr, value: Option<&Utf8CStr>) -> LoggedResult<()> {
|
|
let mut buf = Utf8CStrBufArr::default();
|
|
let path = FsPathBuf::new(&mut buf)
|
|
.join(PERSIST_PROP_DIR!())
|
|
.join(name);
|
|
if let Some(value) = value {
|
|
let mut buf = Utf8CStrBufArr::default();
|
|
let mut tmp = FsPathBuf::new(&mut buf)
|
|
.join(PERSIST_PROP_DIR!())
|
|
.join("prop.XXXXXX");
|
|
{
|
|
let mut f = unsafe {
|
|
let fd = mkstemp(tmp.as_mut_ptr()).check_os_err()?;
|
|
File::from_raw_fd(fd)
|
|
};
|
|
f.write_all(value.as_bytes())?;
|
|
}
|
|
debug!("resetprop: write prop to [{}]", tmp);
|
|
tmp.rename_to(path)?
|
|
} else {
|
|
path.remove().silent()?;
|
|
debug!("resetprop: unlink [{}]", path);
|
|
}
|
|
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 buf = Utf8CStrBufArr::default();
|
|
let mut tmp = FsPathBuf::new(&mut buf).join(concat!(PERSIST_PROP!(), ".XXXXXX"));
|
|
{
|
|
let f = unsafe {
|
|
let fd = mkstemp(tmp.as_mut_ptr()).check_os_err()?;
|
|
File::from_raw_fd(fd)
|
|
};
|
|
debug!("resetprop: encode with protobuf [{}]", tmp);
|
|
props.write_message(&mut Writer::new(BufWriter::new(f)))?;
|
|
}
|
|
clone_attr(FsPath::from(cstr!(PERSIST_PROP!())), &tmp)?;
|
|
tmp.rename_to(cstr!(PERSIST_PROP!()))?;
|
|
Ok(())
|
|
}
|
|
|
|
pub unsafe fn persist_get_prop(name: &Utf8CStr, prop_cb: Pin<&mut PropCb>) {
|
|
fn inner(name: &Utf8CStr, mut prop_cb: Pin<&mut PropCb>) -> LoggedResult<()> {
|
|
if check_proto() {
|
|
let mut props = proto_read_props()?;
|
|
let prop = props.find(name)?;
|
|
if let PersistentPropertyRecord {
|
|
name: Some(ref mut n),
|
|
value: Some(ref mut v),
|
|
} = prop
|
|
{
|
|
prop_cb.exec(Utf8CStr::from_string(n), Utf8CStr::from_string(v));
|
|
}
|
|
} else {
|
|
let mut value = file_get_prop(name)?;
|
|
prop_cb.exec(name, Utf8CStr::from_string(&mut value));
|
|
debug!("resetprop: found prop [{}] = [{}]", name, value);
|
|
}
|
|
Ok(())
|
|
}
|
|
inner(name, prop_cb).ok();
|
|
}
|
|
|
|
pub unsafe fn persist_get_props(prop_cb: Pin<&mut PropCb>) {
|
|
fn inner(mut prop_cb: Pin<&mut PropCb>) -> LoggedResult<()> {
|
|
if check_proto() {
|
|
let mut props = proto_read_props()?;
|
|
props.iter_mut().for_each(|prop| {
|
|
if let PersistentPropertyRecord {
|
|
name: Some(ref mut n),
|
|
value: Some(ref mut v),
|
|
} = prop
|
|
{
|
|
prop_cb.exec(Utf8CStr::from_string(n), Utf8CStr::from_string(v));
|
|
}
|
|
});
|
|
} else {
|
|
let mut dir = Directory::open(cstr!(PERSIST_PROP_DIR!()))?;
|
|
dir.pre_order_walk(|e| {
|
|
if e.is_file() {
|
|
if let Ok(name) = Utf8CStr::from_cstr(e.d_name()) {
|
|
if let Ok(mut value) = file_get_prop(name) {
|
|
prop_cb.exec(name, Utf8CStr::from_string(&mut value));
|
|
}
|
|
}
|
|
}
|
|
// Do not traverse recursively
|
|
Ok(WalkResult::Skip)
|
|
})?;
|
|
}
|
|
Ok(())
|
|
}
|
|
inner(prop_cb).ok();
|
|
}
|
|
|
|
pub unsafe fn persist_delete_prop(name: &Utf8CStr) -> bool {
|
|
fn inner(name: &Utf8CStr) -> LoggedResult<()> {
|
|
if check_proto() {
|
|
let mut props = proto_read_props()?;
|
|
let idx = props.find_index(name).silent()?;
|
|
props.remove(idx);
|
|
proto_write_props(&props)
|
|
} else {
|
|
file_set_prop(name, None)
|
|
}
|
|
}
|
|
inner(name).is_ok()
|
|
}
|
|
|
|
pub unsafe fn persist_set_prop(name: &Utf8CStr, value: &Utf8CStr) -> bool {
|
|
unsafe fn inner(name: &Utf8CStr, value: &Utf8CStr) -> LoggedResult<()> {
|
|
if check_proto() {
|
|
let mut props = proto_read_props()?;
|
|
match props.find_index(name) {
|
|
Ok(idx) => props[idx].value = Some(value.to_string()),
|
|
Err(idx) => props.insert(
|
|
idx,
|
|
PersistentPropertyRecord {
|
|
name: Some(name.to_string()),
|
|
value: Some(value.to_string()),
|
|
},
|
|
),
|
|
}
|
|
proto_write_props(&props)
|
|
} else {
|
|
file_set_prop(name, Some(value))
|
|
}
|
|
}
|
|
inner(name, value).is_ok()
|
|
}
|