Add more to the Utf8CStr family

Better C strings with path operations
This commit is contained in:
topjohnwu
2023-09-12 17:35:01 -07:00
parent 4eaf701cb7
commit 89aee6ffa7
13 changed files with 783 additions and 437 deletions

View File

@@ -3,7 +3,7 @@ use std::fs::File;
use std::io;
use std::sync::{Mutex, OnceLock};
use base::{copy_str, cstr, Directory, ResultExt, Utf8CStr, WalkResult};
use base::{cstr, Directory, ResultExt, Utf8CStr, Utf8CStrBuf, Utf8CStrSlice, WalkResult};
use crate::logging::{magisk_logging, zygisk_logging};
@@ -36,8 +36,7 @@ impl MagiskD {}
pub fn find_apk_path(pkg: &[u8], data: &mut [u8]) -> usize {
use WalkResult::*;
fn inner(pkg: &[u8], data: &mut [u8]) -> io::Result<usize> {
let mut len = 0_usize;
fn inner(pkg: &[u8], buf: &mut dyn Utf8CStrBuf) -> io::Result<usize> {
let pkg = match Utf8CStr::from_bytes(pkg) {
Ok(pkg) => pkg,
Err(e) => return Err(io::Error::new(io::ErrorKind::Other, e)),
@@ -49,7 +48,7 @@ pub fn find_apk_path(pkg: &[u8], data: &mut [u8]) -> usize {
let d_name = e.d_name().to_bytes();
if d_name.starts_with(pkg.as_bytes()) && d_name[pkg.len()] == b'-' {
// Found the APK path, we can abort now
len = e.path(data)?;
e.path(buf)?;
return Ok(Abort);
}
if d_name.starts_with(b"~~") {
@@ -57,10 +56,12 @@ pub fn find_apk_path(pkg: &[u8], data: &mut [u8]) -> usize {
}
Ok(Skip)
})?;
if len > 0 {
len += copy_str(&mut data[len..], "/base.apk");
if !buf.is_empty() {
buf.append("/base.apk");
}
Ok(len)
Ok(buf.len())
}
inner(pkg, data).log().unwrap_or(0)
inner(pkg, &mut Utf8CStrSlice::from(data))
.log()
.unwrap_or(0)
}

View File

@@ -1,5 +1,6 @@
use std::cmp::min;
use std::ffi::{c_char, c_void};
use std::fmt::Write as FmtWrite;
use std::fs::File;
use std::io::{IoSlice, Read, Write};
use std::os::fd::{AsRawFd, FromRawFd, RawFd};
@@ -244,8 +245,8 @@ extern "C" fn logfile_writer(arg: *mut c_void) -> *mut c_void {
let mut logfile: LogFile = Buffer(&mut tmp);
let mut meta = LogMeta::default();
let mut buf: [u8; MAX_MSG_LEN] = [0; MAX_MSG_LEN];
let mut aux: [u8; 64] = [0; 64];
let mut msg_buf = [0u8; MAX_MSG_LEN];
let mut aux = Utf8CStrArr::<64>::new();
loop {
// Read request
@@ -262,16 +263,16 @@ extern "C" fn logfile_writer(arg: *mut c_void) -> *mut c_void {
continue;
}
if meta.len < 0 || meta.len > buf.len() as i32 {
if meta.len < 0 || meta.len > MAX_MSG_LEN as i32 {
continue;
}
// Read the rest of the message
let msg = &mut buf[..(meta.len as usize)];
let msg = &mut msg_buf[..(meta.len as usize)];
pipe.read_exact(msg)?;
// Start building the log string
aux.clear();
let prio =
ALogPriority::from_i32(meta.prio).unwrap_or(ALogPriority::ANDROID_LOG_UNKNOWN);
let prio = match prio {
@@ -287,7 +288,6 @@ extern "C" fn logfile_writer(arg: *mut c_void) -> *mut c_void {
// Note: the obvious better implementation is to use the rust chrono crate, however
// the crate cannot fetch the proper local timezone without pulling in a bunch of
// timezone handling code. To reduce binary size, fallback to use localtime_r in libc.
let mut aux_len: usize;
unsafe {
let mut ts: timespec = std::mem::zeroed();
let mut tm: tm = std::mem::zeroed();
@@ -296,24 +296,22 @@ extern "C" fn logfile_writer(arg: *mut c_void) -> *mut c_void {
{
continue;
}
aux_len = strftime(
aux.as_mut_ptr().cast(),
aux.len(),
let len = strftime(
aux.mut_buf().as_mut_ptr().cast(),
aux.capacity(),
raw_cstr!("%m-%d %T"),
&tm,
);
aux.set_len(len);
let ms = ts.tv_nsec / 1000000;
aux_len += bfmt!(
&mut aux[aux_len..],
aux.write_fmt(format_args!(
".{:03} {:5} {:5} {} : ",
ms,
meta.pid,
meta.tid,
prio
);
ms, meta.pid, meta.tid, prio
))
.ok();
}
let io1 = IoSlice::new(&aux[..aux_len]);
let io1 = IoSlice::new(aux.as_bytes_with_nul());
let io2 = IoSlice::new(msg);
// We don't need to care the written len because we are writing less than PIPE_BUF
// It's guaranteed to always write the whole thing atomically

View File

@@ -1,18 +1,19 @@
use core::ffi::c_char;
use std::io::Read;
use std::{
fs::{read_to_string, remove_file, rename, File},
fs::File,
io::{BufWriter, Write},
ops::{Deref, DerefMut},
os::fd::FromRawFd,
path::{Path, PathBuf},
pin::Pin,
};
use quick_protobuf::{BytesReader, MessageRead, MessageWrite, Writer};
use base::libc::{O_CLOEXEC, O_RDONLY};
use base::{
cstr, debug, libc::mkstemp, raw_cstr, Directory, LoggedError, LoggedResult, MappedFile,
StringExt, Utf8CStr, WalkResult,
cstr, debug, libc::mkstemp, raw_cstr, Directory, FsPath, FsPathBuf, LibcReturn, LoggedError,
LoggedResult, MappedFile, Utf8CStr, Utf8CStrArr, WalkResult,
};
use crate::ffi::{clone_attr, prop_cb_exec, PropCb};
@@ -76,36 +77,41 @@ impl PropExt for PersistentProperties {
}
fn check_proto() -> bool {
Path::new(PERSIST_PROP!()).exists()
FsPath::from(cstr!(PERSIST_PROP!())).exists()
}
fn file_get_prop(name: &Utf8CStr) -> LoggedResult<String> {
let path = PathBuf::new().join(PERSIST_PROP_DIR!()).join(name);
let path = path.as_path();
debug!("resetprop: read prop from [{}]\n", path.display());
Ok(read_to_string(path)?)
let mut buf = Utf8CStrArr::default();
let path = FsPathBuf::new(&mut buf)
.join(PERSIST_PROP_DIR!())
.join(name);
let mut file = path.open(O_RDONLY | O_CLOEXEC)?;
debug!("resetprop: read prop from [{}]\n", 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 path = PathBuf::new().join(PERSIST_PROP_DIR!()).join(name);
let path = path.as_path();
let mut buf = Utf8CStrArr::default();
let path = FsPathBuf::new(&mut buf)
.join(PERSIST_PROP_DIR!())
.join(name);
if let Some(value) = value {
let mut tmp = String::from(concat!(PERSIST_PROP_DIR!(), ".prop.XXXXXX"));
let mut buf = Utf8CStrArr::default();
let mut tmp = FsPathBuf::new(&mut buf).join(concat!(PERSIST_PROP_DIR!(), ".prop.XXXXXX"));
{
let mut f = unsafe {
let fd = mkstemp(tmp.as_mut_ptr() as *mut c_char);
if fd < 0 {
return Err(Default::default());
}
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 [{}]\n", tmp);
rename(tmp, path)?;
tmp.rename_to(path)?
} else {
debug!("resetprop: unlink [{}]\n", path.display());
remove_file(path)?;
debug!("resetprop: unlink [{}]\n", path);
path.remove()?;
}
Ok(())
}
@@ -122,23 +128,18 @@ fn proto_read_props() -> LoggedResult<PersistentProperties> {
}
fn proto_write_props(props: &PersistentProperties) -> LoggedResult<()> {
let mut tmp = String::from(concat!(PERSIST_PROP!(), ".XXXXXX"));
tmp.nul_terminate();
let mut buf = Utf8CStrArr::default();
let mut tmp = FsPathBuf::new(&mut buf).join(concat!(PERSIST_PROP!(), ".XXXXXX"));
{
let f = unsafe {
let fd = mkstemp(tmp.as_mut_ptr().cast());
if fd < 0 {
return Err(Default::default());
}
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)))?;
}
unsafe {
clone_attr(raw_cstr!(PERSIST_PROP!()), tmp.as_ptr().cast());
}
rename(tmp, PERSIST_PROP!())?;
unsafe { clone_attr(raw_cstr!(PERSIST_PROP!()), tmp.as_ptr()) };
tmp.rename_to(cstr!(PERSIST_PROP!()))?;
Ok(())
}