mirror of
https://github.com/topjohnwu/Magisk.git
synced 2025-10-27 15:31:31 +00:00
Simplify OsError
This commit is contained in:
@@ -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
|
||||
}
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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>;
|
||||
|
||||
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user