diff --git a/native/src/base/cxx_extern.rs b/native/src/base/cxx_extern.rs index 6c9bbbc0d..f823148fd 100644 --- a/native/src/base/cxx_extern.rs +++ b/native/src/base/cxx_extern.rs @@ -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() diff --git a/native/src/base/dir.rs b/native/src/base/dir.rs index e391bb4a3..290f0ccbf 100644 --- a/native/src/base/dir.rs +++ b/native/src/base/dir.rs @@ -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 { - unsafe { self.dir.open_raw_fd(self.name(), flags, 0) } - } - - pub fn open_as_dir(&self) -> io::Result { + pub fn open_as_dir(&self) -> OsResult { 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 { + pub fn open_as_file(&self, flags: i32) -> OsResult { 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 { + pub fn get_attr(&self) -> OsResult { 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 { - let dirp = unsafe { libc::opendir(path.as_ptr()) }.check_os_err()?; + pub fn open(path: &Utf8CStr) -> OsResult { + 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>> { + pub fn read(&mut self) -> OsResult<'static, Option> { *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 { + 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 { + 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 io::Result>( + pub fn post_order_walk OsResultStatic>( &mut self, mut f: F, - ) -> io::Result { + ) -> OsResultStatic { self.post_order_walk_impl(&mut f) } - pub fn pre_order_walk io::Result>( + pub fn pre_order_walk OsResultStatic>( &mut self, mut f: F, - ) -> io::Result { + ) -> OsResultStatic { 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 io::Result>( + fn post_order_walk_impl OsResultStatic>( &mut self, f: &mut F, - ) -> io::Result { + ) -> OsResultStatic { use WalkResult::*; loop { match self.read()? { @@ -365,10 +385,10 @@ impl Directory { } } - fn pre_order_walk_impl io::Result>( + fn pre_order_walk_impl OsResultStatic>( &mut self, f: &mut F, - ) -> io::Result { + ) -> OsResultStatic { use WalkResult::*; loop { match self.read()? { @@ -391,10 +411,11 @@ impl Directory { } impl TryFrom for Directory { - type Error = io::Error; + type Error = OsError<'static>; - fn try_from(fd: OwnedFd) -> io::Result { - 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 }) } } diff --git a/native/src/base/files.rs b/native/src/base/files.rs index d254e6bdd..1a1e06d65 100644 --- a/native/src/base/files.rs +++ b/native/src/base/files.rs @@ -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 { - 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(&mut self, data: &mut F) -> io::Result<()>; @@ -137,6 +115,32 @@ impl WriteExt for T { } } +pub fn __open_fd_impl(path: &Utf8CStr, flags: i32, mode: mode_t) -> OsResult { + 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 { + pub fn open(&self, flags: i32) -> OsResult { Ok(File::from(open_fd!(self, flags)?)) } - pub fn create(&self, flags: i32, mode: mode_t) -> io::Result { + pub fn create(&self, flags: i32, mode: mode_t) -> OsResult { Ok(File::from(open_fd!(self, O_CREAT | flags, mode)?)) } @@ -209,75 +213,80 @@ impl FsPath { } } - pub fn rename_to>(&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 { + pub fn get_attr(&self) -> OsResult { 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 { + pub fn get_attr(&self) -> OsResult { 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 { +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 { + pub fn open(path: &Utf8CStr) -> OsResult { Ok(MappedFile(map_file(path, false)?)) } - pub fn open_rw(path: &Utf8CStr) -> io::Result { + pub fn open_rw(path: &Utf8CStr) -> OsResult { Ok(MappedFile(map_file(path, true)?)) } - pub fn openat(dir: &T, path: &Utf8CStr) -> io::Result { + 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(dir: &T, path: &Utf8CStr) -> io::Result { + 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 { + pub fn create(fd: BorrowedFd, sz: usize, rw: bool) -> OsResult { 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)) } diff --git a/native/src/base/misc.rs b/native/src/base/misc.rs index 99cdf2fd2..8685f9d8d 100644 --- a/native/src/base/misc.rs +++ b/native/src/base/misc.rs @@ -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 { - 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 LibcReturn for *const T { - #[inline] - fn is_error(&self) -> bool { - self.is_null() - } -} - -impl LibcReturn for *mut T { - #[inline] - fn is_error(&self) -> bool { - self.is_null() - } -} - pub trait BytesExt { fn find(&self, needle: &[u8]) -> Option; fn contains(&self, needle: &[u8]) -> bool { diff --git a/native/src/base/mount.rs b/native/src/base/mount.rs index bb0c6278f..c35dd648b 100644 --- a/native/src/base/mount.rs +++ b/native/src/base/mount.rs @@ -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) } } } diff --git a/native/src/base/result.rs b/native/src/base/result.rs index 4dee58986..30fd9bff6 100644 --- a/native/src/base/result.rs +++ b/native/src/base/result.rs @@ -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 From 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 LibcReturn for *const T { + #[inline] + fn is_error(&self) -> bool { + self.is_null() + } +} + +impl LibcReturn for *mut T { + #[inline] + fn is_error(&self) -> bool { + self.is_null() + } +} + +#[derive(Debug)] +enum OwnableStr<'a> { + None, + Borrowed(&'a str), + Owned(Box), +} + +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> 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>; + +#[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> for OsErrorStatic { + fn from(value: OsError<'a>) -> Self { + OsErrorStatic::Os(value.into_owned()) + } +} + +pub type OsResultStatic = Result; diff --git a/native/src/core/mount.rs b/native/src/core/mount.rs index 084c11fe0..af0824253 100644 --- a/native/src/core/mount.rs +++ b/native/src/core/mount.rs @@ -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(); } diff --git a/native/src/core/package.rs b/native/src/core/package.rs index 6f6afb05e..220655634 100644 --- a/native/src/core/package.rs +++ b/native/src/core/package.rs @@ -152,7 +152,7 @@ fn read_certificate(apk: &mut File, version: i32) -> Vec { 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); diff --git a/native/src/core/resetprop/persist.rs b/native/src/core/resetprop/persist.rs index d42ca98f3..c054b7ec2 100644 --- a/native/src/core/resetprop/persist.rs +++ b/native/src/core/resetprop/persist.rs @@ -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(()) } diff --git a/native/src/core/zygisk/daemon.rs b/native/src/core/zygisk/daemon.rs index 92c412b7c..b5a48f954 100644 --- a/native/src/core/zygisk/daemon.rs +++ b/native/src/core/zygisk/daemon.rs @@ -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(); } diff --git a/native/src/init/init.rs b/native/src/init/init.rs index 1299f5966..11fca4075 100644 --- a/native/src/init/init.rs +++ b/native/src/init/init.rs @@ -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()); } diff --git a/native/src/init/mount.rs b/native/src/init/mount.rs index c38388e74..7f8c6fb6e 100644 --- a/native/src/init/mount.rs +++ b/native/src/init/mount.rs @@ -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); } diff --git a/native/src/init/selinux.rs b/native/src/init/selinux.rs index 8abf61142..70fafd2dc 100644 --- a/native/src/init/selinux.rs +++ b/native/src/init/selinux.rs @@ -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(()); }