1use std::{
2 mem::MaybeUninit,
3 os::fd::{AsRawFd as _, OwnedFd},
4};
5
6use dope_sys::{Errno, io::file, kernel};
7use o3::{alloc::BoxArrayExt as _, base::marker::ThreadBound};
8
9use crate::Uring;
10
11const CAPACITY: usize = 32 * 1024;
12
13pub struct Stream {
14 file: OwnedFd,
15 buffer: Box<[MaybeUninit<u8>; CAPACITY]>,
16 offset: usize,
17 filled: usize,
18 _thread: ThreadBound,
19}
20
21unsafe impl file::raw::Directory for Uring {
24 type Stream = Stream;
25
26 fn from_fd<E: From<Errno>>(file: OwnedFd) -> Result<Stream, file::OpenError<E>> {
27 Ok(Stream {
28 file,
29 buffer: Box::try_uninit().map_err(file::OpenError::Allocation)?,
30 offset: 0,
31 filled: 0,
32 _thread: ThreadBound::NEW,
33 })
34 }
35
36 fn descriptor(stream: &Stream) -> kernel::raw::Descriptor {
37 unsafe { kernel::raw::Descriptor::new(stream.file.as_raw_fd()) }
39 }
40
41 fn next<E: From<Errno>>(
42 stream: &mut Stream,
43 ) -> Result<Option<file::Entry<'_>>, file::ReadError<E>> {
44 loop {
45 if stream.offset == stream.filled {
46 let result = unsafe {
49 libc::syscall(
50 libc::SYS_getdents64,
51 stream.file.as_raw_fd(),
52 stream.buffer.as_mut_ptr(),
53 CAPACITY,
54 )
55 };
56 let count = unsafe {
59 kernel::raw::Status::from_count(result as libc::ssize_t)
60 .try_count::<Errno>(|| kernel::raw::Code::last::<Self>().into())
61 };
62 stream.filled = match count {
63 Ok(count) => count.get(),
64 Err(Errno::NOT_FOUND) => 0,
65 Err(error) => return Err(file::ReadError::Syscall(E::from(error))),
66 };
67 stream.offset = 0;
68 if stream.filled == 0 {
69 return Ok(None);
70 }
71 }
72 let pointer = unsafe {
77 stream
78 .buffer
79 .as_ptr()
80 .add(stream.offset)
81 .cast::<libc::dirent64>()
82 };
83 stream.offset += unsafe { (&raw const (*pointer).d_reclen).read_unaligned() } as usize;
84 if unsafe { (&raw const (*pointer).d_ino).read_unaligned() } == 0 {
85 continue;
86 }
87 let kind = unsafe { (&raw const (*pointer).d_type).read() };
88 let name = unsafe { std::ffi::CStr::from_ptr((&raw const (*pointer).d_name).cast()) };
89 return Ok(Some(file::Entry {
90 name,
91 kind: file::Kind::from_dirent(kind),
92 }));
93 }
94 }
95}