Introduce BorrowedDirectory

This commit is contained in:
topjohnwu 2025-04-14 15:17:16 -07:00 committed by John Wu
parent 30e79310ab
commit 55b036c071
2 changed files with 38 additions and 6 deletions

View File

@ -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<dirent>,
d_name_len: usize,
}
@ -168,6 +169,30 @@ pub struct Directory {
inner: NonNull<libc::DIR>,
}
#[repr(transparent)]
pub struct BorrowedDirectory<'a> {
inner: NonNull<libc::DIR>,
phantom: PhantomData<&'a Directory>,
}
impl Deref for BorrowedDirectory<'_> {
type Target = Directory;
fn deref(&self) -> &Directory {
// SAFETY: layout of NonNull<libc::DIR> 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<libc::DIR> 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<Directory> {
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,
};

View File

@ -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<Directory>) -> *mut libc::dirent {
unsafe extern "C" fn xreaddir(mut dir: BorrowedDirectory) -> *mut libc::dirent {
dir.read()
.log_cxx()
.ok()