diff --git a/native/src/base/cstr.rs b/native/src/base/cstr.rs index 99e2ab1b6..36f79eb6f 100644 --- a/native/src/base/cstr.rs +++ b/native/src/base/cstr.rs @@ -125,9 +125,7 @@ impl Default for Utf8CStrBuffer<'static, 4096> { // Trait definitions -pub trait Utf8CStrBuf: - Write + AsRef + AsMut + Deref + DerefMut -{ +pub trait Utf8CStrBuf: Write + AsRef + Deref { // The length of the string without the terminating null character. // assert_true(len <= capacity - 1) fn len(&self) -> usize; @@ -143,6 +141,7 @@ pub trait Utf8CStrBuf: // is capacity - 1, because the last byte is reserved for the terminating null character. fn capacity(&self) -> usize; fn clear(&mut self); + fn as_mut_ptr(&mut self) -> *mut c_char; #[inline(always)] fn is_empty(&self) -> bool { @@ -150,52 +149,8 @@ pub trait Utf8CStrBuf: } } -trait Utf8CStrBufWithSlice: Utf8CStrBuf { - fn buf(&self) -> &[u8]; - unsafe fn mut_buf(&mut self) -> &mut [u8]; -} - trait AsUtf8CStr { fn as_utf8_cstr(&self) -> &Utf8CStr; - fn as_utf8_cstr_mut(&mut self) -> &mut Utf8CStr; -} - -impl AsUtf8CStr for T { - #[inline(always)] - fn as_utf8_cstr(&self) -> &Utf8CStr { - // SAFETY: the internal buffer is always UTF-8 checked - // SAFETY: self.used is guaranteed to always <= SIZE - 1 - unsafe { Utf8CStr::from_bytes_unchecked(self.buf().get_unchecked(..(self.len() + 1))) } - } - - #[inline(always)] - fn as_utf8_cstr_mut(&mut self) -> &mut Utf8CStr { - // SAFETY: the internal buffer is always UTF-8 checked - // SAFETY: self.used is guaranteed to always <= SIZE - 1 - unsafe { - let len = self.len() + 1; - Utf8CStr::from_bytes_unchecked_mut(self.mut_buf().get_unchecked_mut(..len)) - } - } -} - -// Implementation for Utf8CString - -fn utf8_cstr_append(buf: &mut dyn Utf8CStrBufWithSlice, s: &[u8]) -> usize { - let mut used = buf.len(); - if used >= buf.capacity() - 1 { - // Truncate - return 0; - } - let dest = unsafe { &mut buf.mut_buf()[used..] }; - let len = min(s.len(), dest.len() - 1); - if len > 0 { - dest[..len].copy_from_slice(&s[..len]); - } - dest[len] = b'\0'; - used += len; - unsafe { buf.set_len(used) }; - len } pub trait StringExt { @@ -257,17 +212,6 @@ impl AsUtf8CStr for Utf8CString { // SAFETY: the internal string is always null terminated unsafe { mem::transmute(slice::from_raw_parts(self.0.as_ptr(), self.0.len() + 1)) } } - - #[inline(always)] - fn as_utf8_cstr_mut(&mut self) -> &mut Utf8CStr { - // SAFETY: the internal string is always null terminated - unsafe { - mem::transmute(slice::from_raw_parts_mut( - self.0.as_mut_ptr(), - self.0.len() + 1, - )) - } - } } impl Utf8CStrBuf for Utf8CString { @@ -296,6 +240,10 @@ impl Utf8CStrBuf for Utf8CString { self.0.clear(); self.0.nul_terminate(); } + + fn as_mut_ptr(&mut self) -> *mut c_char { + self.0.as_mut_ptr().cast() + } } impl From for Utf8CString { @@ -330,18 +278,6 @@ impl<'a> From<&'a mut [u8]> for Utf8CStrBufRef<'a> { } } -impl Utf8CStrBufWithSlice for Utf8CStrBufRef<'_> { - #[inline(always)] - fn buf(&self) -> &[u8] { - self.buf - } - - #[inline(always)] - unsafe fn mut_buf(&mut self) -> &mut [u8] { - self.buf - } -} - // UTF-8 validated + null terminated buffer on the stack pub struct Utf8CStrBufArr { used: usize, @@ -357,18 +293,6 @@ impl Utf8CStrBufArr { } } -impl Utf8CStrBufWithSlice for Utf8CStrBufArr { - #[inline(always)] - fn buf(&self) -> &[u8] { - &self.buf - } - - #[inline(always)] - unsafe fn mut_buf(&mut self) -> &mut [u8] { - &mut self.buf - } -} - impl Default for Utf8CStrBufArr<4096> { fn default() -> Self { Utf8CStrBufArr::<4096>::new() @@ -400,7 +324,7 @@ impl Utf8CStr { Self::from_cstr(CStr::from_bytes_with_nul(buf)?) } - pub fn from_string(s: &mut String) -> &mut Utf8CStr { + pub fn from_string(s: &mut String) -> &Utf8CStr { let buf = s.nul_terminate(); // SAFETY: the null byte is explicitly added to the buffer unsafe { mem::transmute(buf) } @@ -411,11 +335,6 @@ impl Utf8CStr { unsafe { mem::transmute(buf) } } - #[inline(always)] - unsafe fn from_bytes_unchecked_mut(buf: &mut [u8]) -> &mut Utf8CStr { - unsafe { mem::transmute(buf) } - } - pub unsafe fn from_ptr<'a>(ptr: *const c_char) -> Result<&'a Utf8CStr, StrErr> { if ptr.is_null() { return Err(StrErr::NullPointerError); @@ -457,13 +376,6 @@ impl Utf8CStr { // SAFETY: The length of the slice is at least 1 due to null termination check unsafe { str::from_utf8_unchecked(self.0.get_unchecked(..self.0.len() - 1)) } } - - #[inline(always)] - pub fn as_str_mut(&mut self) -> &mut str { - // SAFETY: Already UTF-8 validated during construction - // SAFETY: The length of the slice is at least 1 due to null termination check - unsafe { str::from_utf8_unchecked_mut(self.0.get_unchecked_mut(..self.0.len() - 1)) } - } } impl Deref for Utf8CStr { @@ -475,13 +387,6 @@ impl Deref for Utf8CStr { } } -impl DerefMut for Utf8CStr { - #[inline(always)] - fn deref_mut(&mut self) -> &mut Self::Target { - self.as_str_mut() - } -} - impl ToOwned for Utf8CStr { type Owned = Utf8CString; @@ -524,47 +429,28 @@ impl FsPath { unsafe { mem::transmute(value) } } - #[inline(always)] - pub fn from_mut + ?Sized>(value: &mut T) -> &mut FsPath { - unsafe { mem::transmute(value.as_mut()) } + pub fn follow_link(&self) -> &FsPathFollow { + unsafe { mem::transmute(self) } } } -impl Deref for FsPath { - type Target = Utf8CStr; - +impl AsUtf8CStr for FsPath { #[inline(always)] - fn deref(&self) -> &Utf8CStr { + fn as_utf8_cstr(&self) -> &Utf8CStr { &self.0 } } -impl DerefMut for FsPath { - #[inline(always)] - fn deref_mut(&mut self) -> &mut Utf8CStr { - &mut self.0 - } -} - #[repr(transparent)] pub struct FsPathFollow(Utf8CStr); -impl Deref for FsPathFollow { - type Target = Utf8CStr; - +impl AsUtf8CStr for FsPathFollow { #[inline(always)] - fn deref(&self) -> &Utf8CStr { + fn as_utf8_cstr(&self) -> &Utf8CStr { &self.0 } } -impl DerefMut for FsPathFollow { - #[inline(always)] - fn deref_mut(&mut self) -> &mut Utf8CStr { - &mut self.0 - } -} - pub struct FsPathBuf<'a, const N: usize>(pub Utf8CStrBuffer<'a, N>); impl From for FsPathBuf<'static, 0> { @@ -624,15 +510,30 @@ impl Deref for FsPathBuf<'_, N> { } } -impl DerefMut for FsPathBuf<'_, N> { - fn deref_mut(&mut self) -> &mut FsPath { - FsPath::from_mut(self.0.deref_mut()) - } +// impl Deref for T { ... } +macro_rules! impl_cstr_deref { + ($( ($t:ty, $($g:tt)*) )*) => {$( + impl<$($g)*> Deref for $t { + type Target = Utf8CStr; + + #[inline(always)] + fn deref(&self) -> &Utf8CStr { + self.as_utf8_cstr() + } + } + )*} } -// Boilerplate trait implementations +impl_cstr_deref!( + (FsPath,) + (FsPathFollow,) + (Utf8CStrBufRef<'_>,) + (Utf8CStrBufArr, const N: usize) + (Utf8CString,) +); -macro_rules! impl_str { +// impl> BoilerPlate for T { ... } +macro_rules! impl_cstr_misc { ($( ($t:ty, $($g:tt)*) )*) => {$( impl<$($g)*> AsRef for $t { #[inline(always)] @@ -709,7 +610,7 @@ macro_rules! impl_str { )*} } -impl_str!( +impl_cstr_misc!( (Utf8CStr,) (FsPath,) (FsPathFollow,) @@ -719,46 +620,31 @@ impl_str!( (Utf8CString,) ); -macro_rules! impl_str_buf { - ($( ($t:ty, $($g:tt)*) )*) => {$( - impl<$($g)*> Write for $t { - #[inline(always)] - fn write_str(&mut self, s: &str) -> fmt::Result { - self.push_str(s); - Ok(()) - } - } - impl<$($g)*> Deref for $t { - type Target = Utf8CStr; - - #[inline(always)] - fn deref(&self) -> &Utf8CStr { - self.as_utf8_cstr() - } - } - impl<$($g)*> DerefMut for $t { - #[inline(always)] - fn deref_mut(&mut self) -> &mut Utf8CStr { - self.as_utf8_cstr_mut() - } - } - impl<$($g)*> AsMut for $t { - #[inline(always)] - fn as_mut(&mut self) -> &mut Utf8CStr { - self.as_utf8_cstr_mut() - } - } - )*} +fn copy_cstr_truncate(dest: &mut [u8], src: &[u8]) -> usize { + if dest.len() <= 1 { + // Truncate + return 0; + } + let len = min(src.len(), dest.len() - 1); + if len > 0 { + dest[..len].copy_from_slice(&src[..len]); + } + dest[len] = b'\0'; + len } -impl_str_buf!( - (Utf8CStrBufRef<'_>,) - (Utf8CStrBufArr, const N: usize) - (Utf8CString,) -); - -macro_rules! impl_str_buf_with_slice { +// impl AsUtf8CStr for T { ... } +// impl Utf8CStrBuf for T { ... } +macro_rules! impl_cstr_buf { ($( ($t:ty, $($g:tt)*) )*) => {$( + impl<$($g)*> AsUtf8CStr for $t { + #[inline(always)] + fn as_utf8_cstr(&self) -> &Utf8CStr { + // SAFETY: the internal buffer is always UTF-8 checked + // SAFETY: self.used is guaranteed to always <= SIZE - 1 + unsafe { Utf8CStr::from_bytes_unchecked(self.buf.get_unchecked(..(self.used + 1))) } + } + } impl<$($g)*> Utf8CStrBuf for $t { #[inline(always)] fn len(&self) -> usize { @@ -770,7 +656,11 @@ macro_rules! impl_str_buf_with_slice { } #[inline(always)] fn push_str(&mut self, s: &str) -> usize { - utf8_cstr_append(self, s.as_bytes()) + // SAFETY: self.used is guaranteed to always <= SIZE - 1 + let dest = unsafe { self.buf.get_unchecked_mut(self.used..) }; + let len = copy_cstr_truncate(dest, s.as_bytes()); + self.used += len; + len } #[inline(always)] fn capacity(&self) -> usize { @@ -781,15 +671,38 @@ macro_rules! impl_str_buf_with_slice { self.buf[0] = b'\0'; self.used = 0; } + #[inline(always)] + fn as_mut_ptr(&mut self) -> *mut c_char { + self.buf.as_mut_ptr().cast() + } } )*} } -impl_str_buf_with_slice!( +impl_cstr_buf!( (Utf8CStrBufRef<'_>,) (Utf8CStrBufArr, const N: usize) ); +// impl Write for T { ... } +macro_rules! impl_cstr_buf_write { + ($( ($t:ty, $($g:tt)*) )*) => {$( + impl<$($g)*> Write for $t { + #[inline(always)] + fn write_str(&mut self, s: &str) -> fmt::Result { + self.push_str(s); + Ok(()) + } + } + )*} +} + +impl_cstr_buf_write!( + (Utf8CStrBufRef<'_>,) + (Utf8CStrBufArr, const N: usize) + (Utf8CString,) +); + #[macro_export] macro_rules! cstr { ($str:expr) => {{ diff --git a/native/src/base/files.rs b/native/src/base/files.rs index 1a1e06d65..46c4584cb 100644 --- a/native/src/base/files.rs +++ b/native/src/base/files.rs @@ -194,10 +194,6 @@ impl FileAttr { const XATTR_NAME_SELINUX: &CStr = c"security.selinux"; impl FsPath { - pub fn follow_link(&self) -> &FsPathFollow { - unsafe { mem::transmute(self) } - } - pub fn open(&self, flags: i32) -> OsResult { Ok(File::from(open_fd!(self, flags)?)) } diff --git a/native/src/core/resetprop/persist.rs b/native/src/core/resetprop/persist.rs index 7dafd6083..e617f50d5 100644 --- a/native/src/core/resetprop/persist.rs +++ b/native/src/core/resetprop/persist.rs @@ -84,7 +84,7 @@ fn file_set_prop(name: &Utf8CStr, value: Option<&Utf8CStr>) -> LoggedResult<()> .join("prop.XXXXXX"); { let mut f = unsafe { - mkstemp(tmp.as_mut_ptr()) + mkstemp(tmp.0.as_mut_ptr()) .as_os_result("mkstemp", None, None) .map(|fd| File::from_raw_fd(fd))? }; @@ -114,7 +114,7 @@ fn proto_write_props(props: &PersistentProperties) -> LoggedResult<()> { let mut tmp = FsPathBuf::default().join(concatcp!(PERSIST_PROP, ".XXXXXX")); { let f = unsafe { - mkstemp(tmp.as_mut_ptr()) + mkstemp(tmp.0.as_mut_ptr()) .as_os_result("mkstemp", None, None) .map(|fd| File::from_raw_fd(fd))? };