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++ // Functions listed here are just to export to C++
use std::ffi::CStr;
use std::io; use std::io;
use std::os::fd::{BorrowedFd, OwnedFd, RawFd}; use std::os::fd::{BorrowedFd, OwnedFd, RawFd};
@ -10,6 +9,7 @@ use libc::mode_t;
use crate::{ use crate::{
fd_path, map_fd, map_file, mkdirs, realpath, rm_rf, slice_from_ptr_mut, Directory, ResultExt, 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 { 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] #[no_mangle]
unsafe extern "C" fn canonical_path(path: *const c_char, buf: *mut u8, bufsz: usize) -> isize { 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"] #[export_name = "mkdirs"]
unsafe extern "C" fn mkdirs_for_cxx(path: *const c_char, mode: mode_t) -> i32 { 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"] #[export_name = "rm_rf"]
unsafe extern "C" fn rm_rf_for_cxx(path: *const c_char) -> bool { 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] #[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] { pub(crate) fn map_file_for_cxx(path: &[u8], rw: bool) -> &'static mut [u8] {
unsafe { unsafe {
map_file(CStr::from_bytes_with_nul_unchecked(path), rw) map_file(Utf8CStr::from_bytes_unchecked(path), rw)
.log() .log()
.unwrap_or(&mut []) .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 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 { unsafe {
let fd = libc::open(path.as_ptr(), flags, mode as c_uint).check_os_err()?; let fd = libc::open(path.as_ptr(), flags, mode as c_uint).check_os_err()?;
Ok(OwnedFd::from_raw_fd(fd)) 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 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 = let r =
unsafe { readlink_unsafe(path.as_ptr(), data.as_mut_ptr(), data.len()) }.check_os_err()?; unsafe { readlink_unsafe(path.as_ptr(), data.as_mut_ptr(), data.len()) }.check_os_err()?;
Ok(r as usize) 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 // 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 fd = open_fd!(path, O_PATH | O_CLOEXEC)?;
let mut st1: libc::stat; let mut st1: libc::stat;
let mut st2: libc::stat; let mut st2: libc::stat;
@ -75,7 +75,7 @@ pub fn realpath(path: &CStr, buf: &mut [u8]) -> io::Result<usize> {
Ok(len) 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 mut buf = [0_u8; 4096];
let len = copy_cstr(&mut buf, path); let len = copy_cstr(&mut buf, path);
let buf = &mut buf[..len]; let buf = &mut buf[..len];
@ -277,7 +277,7 @@ pub enum WalkResult {
} }
impl Directory { 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()?; let dirp = unsafe { libc::opendir(path.as_ptr()) }.check_os_err()?;
Ok(Directory { dirp }) 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 { unsafe {
let mut stat: libc::stat = mem::zeroed(); let mut stat: libc::stat = mem::zeroed();
libc::lstat(path.as_ptr(), &mut stat).check_os_err()?; 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]); pub struct MappedFile(&'static mut [u8]);
impl MappedFile { impl MappedFile {
pub fn open(path: &CStr) -> io::Result<MappedFile> { pub fn open(path: &Utf8CStr) -> io::Result<MappedFile> {
Ok(MappedFile(map_file(path, false)?)) 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)?)) 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 // 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 flag = if rw { O_RDWR } else { O_RDONLY };
let fd = open_fd!(path, flag | O_CLOEXEC)?; let fd = open_fd!(path, flag | O_CLOEXEC)?;
map_fd(fd.as_fd(), fd.size()?, rw) 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 len
} }
pub fn copy_cstr(dest: &mut [u8], src: &CStr) -> usize { pub fn copy_cstr<T: AsRef<CStr> + ?Sized>(dest: &mut [u8], src: &T) -> usize {
let src = src.to_bytes_with_nul(); let src = src.as_ref().to_bytes_with_nul();
let len = min(src.len(), dest.len()); let len = min(src.len(), dest.len());
dest[..len].copy_from_slice(&src[..len]); dest[..len].copy_from_slice(&src[..len]);
len len
@ -69,7 +69,9 @@ macro_rules! bfmt_cstr {
($buf:expr, $($args:tt)*) => {{ ($buf:expr, $($args:tt)*) => {{
let len = $crate::fmt_to_buf($buf, format_args!($($args)*)); let len = $crate::fmt_to_buf($buf, format_args!($($args)*));
#[allow(unused_unsafe)] #[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)] #[allow(unused_unsafe)]
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 { pub unsafe fn from_bytes_unchecked(buf: &[u8]) -> &Utf8CStr {
&*(buf as *const [u8] as *const Utf8CStr) &*(buf as *const [u8] as *const Utf8CStr)
} }
@ -146,35 +149,46 @@ impl Utf8CStr {
Self::from_cstr(unsafe { CStr::from_ptr(ptr) }) Self::from_cstr(unsafe { CStr::from_ptr(ptr) })
} }
#[inline]
pub fn as_bytes(&self) -> &[u8] { pub fn as_bytes(&self) -> &[u8] {
// The length of the slice is at least 1 due to null termination check // The length of the slice is at least 1 due to null termination check
unsafe { self.inner.get_unchecked(..self.inner.len() - 1) } unsafe { self.inner.get_unchecked(..self.inner.len() - 1) }
} }
#[inline]
pub fn as_bytes_with_nul(&self) -> &[u8] { pub fn as_bytes_with_nul(&self) -> &[u8] {
&self.inner &self.inner
} }
#[inline]
pub fn as_ptr(&self) -> *const c_char { pub fn as_ptr(&self) -> *const c_char {
self.inner.as_ptr().cast() self.inner.as_ptr().cast()
} }
#[inline]
pub fn as_cstr(&self) -> &CStr {
self.as_ref()
}
} }
impl Deref for Utf8CStr { impl Deref for Utf8CStr {
type Target = str; type Target = str;
#[inline]
fn deref(&self) -> &str { fn deref(&self) -> &str {
self.as_ref() self.as_ref()
} }
} }
impl Display for Utf8CStr { impl Display for Utf8CStr {
#[inline]
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
Display::fmt(self.deref(), f) Display::fmt(self.deref(), f)
} }
} }
impl Debug for Utf8CStr { impl Debug for Utf8CStr {
#[inline]
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
Debug::fmt(self.deref(), f) Debug::fmt(self.deref(), f)
} }
@ -199,24 +213,42 @@ impl AsRef<str> for Utf8CStr {
impl AsRef<OsStr> for Utf8CStr { impl AsRef<OsStr> for Utf8CStr {
#[inline] #[inline]
fn as_ref(&self) -> &OsStr { fn as_ref(&self) -> &OsStr {
OsStr::new(self as &str) OsStr::new(self.deref())
} }
} }
impl AsRef<Path> for Utf8CStr { impl AsRef<Path> for Utf8CStr {
#[inline] #[inline]
fn as_ref(&self) -> &Path { 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> { impl PartialEq<CStr> for Utf8CStr {
if ptr.is_null() { #[inline]
Err(StrErr::NullPointerError) fn eq(&self, other: &CStr) -> bool {
} else { self.as_cstr() == other
unsafe { CStr::from_ptr(ptr.cast()) } }
.to_str() }
.map_err(StrErr::from)
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::os::unix::io::RawFd;
use std::ptr; use std::ptr;
@ -8,10 +7,9 @@ use libc::{
ssize_t, SYS_dup3, 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 { mod unsafe_impl {
use std::ffi::CStr;
use std::os::unix::io::RawFd; use std::os::unix::io::RawFd;
use anyhow::Context; use anyhow::Context;
@ -19,8 +17,8 @@ mod unsafe_impl {
use libc::{c_char, nfds_t, off_t, pollfd}; use libc::{c_char, nfds_t, off_t, pollfd};
use crate::{ use crate::{
perror, ptr_to_str, readlink, readlink_unsafe, slice_from_ptr, slice_from_ptr_mut, perror, ptr_to_str, readlink_unsafe, realpath, slice_from_ptr, slice_from_ptr_mut,
ResultExt, ResultExt, Utf8CStr,
}; };
#[no_mangle] #[no_mangle]
@ -40,10 +38,13 @@ mod unsafe_impl {
#[no_mangle] #[no_mangle]
unsafe extern "C" fn xrealpath(path: *const c_char, buf: *mut u8, bufsz: usize) -> isize { 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)) match Utf8CStr::from_ptr(path) {
.with_context(|| format!("realpath {} failed", ptr_to_str(path))) Ok(p) => realpath(p, slice_from_ptr_mut(buf, bufsz))
.with_context(|| format!("realpath {} failed", p))
.log() .log()
.map_or(-1, |v| v as isize) .map_or(-1, |v| v as isize),
Err(_) => -1,
}
} }
#[no_mangle] #[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] #[no_mangle]
pub unsafe extern "C" fn xsymlink(target: *const c_char, linkpath: *const c_char) -> i32 { pub unsafe extern "C" fn xsymlink(target: *const c_char, linkpath: *const c_char) -> i32 {
let r = libc::symlink(target, linkpath); 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] #[no_mangle]
pub unsafe extern "C" fn xmkdirs(path: *const c_char, mode: mode_t) -> i32 { pub unsafe extern "C" fn xmkdirs(path: *const c_char, mode: mode_t) -> i32 {
mkdirs(CStr::from_ptr(path), mode) match Utf8CStr::from_ptr(path) {
.with_context(|| format!("mkdirs {}", ptr_to_str(path))) Ok(p) => mkdirs(p, mode)
.with_context(|| format!("mkdirs {} failed", p))
.log() .log()
.map_or(-1, |_| 0) .map_or(-1, |_| 0),
Err(_) => -1,
}
} }
#[no_mangle] #[no_mangle]

View File

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

View File

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

View File

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