mirror of
https://github.com/topjohnwu/Magisk.git
synced 2025-12-12 10:46:07 +00:00
Create custom cxx binding to Utf8CStr
This commit is contained in:
@@ -6,10 +6,12 @@ use std::path::Path;
|
||||
use std::str::{Utf8Chunks, Utf8Error};
|
||||
use std::{fmt, mem, slice, str};
|
||||
|
||||
use crate::slice_from_ptr_mut;
|
||||
use cxx::{type_id, ExternType};
|
||||
use libc::c_char;
|
||||
use thiserror::Error;
|
||||
|
||||
use crate::slice_from_ptr_mut;
|
||||
|
||||
// Utf8CStr types are UTF-8 validated and null terminated strings.
|
||||
//
|
||||
// Several Utf8CStr types:
|
||||
@@ -380,6 +382,22 @@ impl DerefMut for Utf8CStr {
|
||||
}
|
||||
}
|
||||
|
||||
// Notice that we only implement ExternType on Utf8CStr *reference*
|
||||
unsafe impl ExternType for &Utf8CStr {
|
||||
type Id = type_id!("rust::Utf8CStr");
|
||||
type Kind = cxx::kind::Trivial;
|
||||
}
|
||||
|
||||
macro_rules! const_assert_eq {
|
||||
($left:expr, $right:expr $(,)?) => {
|
||||
const _: [(); $left] = [(); $right];
|
||||
};
|
||||
}
|
||||
|
||||
// Assert ABI layout
|
||||
const_assert_eq!(mem::size_of::<&Utf8CStr>(), mem::size_of::<[usize; 2]>());
|
||||
const_assert_eq!(mem::align_of::<&Utf8CStr>(), mem::align_of::<[usize; 2]>());
|
||||
|
||||
// File system path extensions types
|
||||
|
||||
#[repr(transparent)]
|
||||
|
||||
@@ -10,7 +10,8 @@ use libc::mode_t;
|
||||
use crate::logging::CxxResultExt;
|
||||
pub(crate) use crate::xwrap::*;
|
||||
use crate::{
|
||||
clone_attr, fclone_attr, fd_path, map_fd, map_file, Directory, FsPath, Utf8CStr, Utf8CStrBufRef,
|
||||
clone_attr, cstr, fclone_attr, fd_path, map_fd, map_file, slice_from_ptr, Directory, FsPath,
|
||||
Utf8CStr, Utf8CStrBufRef,
|
||||
};
|
||||
|
||||
pub(crate) fn fd_path_for_cxx(fd: RawFd, buf: &mut [u8]) -> isize {
|
||||
@@ -57,12 +58,8 @@ unsafe extern "C" fn frm_rf(fd: OwnedFd) -> bool {
|
||||
inner(fd).is_ok()
|
||||
}
|
||||
|
||||
pub(crate) fn map_file_for_cxx(path: &[u8], rw: bool) -> &'static mut [u8] {
|
||||
unsafe {
|
||||
map_file(Utf8CStr::from_bytes_unchecked(path), rw)
|
||||
.log_cxx()
|
||||
.unwrap_or(&mut [])
|
||||
}
|
||||
pub(crate) fn map_file_for_cxx(path: &Utf8CStr, rw: bool) -> &'static mut [u8] {
|
||||
map_file(path, rw).log_cxx().unwrap_or(&mut [])
|
||||
}
|
||||
|
||||
pub(crate) fn map_fd_for_cxx(fd: RawFd, sz: usize, rw: bool) -> &'static mut [u8] {
|
||||
@@ -171,3 +168,18 @@ unsafe extern "C" fn fclone_attr_for_cxx(a: RawFd, b: RawFd) -> bool {
|
||||
.log_cxx_with_msg(|w| w.write_str("fclone_attr failed"))
|
||||
.is_ok()
|
||||
}
|
||||
|
||||
#[export_name = "cxx$utf8str$new"]
|
||||
unsafe extern "C" fn str_new(this: &mut &Utf8CStr, s: *const u8, len: usize) {
|
||||
*this = Utf8CStr::from_bytes(slice_from_ptr(s, len)).unwrap_or(cstr!(""));
|
||||
}
|
||||
|
||||
#[export_name = "cxx$utf8str$ptr"]
|
||||
unsafe extern "C" fn str_ptr(this: &&Utf8CStr) -> *const u8 {
|
||||
this.as_ptr().cast()
|
||||
}
|
||||
|
||||
#[export_name = "cxx$utf8str$len"]
|
||||
unsafe extern "C" fn str_len(this: &&Utf8CStr) -> usize {
|
||||
this.len()
|
||||
}
|
||||
|
||||
@@ -189,7 +189,7 @@ sFILE make_file(FILE *fp) {
|
||||
}
|
||||
|
||||
mmap_data::mmap_data(const char *name, bool rw) {
|
||||
auto slice = rust::map_file(byte_view(name), rw);
|
||||
auto slice = rust::map_file(name, rw);
|
||||
if (!slice.empty()) {
|
||||
_buf = slice.data();
|
||||
_sz = slice.size();
|
||||
|
||||
@@ -34,12 +34,17 @@ pub mod ffi {
|
||||
|
||||
unsafe extern "C++" {
|
||||
include!("misc.hpp");
|
||||
|
||||
#[namespace = "rust"]
|
||||
#[cxx_name = "Utf8CStr"]
|
||||
type Utf8CStrRef<'a> = &'a crate::cstr::Utf8CStr;
|
||||
|
||||
fn mut_u8_patch(buf: &mut [u8], from: &[u8], to: &[u8]) -> Vec<usize>;
|
||||
}
|
||||
|
||||
extern "Rust" {
|
||||
#[cxx_name = "log_with_rs"]
|
||||
fn log_from_cxx(level: LogLevelCxx, msg: &[u8]);
|
||||
fn log_from_cxx(level: LogLevelCxx, msg: Utf8CStrRef);
|
||||
#[cxx_name = "set_log_level_state"]
|
||||
fn set_log_level_state_cxx(level: LogLevelCxx, enabled: bool);
|
||||
fn exit_on_error(b: bool);
|
||||
@@ -53,7 +58,7 @@ pub mod ffi {
|
||||
#[cxx_name = "fd_path"]
|
||||
fn fd_path_for_cxx(fd: i32, buf: &mut [u8]) -> isize;
|
||||
#[cxx_name = "map_file"]
|
||||
fn map_file_for_cxx(path: &[u8], rw: bool) -> &'static mut [u8];
|
||||
fn map_file_for_cxx(path: Utf8CStrRef, rw: bool) -> &'static mut [u8];
|
||||
#[cxx_name = "map_fd"]
|
||||
fn map_fd_for_cxx(fd: i32, sz: usize, rw: bool) -> &'static mut [u8];
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@ static int fmt_and_log_with_rs(LogLevel level, const char *fmt, va_list ap) {
|
||||
buf[0] = '\0';
|
||||
// Fortify logs when a fatal error occurs. Do not run through fortify again
|
||||
int len = std::min(__call_bypassing_fortify(vsnprintf)(buf, sz, fmt, ap), sz - 1);
|
||||
log_with_rs(level, byte_view(buf, len + 1));
|
||||
log_with_rs(level, rust::Utf8CStr(buf, len + 1));
|
||||
return len;
|
||||
}
|
||||
|
||||
|
||||
@@ -101,10 +101,8 @@ fn log_with_writer<F: FnOnce(LogWriter)>(level: LogLevel, f: F) {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn log_from_cxx(level: LogLevelCxx, msg: &[u8]) {
|
||||
pub fn log_from_cxx(level: LogLevelCxx, msg: &Utf8CStr) {
|
||||
if let Some(level) = LogLevel::from_i32(level.repr) {
|
||||
// SAFETY: The null termination is handled on the C++ side
|
||||
let msg = unsafe { Utf8CStr::from_bytes_unchecked(msg) };
|
||||
log_with_writer(level, |write| write(level, msg));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -274,3 +274,19 @@ int ssprintf(char *dest, size_t size, const char *fmt, ...) {
|
||||
size_t strscpy(char *dest, const char *src, size_t size) {
|
||||
return std::min(strlcpy(dest, src, size), size - 1);
|
||||
}
|
||||
|
||||
extern "C" void cxx$utf8str$new(rust::Utf8CStr *self, const void *s, size_t len);
|
||||
extern "C" const char *cxx$utf8str$ptr(const rust::Utf8CStr *self);
|
||||
extern "C" size_t cxx$utf8str$len(const rust::Utf8CStr *self);
|
||||
|
||||
rust::Utf8CStr::Utf8CStr(const char *s, size_t len) {
|
||||
cxx$utf8str$new(this, s, len);
|
||||
}
|
||||
|
||||
const char *rust::Utf8CStr::data() const {
|
||||
return cxx$utf8str$ptr(this);
|
||||
}
|
||||
|
||||
size_t rust::Utf8CStr::length() const {
|
||||
return cxx$utf8str$len(this);
|
||||
}
|
||||
|
||||
@@ -331,3 +331,30 @@ constexpr auto operator+(T e) noexcept ->
|
||||
std::enable_if_t<std::is_enum<T>::value, std::underlying_type_t<T>> {
|
||||
return static_cast<std::underlying_type_t<T>>(e);
|
||||
}
|
||||
|
||||
namespace rust {
|
||||
|
||||
struct Utf8CStr {
|
||||
const char *data() const;
|
||||
size_t length() const;
|
||||
Utf8CStr(const char *s, size_t len);
|
||||
|
||||
Utf8CStr() : Utf8CStr("", 1) {};
|
||||
Utf8CStr(const Utf8CStr &o) = default;
|
||||
Utf8CStr(Utf8CStr &&o) = default;
|
||||
Utf8CStr(const char *s) : Utf8CStr(s, strlen(s) + 1) {};
|
||||
Utf8CStr(std::string_view s) : Utf8CStr(s.data(), s.length() + 1) {};
|
||||
Utf8CStr(std::string s) : Utf8CStr(s.data(), s.length() + 1) {};
|
||||
const char *c_str() const { return this->data(); }
|
||||
size_t size() const { return this->length(); }
|
||||
bool empty() const { return this->length() == 0 ; }
|
||||
operator std::string_view() { return {data(), length()}; }
|
||||
|
||||
private:
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wunused-private-field"
|
||||
std::array<std::uintptr_t, 2> repr;
|
||||
#pragma clang diagnostic pop
|
||||
};
|
||||
|
||||
} // namespace rust
|
||||
|
||||
Reference in New Issue
Block a user