/// A directory iterator implemented with getdents. /// /// Note: This implementation does not handle growing the buffer. If this /// functionality is necessary, you'll need to drop the current iterator, /// resize the buffer, and then re-create the iterator. The iterator is /// guaranteed to continue where it left off provided the file descriptor isn't /// changed. See the example in [`RawDir::new`]. pubstruct RawDir<'buf, Fd: AsFd> {
fd: Fd,
buf: &'buf mut [MaybeUninit<u8>],
initialized: usize,
offset: usize,
}
impl<'buf, Fd: AsFd> RawDir<'buf, Fd> { /// Create a new iterator from the given file descriptor and buffer. /// /// Note: the buffer size may be trimmed to accommodate alignment /// requirements. /// /// # Examples /// /// ## Simple but non-portable /// /// These examples are non-portable, because file systems may not have a /// maximum file name length. If you can make assumptions that bound /// this length, then these examples may suffice. /// /// Using the heap: /// /// ``` /// # use std::mem::MaybeUninit; /// # use rustix::fs::{CWD, Mode, OFlags, openat, RawDir}; /// # use rustix::cstr; /// /// let fd = openat( /// CWD, /// cstr!("."), /// OFlags::RDONLY | OFlags::DIRECTORY | OFlags::CLOEXEC, /// Mode::empty(), /// ) /// .unwrap(); /// /// let mut buf = Vec::with_capacity(8192); /// let mut iter = RawDir::new(fd, buf.spare_capacity_mut()); /// while let Some(entry) = iter.next() { /// let entry = entry.unwrap(); /// dbg!(&entry); /// } /// ``` /// /// Using the stack: /// /// ``` /// # use std::mem::MaybeUninit; /// # use rustix::fs::{CWD, Mode, OFlags, openat, RawDir}; /// # use rustix::cstr; /// /// let fd = openat( /// CWD, /// cstr!("."), /// OFlags::RDONLY | OFlags::DIRECTORY | OFlags::CLOEXEC, /// Mode::empty(), /// ) /// .unwrap(); /// /// let mut buf = [MaybeUninit::uninit(); 2048]; /// let mut iter = RawDir::new(fd, &mut buf); /// while let Some(entry) = iter.next() { /// let entry = entry.unwrap(); /// dbg!(&entry); /// } /// ``` /// /// ## Portable /// /// Heap allocated growing buffer for supporting directory entries with /// arbitrarily large file names: /// /// ```notrust /// # // The `notrust` above can be removed when we can depend on Rust 1.65. /// # use std::mem::MaybeUninit; /// # use rustix::fs::{CWD, Mode, OFlags, openat, RawDir}; /// # use rustix::io::Errno; /// # use rustix::cstr; /// /// let fd = openat( /// CWD, /// cstr!("."), /// OFlags::RDONLY | OFlags::DIRECTORY | OFlags::CLOEXEC, /// Mode::empty(), /// ) /// .unwrap(); /// /// let mut buf = Vec::with_capacity(8192); /// 'read: loop { /// 'resize: { /// let mut iter = RawDir::new(&fd, buf.spare_capacity_mut()); /// while let Some(entry) = iter.next() { /// let entry = match entry { /// Err(Errno::INVAL) => break 'resize, /// r => r.unwrap(), /// }; /// dbg!(&entry); /// } /// break 'read; /// } /// /// let new_capacity = buf.capacity() * 2; /// buf.reserve(new_capacity); /// } /// ``` pubfn new(fd: Fd, buf: &'buf mut [MaybeUninit<u8>]) -> Self { Self {
fd,
buf: { let offset = buf.as_ptr().align_offset(align_of::<linux_dirent64>()); if offset < buf.len() {
&mut buf[offset..]
} else {
&mut []
}
},
initialized: 0,
offset: 0,
}
}
}
/// A raw directory entry, similar to [`std::fs::DirEntry`]. /// /// Unlike the std version, this may represent the `.` or `..` entries. pubstruct RawDirEntry<'a> {
file_name: &'a CStr,
file_type: u8,
inode_number: u64,
next_entry_cookie: i64,
}
impl<'a> RawDirEntry<'a> { /// Returns the file name of this directory entry. #[inline] pubfn file_name(&self) -> &CStr { self.file_name
}
/// Returns the type of this directory entry. #[inline] pubfn file_type(&self) -> FileType {
FileType::from_dirent_d_type(self.file_type)
}
/// Returns the inode number of this directory entry. #[inline] #[doc(alias = "inode_number")] pubfn ino(&self) -> u64 { self.inode_number
}
/// Returns the seek cookie to the next directory entry. #[inline] #[doc(alias = "off")] pubfn next_entry_cookie(&self) -> u64 { self.next_entry_cookie as u64
}
}
impl<'buf, Fd: AsFd> RawDir<'buf, Fd> { /// Identical to [`Iterator::next`] except that [`Iterator::Item`] borrows /// from self. /// /// Note: this interface will be broken to implement a stdlib iterator API /// with GAT support once one becomes available. #[allow(unsafe_code)] #[allow(clippy::should_implement_trait)] pubfn next(&mutself) -> Option<io::Result<RawDirEntry<'_>>> { ifself.is_buffer_empty() { match getdents_uninit(self.fd.as_fd(), self.buf) {
Ok(0) => return None,
Ok(bytes_read) => { self.initialized = bytes_read; self.offset = 0;
}
Err(e) => return Some(Err(e)),
}
}
let dirent_ptr = self.buf[self.offset..].as_ptr(); // SAFETY: // - This data is initialized by the check above. // - Assumption: the kernel will not give us partial structs. // - Assumption: the kernel uses proper alignment between structs. // - The starting pointer is aligned (performed in RawDir::new) let dirent = unsafe { &*dirent_ptr.cast::<linux_dirent64>() };
/// Returns true if the internal buffer is empty and will be refilled when /// calling [`next`]. /// /// [`next`]: Self::next pubfn is_buffer_empty(&self) -> bool { self.offset >= self.initialized
}
}
Messung V0.5 in Prozent
¤ Dauer der Verarbeitung: 0.9 Sekunden
(vorverarbeitet am 2026-06-18)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.