Simplify OsError

This commit is contained in:
topjohnwu
2025-09-08 11:24:33 -07:00
parent 1df5b34175
commit 17082af438
5 changed files with 115 additions and 158 deletions

View File

@@ -13,7 +13,7 @@ use crate::ffi::{FnBoolStr, FnBoolStrStr};
use crate::files::map_file_at;
pub(crate) use crate::xwrap::*;
use crate::{
BufReadExt, Directory, OsResultStatic, ResultExt, Utf8CStr, clone_attr, cstr, fclone_attr,
BufReadExt, Directory, LoggedResult, ResultExt, Utf8CStr, clone_attr, cstr, fclone_attr,
map_fd, map_file, slice_from_ptr,
};
@@ -54,7 +54,7 @@ unsafe extern "C" fn rm_rf_for_cxx(path: *const c_char) -> bool {
#[unsafe(no_mangle)]
unsafe extern "C" fn frm_rf(fd: OwnedFd) -> bool {
fn inner(fd: OwnedFd) -> OsResultStatic<()> {
fn inner(fd: OwnedFd) -> LoggedResult<()> {
Directory::try_from(fd)?.remove_all()
}
inner(fd).is_ok()
@@ -113,7 +113,7 @@ unsafe extern "C" fn cp_afc_for_cxx(src: *const c_char, dest: *const c_char) ->
if let Ok(src) = Utf8CStr::from_ptr(src)
&& let Ok(dest) = Utf8CStr::from_ptr(dest)
{
return src.copy_to(dest).log().is_ok();
return src.copy_to(dest).is_ok();
}
false
}
@@ -125,7 +125,7 @@ unsafe extern "C" fn mv_path_for_cxx(src: *const c_char, dest: *const c_char) ->
if let Ok(src) = Utf8CStr::from_ptr(src)
&& let Ok(dest) = Utf8CStr::from_ptr(dest)
{
return src.move_to(dest).log().is_ok();
return src.move_to(dest).is_ok();
}
false
}
@@ -137,7 +137,7 @@ unsafe extern "C" fn link_path_for_cxx(src: *const c_char, dest: *const c_char)
if let Ok(src) = Utf8CStr::from_ptr(src)
&& let Ok(dest) = Utf8CStr::from_ptr(dest)
{
return src.link_to(dest).log().is_ok();
return src.link_to(dest).is_ok();
}
false
}

View File

@@ -1,7 +1,7 @@
use crate::cxx_extern::readlinkat;
use crate::{
FsPathBuilder, LibcReturn, OsError, OsResult, OsResultStatic, Utf8CStr, Utf8CStrBuf, cstr,
errno, fd_path, fd_set_attr,
FsPathBuilder, LibcReturn, LoggedResult, OsError, OsResult, Utf8CStr, Utf8CStrBuf, cstr, errno,
fd_path, fd_set_attr,
};
use libc::{EEXIST, O_CLOEXEC, O_CREAT, O_RDONLY, O_TRUNC, O_WRONLY, dirent, mode_t};
use std::fs::File;
@@ -163,6 +163,7 @@ impl Directory {
}
}
// Low-level methods, we should track the caller when error occurs, so return OsResult.
impl Directory {
pub fn open(path: &Utf8CStr) -> OsResult<'_, Directory> {
let dirp = unsafe { libc::opendir(path.as_ptr()) };
@@ -294,22 +295,26 @@ impl Directory {
pub fn resolve_path(&self, buf: &mut dyn Utf8CStrBuf) -> OsResult<'static, ()> {
fd_path(self.as_raw_fd(), buf)
}
}
pub fn post_order_walk<F: FnMut(&DirEntry) -> OsResultStatic<WalkResult>>(
// High-level helper methods, composed of multiple operations.
// We should treat these as application logic and log ASAP, so return LoggedResult.
impl Directory {
pub fn post_order_walk<F: FnMut(&DirEntry) -> LoggedResult<WalkResult>>(
&mut self,
mut f: F,
) -> OsResultStatic<WalkResult> {
) -> LoggedResult<WalkResult> {
self.post_order_walk_impl(&mut f)
}
pub fn pre_order_walk<F: FnMut(&DirEntry) -> OsResultStatic<WalkResult>>(
pub fn pre_order_walk<F: FnMut(&DirEntry) -> LoggedResult<WalkResult>>(
&mut self,
mut f: F,
) -> OsResultStatic<WalkResult> {
) -> LoggedResult<WalkResult> {
self.pre_order_walk_impl(&mut f)
}
pub fn remove_all(mut self) -> OsResultStatic<()> {
pub fn remove_all(mut self) -> LoggedResult<()> {
self.post_order_walk(|e| {
e.unlink()?;
Ok(WalkResult::Continue)
@@ -317,12 +322,12 @@ impl Directory {
Ok(())
}
pub fn copy_into(&mut self, dir: &Directory) -> OsResultStatic<()> {
pub fn copy_into(&mut self, dir: &Directory) -> LoggedResult<()> {
let mut buf = cstr::buf::default();
self.copy_into_impl(dir, &mut buf)
}
pub fn move_into(&mut self, dir: &Directory) -> OsResultStatic<()> {
pub fn move_into(&mut self, dir: &Directory) -> LoggedResult<()> {
let dir_fd = self.as_raw_fd();
while let Some(ref e) = self.read()? {
if e.is_dir() && dir.contains_path(e.name()) {
@@ -346,17 +351,17 @@ impl Directory {
Ok(())
}
pub fn link_into(&mut self, dir: &Directory) -> OsResultStatic<()> {
pub fn link_into(&mut self, dir: &Directory) -> LoggedResult<()> {
let mut buf = cstr::buf::default();
self.link_into_impl(dir, &mut buf)
}
}
impl Directory {
fn post_order_walk_impl<F: FnMut(&DirEntry) -> OsResultStatic<WalkResult>>(
fn post_order_walk_impl<F: FnMut(&DirEntry) -> LoggedResult<WalkResult>>(
&mut self,
f: &mut F,
) -> OsResultStatic<WalkResult> {
) -> LoggedResult<WalkResult> {
use WalkResult::*;
loop {
match self.read()? {
@@ -378,10 +383,10 @@ impl Directory {
}
}
fn pre_order_walk_impl<F: FnMut(&DirEntry) -> OsResultStatic<WalkResult>>(
fn pre_order_walk_impl<F: FnMut(&DirEntry) -> LoggedResult<WalkResult>>(
&mut self,
f: &mut F,
) -> OsResultStatic<WalkResult> {
) -> LoggedResult<WalkResult> {
use WalkResult::*;
loop {
match self.read()? {
@@ -406,7 +411,7 @@ impl Directory {
&mut self,
dest_dir: &Directory,
buf: &mut dyn Utf8CStrBuf,
) -> OsResultStatic<()> {
) -> LoggedResult<()> {
while let Some(ref e) = self.read()? {
e.resolve_path(buf)?;
let attr = buf.get_attr()?;
@@ -436,7 +441,7 @@ impl Directory {
&mut self,
dest_dir: &Directory,
buf: &mut dyn Utf8CStrBuf,
) -> OsResultStatic<()> {
) -> LoggedResult<()> {
let dir_fd = self.as_raw_fd();
while let Some(ref e) = self.read()? {
if e.is_dir() {

View File

@@ -1,5 +1,5 @@
use crate::{
Directory, FsPathFollow, LibcReturn, OsError, OsResult, OsResultStatic, Utf8CStr, Utf8CStrBuf,
Directory, FsPathFollow, LibcReturn, LoggedResult, OsError, OsResult, Utf8CStr, Utf8CStrBuf,
cstr, errno, error,
};
use bytemuck::{Pod, bytes_of, bytes_of_mut};
@@ -219,6 +219,7 @@ impl FileAttr {
const XATTR_NAME_SELINUX: &CStr = c"security.selinux";
// Low-level methods, we should track the caller when error occurs, so return OsResult.
impl Utf8CStr {
pub fn follow_link(&self) -> &FsPathFollow {
unsafe { mem::transmute(self) }
@@ -253,15 +254,6 @@ impl Utf8CStr {
unsafe { libc::remove(self.as_ptr()).check_os_err("remove", Some(self), None) }
}
pub fn remove_all(&self) -> OsResultStatic<()> {
let attr = self.get_attr()?;
if attr.is_dir() {
let dir = Directory::try_from(open_fd(self, O_RDONLY | O_CLOEXEC, 0)?)?;
dir.remove_all()?;
}
Ok(self.remove()?)
}
#[allow(clippy::unnecessary_cast)]
pub fn read_link(&self, buf: &mut dyn Utf8CStrBuf) -> OsResult<'_, ()> {
buf.clear();
@@ -287,35 +279,6 @@ impl Utf8CStr {
Ok(())
}
pub fn mkdirs(&self, mode: mode_t) -> OsResultStatic<()> {
if self.is_empty() {
return Ok(());
}
let mut path = cstr::buf::default();
let mut components = self.split('/').filter(|s| !s.is_empty());
if self.starts_with('/') {
path.append_path("/");
}
loop {
let Some(s) = components.next() else {
break;
};
path.append_path(s);
unsafe {
if libc::mkdir(path.as_ptr(), mode) < 0 && *errno() != EEXIST {
return Err(OsError::last_os_error("mkdir", Some(&path), None))?;
}
}
}
*errno() = 0;
Ok(())
}
// Inspired by https://android.googlesource.com/platform/bionic/+/master/libc/bionic/realpath.cpp
pub fn realpath(&self, buf: &mut dyn Utf8CStrBuf) -> OsResult<'_, ()> {
let fd = self.open(O_PATH | O_CLOEXEC)?;
@@ -408,7 +371,79 @@ impl Utf8CStr {
}
}
pub fn copy_to(&self, path: &Utf8CStr) -> OsResultStatic<()> {
pub fn parent_dir(&self) -> Option<&str> {
Path::new(self.as_str())
.parent()
.map(Path::as_os_str)
// SAFETY: all substring of self is valid UTF-8
.map(|s| unsafe { std::str::from_utf8_unchecked(s.as_bytes()) })
}
pub fn file_name(&self) -> Option<&str> {
Path::new(self.as_str())
.file_name()
// SAFETY: all substring of self is valid UTF-8
.map(|s| unsafe { std::str::from_utf8_unchecked(s.as_bytes()) })
}
// ln -s target self
pub fn create_symlink_to<'a>(&'a self, target: &'a Utf8CStr) -> OsResult<'a, ()> {
unsafe {
libc::symlink(target.as_ptr(), self.as_ptr()).check_os_err(
"symlink",
Some(target),
Some(self),
)
}
}
pub fn mkfifo(&self, mode: mode_t) -> OsResult<'_, ()> {
unsafe { libc::mkfifo(self.as_ptr(), mode).check_os_err("mkfifo", Some(self), None) }
}
}
// High-level helper methods, composed of multiple operations.
// We should treat these as application logic and log ASAP, so return LoggedResult.
impl Utf8CStr {
pub fn remove_all(&self) -> LoggedResult<()> {
let attr = self.get_attr()?;
if attr.is_dir() {
let dir = Directory::try_from(open_fd(self, O_RDONLY | O_CLOEXEC, 0)?)?;
dir.remove_all()?;
}
Ok(self.remove()?)
}
pub fn mkdirs(&self, mode: mode_t) -> LoggedResult<()> {
if self.is_empty() {
return Ok(());
}
let mut path = cstr::buf::default();
let mut components = self.split('/').filter(|s| !s.is_empty());
if self.starts_with('/') {
path.append_path("/");
}
loop {
let Some(s) = components.next() else {
break;
};
path.append_path(s);
unsafe {
if libc::mkdir(path.as_ptr(), mode) < 0 && *errno() != EEXIST {
return Err(OsError::last_os_error("mkdir", Some(&path), None))?;
}
}
}
*errno() = 0;
Ok(())
}
pub fn copy_to(&self, path: &Utf8CStr) -> LoggedResult<()> {
let attr = self.get_attr()?;
if attr.is_dir() {
path.mkdir(0o777)?;
@@ -438,7 +473,7 @@ impl Utf8CStr {
Ok(())
}
pub fn move_to(&self, path: &Utf8CStr) -> OsResultStatic<()> {
pub fn move_to(&self, path: &Utf8CStr) -> LoggedResult<()> {
if path.exists() {
let attr = path.get_attr()?;
if attr.is_dir() {
@@ -453,23 +488,8 @@ impl Utf8CStr {
Ok(())
}
pub fn parent_dir(&self) -> Option<&str> {
Path::new(self.as_str())
.parent()
.map(Path::as_os_str)
// SAFETY: all substring of self is valid UTF-8
.map(|s| unsafe { std::str::from_utf8_unchecked(s.as_bytes()) })
}
pub fn file_name(&self) -> Option<&str> {
Path::new(self.as_str())
.file_name()
// SAFETY: all substring of self is valid UTF-8
.map(|s| unsafe { std::str::from_utf8_unchecked(s.as_bytes()) })
}
// ln self path
pub fn link_to(&self, path: &Utf8CStr) -> OsResultStatic<()> {
pub fn link_to(&self, path: &Utf8CStr) -> LoggedResult<()> {
let attr = self.get_attr()?;
if attr.is_dir() {
path.mkdir(0o777)?;
@@ -488,21 +508,6 @@ impl Utf8CStr {
Ok(())
}
}
// ln -s target self
pub fn create_symlink_to<'a>(&'a self, target: &'a Utf8CStr) -> OsResult<'a, ()> {
unsafe {
libc::symlink(target.as_ptr(), self.as_ptr()).check_os_err(
"symlink",
Some(target),
Some(self),
)
}
}
pub fn mkfifo(&self, mode: mode_t) -> OsResult<'_, ()> {
unsafe { libc::mkfifo(self.as_ptr(), mode).check_os_err("mkfifo", Some(self), None) }
}
}
impl FsPathFollow {

View File

@@ -4,7 +4,6 @@ use std::fmt::Display;
use std::panic::Location;
use std::ptr::NonNull;
use std::{fmt, io};
use thiserror::Error;
// Error handling throughout the Rust codebase in Magisk:
//
@@ -276,43 +275,12 @@ impl<T> LibcReturn for *mut T {
}
}
#[derive(Debug)]
enum OwnableStr<'a> {
None,
Borrowed(&'a str),
Owned(Box<str>),
}
impl OwnableStr<'_> {
fn into_owned(self) -> OwnableStr<'static> {
match self {
OwnableStr::None => OwnableStr::None,
OwnableStr::Borrowed(s) => OwnableStr::Owned(Box::from(s)),
OwnableStr::Owned(s) => OwnableStr::Owned(s),
}
}
fn ok(&self) -> Option<&str> {
match self {
OwnableStr::None => None,
OwnableStr::Borrowed(s) => Some(*s),
OwnableStr::Owned(s) => Some(s),
}
}
}
impl<'a> From<Option<&'a str>> for OwnableStr<'a> {
fn from(value: Option<&'a str>) -> Self {
value.map(OwnableStr::Borrowed).unwrap_or(OwnableStr::None)
}
}
#[derive(Debug)]
pub struct OsError<'a> {
code: i32,
name: &'static str,
arg1: OwnableStr<'a>,
arg2: OwnableStr<'a>,
arg1: Option<&'a str>,
arg2: Option<&'a str>,
}
impl OsError<'_> {
@@ -325,8 +293,8 @@ impl OsError<'_> {
OsError {
code,
name,
arg1: OwnableStr::from(arg1),
arg2: OwnableStr::from(arg2),
arg1,
arg2,
}
}
@@ -342,15 +310,6 @@ impl OsError<'_> {
Self::new(self.code, self.name, arg1, arg2)
}
pub fn into_owned(self) -> OsError<'static> {
OsError {
code: self.code,
name: self.name,
arg1: self.arg1.into_owned(),
arg2: self.arg2.into_owned(),
}
}
fn as_io_error(&self) -> io::Error {
io::Error::from_raw_os_error(self.code)
}
@@ -362,7 +321,7 @@ impl Display for OsError<'_> {
if self.name.is_empty() {
write!(f, "{error:#}")
} else {
match (self.arg1.ok(), self.arg2.ok()) {
match (self.arg1, self.arg2) {
(Some(arg1), Some(arg2)) => {
write!(f, "{} '{}' '{}': {:#}", self.name, arg1, arg2, error)
}
@@ -380,20 +339,3 @@ impl Display for OsError<'_> {
impl std::error::Error for OsError<'_> {}
pub type OsResult<'a, T> = Result<T, OsError<'a>>;
#[derive(Debug, Error)]
pub enum OsErrorStatic {
#[error(transparent)]
Os(OsError<'static>),
#[error(transparent)]
Io(#[from] io::Error),
}
// Convert non-static OsError to static
impl<'a> From<OsError<'a>> for OsErrorStatic {
fn from(value: OsError<'a>) -> Self {
OsErrorStatic::Os(value.into_owned())
}
}
pub type OsResultStatic<T> = Result<T, OsErrorStatic>;

View File

@@ -4,7 +4,7 @@ use crate::ffi::{ModuleInfo, exec_module_scripts, exec_script, get_magisk_tmp};
use crate::mount::setup_module_mount;
use crate::resetprop::load_prop_file;
use base::{
DirEntry, Directory, FsPathBuilder, LibcReturn, LoggedResult, OsResultStatic, ResultExt,
DirEntry, Directory, FsPathBuilder, LibcReturn, LoggedResult, OsResult, ResultExt,
SilentLogExt, Utf8CStr, Utf8CStrBuf, Utf8CString, WalkResult, clone_attr, cstr, debug, error,
info, libc, raw_cstr, warn,
};
@@ -42,7 +42,12 @@ fn bind_mount(reason: &str, src: &Utf8CStr, dest: &Utf8CStr, rec: bool) {
dest.remount_mount_point_flags(MS_RDONLY).log_ok();
}
fn mount_dummy(reason: &str, src: &Utf8CStr, dest: &Utf8CStr, is_dir: bool) -> OsResultStatic<()> {
fn mount_dummy<'a>(
reason: &str,
src: &Utf8CStr,
dest: &'a Utf8CStr,
is_dir: bool,
) -> OsResult<'a, ()> {
if is_dir {
dest.mkdir(0o000)?;
} else {