mirror of
https://github.com/topjohnwu/Magisk.git
synced 2025-04-29 22:14:27 +02:00
Provide richer error messages
Make sure most syscall/libc calls results are mapped to OsResult that can produce more detailed error messages.
This commit is contained in:
parent
c1e061603b
commit
7bd901273c
@ -1,6 +1,5 @@
|
||||
// Functions in this file are only for exporting to C++, DO NOT USE IN RUST
|
||||
|
||||
use std::io;
|
||||
use std::os::fd::{BorrowedFd, OwnedFd, RawFd};
|
||||
|
||||
use cfg_if::cfg_if;
|
||||
@ -9,8 +8,8 @@ use libc::{c_char, mode_t};
|
||||
use crate::files::map_file_at;
|
||||
pub(crate) use crate::xwrap::*;
|
||||
use crate::{
|
||||
CxxResultExt, Directory, FsPath, Utf8CStr, clone_attr, cstr, cstr_buf, fclone_attr, fd_path,
|
||||
map_fd, map_file, slice_from_ptr,
|
||||
CxxResultExt, Directory, FsPath, OsResultStatic, Utf8CStr, clone_attr, cstr, cstr_buf,
|
||||
fclone_attr, fd_path, map_fd, map_file, slice_from_ptr,
|
||||
};
|
||||
|
||||
pub(crate) fn fd_path_for_cxx(fd: RawFd, buf: &mut [u8]) -> isize {
|
||||
@ -57,7 +56,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) -> io::Result<()> {
|
||||
fn inner(fd: OwnedFd) -> OsResultStatic<()> {
|
||||
Directory::try_from(fd)?.remove_all()
|
||||
}
|
||||
inner(fd).is_ok()
|
||||
|
@ -1,14 +1,14 @@
|
||||
use crate::cxx_extern::readlinkat_for_cxx;
|
||||
use crate::{
|
||||
FileAttr, FsPath, LibcReturn, Utf8CStr, Utf8CStrBuf, cstr, cstr_buf, errno, fd_path,
|
||||
fd_set_attr,
|
||||
FileAttr, FsPath, LibcReturn, OsError, OsResult, OsResultStatic, Utf8CStr, Utf8CStrBuf, cstr,
|
||||
cstr_buf, errno, fd_path, fd_set_attr,
|
||||
};
|
||||
use libc::{O_CLOEXEC, O_CREAT, O_RDONLY, O_TRUNC, O_WRONLY, dirent};
|
||||
use libc::{EEXIST, O_CLOEXEC, O_CREAT, O_RDONLY, O_TRUNC, O_WRONLY, dirent, mode_t};
|
||||
use std::ffi::CStr;
|
||||
use std::fs::File;
|
||||
use std::ops::Deref;
|
||||
use std::os::fd::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, OwnedFd, RawFd};
|
||||
use std::{io, mem, slice};
|
||||
use std::{mem, slice};
|
||||
|
||||
pub struct DirEntry<'a> {
|
||||
dir: &'a Directory,
|
||||
@ -26,7 +26,12 @@ impl DirEntry<'_> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn path(&self, buf: &mut dyn Utf8CStrBuf) -> io::Result<()> {
|
||||
#[inline(always)]
|
||||
fn utf8_name(&self) -> Option<&str> {
|
||||
self.name().to_str().ok()
|
||||
}
|
||||
|
||||
pub fn path(&self, buf: &mut dyn Utf8CStrBuf) -> OsResult<'static, ()> {
|
||||
self.dir.path(buf)?;
|
||||
buf.push_str("/");
|
||||
buf.push_lossy(self.name().to_bytes());
|
||||
@ -61,15 +66,19 @@ impl DirEntry<'_> {
|
||||
self.d_type == libc::DT_SOCK
|
||||
}
|
||||
|
||||
pub fn unlink(&self) -> io::Result<()> {
|
||||
pub fn unlink(&self) -> OsResult<()> {
|
||||
let flag = if self.is_dir() { libc::AT_REMOVEDIR } else { 0 };
|
||||
unsafe {
|
||||
libc::unlinkat(self.dir.as_raw_fd(), self.d_name.as_ptr(), flag).check_os_err()?;
|
||||
libc::unlinkat(self.dir.as_raw_fd(), self.d_name.as_ptr(), flag).check_os_err(
|
||||
"unlinkat",
|
||||
self.utf8_name(),
|
||||
None,
|
||||
)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn read_link(&self, buf: &mut dyn Utf8CStrBuf) -> io::Result<()> {
|
||||
pub fn read_link(&self, buf: &mut dyn Utf8CStrBuf) -> OsResult<()> {
|
||||
buf.clear();
|
||||
unsafe {
|
||||
let r = readlinkat_for_cxx(
|
||||
@ -78,52 +87,66 @@ impl DirEntry<'_> {
|
||||
buf.as_mut_ptr().cast(),
|
||||
buf.capacity(),
|
||||
)
|
||||
.check_os_err()? as usize;
|
||||
.as_os_result("readlinkat", self.utf8_name(), None)? as usize;
|
||||
buf.set_len(r);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
unsafe fn open_fd(&self, flags: i32) -> io::Result<RawFd> {
|
||||
unsafe { self.dir.open_raw_fd(self.name(), flags, 0) }
|
||||
}
|
||||
|
||||
pub fn open_as_dir(&self) -> io::Result<Directory> {
|
||||
pub fn open_as_dir(&self) -> OsResult<Directory> {
|
||||
if !self.is_dir() {
|
||||
return Err(io::Error::from(io::ErrorKind::NotADirectory));
|
||||
return Err(OsError::with_os_error(
|
||||
libc::ENOTDIR,
|
||||
"fdopendir",
|
||||
self.utf8_name(),
|
||||
None,
|
||||
));
|
||||
}
|
||||
unsafe { Directory::try_from(OwnedFd::from_raw_fd(self.open_fd(O_RDONLY)?)) }
|
||||
self.dir.openat_as_dir(self.name())
|
||||
}
|
||||
|
||||
pub fn open_as_file(&self, flags: i32) -> io::Result<File> {
|
||||
pub fn open_as_file(&self, flags: i32) -> OsResult<File> {
|
||||
if self.is_dir() {
|
||||
return Err(io::Error::from(io::ErrorKind::IsADirectory));
|
||||
return Err(OsError::with_os_error(
|
||||
libc::EISDIR,
|
||||
"open_as_file",
|
||||
self.utf8_name(),
|
||||
None,
|
||||
));
|
||||
}
|
||||
unsafe { Ok(File::from_raw_fd(self.open_fd(flags)?)) }
|
||||
self.dir.openat_as_file(self.name(), flags, 0)
|
||||
}
|
||||
|
||||
pub fn get_attr(&self) -> io::Result<FileAttr> {
|
||||
pub fn get_attr(&self) -> OsResult<FileAttr> {
|
||||
let mut path = cstr_buf::default();
|
||||
self.path(&mut path)?;
|
||||
FsPath::from(&path).get_attr()
|
||||
FsPath::from(&path)
|
||||
.get_attr()
|
||||
.map_err(|e| e.set_args(self.utf8_name(), None))
|
||||
}
|
||||
|
||||
pub fn set_attr(&self, attr: &FileAttr) -> io::Result<()> {
|
||||
pub fn set_attr(&self, attr: &FileAttr) -> OsResult<()> {
|
||||
let mut path = cstr_buf::default();
|
||||
self.path(&mut path)?;
|
||||
FsPath::from(&path).set_attr(attr)
|
||||
FsPath::from(&path)
|
||||
.set_attr(attr)
|
||||
.map_err(|e| e.set_args(self.utf8_name(), None))
|
||||
}
|
||||
|
||||
pub fn get_secontext(&self, con: &mut dyn Utf8CStrBuf) -> io::Result<()> {
|
||||
pub fn get_secontext(&self, con: &mut dyn Utf8CStrBuf) -> OsResult<()> {
|
||||
let mut path = cstr_buf::default();
|
||||
self.path(&mut path)?;
|
||||
FsPath::from(&path).get_secontext(con)
|
||||
FsPath::from(&path)
|
||||
.get_secontext(con)
|
||||
.map_err(|e| e.set_args(self.utf8_name(), None))
|
||||
}
|
||||
|
||||
pub fn set_secontext(&self, con: &Utf8CStr) -> io::Result<()> {
|
||||
pub fn set_secontext<'a>(&'a self, con: &'a Utf8CStr) -> OsResult<'a, ()> {
|
||||
let mut path = cstr_buf::default();
|
||||
self.path(&mut path)?;
|
||||
FsPath::from(&path).set_secontext(con)
|
||||
FsPath::from(&path)
|
||||
.set_secontext(con)
|
||||
.map_err(|e| e.set_args(self.utf8_name(), Some(con)))
|
||||
}
|
||||
}
|
||||
|
||||
@ -146,17 +169,18 @@ pub enum WalkResult {
|
||||
}
|
||||
|
||||
impl Directory {
|
||||
pub fn open(path: &Utf8CStr) -> io::Result<Directory> {
|
||||
let dirp = unsafe { libc::opendir(path.as_ptr()) }.check_os_err()?;
|
||||
pub fn open(path: &Utf8CStr) -> OsResult<Directory> {
|
||||
let dirp = unsafe { libc::opendir(path.as_ptr()) };
|
||||
let dirp = dirp.as_os_result("opendir", Some(path), None)?;
|
||||
Ok(Directory { dirp })
|
||||
}
|
||||
|
||||
pub fn read(&mut self) -> io::Result<Option<DirEntry<'_>>> {
|
||||
pub fn read(&mut self) -> OsResult<'static, Option<DirEntry>> {
|
||||
*errno() = 0;
|
||||
let e = unsafe { libc::readdir(self.dirp) };
|
||||
if e.is_null() {
|
||||
return if *errno() != 0 {
|
||||
Err(io::Error::last_os_error())
|
||||
Err(OsError::last_os_error("readdir", None, None))
|
||||
} else {
|
||||
Ok(None)
|
||||
};
|
||||
@ -182,17 +206,33 @@ impl Directory {
|
||||
unsafe { libc::rewinddir(self.dirp) }
|
||||
}
|
||||
|
||||
unsafe fn open_raw_fd(&self, name: &CStr, flags: i32, mode: i32) -> io::Result<RawFd> {
|
||||
fn openat<'a>(&self, name: &'a CStr, flags: i32, mode: u32) -> OsResult<'a, OwnedFd> {
|
||||
unsafe {
|
||||
libc::openat(self.as_raw_fd(), name.as_ptr(), flags | O_CLOEXEC, mode).check_os_err()
|
||||
libc::openat(self.as_raw_fd(), name.as_ptr(), flags | O_CLOEXEC, mode)
|
||||
.as_os_result("openat", name.to_str().ok(), None)
|
||||
.map(|fd| OwnedFd::from_raw_fd(fd))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn open_fd(&self, name: &Utf8CStr, flags: i32, mode: i32) -> io::Result<OwnedFd> {
|
||||
pub fn openat_as_dir<'a>(&self, name: &'a CStr) -> OsResult<'a, Directory> {
|
||||
let fd = self.openat(name, O_RDONLY, 0)?;
|
||||
Directory::try_from(fd).map_err(|e| e.set_args(name.to_str().ok(), None))
|
||||
}
|
||||
|
||||
pub fn openat_as_file<'a>(&self, name: &'a CStr, flags: i32, mode: u32) -> OsResult<'a, File> {
|
||||
let fd = self.openat(name, flags, mode)?;
|
||||
Ok(File::from(fd))
|
||||
}
|
||||
|
||||
pub fn mkdirat<'a>(&self, name: &'a CStr, mode: u32) -> OsResult<'a, ()> {
|
||||
unsafe {
|
||||
self.open_raw_fd(name.as_cstr(), flags, mode)
|
||||
.map(|fd| OwnedFd::from_raw_fd(fd))
|
||||
if libc::mkdirat(self.as_raw_fd(), name.as_ptr(), mode as mode_t) < 0
|
||||
&& *errno() != EEXIST
|
||||
{
|
||||
return Err(OsError::last_os_error("mkdirat", name.to_str().ok(), None));
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn contains_path(&self, path: &CStr) -> bool {
|
||||
@ -210,25 +250,25 @@ impl Directory {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn path(&self, buf: &mut dyn Utf8CStrBuf) -> io::Result<()> {
|
||||
pub fn path(&self, buf: &mut dyn Utf8CStrBuf) -> OsResult<'static, ()> {
|
||||
fd_path(self.as_raw_fd(), buf)
|
||||
}
|
||||
|
||||
pub fn post_order_walk<F: FnMut(&DirEntry) -> io::Result<WalkResult>>(
|
||||
pub fn post_order_walk<F: FnMut(&DirEntry) -> OsResultStatic<WalkResult>>(
|
||||
&mut self,
|
||||
mut f: F,
|
||||
) -> io::Result<WalkResult> {
|
||||
) -> OsResultStatic<WalkResult> {
|
||||
self.post_order_walk_impl(&mut f)
|
||||
}
|
||||
|
||||
pub fn pre_order_walk<F: FnMut(&DirEntry) -> io::Result<WalkResult>>(
|
||||
pub fn pre_order_walk<F: FnMut(&DirEntry) -> OsResultStatic<WalkResult>>(
|
||||
&mut self,
|
||||
mut f: F,
|
||||
) -> io::Result<WalkResult> {
|
||||
) -> OsResultStatic<WalkResult> {
|
||||
self.pre_order_walk_impl(&mut f)
|
||||
}
|
||||
|
||||
pub fn remove_all(&mut self) -> io::Result<()> {
|
||||
pub fn remove_all(&mut self) -> OsResultStatic<()> {
|
||||
self.post_order_walk(|e| {
|
||||
e.unlink()?;
|
||||
Ok(WalkResult::Continue)
|
||||
@ -236,60 +276,47 @@ impl Directory {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn copy_into(&mut self, dir: &Directory) -> io::Result<()> {
|
||||
pub fn copy_into(&mut self, dir: &Directory) -> OsResultStatic<()> {
|
||||
while let Some(ref e) = self.read()? {
|
||||
let attr = e.get_attr()?;
|
||||
let new_entry = DirEntry {
|
||||
dir,
|
||||
entry: e.entry,
|
||||
d_name_len: e.d_name_len,
|
||||
};
|
||||
if e.is_dir() {
|
||||
unsafe {
|
||||
libc::mkdirat(dir.as_raw_fd(), e.d_name.as_ptr(), 0o777).as_os_err()?;
|
||||
}
|
||||
dir.mkdirat(e.name(), 0o777)?;
|
||||
let mut src = e.open_as_dir()?;
|
||||
let dest = new_entry.open_as_dir()?;
|
||||
let dest = dir.openat_as_dir(e.name())?;
|
||||
src.copy_into(&dest)?;
|
||||
fd_set_attr(dest.as_raw_fd(), &attr)?;
|
||||
} else if e.is_file() {
|
||||
let mut src = e.open_as_file(O_RDONLY)?;
|
||||
let mut dest = unsafe {
|
||||
File::from_raw_fd(dir.open_raw_fd(
|
||||
e.name(),
|
||||
O_WRONLY | O_CREAT | O_TRUNC,
|
||||
0o777,
|
||||
)?)
|
||||
};
|
||||
let mut dest = dir.openat_as_file(e.name(), O_WRONLY | O_CREAT | O_TRUNC, 0o777)?;
|
||||
std::io::copy(&mut src, &mut dest)?;
|
||||
fd_set_attr(dest.as_raw_fd(), &attr)?;
|
||||
} else if e.is_symlink() {
|
||||
let mut path = cstr_buf::default();
|
||||
e.read_link(&mut path)?;
|
||||
let mut target = cstr_buf::default();
|
||||
e.read_link(&mut target)?;
|
||||
unsafe {
|
||||
libc::symlinkat(path.as_ptr(), dir.as_raw_fd(), e.d_name.as_ptr())
|
||||
.as_os_err()?;
|
||||
libc::symlinkat(target.as_ptr(), dir.as_raw_fd(), e.d_name.as_ptr())
|
||||
.check_os_err("symlinkat", Some(&target), e.utf8_name())?;
|
||||
}
|
||||
let new_entry = DirEntry {
|
||||
dir,
|
||||
entry: e.entry,
|
||||
d_name_len: e.d_name_len,
|
||||
};
|
||||
new_entry.set_attr(&attr)?;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn move_into(&mut self, dir: &Directory) -> io::Result<()> {
|
||||
pub fn move_into(&mut self, dir: &Directory) -> OsResultStatic<()> {
|
||||
let dir_fd = self.as_raw_fd();
|
||||
while let Some(ref e) = self.read()? {
|
||||
if e.is_dir() && dir.contains_path(e.name()) {
|
||||
// Destination folder exists, needs recursive move
|
||||
let mut src = e.open_as_dir()?;
|
||||
let new_entry = DirEntry {
|
||||
dir,
|
||||
entry: e.entry,
|
||||
d_name_len: e.d_name_len,
|
||||
};
|
||||
let dest = new_entry.open_as_dir()?;
|
||||
let dest = dir.openat_as_dir(e.name())?;
|
||||
src.move_into(&dest)?;
|
||||
return e.unlink();
|
||||
return Ok(e.unlink()?);
|
||||
}
|
||||
|
||||
unsafe {
|
||||
@ -299,27 +326,20 @@ impl Directory {
|
||||
dir.as_raw_fd(),
|
||||
e.d_name.as_ptr(),
|
||||
)
|
||||
.as_os_err()?;
|
||||
.check_os_err("renameat", e.utf8_name(), None)?;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn link_into(&mut self, dir: &Directory) -> io::Result<()> {
|
||||
pub fn link_into(&mut self, dir: &Directory) -> OsResultStatic<()> {
|
||||
let dir_fd = self.as_raw_fd();
|
||||
while let Some(ref e) = self.read()? {
|
||||
if e.is_dir() {
|
||||
unsafe {
|
||||
libc::mkdirat(dir.as_raw_fd(), e.d_name.as_ptr(), 0o777).as_os_err()?;
|
||||
}
|
||||
dir.mkdirat(e.name(), 0o777)?;
|
||||
let attr = e.get_attr()?;
|
||||
let new_entry = DirEntry {
|
||||
dir,
|
||||
entry: e.entry,
|
||||
d_name_len: e.d_name_len,
|
||||
};
|
||||
let mut src = e.open_as_dir()?;
|
||||
let dest = new_entry.open_as_dir()?;
|
||||
let dest = dir.openat_as_dir(e.name())?;
|
||||
src.link_into(&dest)?;
|
||||
fd_set_attr(dest.as_raw_fd(), &attr)?;
|
||||
} else {
|
||||
@ -331,7 +351,7 @@ impl Directory {
|
||||
e.d_name.as_ptr(),
|
||||
0,
|
||||
)
|
||||
.as_os_err()?;
|
||||
.check_os_err("linkat", e.utf8_name(), None)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -340,10 +360,10 @@ impl Directory {
|
||||
}
|
||||
|
||||
impl Directory {
|
||||
fn post_order_walk_impl<F: FnMut(&DirEntry) -> io::Result<WalkResult>>(
|
||||
fn post_order_walk_impl<F: FnMut(&DirEntry) -> OsResultStatic<WalkResult>>(
|
||||
&mut self,
|
||||
f: &mut F,
|
||||
) -> io::Result<WalkResult> {
|
||||
) -> OsResultStatic<WalkResult> {
|
||||
use WalkResult::*;
|
||||
loop {
|
||||
match self.read()? {
|
||||
@ -365,10 +385,10 @@ impl Directory {
|
||||
}
|
||||
}
|
||||
|
||||
fn pre_order_walk_impl<F: FnMut(&DirEntry) -> io::Result<WalkResult>>(
|
||||
fn pre_order_walk_impl<F: FnMut(&DirEntry) -> OsResultStatic<WalkResult>>(
|
||||
&mut self,
|
||||
f: &mut F,
|
||||
) -> io::Result<WalkResult> {
|
||||
) -> OsResultStatic<WalkResult> {
|
||||
use WalkResult::*;
|
||||
loop {
|
||||
match self.read()? {
|
||||
@ -391,10 +411,11 @@ impl Directory {
|
||||
}
|
||||
|
||||
impl TryFrom<OwnedFd> for Directory {
|
||||
type Error = io::Error;
|
||||
type Error = OsError<'static>;
|
||||
|
||||
fn try_from(fd: OwnedFd) -> io::Result<Self> {
|
||||
let dirp = unsafe { libc::fdopendir(fd.into_raw_fd()) }.check_os_err()?;
|
||||
fn try_from(fd: OwnedFd) -> OsResult<'static, Self> {
|
||||
let dirp = unsafe { libc::fdopendir(fd.into_raw_fd()) };
|
||||
let dirp = dirp.as_os_result("fdopendir", None, None)?;
|
||||
Ok(Directory { dirp })
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
use crate::{
|
||||
Directory, FsPath, FsPathBuf, FsPathFollow, LibcReturn, Utf8CStr, Utf8CStrBuf, cstr_buf, errno,
|
||||
error,
|
||||
Directory, FsPath, FsPathBuf, FsPathFollow, LibcReturn, OsError, OsResult, OsResultStatic,
|
||||
Utf8CStr, Utf8CStrBuf, cstr_buf, errno, error,
|
||||
};
|
||||
use bytemuck::{Pod, bytes_of, bytes_of_mut};
|
||||
use libc::{
|
||||
@ -19,28 +19,6 @@ use std::os::unix::io::{AsRawFd, FromRawFd, OwnedFd, RawFd};
|
||||
use std::path::Path;
|
||||
use std::{io, mem, ptr, slice};
|
||||
|
||||
pub fn __open_fd_impl(path: &Utf8CStr, flags: i32, mode: mode_t) -> io::Result<OwnedFd> {
|
||||
unsafe {
|
||||
let fd = libc::open(path.as_ptr(), flags, mode as c_uint).check_os_err()?;
|
||||
Ok(OwnedFd::from_raw_fd(fd))
|
||||
}
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! open_fd {
|
||||
($path:expr, $flags:expr) => {
|
||||
$crate::__open_fd_impl($path, $flags, 0)
|
||||
};
|
||||
($path:expr, $flags:expr, $mode:expr) => {
|
||||
$crate::__open_fd_impl($path, $flags, $mode)
|
||||
};
|
||||
}
|
||||
|
||||
pub fn fd_path(fd: RawFd, buf: &mut dyn Utf8CStrBuf) -> io::Result<()> {
|
||||
let path = FsPathBuf::default().join("/proc/self/fd").join_fmt(fd);
|
||||
path.read_link(buf)
|
||||
}
|
||||
|
||||
pub trait ReadExt {
|
||||
fn skip(&mut self, len: usize) -> io::Result<()>;
|
||||
fn read_pod<F: Pod>(&mut self, data: &mut F) -> io::Result<()>;
|
||||
@ -137,6 +115,32 @@ impl<T: Write> WriteExt for T {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn __open_fd_impl(path: &Utf8CStr, flags: i32, mode: mode_t) -> OsResult<OwnedFd> {
|
||||
unsafe {
|
||||
let fd = libc::open(path.as_ptr(), flags, mode as c_uint).as_os_result(
|
||||
"open",
|
||||
Some(path),
|
||||
None,
|
||||
)?;
|
||||
Ok(OwnedFd::from_raw_fd(fd))
|
||||
}
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! open_fd {
|
||||
($path:expr, $flags:expr) => {
|
||||
$crate::__open_fd_impl($path, $flags, 0)
|
||||
};
|
||||
($path:expr, $flags:expr, $mode:expr) => {
|
||||
$crate::__open_fd_impl($path, $flags, $mode)
|
||||
};
|
||||
}
|
||||
|
||||
pub fn fd_path(fd: RawFd, buf: &mut dyn Utf8CStrBuf) -> OsResult<'static, ()> {
|
||||
let path = FsPathBuf::default().join("/proc/self/fd").join_fmt(fd);
|
||||
path.read_link(buf).map_err(|e| e.set_args(None, None))
|
||||
}
|
||||
|
||||
pub struct FileAttr {
|
||||
pub st: libc::stat,
|
||||
#[cfg(feature = "selinux")]
|
||||
@ -194,11 +198,11 @@ impl FsPath {
|
||||
unsafe { mem::transmute(self) }
|
||||
}
|
||||
|
||||
pub fn open(&self, flags: i32) -> io::Result<File> {
|
||||
pub fn open(&self, flags: i32) -> OsResult<File> {
|
||||
Ok(File::from(open_fd!(self, flags)?))
|
||||
}
|
||||
|
||||
pub fn create(&self, flags: i32, mode: mode_t) -> io::Result<File> {
|
||||
pub fn create(&self, flags: i32, mode: mode_t) -> OsResult<File> {
|
||||
Ok(File::from(open_fd!(self, O_CREAT | flags, mode)?))
|
||||
}
|
||||
|
||||
@ -209,75 +213,80 @@ impl FsPath {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn rename_to<T: AsRef<Utf8CStr>>(&self, name: T) -> io::Result<()> {
|
||||
unsafe { libc::rename(self.as_ptr(), name.as_ref().as_ptr()).as_os_err() }
|
||||
pub fn rename_to<'a>(&'a self, name: &'a FsPath) -> OsResult<'a, ()> {
|
||||
unsafe {
|
||||
libc::rename(self.as_ptr(), name.as_ptr()).check_os_err(
|
||||
"rename",
|
||||
Some(self),
|
||||
Some(name),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn remove(&self) -> io::Result<()> {
|
||||
unsafe { libc::remove(self.as_ptr()).as_os_err() }
|
||||
pub fn remove(&self) -> OsResult<()> {
|
||||
unsafe { libc::remove(self.as_ptr()).check_os_err("remove", Some(self), None) }
|
||||
}
|
||||
|
||||
pub fn remove_all(&self) -> io::Result<()> {
|
||||
pub fn remove_all(&self) -> OsResultStatic<()> {
|
||||
let attr = self.get_attr()?;
|
||||
if attr.is_dir() {
|
||||
let mut dir = Directory::try_from(open_fd!(self, O_RDONLY | O_CLOEXEC)?)?;
|
||||
dir.remove_all()?;
|
||||
}
|
||||
self.remove()
|
||||
Ok(self.remove()?)
|
||||
}
|
||||
|
||||
#[allow(clippy::unnecessary_cast)]
|
||||
pub fn read_link(&self, buf: &mut dyn Utf8CStrBuf) -> io::Result<()> {
|
||||
pub fn read_link(&self, buf: &mut dyn Utf8CStrBuf) -> OsResult<()> {
|
||||
buf.clear();
|
||||
unsafe {
|
||||
let r = libc::readlink(self.as_ptr(), buf.as_mut_ptr(), buf.capacity() - 1)
|
||||
.check_os_err()? as isize;
|
||||
.as_os_result("readlink", Some(self), None)? as isize;
|
||||
*(buf.as_mut_ptr().offset(r) as *mut u8) = b'\0';
|
||||
buf.set_len(r as usize);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn mkdir(&self, mode: mode_t) -> io::Result<()> {
|
||||
pub fn mkdir(&self, mode: mode_t) -> OsResult<()> {
|
||||
unsafe {
|
||||
if libc::mkdir(self.as_ptr(), mode) < 0 {
|
||||
if *errno() == EEXIST {
|
||||
libc::chmod(self.as_ptr(), mode).as_os_err()?;
|
||||
libc::chmod(self.as_ptr(), mode).check_os_err("chmod", Some(self), None)?;
|
||||
} else {
|
||||
return Err(io::Error::last_os_error());
|
||||
return Err(OsError::last_os_error("mkdir", Some(self), None));
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn mkdirs(&self, mode: mode_t) -> io::Result<()> {
|
||||
pub fn mkdirs(&self, mode: mode_t) -> OsResultStatic<()> {
|
||||
if self.is_empty() {
|
||||
return Ok(());
|
||||
}
|
||||
let mut arr = cstr_buf::default();
|
||||
arr.push_str(self);
|
||||
let mut off = 1;
|
||||
unsafe {
|
||||
let buf = arr.as_bytes_mut();
|
||||
while let Some(p) = buf[off..].iter().position(|c| *c == b'/') {
|
||||
buf[off + p] = b'\0';
|
||||
if libc::mkdir(buf.as_ptr().cast(), mode) < 0 && *errno() != EEXIST {
|
||||
return Err(io::Error::last_os_error());
|
||||
|
||||
let mut path = FsPathBuf::default();
|
||||
let mut components = self.split('/').filter(|s| !s.is_empty());
|
||||
loop {
|
||||
let Some(s) = components.next() else {
|
||||
break;
|
||||
};
|
||||
path = path.join(s);
|
||||
|
||||
unsafe {
|
||||
if libc::mkdir(path.as_ptr(), mode) < 0 && *errno() != EEXIST {
|
||||
return Err(OsError::last_os_error("mkdir", Some(&path), None))?;
|
||||
}
|
||||
buf[off + p] = b'/';
|
||||
off += p + 1;
|
||||
}
|
||||
if libc::mkdir(buf.as_ptr().cast(), mode) < 0 && *errno() != EEXIST {
|
||||
return Err(io::Error::last_os_error());
|
||||
}
|
||||
}
|
||||
|
||||
*errno() = 0;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// Inspired by https://android.googlesource.com/platform/bionic/+/master/libc/bionic/realpath.cpp
|
||||
pub fn realpath(&self, buf: &mut dyn Utf8CStrBuf) -> io::Result<()> {
|
||||
pub fn realpath(&self, buf: &mut dyn Utf8CStrBuf) -> OsResult<()> {
|
||||
let fd = open_fd!(self, O_PATH | O_CLOEXEC)?;
|
||||
let mut st1: libc::stat;
|
||||
let mut st2: libc::stat;
|
||||
@ -292,19 +301,19 @@ impl FsPath {
|
||||
fd_path(fd.as_raw_fd(), buf)?;
|
||||
unsafe {
|
||||
st2 = mem::zeroed();
|
||||
libc::stat(buf.as_ptr(), &mut st2).as_os_err()?;
|
||||
libc::stat(buf.as_ptr(), &mut st2).check_os_err("stat", Some(self), None)?;
|
||||
if !skip_check && (st2.st_dev != st1.st_dev || st2.st_ino != st1.st_ino) {
|
||||
*errno() = ENOENT;
|
||||
return Err(io::Error::last_os_error());
|
||||
return Err(OsError::last_os_error("realpath", Some(self), None));
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn get_attr(&self) -> io::Result<FileAttr> {
|
||||
pub fn get_attr(&self) -> OsResult<FileAttr> {
|
||||
let mut attr = FileAttr::new();
|
||||
unsafe {
|
||||
libc::lstat(self.as_ptr(), &mut attr.st).as_os_err()?;
|
||||
libc::lstat(self.as_ptr(), &mut attr.st).check_os_err("lstat", Some(self), None)?;
|
||||
|
||||
#[cfg(feature = "selinux")]
|
||||
self.get_secontext(&mut attr.con)?;
|
||||
@ -312,12 +321,20 @@ impl FsPath {
|
||||
Ok(attr)
|
||||
}
|
||||
|
||||
pub fn set_attr(&self, attr: &FileAttr) -> io::Result<()> {
|
||||
pub fn set_attr<'a>(&'a self, attr: &'a FileAttr) -> OsResult<'a, ()> {
|
||||
unsafe {
|
||||
if !attr.is_symlink() {
|
||||
libc::chmod(self.as_ptr(), (attr.st.st_mode & 0o777).as_()).as_os_err()?;
|
||||
libc::chmod(self.as_ptr(), (attr.st.st_mode & 0o777).as_()).check_os_err(
|
||||
"chmod",
|
||||
Some(self),
|
||||
None,
|
||||
)?;
|
||||
}
|
||||
libc::lchown(self.as_ptr(), attr.st.st_uid, attr.st.st_gid).as_os_err()?;
|
||||
libc::lchown(self.as_ptr(), attr.st.st_uid, attr.st.st_gid).check_os_err(
|
||||
"lchown",
|
||||
Some(self),
|
||||
None,
|
||||
)?;
|
||||
|
||||
#[cfg(feature = "selinux")]
|
||||
if !attr.con.is_empty() {
|
||||
@ -327,7 +344,7 @@ impl FsPath {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn get_secontext(&self, con: &mut dyn Utf8CStrBuf) -> io::Result<()> {
|
||||
pub fn get_secontext(&self, con: &mut dyn Utf8CStrBuf) -> OsResult<()> {
|
||||
unsafe {
|
||||
let sz = libc::lgetxattr(
|
||||
self.as_ptr(),
|
||||
@ -338,7 +355,7 @@ impl FsPath {
|
||||
if sz < 1 {
|
||||
con.clear();
|
||||
if *errno() != libc::ENODATA {
|
||||
return Err(io::Error::last_os_error());
|
||||
return Err(OsError::last_os_error("lgetxattr", Some(self), None));
|
||||
}
|
||||
} else {
|
||||
con.set_len((sz - 1) as usize);
|
||||
@ -347,7 +364,7 @@ impl FsPath {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn set_secontext(&self, con: &Utf8CStr) -> io::Result<()> {
|
||||
pub fn set_secontext<'a>(&'a self, con: &'a Utf8CStr) -> OsResult<'a, ()> {
|
||||
unsafe {
|
||||
libc::lsetxattr(
|
||||
self.as_ptr(),
|
||||
@ -356,11 +373,11 @@ impl FsPath {
|
||||
con.len() + 1,
|
||||
0,
|
||||
)
|
||||
.as_os_err()
|
||||
.check_os_err("lsetxattr", Some(self), Some(con))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn copy_to(&self, path: &FsPath) -> io::Result<()> {
|
||||
pub fn copy_to(&self, path: &FsPath) -> OsResultStatic<()> {
|
||||
let attr = self.get_attr()?;
|
||||
if attr.is_dir() {
|
||||
path.mkdir(0o777)?;
|
||||
@ -378,7 +395,11 @@ impl FsPath {
|
||||
let mut buf = cstr_buf::default();
|
||||
self.read_link(&mut buf)?;
|
||||
unsafe {
|
||||
libc::symlink(buf.as_ptr(), path.as_ptr()).as_os_err()?;
|
||||
libc::symlink(buf.as_ptr(), path.as_ptr()).check_os_err(
|
||||
"symlink",
|
||||
Some(&buf),
|
||||
Some(path),
|
||||
)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -386,7 +407,7 @@ impl FsPath {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn move_to(&self, path: &FsPath) -> io::Result<()> {
|
||||
pub fn move_to(&self, path: &FsPath) -> OsResultStatic<()> {
|
||||
if path.exists() {
|
||||
let attr = path.get_attr()?;
|
||||
if attr.is_dir() {
|
||||
@ -397,7 +418,8 @@ impl FsPath {
|
||||
path.remove()?;
|
||||
}
|
||||
}
|
||||
self.rename_to(path)
|
||||
self.rename_to(path)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn parent(&self, buf: &mut dyn Utf8CStrBuf) -> bool {
|
||||
@ -414,26 +436,39 @@ impl FsPath {
|
||||
}
|
||||
|
||||
// ln self path
|
||||
pub fn link_to(&self, path: &FsPath) -> io::Result<()> {
|
||||
pub fn link_to(&self, path: &FsPath) -> OsResultStatic<()> {
|
||||
let attr = self.get_attr()?;
|
||||
if attr.is_dir() {
|
||||
path.mkdir(0o777)?;
|
||||
path.set_attr(&attr)?;
|
||||
let mut src = Directory::open(self)?;
|
||||
let dest = Directory::open(path)?;
|
||||
src.link_into(&dest)
|
||||
Ok(src.link_into(&dest)?)
|
||||
} else {
|
||||
unsafe { libc::link(self.as_ptr(), path.as_ptr()).as_os_err() }
|
||||
unsafe {
|
||||
libc::link(self.as_ptr(), path.as_ptr()).check_os_err(
|
||||
"link",
|
||||
Some(self),
|
||||
Some(path),
|
||||
)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
// ln -s target self
|
||||
pub fn create_symlink_to(&self, target: &FsPath) -> io::Result<()> {
|
||||
unsafe { libc::symlink(target.as_ptr(), self.as_ptr()).as_os_err() }
|
||||
pub fn create_symlink_to<'a>(&'a self, target: &'a FsPath) -> 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) -> io::Result<()> {
|
||||
unsafe { libc::mkfifo(self.as_ptr(), mode).as_os_err() }
|
||||
pub fn mkfifo(&self, mode: mode_t) -> OsResult<()> {
|
||||
unsafe { libc::mkfifo(self.as_ptr(), mode).check_os_err("mkfifo", Some(self), None) }
|
||||
}
|
||||
}
|
||||
|
||||
@ -442,10 +477,10 @@ impl FsPathFollow {
|
||||
unsafe { libc::access(self.as_ptr(), F_OK) == 0 }
|
||||
}
|
||||
|
||||
pub fn get_attr(&self) -> io::Result<FileAttr> {
|
||||
pub fn get_attr(&self) -> OsResult<FileAttr> {
|
||||
let mut attr = FileAttr::new();
|
||||
unsafe {
|
||||
libc::stat(self.as_ptr(), &mut attr.st).as_os_err()?;
|
||||
libc::stat(self.as_ptr(), &mut attr.st).check_os_err("stat", Some(self), None)?;
|
||||
|
||||
#[cfg(feature = "selinux")]
|
||||
self.get_secontext(&mut attr.con)?;
|
||||
@ -453,10 +488,18 @@ impl FsPathFollow {
|
||||
Ok(attr)
|
||||
}
|
||||
|
||||
pub fn set_attr(&self, attr: &FileAttr) -> io::Result<()> {
|
||||
pub fn set_attr<'a>(&'a self, attr: &'a FileAttr) -> OsResult<'a, ()> {
|
||||
unsafe {
|
||||
libc::chmod(self.as_ptr(), (attr.st.st_mode & 0o777).as_()).as_os_err()?;
|
||||
libc::chown(self.as_ptr(), attr.st.st_uid, attr.st.st_gid).as_os_err()?;
|
||||
libc::chmod(self.as_ptr(), (attr.st.st_mode & 0o777).as_()).check_os_err(
|
||||
"chmod",
|
||||
Some(self),
|
||||
None,
|
||||
)?;
|
||||
libc::chown(self.as_ptr(), attr.st.st_uid, attr.st.st_gid).check_os_err(
|
||||
"chown",
|
||||
Some(self),
|
||||
None,
|
||||
)?;
|
||||
|
||||
#[cfg(feature = "selinux")]
|
||||
if !attr.con.is_empty() {
|
||||
@ -466,7 +509,7 @@ impl FsPathFollow {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn get_secontext(&self, con: &mut dyn Utf8CStrBuf) -> io::Result<()> {
|
||||
pub fn get_secontext(&self, con: &mut dyn Utf8CStrBuf) -> OsResult<()> {
|
||||
unsafe {
|
||||
let sz = libc::getxattr(
|
||||
self.as_ptr(),
|
||||
@ -477,7 +520,7 @@ impl FsPathFollow {
|
||||
if sz < 1 {
|
||||
con.clear();
|
||||
if *errno() != libc::ENODATA {
|
||||
return Err(io::Error::last_os_error());
|
||||
return Err(OsError::last_os_error("getxattr", Some(self), None));
|
||||
}
|
||||
} else {
|
||||
con.set_len((sz - 1) as usize);
|
||||
@ -486,7 +529,7 @@ impl FsPathFollow {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn set_secontext(&self, con: &Utf8CStr) -> io::Result<()> {
|
||||
pub fn set_secontext<'a>(&'a self, con: &'a Utf8CStr) -> OsResult<'a, ()> {
|
||||
unsafe {
|
||||
libc::setxattr(
|
||||
self.as_ptr(),
|
||||
@ -495,86 +538,97 @@ impl FsPathFollow {
|
||||
con.len() + 1,
|
||||
0,
|
||||
)
|
||||
.as_os_err()
|
||||
.check_os_err("setxattr", Some(self), Some(con))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn fd_get_attr(fd: RawFd) -> io::Result<FileAttr> {
|
||||
pub fn fd_get_attr(fd: RawFd) -> OsResult<'static, FileAttr> {
|
||||
let mut attr = FileAttr::new();
|
||||
unsafe {
|
||||
libc::fstat(fd, &mut attr.st).as_os_err()?;
|
||||
libc::fstat(fd, &mut attr.st).check_os_err("fstat", None, None)?;
|
||||
|
||||
#[cfg(feature = "selinux")]
|
||||
{
|
||||
let sz = libc::fgetxattr(
|
||||
fd,
|
||||
XATTR_NAME_SELINUX.as_ptr(),
|
||||
attr.con.as_mut_ptr().cast(),
|
||||
attr.con.capacity(),
|
||||
);
|
||||
if sz < 1 {
|
||||
if *errno() != libc::ENODATA {
|
||||
return Err(io::Error::last_os_error());
|
||||
}
|
||||
} else {
|
||||
attr.con.set_len((sz - 1) as usize);
|
||||
}
|
||||
}
|
||||
fd_get_secontext(fd, &mut attr.con)?;
|
||||
}
|
||||
Ok(attr)
|
||||
}
|
||||
|
||||
pub fn fd_set_attr(fd: RawFd, attr: &FileAttr) -> io::Result<()> {
|
||||
pub fn fd_set_attr(fd: RawFd, attr: &FileAttr) -> OsResult<()> {
|
||||
unsafe {
|
||||
libc::fchmod(fd, (attr.st.st_mode & 0o777).as_()).as_os_err()?;
|
||||
libc::fchown(fd, attr.st.st_uid, attr.st.st_gid).as_os_err()?;
|
||||
libc::fchmod(fd, (attr.st.st_mode & 0o777).as_()).check_os_err("fchmod", None, None)?;
|
||||
libc::fchown(fd, attr.st.st_uid, attr.st.st_gid).check_os_err("fchown", None, None)?;
|
||||
|
||||
#[cfg(feature = "selinux")]
|
||||
if !attr.con.is_empty() {
|
||||
libc::fsetxattr(
|
||||
fd,
|
||||
XATTR_NAME_SELINUX.as_ptr(),
|
||||
attr.con.as_ptr().cast(),
|
||||
attr.con.len() + 1,
|
||||
0,
|
||||
)
|
||||
.as_os_err()?;
|
||||
fd_set_secontext(fd, &attr.con)?;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn clone_attr(a: &FsPath, b: &FsPath) -> io::Result<()> {
|
||||
let attr = a.get_attr()?;
|
||||
b.set_attr(&attr)
|
||||
pub fn fd_get_secontext(fd: RawFd, con: &mut dyn Utf8CStrBuf) -> OsResult<'static, ()> {
|
||||
unsafe {
|
||||
let sz = libc::fgetxattr(
|
||||
fd,
|
||||
XATTR_NAME_SELINUX.as_ptr(),
|
||||
con.as_mut_ptr().cast(),
|
||||
con.capacity(),
|
||||
);
|
||||
if sz < 1 {
|
||||
if *errno() != libc::ENODATA {
|
||||
return Err(OsError::last_os_error("fgetxattr", None, None));
|
||||
}
|
||||
} else {
|
||||
con.set_len((sz - 1) as usize);
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn fclone_attr(a: RawFd, b: RawFd) -> io::Result<()> {
|
||||
pub fn fd_set_secontext(fd: RawFd, con: &Utf8CStr) -> OsResult<()> {
|
||||
unsafe {
|
||||
libc::fsetxattr(
|
||||
fd,
|
||||
XATTR_NAME_SELINUX.as_ptr(),
|
||||
con.as_ptr().cast(),
|
||||
con.len() + 1,
|
||||
0,
|
||||
)
|
||||
.check_os_err("fsetxattr", Some(con), None)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn clone_attr<'a>(a: &'a FsPath, b: &'a FsPath) -> OsResult<'a, ()> {
|
||||
let attr = a.get_attr()?;
|
||||
b.set_attr(&attr).map_err(|e| e.set_args(Some(b), None))
|
||||
}
|
||||
|
||||
pub fn fclone_attr(a: RawFd, b: RawFd) -> OsResult<'static, ()> {
|
||||
let attr = fd_get_attr(a)?;
|
||||
fd_set_attr(b, &attr)
|
||||
fd_set_attr(b, &attr).map_err(|e| e.set_args(None, None))
|
||||
}
|
||||
|
||||
pub struct MappedFile(&'static mut [u8]);
|
||||
|
||||
impl MappedFile {
|
||||
pub fn open(path: &Utf8CStr) -> io::Result<MappedFile> {
|
||||
pub fn open(path: &Utf8CStr) -> OsResult<MappedFile> {
|
||||
Ok(MappedFile(map_file(path, false)?))
|
||||
}
|
||||
|
||||
pub fn open_rw(path: &Utf8CStr) -> io::Result<MappedFile> {
|
||||
pub fn open_rw(path: &Utf8CStr) -> OsResult<MappedFile> {
|
||||
Ok(MappedFile(map_file(path, true)?))
|
||||
}
|
||||
|
||||
pub fn openat<T: AsFd>(dir: &T, path: &Utf8CStr) -> io::Result<MappedFile> {
|
||||
pub fn openat<'a, T: AsFd>(dir: &T, path: &'a Utf8CStr) -> OsResult<'a, MappedFile> {
|
||||
Ok(MappedFile(map_file_at(dir.as_fd(), path, false)?))
|
||||
}
|
||||
|
||||
pub fn openat_rw<T: AsFd>(dir: &T, path: &Utf8CStr) -> io::Result<MappedFile> {
|
||||
pub fn openat_rw<'a, T: AsFd>(dir: &T, path: &'a Utf8CStr) -> OsResult<'a, MappedFile> {
|
||||
Ok(MappedFile(map_file_at(dir.as_fd(), path, true)?))
|
||||
}
|
||||
|
||||
pub fn create(fd: BorrowedFd, sz: usize, rw: bool) -> io::Result<MappedFile> {
|
||||
pub fn create(fd: BorrowedFd, sz: usize, rw: bool) -> OsResult<MappedFile> {
|
||||
Ok(MappedFile(map_fd(fd, sz, rw)?))
|
||||
}
|
||||
}
|
||||
@ -605,15 +659,15 @@ unsafe extern "C" {
|
||||
}
|
||||
|
||||
// We mark the returned slice static because it is valid until explicitly unmapped
|
||||
pub(crate) fn map_file(path: &Utf8CStr, rw: bool) -> io::Result<&'static mut [u8]> {
|
||||
pub(crate) fn map_file(path: &Utf8CStr, rw: bool) -> OsResult<&'static mut [u8]> {
|
||||
unsafe { map_file_at(BorrowedFd::borrow_raw(libc::AT_FDCWD), path, rw) }
|
||||
}
|
||||
|
||||
pub(crate) fn map_file_at(
|
||||
pub(crate) fn map_file_at<'a>(
|
||||
dirfd: BorrowedFd,
|
||||
path: &Utf8CStr,
|
||||
path: &'a Utf8CStr,
|
||||
rw: bool,
|
||||
) -> io::Result<&'static mut [u8]> {
|
||||
) -> OsResult<'a, &'static mut [u8]> {
|
||||
#[cfg(target_pointer_width = "64")]
|
||||
const BLKGETSIZE64: u32 = 0x80081272;
|
||||
|
||||
@ -623,23 +677,29 @@ pub(crate) fn map_file_at(
|
||||
let flag = if rw { O_RDWR } else { O_RDONLY };
|
||||
let fd = unsafe {
|
||||
OwnedFd::from_raw_fd(
|
||||
libc::openat(dirfd.as_raw_fd(), path.as_ptr(), flag | O_CLOEXEC).check_os_err()?,
|
||||
libc::openat(dirfd.as_raw_fd(), path.as_ptr(), flag | O_CLOEXEC).as_os_result(
|
||||
"openat",
|
||||
Some(path),
|
||||
None,
|
||||
)?,
|
||||
)
|
||||
};
|
||||
|
||||
let attr = fd_get_attr(fd.as_raw_fd())?;
|
||||
let sz = if attr.is_block_device() {
|
||||
let mut sz = 0_u64;
|
||||
unsafe { ioctl(fd.as_raw_fd(), BLKGETSIZE64, &mut sz) }.as_os_err()?;
|
||||
unsafe {
|
||||
ioctl(fd.as_raw_fd(), BLKGETSIZE64, &mut sz).check_os_err("ioctl", Some(path), None)?;
|
||||
}
|
||||
sz
|
||||
} else {
|
||||
attr.st.st_size as u64
|
||||
};
|
||||
|
||||
map_fd(fd.as_fd(), sz as usize, rw)
|
||||
map_fd(fd.as_fd(), sz as usize, rw).map_err(|e| e.set_args(Some(path), None))
|
||||
}
|
||||
|
||||
pub(crate) fn map_fd(fd: BorrowedFd, sz: usize, rw: bool) -> io::Result<&'static mut [u8]> {
|
||||
pub(crate) fn map_fd(fd: BorrowedFd, sz: usize, rw: bool) -> OsResult<'static, &'static mut [u8]> {
|
||||
let flag = if rw {
|
||||
libc::MAP_SHARED
|
||||
} else {
|
||||
@ -655,7 +715,7 @@ pub(crate) fn map_fd(fd: BorrowedFd, sz: usize, rw: bool) -> io::Result<&'static
|
||||
0,
|
||||
);
|
||||
if ptr == libc::MAP_FAILED {
|
||||
return Err(io::Error::last_os_error());
|
||||
return Err(OsError::last_os_error("mmap", None, None));
|
||||
}
|
||||
Ok(slice::from_raw_parts_mut(ptr.cast(), sz))
|
||||
}
|
||||
|
@ -7,7 +7,7 @@ use std::mem::ManuallyDrop;
|
||||
use std::process::exit;
|
||||
use std::sync::Arc;
|
||||
use std::sync::atomic::{AtomicPtr, Ordering};
|
||||
use std::{fmt, io, slice, str};
|
||||
use std::{fmt, slice, str};
|
||||
|
||||
pub fn errno() -> &'static mut i32 {
|
||||
unsafe { &mut *libc::__errno() }
|
||||
@ -37,52 +37,6 @@ pub unsafe fn slice_from_ptr_mut<'a, T>(buf: *mut T, len: usize) -> &'a mut [T]
|
||||
}
|
||||
}
|
||||
|
||||
// Check libc return value and map to Result
|
||||
pub trait LibcReturn
|
||||
where
|
||||
Self: Copy,
|
||||
{
|
||||
fn is_error(&self) -> bool;
|
||||
fn check_os_err(self) -> io::Result<Self> {
|
||||
if self.is_error() {
|
||||
Err(io::Error::last_os_error())
|
||||
} else {
|
||||
Ok(self)
|
||||
}
|
||||
}
|
||||
fn as_os_err(self) -> io::Result<()> {
|
||||
self.check_os_err()?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! impl_libc_return {
|
||||
($($t:ty)*) => ($(
|
||||
impl LibcReturn for $t {
|
||||
#[inline]
|
||||
fn is_error(&self) -> bool {
|
||||
*self < 0
|
||||
}
|
||||
}
|
||||
)*)
|
||||
}
|
||||
|
||||
impl_libc_return! { i8 i16 i32 i64 isize }
|
||||
|
||||
impl<T> LibcReturn for *const T {
|
||||
#[inline]
|
||||
fn is_error(&self) -> bool {
|
||||
self.is_null()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> LibcReturn for *mut T {
|
||||
#[inline]
|
||||
fn is_error(&self) -> bool {
|
||||
self.is_null()
|
||||
}
|
||||
}
|
||||
|
||||
pub trait BytesExt {
|
||||
fn find(&self, needle: &[u8]) -> Option<usize>;
|
||||
fn contains(&self, needle: &[u8]) -> bool {
|
||||
|
@ -1,9 +1,9 @@
|
||||
use crate::{FsPath, LibcReturn, Utf8CStr};
|
||||
use crate::{FsPath, LibcReturn, OsResult, Utf8CStr};
|
||||
use libc::c_ulong;
|
||||
use std::ptr;
|
||||
|
||||
impl FsPath {
|
||||
pub fn bind_mount_to(&self, path: &FsPath) -> std::io::Result<()> {
|
||||
pub fn bind_mount_to<'a>(&'a self, path: &'a FsPath) -> OsResult<'a, ()> {
|
||||
unsafe {
|
||||
libc::mount(
|
||||
self.as_ptr(),
|
||||
@ -12,11 +12,11 @@ impl FsPath {
|
||||
libc::MS_BIND,
|
||||
ptr::null(),
|
||||
)
|
||||
.as_os_err()
|
||||
.check_os_err("bind_mount", Some(self), Some(path))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn remount_with_flags(&self, flags: c_ulong) -> std::io::Result<()> {
|
||||
pub fn remount_with_flags(&self, flags: c_ulong) -> OsResult<()> {
|
||||
unsafe {
|
||||
libc::mount(
|
||||
ptr::null(),
|
||||
@ -25,11 +25,11 @@ impl FsPath {
|
||||
libc::MS_BIND | libc::MS_REMOUNT | flags,
|
||||
ptr::null(),
|
||||
)
|
||||
.as_os_err()
|
||||
.check_os_err("remount", Some(self), None)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn remount_with_data(&self, data: &Utf8CStr) -> std::io::Result<()> {
|
||||
pub fn remount_with_data(&self, data: &Utf8CStr) -> OsResult<()> {
|
||||
unsafe {
|
||||
libc::mount(
|
||||
ptr::null(),
|
||||
@ -38,11 +38,11 @@ impl FsPath {
|
||||
libc::MS_REMOUNT,
|
||||
data.as_ptr().cast(),
|
||||
)
|
||||
.as_os_err()
|
||||
.check_os_err("remount", Some(self), None)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn move_mount_to(&self, path: &FsPath) -> std::io::Result<()> {
|
||||
pub fn move_mount_to<'a>(&'a self, path: &'a FsPath) -> OsResult<'a, ()> {
|
||||
unsafe {
|
||||
libc::mount(
|
||||
self.as_ptr(),
|
||||
@ -51,15 +51,17 @@ impl FsPath {
|
||||
libc::MS_MOVE,
|
||||
ptr::null(),
|
||||
)
|
||||
.as_os_err()
|
||||
.check_os_err("move_mount", Some(self), Some(path))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn unmount(&self) -> std::io::Result<()> {
|
||||
unsafe { libc::umount2(self.as_ptr(), libc::MNT_DETACH).as_os_err() }
|
||||
pub fn unmount(&self) -> OsResult<()> {
|
||||
unsafe {
|
||||
libc::umount2(self.as_ptr(), libc::MNT_DETACH).check_os_err("unmount", Some(self), None)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_mount_private(&self, recursive: bool) -> std::io::Result<()> {
|
||||
pub fn set_mount_private(&self, recursive: bool) -> OsResult<()> {
|
||||
let flag = if recursive { libc::MS_REC } else { 0 };
|
||||
unsafe {
|
||||
libc::mount(
|
||||
@ -69,7 +71,7 @@ impl FsPath {
|
||||
libc::MS_PRIVATE | flag,
|
||||
ptr::null(),
|
||||
)
|
||||
.as_os_err()
|
||||
.check_os_err("set_mount_private", Some(self), None)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,9 +1,9 @@
|
||||
use std::fmt;
|
||||
use crate::logging::Formatter;
|
||||
use crate::{LogLevel, errno, log_with_args, log_with_formatter};
|
||||
use std::fmt::Display;
|
||||
use std::panic::Location;
|
||||
|
||||
use crate::logging::Formatter;
|
||||
use crate::{LogLevel, log_with_args, log_with_formatter};
|
||||
use std::{fmt, io};
|
||||
use thiserror::Error;
|
||||
|
||||
// Error handling throughout the Rust codebase in Magisk:
|
||||
//
|
||||
@ -205,3 +205,191 @@ impl<T: Display> From<T> for LoggedError {
|
||||
LoggedError::default()
|
||||
}
|
||||
}
|
||||
|
||||
// Check libc return value and map to Result
|
||||
pub trait LibcReturn
|
||||
where
|
||||
Self: Copy,
|
||||
{
|
||||
fn is_error(&self) -> bool;
|
||||
|
||||
fn as_os_result<'a>(
|
||||
self,
|
||||
name: &'static str,
|
||||
arg1: Option<&'a str>,
|
||||
arg2: Option<&'a str>,
|
||||
) -> OsResult<'a, Self> {
|
||||
if self.is_error() {
|
||||
Err(OsError::last_os_error(name, arg1, arg2))
|
||||
} else {
|
||||
Ok(self)
|
||||
}
|
||||
}
|
||||
|
||||
fn check_os_err<'a>(
|
||||
self,
|
||||
name: &'static str,
|
||||
arg1: Option<&'a str>,
|
||||
arg2: Option<&'a str>,
|
||||
) -> OsResult<'a, ()> {
|
||||
self.as_os_result(name, arg1, arg2)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn check_io_err(self) -> io::Result<()> {
|
||||
if self.is_error() {
|
||||
Err(io::Error::last_os_error())
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! impl_libc_return {
|
||||
($($t:ty)*) => ($(
|
||||
impl LibcReturn for $t {
|
||||
#[inline]
|
||||
fn is_error(&self) -> bool {
|
||||
*self < 0
|
||||
}
|
||||
}
|
||||
)*)
|
||||
}
|
||||
|
||||
impl_libc_return! { i8 i16 i32 i64 isize }
|
||||
|
||||
impl<T> LibcReturn for *const T {
|
||||
#[inline]
|
||||
fn is_error(&self) -> bool {
|
||||
self.is_null()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> LibcReturn for *mut T {
|
||||
#[inline]
|
||||
fn is_error(&self) -> bool {
|
||||
self.is_null()
|
||||
}
|
||||
}
|
||||
|
||||
#[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>,
|
||||
}
|
||||
|
||||
impl OsError<'_> {
|
||||
pub fn with_os_error<'a>(
|
||||
code: i32,
|
||||
name: &'static str,
|
||||
arg1: Option<&'a str>,
|
||||
arg2: Option<&'a str>,
|
||||
) -> OsError<'a> {
|
||||
OsError {
|
||||
code,
|
||||
name,
|
||||
arg1: OwnableStr::from(arg1),
|
||||
arg2: OwnableStr::from(arg2),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn last_os_error<'a>(
|
||||
name: &'static str,
|
||||
arg1: Option<&'a str>,
|
||||
arg2: Option<&'a str>,
|
||||
) -> OsError<'a> {
|
||||
Self::with_os_error(*errno(), name, arg1, arg2)
|
||||
}
|
||||
|
||||
pub fn set_args<'a>(self, arg1: Option<&'a str>, arg2: Option<&'a str>) -> OsError<'a> {
|
||||
Self::with_os_error(self.code, self.name, arg1, arg2)
|
||||
}
|
||||
|
||||
pub fn into_owned(self) -> OsError<'static> {
|
||||
OsError {
|
||||
code: *errno(),
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for OsError<'_> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
let error = self.as_io_error();
|
||||
if self.name.is_empty() {
|
||||
write!(f, "{:#}", error)
|
||||
} else {
|
||||
match (self.arg1.ok(), self.arg2.ok()) {
|
||||
(Some(arg1), Some(arg2)) => {
|
||||
write!(f, "{} '{}' '{}': {:#}", self.name, arg1, arg2, error)
|
||||
}
|
||||
(Some(arg1), None) => {
|
||||
write!(f, "{} '{}': {:#}", self.name, arg1, error)
|
||||
}
|
||||
_ => {
|
||||
write!(f, "{}: {:#}", self.name, error)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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>;
|
||||
|
@ -7,8 +7,8 @@ use num_traits::AsPrimitive;
|
||||
|
||||
use base::libc::{c_uint, dev_t};
|
||||
use base::{
|
||||
FsPath, FsPathBuf, LibcReturn, LoggedResult, MountInfo, ResultExt, Utf8CStr, cstr, cstr_buf,
|
||||
debug, info, libc, parse_mount_info, path, warn,
|
||||
FsPath, FsPathBuf, LibcReturn, LoggedResult, MountInfo, ResultExt, Utf8CStr, cstr, debug, info,
|
||||
libc, parse_mount_info, path, warn,
|
||||
};
|
||||
|
||||
use crate::consts::{MODULEMNT, MODULEROOT, PREINITDEV, PREINITMIRR, WORKERDIR};
|
||||
@ -42,16 +42,12 @@ pub fn setup_mounts() {
|
||||
let target = Utf8CStr::from_string(&mut target);
|
||||
let mut preinit_dir = resolve_preinit_dir(target);
|
||||
let preinit_dir = Utf8CStr::from_string(&mut preinit_dir);
|
||||
let preinit_dir = FsPath::from(preinit_dir);
|
||||
let r: LoggedResult<()> = try {
|
||||
FsPath::from(preinit_dir).mkdir(0o700)?;
|
||||
let mut buf = cstr_buf::default();
|
||||
if mnt_path.parent(&mut buf) {
|
||||
FsPath::from(&buf).mkdirs(0o755)?;
|
||||
}
|
||||
preinit_dir.mkdir(0o700)?;
|
||||
mnt_path.mkdirs(0o755)?;
|
||||
mnt_path.remove().ok();
|
||||
unsafe {
|
||||
libc::symlink(preinit_dir.as_ptr(), mnt_path.as_ptr()).as_os_err()?
|
||||
}
|
||||
mnt_path.create_symlink_to(preinit_dir)?;
|
||||
};
|
||||
if r.is_ok() {
|
||||
linked = true;
|
||||
@ -187,17 +183,10 @@ pub fn find_preinit_device() -> String {
|
||||
let preinit_dir = FsPath::from(Utf8CStr::from_string(&mut preinit_dir));
|
||||
let _: LoggedResult<()> = try {
|
||||
preinit_dir.mkdirs(0o700)?;
|
||||
let mut buf = cstr_buf::default();
|
||||
if mirror_dir.parent(&mut buf) {
|
||||
FsPath::from(&buf).mkdirs(0o755)?;
|
||||
}
|
||||
unsafe {
|
||||
libc::umount2(mirror_dir.as_ptr(), libc::MNT_DETACH)
|
||||
.as_os_err()
|
||||
.ok(); // ignore error
|
||||
mirror_dir.remove().ok();
|
||||
libc::symlink(preinit_dir.as_ptr(), mirror_dir.as_ptr()).as_os_err()?;
|
||||
}
|
||||
mirror_dir.mkdirs(0o755)?;
|
||||
mirror_dir.unmount().ok();
|
||||
mirror_dir.remove().ok();
|
||||
mirror_dir.create_symlink_to(preinit_dir)?;
|
||||
};
|
||||
if std::env::var_os("MAKEDEV").is_some() {
|
||||
mirror_dir.clear();
|
||||
@ -208,7 +197,7 @@ pub fn find_preinit_device() -> String {
|
||||
libc::S_IFBLK | 0o600,
|
||||
info.device as dev_t,
|
||||
)
|
||||
.as_os_err()
|
||||
.check_io_err()
|
||||
.log()
|
||||
.ok();
|
||||
}
|
||||
|
@ -152,7 +152,7 @@ fn read_certificate(apk: &mut File, version: i32) -> Vec<u8> {
|
||||
res.log().unwrap_or(vec![])
|
||||
}
|
||||
|
||||
fn find_apk_path(pkg: &str, buf: &mut dyn Utf8CStrBuf) -> io::Result<()> {
|
||||
fn find_apk_path(pkg: &str, buf: &mut dyn Utf8CStrBuf) -> LoggedResult<()> {
|
||||
Directory::open(cstr!("/data/app"))?.pre_order_walk(|e| {
|
||||
if !e.is_dir() {
|
||||
return Ok(Skip);
|
||||
|
@ -84,13 +84,14 @@ fn file_set_prop(name: &Utf8CStr, value: Option<&Utf8CStr>) -> LoggedResult<()>
|
||||
.join("prop.XXXXXX");
|
||||
{
|
||||
let mut f = unsafe {
|
||||
let fd = mkstemp(tmp.as_mut_ptr()).check_os_err()?;
|
||||
File::from_raw_fd(fd)
|
||||
mkstemp(tmp.as_mut_ptr())
|
||||
.as_os_result("mkstemp", None, None)
|
||||
.map(|fd| File::from_raw_fd(fd))?
|
||||
};
|
||||
f.write_all(value.as_bytes())?;
|
||||
}
|
||||
debug!("resetprop: write prop to [{}]", tmp);
|
||||
tmp.rename_to(path)?
|
||||
tmp.rename_to(&path)?
|
||||
} else {
|
||||
path.remove().silent()?;
|
||||
debug!("resetprop: unlink [{}]", path);
|
||||
@ -113,14 +114,15 @@ fn proto_write_props(props: &PersistentProperties) -> LoggedResult<()> {
|
||||
let mut tmp = FsPathBuf::default().join(concatcp!(PERSIST_PROP, ".XXXXXX"));
|
||||
{
|
||||
let f = unsafe {
|
||||
let fd = mkstemp(tmp.as_mut_ptr()).check_os_err()?;
|
||||
File::from_raw_fd(fd)
|
||||
mkstemp(tmp.as_mut_ptr())
|
||||
.as_os_result("mkstemp", None, None)
|
||||
.map(|fd| File::from_raw_fd(fd))?
|
||||
};
|
||||
debug!("resetprop: encode with protobuf [{}]", tmp);
|
||||
props.write_message(&mut Writer::new(BufWriter::new(f)))?;
|
||||
}
|
||||
clone_attr(path!(PERSIST_PROP), &tmp)?;
|
||||
tmp.rename_to(cstr!(PERSIST_PROP))?;
|
||||
tmp.rename_to(path!(PERSIST_PROP))?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
@ -189,7 +189,7 @@ impl MagiskD {
|
||||
.join("zygisk");
|
||||
// Create the unloaded marker file
|
||||
if let Ok(dir) = Directory::open(&path) {
|
||||
dir.open_fd(cstr!("unloaded"), O_CREAT | O_RDONLY, 0o644)
|
||||
dir.openat_as_file(cstr!("unloaded").as_cstr(), O_CREAT | O_RDONLY, 0o644)
|
||||
.log()
|
||||
.ok();
|
||||
}
|
||||
|
@ -130,7 +130,7 @@ impl MagiskInit {
|
||||
null(),
|
||||
)
|
||||
}
|
||||
.as_os_err()?;
|
||||
.check_io_err()?;
|
||||
self.mount_list.push("/proc".to_string());
|
||||
}
|
||||
if !path!("/sys/block").exists() {
|
||||
@ -144,7 +144,7 @@ impl MagiskInit {
|
||||
null(),
|
||||
)
|
||||
}
|
||||
.as_os_err()?;
|
||||
.check_io_err()?;
|
||||
self.mount_list.push("/sys".to_string());
|
||||
}
|
||||
|
||||
|
@ -45,7 +45,7 @@ pub(crate) fn switch_root(path: &Utf8CStr) {
|
||||
mounts.insert(info.target);
|
||||
}
|
||||
unsafe {
|
||||
chdir(path.as_ptr()).as_os_err()?;
|
||||
chdir(path.as_ptr()).check_io_err()?;
|
||||
FsPath::from(path).move_mount_to(path!("/"))?;
|
||||
chroot(raw_cstr!("."));
|
||||
}
|
||||
@ -89,7 +89,7 @@ impl MagiskInit {
|
||||
raw_cstr!("mode=755").cast(),
|
||||
)
|
||||
}
|
||||
.as_os_err()
|
||||
.check_io_err()
|
||||
.log_ok();
|
||||
|
||||
path!("/init").copy_to(path!("/data/magiskinit")).log_ok();
|
||||
@ -108,7 +108,7 @@ impl MagiskInit {
|
||||
}
|
||||
unsafe {
|
||||
execve(raw_cstr!("/init"), self.argv.cast(), environ.cast())
|
||||
.as_os_err()
|
||||
.check_io_err()
|
||||
.log_ok();
|
||||
exit(1);
|
||||
}
|
||||
|
@ -151,7 +151,7 @@ impl MagiskInit {
|
||||
0,
|
||||
ptr::null(),
|
||||
)
|
||||
.as_os_err()?;
|
||||
.check_io_err()?;
|
||||
}
|
||||
}
|
||||
|
||||
@ -174,7 +174,7 @@ impl MagiskInit {
|
||||
}
|
||||
|
||||
// Create a new process waiting for init operations
|
||||
let pid = unsafe { libc::fork().check_os_err()? };
|
||||
let pid = unsafe { libc::fork() };
|
||||
if pid != 0 {
|
||||
return Ok(());
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user