diff --git a/native/src/base/dir.rs b/native/src/base/dir.rs index dad493709..b356704ed 100644 --- a/native/src/base/dir.rs +++ b/native/src/base/dir.rs @@ -6,13 +6,14 @@ use crate::{ use libc::{EEXIST, O_CLOEXEC, O_CREAT, O_RDONLY, O_TRUNC, O_WRONLY, dirent, mode_t}; use std::ffi::CStr; use std::fs::File; -use std::ops::Deref; +use std::marker::PhantomData; +use std::ops::{Deref, DerefMut}; use std::os::fd::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, OwnedFd, RawFd}; use std::ptr::NonNull; use std::{mem, slice}; pub struct DirEntry<'a> { - dir: &'a Directory, + dir: BorrowedDirectory<'a>, entry: NonNull, d_name_len: usize, } @@ -168,6 +169,30 @@ pub struct Directory { inner: NonNull, } +#[repr(transparent)] +pub struct BorrowedDirectory<'a> { + inner: NonNull, + phantom: PhantomData<&'a Directory>, +} + +impl Deref for BorrowedDirectory<'_> { + type Target = Directory; + + fn deref(&self) -> &Directory { + // SAFETY: layout of NonNull is the same as Directory + // SAFETY: the lifetime of the raw pointer is tracked in the PhantomData + unsafe { mem::transmute(&self.inner) } + } +} + +impl DerefMut for BorrowedDirectory<'_> { + fn deref_mut(&mut self) -> &mut Directory { + // SAFETY: layout of NonNull is the same as Directory + // SAFETY: the lifetime of the raw pointer is tracked in the PhantomData + unsafe { mem::transmute(&mut self.inner) } + } +} + pub enum WalkResult { Continue, Abort, @@ -175,6 +200,13 @@ pub enum WalkResult { } impl Directory { + fn borrow(&self) -> BorrowedDirectory { + BorrowedDirectory { + inner: self.inner, + phantom: PhantomData, + } + } + pub fn open(path: &Utf8CStr) -> OsResult { let dirp = unsafe { libc::opendir(path.as_ptr()) }; let dirp = dirp.as_os_result("opendir", Some(path), None)?; @@ -199,7 +231,7 @@ impl Directory { self.read() } else { let e = DirEntry { - dir: self, + dir: self.borrow(), entry: NonNull::from(entry), d_name_len: d_name.to_bytes_with_nul().len(), }; @@ -304,7 +336,7 @@ impl Directory { .check_os_err("symlinkat", Some(&target), e.utf8_name())?; } let new_entry = DirEntry { - dir, + dir: dir.borrow(), entry: e.entry, d_name_len: e.d_name_len, }; diff --git a/native/src/base/xwrap.rs b/native/src/base/xwrap.rs index 8c20d9bb3..f38912b0f 100644 --- a/native/src/base/xwrap.rs +++ b/native/src/base/xwrap.rs @@ -2,7 +2,7 @@ use crate::cxx_extern::readlinkat; use crate::{ - CxxResultExt, Directory, FsPath, LibcReturn, Utf8CStr, cstr_buf, slice_from_ptr, + BorrowedDirectory, CxxResultExt, FsPath, LibcReturn, Utf8CStr, cstr_buf, slice_from_ptr, slice_from_ptr_mut, }; use libc::{ @@ -190,7 +190,7 @@ extern "C" fn xfdopendir(fd: RawFd) -> *mut libc::DIR { } #[unsafe(no_mangle)] -unsafe extern "C" fn xreaddir(mut dir: ManuallyDrop) -> *mut libc::dirent { +unsafe extern "C" fn xreaddir(mut dir: BorrowedDirectory) -> *mut libc::dirent { dir.read() .log_cxx() .ok()