mirror of
https://github.com/topjohnwu/Magisk.git
synced 2024-12-22 07:57:39 +00:00
Move more I/O operations into Rust
This commit is contained in:
parent
5d07d0b964
commit
a55d570213
1
native/src/Cargo.lock
generated
1
native/src/Cargo.lock
generated
@ -75,6 +75,7 @@ dependencies = [
|
||||
"cxx",
|
||||
"cxx-gen",
|
||||
"libc",
|
||||
"num-traits",
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
|
@ -16,3 +16,4 @@ cfg-if = { workspace = true }
|
||||
thiserror = { workspace = true }
|
||||
argh = { workspace = true }
|
||||
bytemuck = { workspace = true }
|
||||
num-traits = { workspace = true }
|
||||
|
@ -7,6 +7,7 @@
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/syscall.h>
|
||||
#include <sys/xattr.h>
|
||||
|
||||
extern "C" {
|
||||
|
||||
@ -90,6 +91,16 @@ int mkfifo(const char *path, mode_t mode) {
|
||||
return mknod(path, (mode & ~S_IFMT) | S_IFIFO, 0);
|
||||
}
|
||||
|
||||
[[gnu::weak]]
|
||||
int fsetxattr(int fd, const char *name, const void *value, size_t size, int flags) {
|
||||
return syscall(__NR_fsetxattr, fd, name, value, size, flags);
|
||||
}
|
||||
|
||||
[[gnu::weak]]
|
||||
int lsetxattr(const char *path, const char *name, const void *value, size_t size, int flags) {
|
||||
return syscall(__NR_lsetxattr, path, name, value, size, flags);
|
||||
}
|
||||
|
||||
#define SPLIT_64(v) (unsigned)((v) & 0xFFFFFFFF), (unsigned)((v) >> 32)
|
||||
|
||||
#if defined(__arm__)
|
||||
|
@ -3,12 +3,15 @@
|
||||
use std::io;
|
||||
use std::os::fd::{BorrowedFd, OwnedFd, RawFd};
|
||||
|
||||
use cfg_if::cfg_if;
|
||||
use cxx::private::c_char;
|
||||
use libc::mode_t;
|
||||
|
||||
use crate::logging::CxxResultExt;
|
||||
pub(crate) use crate::xwrap::*;
|
||||
use crate::{fd_path, map_fd, map_file, Directory, FsPath, Utf8CStr, Utf8CStrSlice};
|
||||
use crate::{
|
||||
clone_attr, fclone_attr, fd_path, map_fd, map_file, Directory, FsPath, Utf8CStr, Utf8CStrSlice,
|
||||
};
|
||||
|
||||
pub(crate) fn fd_path_for_cxx(fd: RawFd, buf: &mut [u8]) -> isize {
|
||||
let mut buf = Utf8CStrSlice::from(buf);
|
||||
@ -69,3 +72,102 @@ pub(crate) fn map_fd_for_cxx(fd: RawFd, sz: usize, rw: bool) -> &'static mut [u8
|
||||
.unwrap_or(&mut [])
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) unsafe fn readlinkat_for_cxx(
|
||||
dirfd: RawFd,
|
||||
path: *const c_char,
|
||||
buf: *mut u8,
|
||||
bufsz: usize,
|
||||
) -> isize {
|
||||
// readlinkat() may fail on x86 platform, returning random value
|
||||
// instead of number of bytes placed in buf (length of link)
|
||||
cfg_if! {
|
||||
if #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] {
|
||||
libc::memset(buf.cast(), 0, bufsz);
|
||||
let mut r = libc::readlinkat(dirfd, path, buf.cast(), bufsz - 1);
|
||||
if r > 0 {
|
||||
r = libc::strlen(buf.cast()) as isize;
|
||||
}
|
||||
} else {
|
||||
let r = libc::readlinkat(dirfd, path, buf.cast(), bufsz - 1);
|
||||
if r >= 0 {
|
||||
*buf.offset(r) = b'\0';
|
||||
}
|
||||
}
|
||||
}
|
||||
r
|
||||
}
|
||||
|
||||
#[export_name = "cp_afc"]
|
||||
unsafe extern "C" fn cp_afc_for_cxx(src: *const c_char, dest: *const c_char) -> bool {
|
||||
if let Ok(src) = Utf8CStr::from_ptr(src) {
|
||||
if let Ok(dest) = Utf8CStr::from_ptr(dest) {
|
||||
let src = FsPath::from(src);
|
||||
let dest = FsPath::from(dest);
|
||||
return src
|
||||
.copy_to(dest)
|
||||
.log_cxx_with_msg(|w| {
|
||||
w.write_fmt(format_args!("cp_afc {} -> {} failed", src, dest))
|
||||
})
|
||||
.is_ok();
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
#[export_name = "mv_path"]
|
||||
unsafe extern "C" fn mv_path_for_cxx(src: *const c_char, dest: *const c_char) -> bool {
|
||||
if let Ok(src) = Utf8CStr::from_ptr(src) {
|
||||
if let Ok(dest) = Utf8CStr::from_ptr(dest) {
|
||||
let src = FsPath::from(src);
|
||||
let dest = FsPath::from(dest);
|
||||
return src
|
||||
.move_to(dest)
|
||||
.log_cxx_with_msg(|w| {
|
||||
w.write_fmt(format_args!("mv_path {} -> {} failed", src, dest))
|
||||
})
|
||||
.is_ok();
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
#[export_name = "link_path"]
|
||||
unsafe extern "C" fn link_path_for_cxx(src: *const c_char, dest: *const c_char) -> bool {
|
||||
if let Ok(src) = Utf8CStr::from_ptr(src) {
|
||||
if let Ok(dest) = Utf8CStr::from_ptr(dest) {
|
||||
let src = FsPath::from(src);
|
||||
let dest = FsPath::from(dest);
|
||||
return src
|
||||
.link_to(dest)
|
||||
.log_cxx_with_msg(|w| {
|
||||
w.write_fmt(format_args!("link_path {} -> {} failed", src, dest))
|
||||
})
|
||||
.is_ok();
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
#[export_name = "clone_attr"]
|
||||
unsafe extern "C" fn clone_attr_for_cxx(src: *const c_char, dest: *const c_char) -> bool {
|
||||
if let Ok(src) = Utf8CStr::from_ptr(src) {
|
||||
if let Ok(dest) = Utf8CStr::from_ptr(dest) {
|
||||
let src = FsPath::from(src);
|
||||
let dest = FsPath::from(dest);
|
||||
return clone_attr(src, dest)
|
||||
.log_cxx_with_msg(|w| {
|
||||
w.write_fmt(format_args!("clone_attr {} -> {} failed", src, dest))
|
||||
})
|
||||
.is_ok();
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
#[export_name = "fclone_attr"]
|
||||
unsafe extern "C" fn fclone_attr_for_cxx(a: RawFd, b: RawFd) -> bool {
|
||||
fclone_attr(a, b)
|
||||
.log_cxx_with_msg(|w| w.write_str("fclone_attr failed"))
|
||||
.is_ok()
|
||||
}
|
||||
|
@ -20,191 +20,6 @@ int fd_pathat(int dirfd, const char *name, char *path, size_t size) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
void mv_path(const char *src, const char *dest) {
|
||||
file_attr attr;
|
||||
getattr(src, &attr);
|
||||
if (S_ISDIR(attr.st.st_mode)) {
|
||||
if (access(dest, F_OK) != 0) {
|
||||
xmkdirs(dest, 0);
|
||||
setattr(dest, &attr);
|
||||
}
|
||||
mv_dir(xopen(src, O_RDONLY | O_CLOEXEC), xopen(dest, O_RDONLY | O_CLOEXEC));
|
||||
} else{
|
||||
xrename(src, dest);
|
||||
}
|
||||
rmdir(src);
|
||||
}
|
||||
|
||||
void mv_dir(int src, int dest) {
|
||||
auto dir = xopen_dir(src);
|
||||
run_finally f([=]{ close(dest); });
|
||||
for (dirent *entry; (entry = xreaddir(dir.get()));) {
|
||||
switch (entry->d_type) {
|
||||
case DT_DIR:
|
||||
if (xfaccessat(dest, entry->d_name, F_OK, 0) == 0) {
|
||||
// Destination folder exists, needs recursive move
|
||||
int newsrc = xopenat(src, entry->d_name, O_RDONLY | O_CLOEXEC);
|
||||
int newdest = xopenat(dest, entry->d_name, O_RDONLY | O_CLOEXEC);
|
||||
mv_dir(newsrc, newdest);
|
||||
unlinkat(src, entry->d_name, AT_REMOVEDIR);
|
||||
break;
|
||||
}
|
||||
// Else fall through
|
||||
case DT_LNK:
|
||||
case DT_REG:
|
||||
renameat(src, entry->d_name, dest, entry->d_name);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void cp_afc(const char *src, const char *dest) {
|
||||
file_attr a;
|
||||
getattr(src, &a);
|
||||
|
||||
if (S_ISDIR(a.st.st_mode)) {
|
||||
xmkdirs(dest, 0);
|
||||
clone_dir(xopen(src, O_RDONLY | O_CLOEXEC), xopen(dest, O_RDONLY | O_CLOEXEC));
|
||||
} else{
|
||||
unlink(dest);
|
||||
if (S_ISREG(a.st.st_mode)) {
|
||||
int sfd = xopen(src, O_RDONLY | O_CLOEXEC);
|
||||
int dfd = xopen(dest, O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC, 0);
|
||||
xsendfile(dfd, sfd, nullptr, a.st.st_size);
|
||||
close(sfd);
|
||||
close(dfd);
|
||||
} else if (S_ISLNK(a.st.st_mode)) {
|
||||
char buf[4096];
|
||||
xreadlink(src, buf, sizeof(buf));
|
||||
xsymlink(buf, dest);
|
||||
}
|
||||
}
|
||||
setattr(dest, &a);
|
||||
}
|
||||
|
||||
void clone_dir(int src, int dest) {
|
||||
auto dir = xopen_dir(src);
|
||||
run_finally f([&]{ close(dest); });
|
||||
for (dirent *entry; (entry = xreaddir(dir.get()));) {
|
||||
file_attr a;
|
||||
getattrat(src, entry->d_name, &a);
|
||||
switch (entry->d_type) {
|
||||
case DT_DIR: {
|
||||
xmkdirat(dest, entry->d_name, 0);
|
||||
setattrat(dest, entry->d_name, &a);
|
||||
int sfd = xopenat(src, entry->d_name, O_RDONLY | O_CLOEXEC);
|
||||
int dst = xopenat(dest, entry->d_name, O_RDONLY | O_CLOEXEC);
|
||||
clone_dir(sfd, dst);
|
||||
break;
|
||||
}
|
||||
case DT_REG: {
|
||||
int sfd = xopenat(src, entry->d_name, O_RDONLY | O_CLOEXEC);
|
||||
int dfd = xopenat(dest, entry->d_name, O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC, 0);
|
||||
xsendfile(dfd, sfd, nullptr, a.st.st_size);
|
||||
fsetattr(dfd, &a);
|
||||
close(dfd);
|
||||
close(sfd);
|
||||
break;
|
||||
}
|
||||
case DT_LNK: {
|
||||
char buf[4096];
|
||||
xreadlinkat(src, entry->d_name, buf, sizeof(buf));
|
||||
xsymlinkat(buf, dest, entry->d_name);
|
||||
setattrat(dest, entry->d_name, &a);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void link_path(const char *src, const char *dest) {
|
||||
link_dir(xopen(src, O_RDONLY | O_CLOEXEC), xopen(dest, O_RDONLY | O_CLOEXEC));
|
||||
}
|
||||
|
||||
void link_dir(int src, int dest) {
|
||||
auto dir = xopen_dir(src);
|
||||
run_finally f([&]{ close(dest); });
|
||||
for (dirent *entry; (entry = xreaddir(dir.get()));) {
|
||||
if (entry->d_type == DT_DIR) {
|
||||
file_attr a;
|
||||
getattrat(src, entry->d_name, &a);
|
||||
xmkdirat(dest, entry->d_name, 0);
|
||||
setattrat(dest, entry->d_name, &a);
|
||||
int sfd = xopenat(src, entry->d_name, O_RDONLY | O_CLOEXEC);
|
||||
int dfd = xopenat(dest, entry->d_name, O_RDONLY | O_CLOEXEC);
|
||||
link_dir(sfd, dfd);
|
||||
} else {
|
||||
xlinkat(src, entry->d_name, dest, entry->d_name, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int getattr(const char *path, file_attr *a) {
|
||||
if (xlstat(path, &a->st) == -1)
|
||||
return -1;
|
||||
char *con;
|
||||
if (lgetfilecon(path, &con) == -1)
|
||||
return -1;
|
||||
strcpy(a->con, con);
|
||||
freecon(con);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int getattrat(int dirfd, const char *name, file_attr *a) {
|
||||
char path[4096];
|
||||
fd_pathat(dirfd, name, path, sizeof(path));
|
||||
return getattr(path, a);
|
||||
}
|
||||
|
||||
int fgetattr(int fd, file_attr *a) {
|
||||
if (xfstat(fd, &a->st) < 0)
|
||||
return -1;
|
||||
char *con;
|
||||
if (fgetfilecon(fd, &con) < 0)
|
||||
return -1;
|
||||
strcpy(a->con, con);
|
||||
freecon(con);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int setattr(const char *path, file_attr *a) {
|
||||
if (chmod(path, a->st.st_mode & 0777) < 0)
|
||||
return -1;
|
||||
if (chown(path, a->st.st_uid, a->st.st_gid) < 0)
|
||||
return -1;
|
||||
if (a->con[0] && lsetfilecon(path, a->con) < 0)
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int setattrat(int dirfd, const char *name, file_attr *a) {
|
||||
char path[4096];
|
||||
fd_pathat(dirfd, name, path, sizeof(path));
|
||||
return setattr(path, a);
|
||||
}
|
||||
|
||||
int fsetattr(int fd, file_attr *a) {
|
||||
if (fchmod(fd, a->st.st_mode & 0777) < 0)
|
||||
return -1;
|
||||
if (fchown(fd, a->st.st_uid, a->st.st_gid) < 0)
|
||||
return -1;
|
||||
if (a->con[0] && fsetfilecon(fd, a->con) < 0)
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void clone_attr(const char *src, const char *dest) {
|
||||
file_attr a;
|
||||
getattr(src, &a);
|
||||
setattr(dest, &a);
|
||||
}
|
||||
|
||||
void fclone_attr(int src, int dest) {
|
||||
file_attr a;
|
||||
fgetattr(src, &a);
|
||||
fsetattr(dest, &a);
|
||||
}
|
||||
|
||||
void full_read(int fd, string &str) {
|
||||
char buf[4096];
|
||||
for (ssize_t len; (len = xread(fd, buf, sizeof(buf))) > 0;)
|
||||
|
@ -20,11 +20,6 @@ static inline T align_padding(T v, int a) {
|
||||
return align_to(v, a) - v;
|
||||
}
|
||||
|
||||
struct file_attr {
|
||||
struct stat st;
|
||||
char con[128];
|
||||
};
|
||||
|
||||
struct mount_info {
|
||||
unsigned int id;
|
||||
unsigned int parent;
|
||||
@ -58,27 +53,19 @@ int mkdirs(const char *path, mode_t mode);
|
||||
ssize_t canonical_path(const char * __restrict__ path, char * __restrict__ buf, size_t bufsiz);
|
||||
bool rm_rf(const char *path);
|
||||
bool frm_rf(int dirfd);
|
||||
void cp_afc(const char *src, const char *dest);
|
||||
void mv_path(const char *src, const char *dest);
|
||||
void link_path(const char *src, const char *dest);
|
||||
void clone_attr(const char *src, const char *dest);
|
||||
void fclone_attr(int src, int dest);
|
||||
|
||||
} // extern "C"
|
||||
|
||||
int fd_pathat(int dirfd, const char *name, char *path, size_t size);
|
||||
void mv_path(const char *src, const char *dest);
|
||||
void mv_dir(int src, int dest);
|
||||
void cp_afc(const char *src, const char *dest);
|
||||
void link_path(const char *src, const char *dest);
|
||||
void link_dir(int src, int dest);
|
||||
static inline ssize_t realpath(
|
||||
const char * __restrict__ path, char * __restrict__ buf, size_t bufsiz) {
|
||||
return canonical_path(path, buf, bufsiz);
|
||||
}
|
||||
int getattr(const char *path, file_attr *a);
|
||||
int getattrat(int dirfd, const char *name, file_attr *a);
|
||||
int fgetattr(int fd, file_attr *a);
|
||||
int setattr(const char *path, file_attr *a);
|
||||
int setattrat(int dirfd, const char *name, file_attr *a);
|
||||
int fsetattr(int fd, file_attr *a);
|
||||
void fclone_attr(int src, int dest);
|
||||
void clone_attr(const char *src, const char *dest);
|
||||
void full_read(int fd, std::string &str);
|
||||
void full_read(const char *filename, std::string &str);
|
||||
std::string full_read(int fd);
|
||||
@ -90,7 +77,6 @@ void file_readline(const char *file, const std::function<bool(std::string_view)>
|
||||
void parse_prop_file(FILE *fp, const std::function<bool(std::string_view, std::string_view)> &fn);
|
||||
void parse_prop_file(const char *file,
|
||||
const std::function<bool(std::string_view, std::string_view)> &fn);
|
||||
void clone_dir(int src, int dest);
|
||||
std::vector<mount_info> parse_mount_info(const char *pid);
|
||||
std::string resolve_preinit_dir(const char *base_dir);
|
||||
|
||||
|
@ -8,11 +8,17 @@ use std::os::android::fs::MetadataExt;
|
||||
use std::os::fd::{AsFd, BorrowedFd, IntoRawFd};
|
||||
use std::os::unix::fs::FileTypeExt;
|
||||
use std::os::unix::io::{AsRawFd, FromRawFd, OwnedFd, RawFd};
|
||||
use std::sync::atomic::{AtomicBool, Ordering};
|
||||
use std::{io, mem, ptr, slice};
|
||||
|
||||
use bytemuck::{bytes_of_mut, Pod};
|
||||
use libc::{c_uint, dirent, mode_t, EEXIST, ENOENT, F_OK, O_CLOEXEC, O_PATH, O_RDONLY, O_RDWR};
|
||||
use libc::{
|
||||
c_uint, dirent, mode_t, EEXIST, ENOENT, F_OK, O_CLOEXEC, O_CREAT, O_PATH, O_RDONLY, O_RDWR,
|
||||
O_TRUNC, O_WRONLY, S_IFDIR, S_IFLNK, S_IFREG,
|
||||
};
|
||||
use num_traits::AsPrimitive;
|
||||
|
||||
use crate::cxx_extern::readlinkat_for_cxx;
|
||||
use crate::{
|
||||
copy_cstr, cstr, errno, error, FsPath, FsPathBuf, LibcReturn, Utf8CStr, Utf8CStrArr,
|
||||
Utf8CStrBuf,
|
||||
@ -132,6 +138,18 @@ impl<T: Write> WriteExt for T {
|
||||
}
|
||||
}
|
||||
|
||||
pub struct FileAttr {
|
||||
pub st: libc::stat,
|
||||
pub con: Utf8CStrArr<128>,
|
||||
}
|
||||
|
||||
const XATTR_NAME_SELINUX: &[u8] = b"security.selinux\0";
|
||||
static SELINUX_ENABLED: AtomicBool = AtomicBool::new(false);
|
||||
|
||||
pub fn enable_selinux() {
|
||||
SELINUX_ENABLED.store(true, Ordering::Relaxed);
|
||||
}
|
||||
|
||||
pub struct DirEntry<'a> {
|
||||
dir: &'a Directory,
|
||||
entry: &'a dirent,
|
||||
@ -175,34 +193,49 @@ impl DirEntry<'_> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn read_link(&self, buf: &mut dyn Utf8CStrBuf) -> io::Result<()> {
|
||||
buf.clear();
|
||||
unsafe {
|
||||
let r = readlinkat_for_cxx(
|
||||
self.dir.as_raw_fd(),
|
||||
self.d_name.as_ptr(),
|
||||
buf.as_mut_ptr().cast(),
|
||||
buf.capacity(),
|
||||
)
|
||||
.check_os_err()? as usize;
|
||||
buf.set_len(r);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
unsafe fn open_fd(&self, flags: i32) -> io::Result<RawFd> {
|
||||
self.dir.open_fd(self.d_name(), flags, 0)
|
||||
}
|
||||
|
||||
pub fn open_as_dir(&self) -> io::Result<Directory> {
|
||||
if !self.is_dir() {
|
||||
return Err(io::Error::from(io::ErrorKind::NotADirectory));
|
||||
}
|
||||
unsafe {
|
||||
let fd = libc::openat(
|
||||
self.dir.as_raw_fd(),
|
||||
self.d_name.as_ptr(),
|
||||
O_RDONLY | O_CLOEXEC,
|
||||
)
|
||||
.check_os_err()?;
|
||||
Directory::try_from(OwnedFd::from_raw_fd(fd))
|
||||
}
|
||||
unsafe { Directory::try_from(OwnedFd::from_raw_fd(self.open_fd(O_RDONLY)?)) }
|
||||
}
|
||||
|
||||
pub fn open_as_file(&self, flags: i32) -> io::Result<File> {
|
||||
if self.is_dir() {
|
||||
return Err(io::Error::from(io::ErrorKind::IsADirectory));
|
||||
}
|
||||
unsafe {
|
||||
let fd = libc::openat(
|
||||
self.dir.as_raw_fd(),
|
||||
self.d_name.as_ptr(),
|
||||
flags | O_CLOEXEC,
|
||||
)
|
||||
.check_os_err()?;
|
||||
Ok(File::from_raw_fd(fd))
|
||||
unsafe { Ok(File::from_raw_fd(self.open_fd(flags)?)) }
|
||||
}
|
||||
|
||||
pub fn get_attr(&self) -> io::Result<FileAttr> {
|
||||
let mut path = Utf8CStrArr::default();
|
||||
self.path(&mut path)?;
|
||||
FsPath::from(path).get_attr()
|
||||
}
|
||||
|
||||
pub fn set_attr(&self, attr: &FileAttr) -> io::Result<()> {
|
||||
let mut path = Utf8CStrArr::default();
|
||||
self.path(&mut path)?;
|
||||
FsPath::from(path).set_attr(attr)
|
||||
}
|
||||
}
|
||||
|
||||
@ -261,6 +294,25 @@ impl Directory {
|
||||
unsafe { libc::rewinddir(self.dirp) }
|
||||
}
|
||||
|
||||
unsafe fn open_fd(&self, name: &CStr, flags: i32, mode: i32) -> io::Result<RawFd> {
|
||||
libc::openat(self.as_raw_fd(), name.as_ptr(), flags | O_CLOEXEC, mode).check_os_err()
|
||||
}
|
||||
|
||||
pub fn contains_path(&self, path: &CStr) -> bool {
|
||||
// WARNING: Using faccessat is incorrect, because the raw linux kernel syscall
|
||||
// does not support the flag AT_SYMLINK_NOFOLLOW until 5.8 with faccessat2.
|
||||
// Use fstatat to check the existence of a file instead.
|
||||
unsafe {
|
||||
let mut st: libc::stat = mem::zeroed();
|
||||
libc::fstatat(
|
||||
self.as_raw_fd(),
|
||||
path.as_ptr(),
|
||||
&mut st,
|
||||
libc::AT_SYMLINK_NOFOLLOW,
|
||||
) == 0
|
||||
}
|
||||
}
|
||||
|
||||
pub fn path(&self, buf: &mut dyn Utf8CStrBuf) -> io::Result<()> {
|
||||
fd_path(self.as_raw_fd(), buf)
|
||||
}
|
||||
@ -286,6 +338,108 @@ impl Directory {
|
||||
})?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn copy_into(&mut self, dir: &Directory) -> io::Result<()> {
|
||||
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()?;
|
||||
}
|
||||
let mut src = e.open_as_dir()?;
|
||||
let dest = new_entry.open_as_dir()?;
|
||||
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_fd(
|
||||
e.d_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_lnk() {
|
||||
let mut path = Utf8CStrArr::default();
|
||||
e.read_link(&mut path)?;
|
||||
unsafe {
|
||||
libc::symlinkat(path.as_ptr(), dir.as_raw_fd(), e.d_name.as_ptr())
|
||||
.as_os_err()?;
|
||||
}
|
||||
new_entry.set_attr(&attr)?;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn move_into(&mut self, dir: &Directory) -> io::Result<()> {
|
||||
let dir_fd = self.as_raw_fd();
|
||||
while let Some(ref e) = self.read()? {
|
||||
if e.is_dir() && dir.contains_path(e.d_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()?;
|
||||
src.move_into(&dest)?;
|
||||
return e.unlink();
|
||||
}
|
||||
|
||||
unsafe {
|
||||
libc::renameat(
|
||||
dir_fd,
|
||||
e.d_name.as_ptr(),
|
||||
dir.as_raw_fd(),
|
||||
e.d_name.as_ptr(),
|
||||
)
|
||||
.as_os_err()?;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn link_into(&mut self, dir: &Directory) -> io::Result<()> {
|
||||
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()?;
|
||||
}
|
||||
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()?;
|
||||
src.link_into(&dest)?;
|
||||
fd_set_attr(dest.as_raw_fd(), &attr)?;
|
||||
} else {
|
||||
unsafe {
|
||||
libc::linkat(
|
||||
dir_fd,
|
||||
e.d_name.as_ptr(),
|
||||
dir.as_raw_fd(),
|
||||
e.d_name.as_ptr(),
|
||||
0,
|
||||
)
|
||||
.as_os_err()?;
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl Directory {
|
||||
@ -410,6 +564,19 @@ impl FsPath {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn mkdir(&self, mode: mode_t) -> io::Result<()> {
|
||||
unsafe {
|
||||
if libc::mkdir(self.as_ptr(), mode) < 0 {
|
||||
if *errno() == EEXIST {
|
||||
libc::chmod(self.as_ptr(), mode).as_os_err()?;
|
||||
} else {
|
||||
return Err(io::Error::last_os_error());
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn mkdirs(&self, mode: mode_t) -> io::Result<()> {
|
||||
let mut buf = [0_u8; 4096];
|
||||
let len = copy_cstr(&mut buf, self);
|
||||
@ -456,6 +623,151 @@ impl FsPath {
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn get_attr(&self) -> io::Result<FileAttr> {
|
||||
let mut attr: FileAttr;
|
||||
unsafe {
|
||||
attr = FileAttr {
|
||||
st: mem::zeroed(),
|
||||
con: Utf8CStrArr::new(),
|
||||
};
|
||||
libc::lstat(self.as_ptr(), &mut attr.st).as_os_err()?;
|
||||
if SELINUX_ENABLED.load(Ordering::Relaxed) {
|
||||
let sz = libc::lgetxattr(
|
||||
self.as_ptr(),
|
||||
XATTR_NAME_SELINUX.as_ptr().cast(),
|
||||
attr.con.as_mut_ptr().cast(),
|
||||
attr.con.capacity(),
|
||||
)
|
||||
.check_os_err()?;
|
||||
attr.con.set_len((sz - 1) as usize);
|
||||
}
|
||||
}
|
||||
Ok(attr)
|
||||
}
|
||||
|
||||
pub fn set_attr(&self, attr: &FileAttr) -> io::Result<()> {
|
||||
unsafe {
|
||||
if (attr.st.st_mode & libc::S_IFMT as c_uint) != S_IFLNK.as_() {
|
||||
libc::chmod(self.as_ptr(), (attr.st.st_mode & 0o777).as_()).as_os_err()?;
|
||||
}
|
||||
libc::lchown(self.as_ptr(), attr.st.st_uid, attr.st.st_gid).as_os_err()?;
|
||||
if !attr.con.is_empty() {
|
||||
libc::lsetxattr(
|
||||
self.as_ptr(),
|
||||
XATTR_NAME_SELINUX.as_ptr().cast(),
|
||||
attr.con.as_ptr().cast(),
|
||||
attr.con.len() + 1,
|
||||
0,
|
||||
)
|
||||
.as_os_err()?;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn copy_to(&self, path: &FsPath) -> io::Result<()> {
|
||||
let attr = self.get_attr()?;
|
||||
if (attr.st.st_mode & libc::S_IFMT as c_uint) == S_IFDIR.as_() {
|
||||
path.mkdir(0o777)?;
|
||||
let mut src = Directory::open(self)?;
|
||||
let dest = Directory::open(path)?;
|
||||
src.copy_into(&dest)?;
|
||||
} else {
|
||||
// It's OK if remove failed
|
||||
path.remove().ok();
|
||||
if (attr.st.st_mode & libc::S_IFMT as c_uint) == S_IFREG.as_() {
|
||||
let mut src = self.open(O_RDONLY | O_CLOEXEC)?;
|
||||
let mut dest = path.create(O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC, 0o777)?;
|
||||
std::io::copy(&mut src, &mut dest)?;
|
||||
} else if (attr.st.st_mode & libc::S_IFMT as c_uint) == S_IFLNK.as_() {
|
||||
let mut buf = Utf8CStrArr::default();
|
||||
self.read_link(&mut buf)?;
|
||||
unsafe {
|
||||
libc::symlink(buf.as_ptr(), path.as_ptr()).as_os_err()?;
|
||||
}
|
||||
}
|
||||
}
|
||||
path.set_attr(&attr)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn move_to(&self, path: &FsPath) -> io::Result<()> {
|
||||
if path.exists() {
|
||||
let attr = path.get_attr()?;
|
||||
if (attr.st.st_mode & libc::S_IFMT as c_uint) == S_IFDIR.as_() {
|
||||
let mut src = Directory::open(self)?;
|
||||
let dest = Directory::open(path)?;
|
||||
return src.move_into(&dest);
|
||||
} else {
|
||||
path.remove()?;
|
||||
}
|
||||
}
|
||||
self.rename_to(path)
|
||||
}
|
||||
|
||||
pub fn link_to(&self, path: &FsPath) -> io::Result<()> {
|
||||
let attr = self.get_attr()?;
|
||||
if (attr.st.st_mode & libc::S_IFMT as c_uint) == S_IFDIR.as_() {
|
||||
path.mkdir(0o777)?;
|
||||
path.set_attr(&attr)?;
|
||||
let mut src = Directory::open(self)?;
|
||||
let dest = Directory::open(path)?;
|
||||
src.link_into(&dest)
|
||||
} else {
|
||||
unsafe { libc::link(self.as_ptr(), path.as_ptr()).as_os_err() }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn fd_get_attr(fd: RawFd) -> io::Result<FileAttr> {
|
||||
let mut attr: FileAttr;
|
||||
unsafe {
|
||||
attr = FileAttr {
|
||||
st: mem::zeroed(),
|
||||
con: Utf8CStrArr::new(),
|
||||
};
|
||||
libc::fstat(fd, &mut attr.st).as_os_err()?;
|
||||
if SELINUX_ENABLED.load(Ordering::Relaxed) {
|
||||
let sz = libc::fgetxattr(
|
||||
fd,
|
||||
XATTR_NAME_SELINUX.as_ptr().cast(),
|
||||
attr.con.as_mut_ptr().cast(),
|
||||
attr.con.capacity(),
|
||||
)
|
||||
.check_os_err()?;
|
||||
attr.con.set_len((sz - 1) as usize);
|
||||
}
|
||||
}
|
||||
Ok(attr)
|
||||
}
|
||||
|
||||
pub fn fd_set_attr(fd: RawFd, attr: &FileAttr) -> io::Result<()> {
|
||||
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()?;
|
||||
if !attr.con.is_empty() {
|
||||
libc::fsetxattr(
|
||||
fd,
|
||||
XATTR_NAME_SELINUX.as_ptr().cast(),
|
||||
attr.con.as_ptr().cast(),
|
||||
attr.con.len() + 1,
|
||||
0,
|
||||
)
|
||||
.as_os_err()?;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn clone_attr(a: &FsPath, b: &FsPath) -> io::Result<()> {
|
||||
let attr = a.get_attr()?;
|
||||
b.set_attr(&attr)
|
||||
}
|
||||
|
||||
pub fn fclone_attr(a: RawFd, b: RawFd) -> io::Result<()> {
|
||||
let attr = fd_get_attr(a)?;
|
||||
fd_set_attr(b, &attr)
|
||||
}
|
||||
|
||||
pub struct MappedFile(&'static mut [u8]);
|
||||
@ -494,13 +806,13 @@ impl Drop for MappedFile {
|
||||
}
|
||||
}
|
||||
|
||||
// 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]> {
|
||||
extern "C" {
|
||||
// Don't use the declaration from the libc crate as request should be u32 not i32
|
||||
fn ioctl(fd: RawFd, request: u32, ...) -> i32;
|
||||
}
|
||||
|
||||
// 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]> {
|
||||
#[cfg(target_pointer_width = "64")]
|
||||
const BLKGETSIZE64: u32 = 0x80081272;
|
||||
|
||||
|
@ -51,5 +51,6 @@ pub mod ffi {
|
||||
fn map_file_for_cxx(path: &[u8], rw: bool) -> &'static mut [u8];
|
||||
#[cxx_name = "map_fd"]
|
||||
fn map_fd_for_cxx(fd: i32, sz: usize, rw: bool) -> &'static mut [u8];
|
||||
fn enable_selinux();
|
||||
}
|
||||
}
|
||||
|
@ -103,6 +103,7 @@ void setfilecon_at(int dirfd, const char *name, const char *con) {
|
||||
}
|
||||
|
||||
void enable_selinux() {
|
||||
rust::enable_selinux();
|
||||
setcon = __setcon;
|
||||
getfilecon = __getfilecon;
|
||||
lgetfilecon = __lgetfilecon;
|
||||
|
@ -4,12 +4,12 @@ use std::ffi::CStr;
|
||||
use std::os::unix::io::RawFd;
|
||||
use std::ptr;
|
||||
|
||||
use cfg_if::cfg_if;
|
||||
use libc::{
|
||||
c_char, c_uint, c_ulong, c_void, dev_t, mode_t, nfds_t, off_t, pollfd, sockaddr, socklen_t,
|
||||
ssize_t, SYS_dup3,
|
||||
};
|
||||
|
||||
use crate::cxx_extern::readlinkat_for_cxx;
|
||||
use crate::{cstr, errno, raw_cstr, CxxResultExt, FsPath, Utf8CStr, Utf8CStrSlice};
|
||||
|
||||
fn ptr_to_str<'a, T>(ptr: *const T) -> &'a str {
|
||||
@ -96,24 +96,10 @@ unsafe extern "C" fn xreadlinkat(
|
||||
buf: *mut u8,
|
||||
bufsz: usize,
|
||||
) -> isize {
|
||||
// readlinkat() may fail on x86 platform, returning random value
|
||||
// instead of number of bytes placed in buf (length of link)
|
||||
cfg_if! {
|
||||
if #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] {
|
||||
libc::memset(buf.cast(), 0, bufsz);
|
||||
let r = libc::readlinkat(dirfd, path, buf.cast(), bufsz - 1);
|
||||
let r = readlinkat_for_cxx(dirfd, path, buf, bufsz);
|
||||
if r < 0 {
|
||||
perror!("readlinkat {}", ptr_to_str(path))
|
||||
}
|
||||
} else {
|
||||
let r = libc::readlinkat(dirfd, path, buf.cast(), bufsz - 1);
|
||||
if r < 0 {
|
||||
perror!("readlinkat {}", ptr_to_str(path))
|
||||
} else {
|
||||
*buf.offset(r) = b'\0';
|
||||
}
|
||||
}
|
||||
}
|
||||
r
|
||||
}
|
||||
|
||||
|
@ -23,9 +23,6 @@ pub mod ffi {
|
||||
type PropCb;
|
||||
unsafe fn get_prop_rs(name: *const c_char, persist: bool) -> String;
|
||||
unsafe fn prop_cb_exec(cb: Pin<&mut PropCb>, name: *const c_char, value: *const c_char);
|
||||
|
||||
include!("../base/files.hpp");
|
||||
unsafe fn clone_attr(src: *const c_char, dst: *const c_char);
|
||||
}
|
||||
|
||||
extern "Rust" {
|
||||
|
@ -164,11 +164,11 @@ void module_node::mount() {
|
||||
void tmpfs_node::mount() {
|
||||
string src = mirror_path();
|
||||
const string &dest = node_path();
|
||||
file_attr a{};
|
||||
const char *src_path;
|
||||
if (access(src.data(), F_OK) == 0)
|
||||
getattr(src.data(), &a);
|
||||
src_path = src.data();
|
||||
else
|
||||
getattr(parent()->node_path().data(), &a);
|
||||
src_path = parent()->node_path().data();
|
||||
if (!isa<tmpfs_node>(parent())) {
|
||||
auto worker_dir = MAGISKTMP + "/" WORKERDIR + dest;
|
||||
mkdirs(worker_dir.data(), 0);
|
||||
@ -177,7 +177,7 @@ void tmpfs_node::mount() {
|
||||
// We don't need another layer of tmpfs if parent is tmpfs
|
||||
mkdir(dest.data(), 0);
|
||||
}
|
||||
setattr(dest.data(), &a);
|
||||
clone_attr(src_path, dest.data());
|
||||
dir_node::mount();
|
||||
}
|
||||
|
||||
|
@ -12,11 +12,11 @@ use quick_protobuf::{BytesReader, MessageRead, MessageWrite, Writer};
|
||||
|
||||
use base::libc::{O_CLOEXEC, O_RDONLY};
|
||||
use base::{
|
||||
cstr, debug, libc::mkstemp, raw_cstr, Directory, FsPath, FsPathBuf, LibcReturn, LoggedError,
|
||||
clone_attr, cstr, debug, libc::mkstemp, Directory, FsPath, FsPathBuf, LibcReturn, LoggedError,
|
||||
LoggedResult, MappedFile, Utf8CStr, Utf8CStrArr, WalkResult,
|
||||
};
|
||||
|
||||
use crate::ffi::{clone_attr, prop_cb_exec, PropCb};
|
||||
use crate::ffi::{prop_cb_exec, PropCb};
|
||||
use crate::resetprop::proto::persistent_properties::{
|
||||
mod_PersistentProperties::PersistentPropertyRecord, PersistentProperties,
|
||||
};
|
||||
@ -140,7 +140,7 @@ fn proto_write_props(props: &PersistentProperties) -> LoggedResult<()> {
|
||||
debug!("resetprop: encode with protobuf [{}]", tmp);
|
||||
props.write_message(&mut Writer::new(BufWriter::new(f)))?;
|
||||
}
|
||||
unsafe { clone_attr(raw_cstr!(PERSIST_PROP!()), tmp.as_ptr()) };
|
||||
clone_attr(FsPath::from(cstr!(PERSIST_PROP!())), &tmp)?;
|
||||
tmp.rename_to(cstr!(PERSIST_PROP!()))?;
|
||||
Ok(())
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user