Replace all CStr usage to Utf8CStr

This commit is contained in:
topjohnwu 2023-06-12 05:59:50 -07:00
parent caae932117
commit cb3ab63815
7 changed files with 97 additions and 62 deletions

View File

@ -1,6 +1,5 @@
// Functions listed here are just to export to C++
use std::ffi::CStr;
use std::io;
use std::os::fd::{BorrowedFd, OwnedFd, RawFd};
@ -10,6 +9,7 @@ use libc::mode_t;
use crate::{
fd_path, map_fd, map_file, mkdirs, realpath, rm_rf, slice_from_ptr_mut, Directory, ResultExt,
Utf8CStr,
};
pub(crate) fn fd_path_for_cxx(fd: RawFd, buf: &mut [u8]) -> isize {
@ -21,17 +21,26 @@ pub(crate) fn fd_path_for_cxx(fd: RawFd, buf: &mut [u8]) -> isize {
#[no_mangle]
unsafe extern "C" fn canonical_path(path: *const c_char, buf: *mut u8, bufsz: usize) -> isize {
realpath(CStr::from_ptr(path), slice_from_ptr_mut(buf, bufsz)).map_or(-1, |v| v as isize)
match Utf8CStr::from_ptr(path) {
Ok(p) => realpath(p, slice_from_ptr_mut(buf, bufsz)).map_or(-1, |v| v as isize),
Err(_) => -1,
}
}
#[export_name = "mkdirs"]
unsafe extern "C" fn mkdirs_for_cxx(path: *const c_char, mode: mode_t) -> i32 {
mkdirs(CStr::from_ptr(path), mode).map_or(-1, |_| 0)
match Utf8CStr::from_ptr(path) {
Ok(p) => mkdirs(p, mode).map_or(-1, |_| 0),
Err(_) => -1,
}
}
#[export_name = "rm_rf"]
unsafe extern "C" fn rm_rf_for_cxx(path: *const c_char) -> bool {
rm_rf(CStr::from_ptr(path)).map_or(false, |_| true)
match Utf8CStr::from_ptr(path) {
Ok(p) => rm_rf(p).map_or(false, |_| true),
Err(_) => false,
}
}
#[no_mangle]
@ -44,7 +53,7 @@ unsafe extern "C" fn frm_rf(fd: OwnedFd) -> bool {
pub(crate) fn map_file_for_cxx(path: &[u8], rw: bool) -> &'static mut [u8] {
unsafe {
map_file(CStr::from_bytes_with_nul_unchecked(path), rw)
map_file(Utf8CStr::from_bytes_unchecked(path), rw)
.log()
.unwrap_or(&mut [])
}

View File

@ -10,9 +10,9 @@ use std::{io, mem, ptr, slice};
use libc::{c_char, c_uint, dirent, mode_t, EEXIST, ENOENT, O_CLOEXEC, O_PATH, O_RDONLY, O_RDWR};
use crate::{bfmt_cstr, copy_cstr, cstr, errno, error, LibcReturn};
use crate::{bfmt_cstr, copy_cstr, cstr, errno, error, LibcReturn, Utf8CStr};
pub fn __open_fd_impl(path: &CStr, flags: i32, mode: mode_t) -> io::Result<OwnedFd> {
pub fn __open_fd_impl(path: &Utf8CStr, flags: i32, mode: mode_t) -> io::Result<OwnedFd> {
unsafe {
let fd = libc::open(path.as_ptr(), flags, mode as c_uint).check_os_err()?;
Ok(OwnedFd::from_raw_fd(fd))
@ -37,7 +37,7 @@ pub unsafe fn readlink_unsafe(path: *const c_char, buf: *mut u8, bufsz: usize) -
r
}
pub fn readlink(path: &CStr, data: &mut [u8]) -> io::Result<usize> {
pub fn readlink(path: &Utf8CStr, data: &mut [u8]) -> io::Result<usize> {
let r =
unsafe { readlink_unsafe(path.as_ptr(), data.as_mut_ptr(), data.len()) }.check_os_err()?;
Ok(r as usize)
@ -50,7 +50,7 @@ pub fn fd_path(fd: RawFd, buf: &mut [u8]) -> io::Result<usize> {
}
// Inspired by https://android.googlesource.com/platform/bionic/+/master/libc/bionic/realpath.cpp
pub fn realpath(path: &CStr, buf: &mut [u8]) -> io::Result<usize> {
pub fn realpath(path: &Utf8CStr, buf: &mut [u8]) -> io::Result<usize> {
let fd = open_fd!(path, O_PATH | O_CLOEXEC)?;
let mut st1: libc::stat;
let mut st2: libc::stat;
@ -75,7 +75,7 @@ pub fn realpath(path: &CStr, buf: &mut [u8]) -> io::Result<usize> {
Ok(len)
}
pub fn mkdirs(path: &CStr, mode: mode_t) -> io::Result<()> {
pub fn mkdirs(path: &Utf8CStr, mode: mode_t) -> io::Result<()> {
let mut buf = [0_u8; 4096];
let len = copy_cstr(&mut buf, path);
let buf = &mut buf[..len];
@ -277,7 +277,7 @@ pub enum WalkResult {
}
impl Directory {
pub fn open(path: &CStr) -> io::Result<Directory> {
pub fn open(path: &Utf8CStr) -> io::Result<Directory> {
let dirp = unsafe { libc::opendir(path.as_ptr()) }.check_os_err()?;
Ok(Directory { dirp })
}
@ -420,7 +420,7 @@ impl Drop for Directory {
}
}
pub fn rm_rf(path: &CStr) -> io::Result<()> {
pub fn rm_rf(path: &Utf8CStr) -> io::Result<()> {
unsafe {
let mut stat: libc::stat = mem::zeroed();
libc::lstat(path.as_ptr(), &mut stat).check_os_err()?;
@ -490,11 +490,11 @@ impl<T: AsRawFd> FdExt for T {
pub struct MappedFile(&'static mut [u8]);
impl MappedFile {
pub fn open(path: &CStr) -> io::Result<MappedFile> {
pub fn open(path: &Utf8CStr) -> io::Result<MappedFile> {
Ok(MappedFile(map_file(path, false)?))
}
pub fn open_rw(path: &CStr) -> io::Result<MappedFile> {
pub fn open_rw(path: &Utf8CStr) -> io::Result<MappedFile> {
Ok(MappedFile(map_file(path, true)?))
}
@ -524,7 +524,7 @@ impl Drop for MappedFile {
}
// We mark the returned slice static because it is valid until explicitly unmapped
pub(crate) fn map_file(path: &CStr, rw: bool) -> io::Result<&'static mut [u8]> {
pub(crate) fn map_file(path: &Utf8CStr, rw: bool) -> io::Result<&'static mut [u8]> {
let flag = if rw { O_RDWR } else { O_RDONLY };
let fd = open_fd!(path, flag | O_CLOEXEC)?;
map_fd(fd.as_fd(), fd.size()?, rw)

View File

@ -17,8 +17,8 @@ pub fn copy_str<T: AsRef<[u8]>>(dest: &mut [u8], src: T) -> usize {
len
}
pub fn copy_cstr(dest: &mut [u8], src: &CStr) -> usize {
let src = src.to_bytes_with_nul();
pub fn copy_cstr<T: AsRef<CStr> + ?Sized>(dest: &mut [u8], src: &T) -> usize {
let src = src.as_ref().to_bytes_with_nul();
let len = min(src.len(), dest.len());
dest[..len].copy_from_slice(&src[..len]);
len
@ -69,7 +69,9 @@ macro_rules! bfmt_cstr {
($buf:expr, $($args:tt)*) => {{
let len = $crate::fmt_to_buf($buf, format_args!($($args)*));
#[allow(unused_unsafe)]
unsafe { std::ffi::CStr::from_bytes_with_nul_unchecked(&$buf[..(len + 1)]) }
unsafe {
$crate::Utf8CStr::from_bytes_unchecked($buf.get_unchecked(..(len + 1)))
}
}};
}
@ -84,7 +86,7 @@ macro_rules! cstr {
);
#[allow(unused_unsafe)]
unsafe {
std::ffi::CStr::from_bytes_with_nul_unchecked(concat!($str, "\0").as_bytes())
$crate::Utf8CStr::from_bytes_unchecked(concat!($str, "\0").as_bytes())
}
}};
}
@ -135,6 +137,7 @@ impl Utf8CStr {
}
}
#[inline]
pub unsafe fn from_bytes_unchecked(buf: &[u8]) -> &Utf8CStr {
&*(buf as *const [u8] as *const Utf8CStr)
}
@ -146,35 +149,46 @@ impl Utf8CStr {
Self::from_cstr(unsafe { CStr::from_ptr(ptr) })
}
#[inline]
pub fn as_bytes(&self) -> &[u8] {
// The length of the slice is at least 1 due to null termination check
unsafe { self.inner.get_unchecked(..self.inner.len() - 1) }
}
#[inline]
pub fn as_bytes_with_nul(&self) -> &[u8] {
&self.inner
}
#[inline]
pub fn as_ptr(&self) -> *const c_char {
self.inner.as_ptr().cast()
}
#[inline]
pub fn as_cstr(&self) -> &CStr {
self.as_ref()
}
}
impl Deref for Utf8CStr {
type Target = str;
#[inline]
fn deref(&self) -> &str {
self.as_ref()
}
}
impl Display for Utf8CStr {
#[inline]
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
Display::fmt(self.deref(), f)
}
}
impl Debug for Utf8CStr {
#[inline]
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
Debug::fmt(self.deref(), f)
}
@ -199,24 +213,42 @@ impl AsRef<str> for Utf8CStr {
impl AsRef<OsStr> for Utf8CStr {
#[inline]
fn as_ref(&self) -> &OsStr {
OsStr::new(self as &str)
OsStr::new(self.deref())
}
}
impl AsRef<Path> for Utf8CStr {
#[inline]
fn as_ref(&self) -> &Path {
Path::new(self)
Path::new(self.deref())
}
}
pub fn ptr_to_str_result<'a, T>(ptr: *const T) -> Result<&'a str, StrErr> {
if ptr.is_null() {
Err(StrErr::NullPointerError)
} else {
unsafe { CStr::from_ptr(ptr.cast()) }
.to_str()
.map_err(StrErr::from)
impl PartialEq<CStr> for Utf8CStr {
#[inline]
fn eq(&self, other: &CStr) -> bool {
self.as_cstr() == other
}
}
impl PartialEq<str> for Utf8CStr {
#[inline]
fn eq(&self, other: &str) -> bool {
self.deref() == other
}
}
impl PartialEq<Utf8CStr> for CStr {
#[inline]
fn eq(&self, other: &Utf8CStr) -> bool {
self == other.as_cstr()
}
}
impl PartialEq<Utf8CStr> for str {
#[inline]
fn eq(&self, other: &Utf8CStr) -> bool {
self == other.deref()
}
}

View File

@ -1,4 +1,3 @@
use std::ffi::CStr;
use std::os::unix::io::RawFd;
use std::ptr;
@ -8,10 +7,9 @@ use libc::{
ssize_t, SYS_dup3,
};
use crate::{cstr, errno, error, mkdirs, perror, ptr_to_str, raw_cstr, ResultExt};
use crate::{cstr, errno, error, mkdirs, perror, ptr_to_str, raw_cstr, ResultExt, Utf8CStr};
mod unsafe_impl {
use std::ffi::CStr;
use std::os::unix::io::RawFd;
use anyhow::Context;
@ -19,8 +17,8 @@ mod unsafe_impl {
use libc::{c_char, nfds_t, off_t, pollfd};
use crate::{
perror, ptr_to_str, readlink, readlink_unsafe, slice_from_ptr, slice_from_ptr_mut,
ResultExt,
perror, ptr_to_str, readlink_unsafe, realpath, slice_from_ptr, slice_from_ptr_mut,
ResultExt, Utf8CStr,
};
#[no_mangle]
@ -40,10 +38,13 @@ mod unsafe_impl {
#[no_mangle]
unsafe extern "C" fn xrealpath(path: *const c_char, buf: *mut u8, bufsz: usize) -> isize {
readlink(CStr::from_ptr(path), slice_from_ptr_mut(buf, bufsz))
.with_context(|| format!("realpath {} failed", ptr_to_str(path)))
.log()
.map_or(-1, |v| v as isize)
match Utf8CStr::from_ptr(path) {
Ok(p) => realpath(p, slice_from_ptr_mut(buf, bufsz))
.with_context(|| format!("realpath {} failed", p))
.log()
.map_or(-1, |v| v as isize),
Err(_) => -1,
}
}
#[no_mangle]
@ -475,16 +476,6 @@ pub extern "C" fn xdup3(oldfd: RawFd, newfd: RawFd, flags: i32) -> RawFd {
}
}
#[inline]
pub fn xreadlink(path: &CStr, data: &mut [u8]) -> isize {
unsafe { unsafe_impl::xreadlink(path.as_ptr(), data.as_mut_ptr(), data.len()) }
}
#[inline]
pub fn xreadlinkat(dirfd: RawFd, path: &CStr, data: &mut [u8]) -> isize {
unsafe { unsafe_impl::xreadlinkat(dirfd, path.as_ptr(), data.as_mut_ptr(), data.len()) }
}
#[no_mangle]
pub unsafe extern "C" fn xsymlink(target: *const c_char, linkpath: *const c_char) -> i32 {
let r = libc::symlink(target, linkpath);
@ -579,10 +570,13 @@ pub unsafe extern "C" fn xmkdir(path: *const c_char, mode: mode_t) -> i32 {
#[no_mangle]
pub unsafe extern "C" fn xmkdirs(path: *const c_char, mode: mode_t) -> i32 {
mkdirs(CStr::from_ptr(path), mode)
.with_context(|| format!("mkdirs {}", ptr_to_str(path)))
.log()
.map_or(-1, |_| 0)
match Utf8CStr::from_ptr(path) {
Ok(p) => mkdirs(p, mode)
.with_context(|| format!("mkdirs {} failed", p))
.log()
.map_or(-1, |_| 0),
Err(_) => -1,
}
}
#[no_mangle]

View File

@ -155,8 +155,8 @@ impl Cpio {
pub(crate) fn load_from_file(path: &Utf8CStr) -> anyhow::Result<Self> {
eprintln!("Loading cpio: [{}]", path);
let data = MappedFile::open(path.as_ref())?;
Self::load_from_data(data.as_ref())
let file = MappedFile::open(path)?;
Self::load_from_data(file.as_ref())
}
fn dump(&self, path: &str) -> anyhow::Result<()> {

View File

@ -7,7 +7,7 @@ use byteorder::{BigEndian, ReadBytesExt};
use protobuf::{EnumFull, Message};
use base::libc::c_char;
use base::{ptr_to_str_result, ReadSeekExt, StrErr};
use base::{ReadSeekExt, StrErr, Utf8CStr};
use base::{ResultExt, WriteExt};
use crate::ffi;
@ -26,9 +26,9 @@ macro_rules! bad_payload {
const PAYLOAD_MAGIC: &str = "CrAU";
fn do_extract_boot_from_payload(
in_path: &str,
partition_name: Option<&str>,
out_path: Option<&str>,
in_path: &Utf8CStr,
partition_name: Option<&Utf8CStr>,
out_path: Option<&Utf8CStr>,
) -> anyhow::Result<()> {
let mut reader = BufReader::new(if in_path == "-" {
unsafe { File::from_raw_fd(0) }
@ -193,13 +193,13 @@ pub fn extract_boot_from_payload(
partition: *const c_char,
out_path: *const c_char,
) -> anyhow::Result<()> {
let in_path = ptr_to_str_result(in_path)?;
let partition = match ptr_to_str_result(partition) {
let in_path = unsafe { Utf8CStr::from_ptr(in_path) }?;
let partition = match unsafe { Utf8CStr::from_ptr(partition) } {
Ok(s) => Some(s),
Err(StrErr::NullPointerError) => None,
Err(e) => Err(e)?,
};
let out_path = match ptr_to_str_result(out_path) {
let out_path = match unsafe { Utf8CStr::from_ptr(out_path) } {
Ok(s) => Some(s),
Err(StrErr::NullPointerError) => None,
Err(e) => Err(e)?,

View File

@ -1,8 +1,8 @@
#![allow(clippy::missing_safety_doc)]
use base::Utf8CStr;
use daemon::*;
use logging::*;
use std::ffi::CStr;
#[path = "../include/consts.rs"]
mod consts;
@ -39,6 +39,6 @@ pub mod ffi {
fn rust_test_entry() {}
pub fn get_prop(name: &CStr, persist: bool) -> String {
pub fn get_prop(name: &Utf8CStr, persist: bool) -> String {
unsafe { ffi::get_prop_rs(name.as_ptr(), persist) }
}