mirror of
https://github.com/topjohnwu/Magisk.git
synced 2024-12-22 16:07: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",
|
||||||
"cxx-gen",
|
"cxx-gen",
|
||||||
"libc",
|
"libc",
|
||||||
|
"num-traits",
|
||||||
"thiserror",
|
"thiserror",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -16,3 +16,4 @@ cfg-if = { workspace = true }
|
|||||||
thiserror = { workspace = true }
|
thiserror = { workspace = true }
|
||||||
argh = { workspace = true }
|
argh = { workspace = true }
|
||||||
bytemuck = { workspace = true }
|
bytemuck = { workspace = true }
|
||||||
|
num-traits = { workspace = true }
|
||||||
|
@ -7,6 +7,7 @@
|
|||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <sys/syscall.h>
|
#include <sys/syscall.h>
|
||||||
|
#include <sys/xattr.h>
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
|
||||||
@ -90,6 +91,16 @@ int mkfifo(const char *path, mode_t mode) {
|
|||||||
return mknod(path, (mode & ~S_IFMT) | S_IFIFO, 0);
|
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)
|
#define SPLIT_64(v) (unsigned)((v) & 0xFFFFFFFF), (unsigned)((v) >> 32)
|
||||||
|
|
||||||
#if defined(__arm__)
|
#if defined(__arm__)
|
||||||
|
@ -3,12 +3,15 @@
|
|||||||
use std::io;
|
use std::io;
|
||||||
use std::os::fd::{BorrowedFd, OwnedFd, RawFd};
|
use std::os::fd::{BorrowedFd, OwnedFd, RawFd};
|
||||||
|
|
||||||
|
use cfg_if::cfg_if;
|
||||||
use cxx::private::c_char;
|
use cxx::private::c_char;
|
||||||
use libc::mode_t;
|
use libc::mode_t;
|
||||||
|
|
||||||
use crate::logging::CxxResultExt;
|
use crate::logging::CxxResultExt;
|
||||||
pub(crate) use crate::xwrap::*;
|
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 {
|
pub(crate) fn fd_path_for_cxx(fd: RawFd, buf: &mut [u8]) -> isize {
|
||||||
let mut buf = Utf8CStrSlice::from(buf);
|
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 [])
|
.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;
|
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) {
|
void full_read(int fd, string &str) {
|
||||||
char buf[4096];
|
char buf[4096];
|
||||||
for (ssize_t len; (len = xread(fd, buf, sizeof(buf))) > 0;)
|
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;
|
return align_to(v, a) - v;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct file_attr {
|
|
||||||
struct stat st;
|
|
||||||
char con[128];
|
|
||||||
};
|
|
||||||
|
|
||||||
struct mount_info {
|
struct mount_info {
|
||||||
unsigned int id;
|
unsigned int id;
|
||||||
unsigned int parent;
|
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);
|
ssize_t canonical_path(const char * __restrict__ path, char * __restrict__ buf, size_t bufsiz);
|
||||||
bool rm_rf(const char *path);
|
bool rm_rf(const char *path);
|
||||||
bool frm_rf(int dirfd);
|
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"
|
} // extern "C"
|
||||||
|
|
||||||
int fd_pathat(int dirfd, const char *name, char *path, size_t size);
|
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(
|
static inline ssize_t realpath(
|
||||||
const char * __restrict__ path, char * __restrict__ buf, size_t bufsiz) {
|
const char * __restrict__ path, char * __restrict__ buf, size_t bufsiz) {
|
||||||
return canonical_path(path, buf, 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(int fd, std::string &str);
|
||||||
void full_read(const char *filename, std::string &str);
|
void full_read(const char *filename, std::string &str);
|
||||||
std::string full_read(int fd);
|
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(FILE *fp, const std::function<bool(std::string_view, std::string_view)> &fn);
|
||||||
void parse_prop_file(const char *file,
|
void parse_prop_file(const char *file,
|
||||||
const std::function<bool(std::string_view, std::string_view)> &fn);
|
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::vector<mount_info> parse_mount_info(const char *pid);
|
||||||
std::string resolve_preinit_dir(const char *base_dir);
|
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::fd::{AsFd, BorrowedFd, IntoRawFd};
|
||||||
use std::os::unix::fs::FileTypeExt;
|
use std::os::unix::fs::FileTypeExt;
|
||||||
use std::os::unix::io::{AsRawFd, FromRawFd, OwnedFd, RawFd};
|
use std::os::unix::io::{AsRawFd, FromRawFd, OwnedFd, RawFd};
|
||||||
|
use std::sync::atomic::{AtomicBool, Ordering};
|
||||||
use std::{io, mem, ptr, slice};
|
use std::{io, mem, ptr, slice};
|
||||||
|
|
||||||
use bytemuck::{bytes_of_mut, Pod};
|
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::{
|
use crate::{
|
||||||
copy_cstr, cstr, errno, error, FsPath, FsPathBuf, LibcReturn, Utf8CStr, Utf8CStrArr,
|
copy_cstr, cstr, errno, error, FsPath, FsPathBuf, LibcReturn, Utf8CStr, Utf8CStrArr,
|
||||||
Utf8CStrBuf,
|
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> {
|
pub struct DirEntry<'a> {
|
||||||
dir: &'a Directory,
|
dir: &'a Directory,
|
||||||
entry: &'a dirent,
|
entry: &'a dirent,
|
||||||
@ -175,34 +193,49 @@ impl DirEntry<'_> {
|
|||||||
Ok(())
|
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> {
|
pub fn open_as_dir(&self) -> io::Result<Directory> {
|
||||||
if !self.is_dir() {
|
if !self.is_dir() {
|
||||||
return Err(io::Error::from(io::ErrorKind::NotADirectory));
|
return Err(io::Error::from(io::ErrorKind::NotADirectory));
|
||||||
}
|
}
|
||||||
unsafe {
|
unsafe { Directory::try_from(OwnedFd::from_raw_fd(self.open_fd(O_RDONLY)?)) }
|
||||||
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))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn open_as_file(&self, flags: i32) -> io::Result<File> {
|
pub fn open_as_file(&self, flags: i32) -> io::Result<File> {
|
||||||
if self.is_dir() {
|
if self.is_dir() {
|
||||||
return Err(io::Error::from(io::ErrorKind::IsADirectory));
|
return Err(io::Error::from(io::ErrorKind::IsADirectory));
|
||||||
}
|
}
|
||||||
unsafe {
|
unsafe { Ok(File::from_raw_fd(self.open_fd(flags)?)) }
|
||||||
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))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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 { 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<()> {
|
pub fn path(&self, buf: &mut dyn Utf8CStrBuf) -> io::Result<()> {
|
||||||
fd_path(self.as_raw_fd(), buf)
|
fd_path(self.as_raw_fd(), buf)
|
||||||
}
|
}
|
||||||
@ -286,6 +338,108 @@ impl Directory {
|
|||||||
})?;
|
})?;
|
||||||
Ok(())
|
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 {
|
impl Directory {
|
||||||
@ -410,6 +564,19 @@ impl FsPath {
|
|||||||
Ok(())
|
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<()> {
|
pub fn mkdirs(&self, mode: mode_t) -> io::Result<()> {
|
||||||
let mut buf = [0_u8; 4096];
|
let mut buf = [0_u8; 4096];
|
||||||
let len = copy_cstr(&mut buf, self);
|
let len = copy_cstr(&mut buf, self);
|
||||||
@ -456,6 +623,151 @@ impl FsPath {
|
|||||||
}
|
}
|
||||||
Ok(())
|
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]);
|
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" {
|
extern "C" {
|
||||||
// Don't use the declaration from the libc crate as request should be u32 not i32
|
// Don't use the declaration from the libc crate as request should be u32 not i32
|
||||||
fn ioctl(fd: RawFd, request: u32, ...) -> 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")]
|
#[cfg(target_pointer_width = "64")]
|
||||||
const BLKGETSIZE64: u32 = 0x80081272;
|
const BLKGETSIZE64: u32 = 0x80081272;
|
||||||
|
|
||||||
|
@ -51,5 +51,6 @@ pub mod ffi {
|
|||||||
fn map_file_for_cxx(path: &[u8], rw: bool) -> &'static mut [u8];
|
fn map_file_for_cxx(path: &[u8], rw: bool) -> &'static mut [u8];
|
||||||
#[cxx_name = "map_fd"]
|
#[cxx_name = "map_fd"]
|
||||||
fn map_fd_for_cxx(fd: i32, sz: usize, rw: bool) -> &'static mut [u8];
|
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() {
|
void enable_selinux() {
|
||||||
|
rust::enable_selinux();
|
||||||
setcon = __setcon;
|
setcon = __setcon;
|
||||||
getfilecon = __getfilecon;
|
getfilecon = __getfilecon;
|
||||||
lgetfilecon = __lgetfilecon;
|
lgetfilecon = __lgetfilecon;
|
||||||
|
@ -4,12 +4,12 @@ use std::ffi::CStr;
|
|||||||
use std::os::unix::io::RawFd;
|
use std::os::unix::io::RawFd;
|
||||||
use std::ptr;
|
use std::ptr;
|
||||||
|
|
||||||
use cfg_if::cfg_if;
|
|
||||||
use libc::{
|
use libc::{
|
||||||
c_char, c_uint, c_ulong, c_void, dev_t, mode_t, nfds_t, off_t, pollfd, sockaddr, socklen_t,
|
c_char, c_uint, c_ulong, c_void, dev_t, mode_t, nfds_t, off_t, pollfd, sockaddr, socklen_t,
|
||||||
ssize_t, SYS_dup3,
|
ssize_t, SYS_dup3,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use crate::cxx_extern::readlinkat_for_cxx;
|
||||||
use crate::{cstr, errno, raw_cstr, CxxResultExt, FsPath, Utf8CStr, Utf8CStrSlice};
|
use crate::{cstr, errno, raw_cstr, CxxResultExt, FsPath, Utf8CStr, Utf8CStrSlice};
|
||||||
|
|
||||||
fn ptr_to_str<'a, T>(ptr: *const T) -> &'a str {
|
fn ptr_to_str<'a, T>(ptr: *const T) -> &'a str {
|
||||||
@ -96,24 +96,10 @@ unsafe extern "C" fn xreadlinkat(
|
|||||||
buf: *mut u8,
|
buf: *mut u8,
|
||||||
bufsz: usize,
|
bufsz: usize,
|
||||||
) -> isize {
|
) -> isize {
|
||||||
// readlinkat() may fail on x86 platform, returning random value
|
let r = readlinkat_for_cxx(dirfd, path, buf, bufsz);
|
||||||
// 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);
|
|
||||||
if r < 0 {
|
if r < 0 {
|
||||||
perror!("readlinkat {}", ptr_to_str(path))
|
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
|
r
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -23,9 +23,6 @@ pub mod ffi {
|
|||||||
type PropCb;
|
type PropCb;
|
||||||
unsafe fn get_prop_rs(name: *const c_char, persist: bool) -> String;
|
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);
|
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" {
|
extern "Rust" {
|
||||||
|
@ -164,11 +164,11 @@ void module_node::mount() {
|
|||||||
void tmpfs_node::mount() {
|
void tmpfs_node::mount() {
|
||||||
string src = mirror_path();
|
string src = mirror_path();
|
||||||
const string &dest = node_path();
|
const string &dest = node_path();
|
||||||
file_attr a{};
|
const char *src_path;
|
||||||
if (access(src.data(), F_OK) == 0)
|
if (access(src.data(), F_OK) == 0)
|
||||||
getattr(src.data(), &a);
|
src_path = src.data();
|
||||||
else
|
else
|
||||||
getattr(parent()->node_path().data(), &a);
|
src_path = parent()->node_path().data();
|
||||||
if (!isa<tmpfs_node>(parent())) {
|
if (!isa<tmpfs_node>(parent())) {
|
||||||
auto worker_dir = MAGISKTMP + "/" WORKERDIR + dest;
|
auto worker_dir = MAGISKTMP + "/" WORKERDIR + dest;
|
||||||
mkdirs(worker_dir.data(), 0);
|
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
|
// We don't need another layer of tmpfs if parent is tmpfs
|
||||||
mkdir(dest.data(), 0);
|
mkdir(dest.data(), 0);
|
||||||
}
|
}
|
||||||
setattr(dest.data(), &a);
|
clone_attr(src_path, dest.data());
|
||||||
dir_node::mount();
|
dir_node::mount();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -12,11 +12,11 @@ use quick_protobuf::{BytesReader, MessageRead, MessageWrite, Writer};
|
|||||||
|
|
||||||
use base::libc::{O_CLOEXEC, O_RDONLY};
|
use base::libc::{O_CLOEXEC, O_RDONLY};
|
||||||
use base::{
|
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,
|
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::{
|
use crate::resetprop::proto::persistent_properties::{
|
||||||
mod_PersistentProperties::PersistentPropertyRecord, PersistentProperties,
|
mod_PersistentProperties::PersistentPropertyRecord, PersistentProperties,
|
||||||
};
|
};
|
||||||
@ -140,7 +140,7 @@ fn proto_write_props(props: &PersistentProperties) -> LoggedResult<()> {
|
|||||||
debug!("resetprop: encode with protobuf [{}]", tmp);
|
debug!("resetprop: encode with protobuf [{}]", tmp);
|
||||||
props.write_message(&mut Writer::new(BufWriter::new(f)))?;
|
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!()))?;
|
tmp.rename_to(cstr!(PERSIST_PROP!()))?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user