diff --git a/native/src/base/files.cpp b/native/src/base/files.cpp index 46b64615e..5d7aa6d85 100644 --- a/native/src/base/files.cpp +++ b/native/src/base/files.cpp @@ -124,7 +124,7 @@ void mv_dir(int src, int dest) { for (dirent *entry; (entry = xreaddir(dir.get()));) { switch (entry->d_type) { case DT_DIR: - if (xfaccessat(dest, entry->d_name) == 0) { + 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); diff --git a/native/src/base/lib.rs b/native/src/base/lib.rs index 710cd6c36..10720625b 100644 --- a/native/src/base/lib.rs +++ b/native/src/base/lib.rs @@ -1,6 +1,7 @@ #![feature(format_args_nl)] pub use libc; + pub use logging::*; pub use misc::*; pub use xwrap::*; @@ -26,3 +27,13 @@ pub mod ffi { fn cmdline_logging(); } } + +#[cxx::bridge(namespace = "rust")] +pub mod ffi2 { + extern "Rust" { + fn xwrite(fd: i32, data: &[u8]) -> isize; + fn xread(fd: i32, data: &mut [u8]) -> isize; + fn xxread(fd: i32, data: &mut [u8]) -> isize; + fn xpipe2(fds: &mut [i32; 2], flags: i32) -> i32; + } +} diff --git a/native/src/base/logging.rs b/native/src/base/logging.rs index 25373adc4..ed4961d67 100644 --- a/native/src/base/logging.rs +++ b/native/src/base/logging.rs @@ -85,14 +85,14 @@ pub fn log_impl(level: LogLevel, args: Arguments) { } pub fn cmdline_logging() { - fn print(level: LogLevel, args: Arguments) { + fn cmdline_print(level: LogLevel, args: Arguments) { if level == LogLevel::Info { print!("{}", args); } else { eprint!("{}", args); } } - fn write(level: LogLevel, msg: &[u8]) { + fn cmdline_write(level: LogLevel, msg: &[u8]) { if level == LogLevel::Info { stdout().write_all(msg).ok(); } else { @@ -101,8 +101,8 @@ pub fn cmdline_logging() { } let logger = Logger { - fmt: print, - write, + fmt: cmdline_print, + write: cmdline_write, flags: LogFlag::ExitOnError, }; unsafe { diff --git a/native/src/base/misc.cpp b/native/src/base/misc.cpp index c23571701..ccb7d8a85 100644 --- a/native/src/base/misc.cpp +++ b/native/src/base/misc.cpp @@ -55,7 +55,7 @@ int gen_rand_str(char *buf, int len, bool varlen) { } int exec_command(exec_t &exec) { - int pipefd[] = {-1, -1}; + auto pipefd = array{-1, -1}; int outfd = -1; if (exec.fd == -1) { @@ -114,7 +114,11 @@ int new_daemon_thread(thread_entry entry, void *arg) { pthread_attr_t attr; pthread_attr_init(&attr); pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); - return xpthread_create(&thread, &attr, entry, arg); + errno = pthread_create(&thread, &attr, entry, arg); + if (errno) { + PLOGE("pthread_create"); + } + return errno; } static char *argv0; diff --git a/native/src/base/xwrap.cpp b/native/src/base/xwrap.cpp index 0ccb31eda..8df52907f 100644 --- a/native/src/base/xwrap.cpp +++ b/native/src/base/xwrap.cpp @@ -14,72 +14,19 @@ using namespace std; -// Write exact same size as count ssize_t xwrite(int fd, const void *buf, size_t count) { - size_t write_sz = 0; - ssize_t ret; - do { - ret = write(fd, (byte *) buf + write_sz, count - write_sz); - if (ret < 0) { - if (errno == EINTR) - continue; - PLOGE("write"); - return ret; - } - write_sz += ret; - } while (write_sz != count && ret != 0); - if (write_sz != count) { - PLOGE("write (%zu != %zu)", count, write_sz); - } - return write_sz; + return rust::xwrite(fd, rust::Slice(static_cast(buf), count)); } -// Read error other than EOF ssize_t xread(int fd, void *buf, size_t count) { - int ret = read(fd, buf, count); - if (ret < 0) { - PLOGE("read"); - } - return ret; + return rust::xread(fd, rust::Slice(static_cast(buf), count)); } -// Read exact same size as count ssize_t xxread(int fd, void *buf, size_t count) { - size_t read_sz = 0; - ssize_t ret; - do { - ret = read(fd, (byte *) buf + read_sz, count - read_sz); - if (ret < 0) { - if (errno == EINTR) - continue; - PLOGE("read"); - return ret; - } - read_sz += ret; - } while (read_sz != count && ret != 0); - if (read_sz != count) { - PLOGE("read (%zu != %zu)", count, read_sz); - } - return read_sz; + return rust::xxread(fd, rust::Slice(static_cast(buf), count)); } -off_t xlseek(int fd, off_t offset, int whence) { - off_t ret = lseek(fd, offset, whence); - if (ret < 0) { - PLOGE("lseek"); - } - return ret; -} - -int xpipe2(int pipefd[2], int flags) { - int ret = pipe2(pipefd, flags); - if (ret < 0) { - PLOGE("pipe2"); - } - return ret; -} - -struct dirent *xreaddir(DIR *dirp) { +dirent *xreaddir(DIR *dirp) { errno = 0; for (dirent *e;;) { e = readdir(dirp); @@ -95,15 +42,6 @@ struct dirent *xreaddir(DIR *dirp) { } } -int xpthread_create(pthread_t *thread, const pthread_attr_t *attr, - void *(*start_routine) (void *), void *arg) { - errno = pthread_create(thread, attr, start_routine, arg); - if (errno) { - PLOGE("pthread_create"); - } - return errno; -} - ssize_t xreadlink(const char *pathname, char *buf, size_t bufsiz) { ssize_t ret = readlink(pathname, buf, bufsiz); if (ret < 0) { @@ -135,20 +73,6 @@ ssize_t xreadlinkat(int dirfd, const char *pathname, char *buf, size_t bufsiz) { #endif } -int xfaccessat(int dirfd, const char *pathname) { - int ret = faccessat(dirfd, pathname, F_OK, 0); - if (ret < 0) { - PLOGE("faccessat %s", pathname); - } -#if defined(__i386__) || defined(__x86_64__) - if (ret > 0 && errno == 0) { - LOGD("faccessat success but ret is %d\n", ret); - ret = 0; - } -#endif - return ret; -} - int xmkdirs(const char *pathname, mode_t mode) { int ret = mkdirs(pathname, mode); if (ret < 0) { diff --git a/native/src/base/xwrap.hpp b/native/src/base/xwrap.hpp index dadd50474..ffa302518 100644 --- a/native/src/base/xwrap.hpp +++ b/native/src/base/xwrap.hpp @@ -5,6 +5,10 @@ #include #include +#include + +using rust::xpipe2; + extern "C" { FILE *xfopen(const char *pathname, const char *mode); @@ -14,13 +18,12 @@ int xopenat(int dirfd, const char *pathname, int flags, mode_t mode = 0); ssize_t xwrite(int fd, const void *buf, size_t count); ssize_t xread(int fd, void *buf, size_t count); ssize_t xxread(int fd, void *buf, size_t count); -off_t xlseek(int fd, off_t offset, int whence); -int xpipe2(int pipefd[2], int flags); +off64_t xlseek64(int fd, off64_t offset, int whence); int xsetns(int fd, int nstype); int xunshare(int flags); DIR *xopendir(const char *name); DIR *xfdopendir(int fd); -struct dirent *xreaddir(DIR *dirp); +dirent *xreaddir(DIR *dirp); pid_t xsetsid(); int xsocket(int domain, int type, int protocol); int xbind(int sockfd, const struct sockaddr *addr, socklen_t addrlen); @@ -28,10 +31,8 @@ int xlisten(int sockfd, int backlog); int xaccept4(int sockfd, struct sockaddr *addr, socklen_t *addrlen, int flags); ssize_t xsendmsg(int sockfd, const struct msghdr *msg, int flags); ssize_t xrecvmsg(int sockfd, struct msghdr *msg, int flags); -int xpthread_create(pthread_t *thread, const pthread_attr_t *attr, - void *(*start_routine)(void *), void *arg); int xaccess(const char *path, int mode); -int xfaccessat(int dirfd, const char *pathname); +int xfaccessat(int dirfd, const char *pathname, int mode, int flags); int xstat(const char *pathname, struct stat *buf); int xlstat(const char *pathname, struct stat *buf); int xfstat(int fd, struct stat *buf); diff --git a/native/src/base/xwrap.rs b/native/src/base/xwrap.rs index 9892f05f7..72ff28dd2 100644 --- a/native/src/base/xwrap.rs +++ b/native/src/base/xwrap.rs @@ -1,10 +1,11 @@ +use std::ffi::CStr; use std::os::unix::io::RawFd; use libc::{ c_char, c_uint, c_ulong, c_void, dev_t, mode_t, sockaddr, socklen_t, ssize_t, SYS_dup3, }; -use crate::{perror, ptr_to_str}; +use crate::{errno, error, perror, ptr_to_str}; #[no_mangle] pub extern "C" fn xfopen(path: *const c_char, mode: *const c_char) -> *mut libc::FILE { @@ -60,6 +61,95 @@ macro_rules! xopen { }; } +// Fully write data slice +pub fn xwrite(fd: RawFd, data: &[u8]) -> isize { + unsafe { + let mut write_sz: usize = 0; + let mut r: ssize_t; + let mut remain: &[u8] = data; + loop { + r = libc::write(fd, remain.as_ptr().cast(), remain.len()); + if r < 0 { + if *errno() == libc::EINTR { + continue; + } + perror!("write"); + return r as isize; + } + let r = r as usize; + write_sz += r; + remain = &remain[r..]; + if r == 0 || remain.len() == 0 { + break; + } + } + if remain.len() != 0 { + error!("write ({} != {})", write_sz, data.len()) + } + return write_sz as isize; + } +} + +pub fn xread(fd: RawFd, data: &mut [u8]) -> isize { + unsafe { + let r = libc::read(fd, data.as_mut_ptr().cast(), data.len()); + if r < 0 { + perror!("read"); + } + return r; + } +} + +// Fully read size of data slice +pub fn xxread(fd: RawFd, data: &mut [u8]) -> isize { + unsafe { + let mut read_sz: usize = 0; + let mut r: ssize_t; + let mut remain: &mut [u8] = data; + loop { + r = libc::read(fd, remain.as_mut_ptr().cast(), remain.len()); + if r < 0 { + if *errno() == libc::EINTR { + continue; + } + perror!("read"); + return r as isize; + } + let r = r as usize; + read_sz += r; + remain = &mut remain[r..]; + if r == 0 || remain.len() == 0 { + break; + } + } + if remain.len() != 0 { + error!("read ({} != {})", read_sz, data.len()) + } + return read_sz as isize; + } +} + +#[no_mangle] +pub extern "C" fn xlseek64(fd: RawFd, offset: i64, whence: i32) -> i64 { + unsafe { + let r = libc::lseek64(fd, offset, whence); + if r < 0 { + perror!("lseek64"); + } + return r; + } +} + +pub fn xpipe2(fds: &mut [i32; 2], flags: i32) -> i32 { + unsafe { + let r = libc::pipe2(fds.as_mut_ptr(), flags); + if r < 0 { + perror!("pipe2"); + } + return r; + } +} + #[no_mangle] pub extern "C" fn xsetns(fd: RawFd, nstype: i32) -> i32 { unsafe { @@ -197,6 +287,22 @@ pub extern "C" fn xaccess(path: *const c_char, mode: i32) -> i32 { } } +#[no_mangle] +pub extern "C" fn xfaccessat(dirfd: RawFd, path: *const c_char, mode: i32, flags: i32) -> i32 { + unsafe { + #[allow(unused_mut)] + let mut r = libc::faccessat(dirfd, path, mode, flags); + if r < 0 { + perror!("faccessat {}", ptr_to_str(path)); + } + #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] + if r > 0 && *errno() == 0 { + r = 0 + } + return r; + } +} + #[no_mangle] pub extern "C" fn xstat(path: *const c_char, buf: *mut libc::stat) -> i32 { unsafe { @@ -279,6 +385,24 @@ pub extern "C" fn xdup3(oldfd: RawFd, newfd: RawFd, flags: i32) -> RawFd { } } +pub fn xreadlink(path: &CStr, data: &mut [u8]) -> isize { + mod e { + extern "C" { + pub fn xreadlink(path: *const u8, buf: *mut u8, bufsz: usize) -> isize; + } + } + unsafe { e::xreadlink(path.as_ptr().cast(), data.as_mut_ptr(), data.len()) } +} + +pub fn xreadlinkat(dirfd: RawFd, path: &CStr, data: &mut [u8]) -> isize { + mod e { + extern "C" { + pub fn xreadlinkat(dirfd: i32, path: *const u8, buf: *mut u8, bufsz: usize) -> isize; + } + } + unsafe { e::xreadlinkat(dirfd, path.as_ptr().cast(), data.as_mut_ptr(), data.len()) } +} + #[no_mangle] pub extern "C" fn xsymlink(target: *const c_char, linkpath: *const c_char) -> i32 { unsafe { @@ -376,7 +500,7 @@ pub extern "C" fn xrename(oldname: *const c_char, newname: *const c_char) -> i32 pub extern "C" fn xmkdir(path: *const c_char, mode: mode_t) -> i32 { unsafe { let r = libc::mkdir(path, mode); - if r < 0 { + if r < 0 && *errno() != libc::EEXIST { perror!("mkdir {}", ptr_to_str(path)); } return r; @@ -387,7 +511,7 @@ pub extern "C" fn xmkdir(path: *const c_char, mode: mode_t) -> i32 { pub extern "C" fn xmkdirat(dirfd: RawFd, path: *const c_char, mode: mode_t) -> i32 { unsafe { let r = libc::mkdirat(dirfd, path, mode); - if r < 0 { + if r < 0 && *errno() != libc::EEXIST { perror!("mkdirat {}", ptr_to_str(path)); } return r; diff --git a/native/src/core/cert.cpp b/native/src/core/cert.cpp index d0c388bf4..08a0e0915 100644 --- a/native/src/core/cert.cpp +++ b/native/src/core/cert.cpp @@ -103,11 +103,11 @@ string read_certificate(int fd, int version) { for (int i = 0;; i++) { // i is the absolute offset to end of file uint16_t comment_sz = 0; - xlseek(fd, -static_cast(sizeof(comment_sz)) - i, SEEK_END); + xlseek64(fd, -static_cast(sizeof(comment_sz)) - i, SEEK_END); xxread(fd, &comment_sz, sizeof(comment_sz)); if (comment_sz == i) { // Double check if we actually found the structure - xlseek(fd, -static_cast(sizeof(EOCD)), SEEK_CUR); + xlseek64(fd, -static_cast(sizeof(EOCD)), SEEK_CUR); uint32_t magic = 0; xxread(fd, &magic, sizeof(magic)); if (magic == EOCD_MAGIC) { @@ -125,14 +125,14 @@ string read_certificate(int fd, int version) { // Seek and read central_dir_off to find start of central directory uint32_t central_dir_off = 0; { - constexpr off_t off = offsetof(EOCD, central_dir_off) - sizeof(EOCD::magic); - xlseek(fd, off, SEEK_CUR); + constexpr off64_t off = offsetof(EOCD, central_dir_off) - sizeof(EOCD::magic); + xlseek64(fd, off, SEEK_CUR); } xxread(fd, ¢ral_dir_off, sizeof(central_dir_off)); // Parse APK comment to get version code if (version >= 0) { - xlseek(fd, sizeof(EOCD::comment_sz), SEEK_CUR); + xlseek64(fd, sizeof(EOCD::comment_sz), SEEK_CUR); FILE *fp = fdopen(fd, "r"); // DO NOT close this file pointer int apk_ver = -1; parse_prop_file(fp, [&](string_view key, string_view value) -> bool { @@ -152,7 +152,7 @@ string read_certificate(int fd, int version) { // Next, find the start of the APK signing block { constexpr int off = sizeof(signing_block::block_sz_) + sizeof(signing_block::magic); - xlseek(fd, (off_t) (central_dir_off - off), SEEK_SET); + xlseek64(fd, (off64_t) (central_dir_off - off), SEEK_SET); } xxread(fd, &u64, sizeof(u64)); // u64 = block_sz_ char magic[sizeof(signing_block::magic)] = {0}; @@ -163,7 +163,7 @@ string read_certificate(int fd, int version) { return {}; } uint64_t signing_blk_sz = 0; - xlseek(fd, -static_cast(u64 + sizeof(signing_blk_sz)), SEEK_CUR); + xlseek64(fd, -static_cast(u64 + sizeof(signing_blk_sz)), SEEK_CUR); xxread(fd, &signing_blk_sz, sizeof(signing_blk_sz)); if (signing_blk_sz != u64) { // block_sz != block_sz_, invalid signing block format, abort @@ -184,12 +184,12 @@ string read_certificate(int fd, int version) { xxread(fd, &id, sizeof(id)); if (id == SIGNATURE_SCHEME_V2_MAGIC) { // Skip [signer sequence length] + [1st signer length] + [signed data length] - xlseek(fd, sizeof(uint32_t) * 3, SEEK_CUR); + xlseek64(fd, sizeof(uint32_t) * 3, SEEK_CUR); xxread(fd, &u32, sizeof(u32)); // digest sequence length - xlseek(fd, u32, SEEK_CUR); // skip all digests + xlseek64(fd, u32, SEEK_CUR); // skip all digests - xlseek(fd, sizeof(uint32_t), SEEK_CUR); // cert sequence length + xlseek64(fd, sizeof(uint32_t), SEEK_CUR); // cert sequence length xxread(fd, &u32, sizeof(u32)); // 1st cert length string cert; @@ -199,7 +199,7 @@ string read_certificate(int fd, int version) { return cert; } else { // Skip this id-value pair - xlseek(fd, u64 - sizeof(id), SEEK_CUR); + xlseek64(fd, u64 - sizeof(id), SEEK_CUR); } } diff --git a/native/src/core/daemon.cpp b/native/src/core/daemon.cpp index 7dfc65f86..325de0b30 100644 --- a/native/src/core/daemon.cpp +++ b/native/src/core/daemon.cpp @@ -107,7 +107,7 @@ static void poll_ctrl_handler(pollfd *pfd) { [[noreturn]] static void poll_loop() { // Register poll_ctrl - int pipefd[2]; + auto pipefd = array{-1, -1}; xpipe2(pipefd, O_CLOEXEC); poll_ctrl = pipefd[1]; pollfd poll_ctrl_pfd = { pipefd[0], POLLIN, 0 };