1 use crate::fd
::{AsFd, BorrowedFd, OwnedFd}
;
2 use crate::ffi
::{CStr, CString}
;
4 fcntl_getfl
, fstat
, fstatfs
, fstatvfs
, openat
, FileType
, Mode
, OFlags
, Stat
, StatFs
, StatVfs
,
7 use crate::process
::fchdir
;
8 use crate::utils
::as_ptr
;
9 use alloc
::borrow
::ToOwned
;
12 use core
::mem
::size_of
;
13 use linux_raw_sys
::general
::{linux_dirent64, SEEK_SET}
;
17 /// The `OwnedFd` that we read directory entries from.
26 /// Construct a `Dir` that reads entries from the given directory
29 pub fn read_from
<Fd
: AsFd
>(fd
: Fd
) -> io
::Result
<Self> {
30 Self::_read_from(fd
.as_fd())
34 fn _read_from(fd
: BorrowedFd
<'_
>) -> io
::Result
<Self> {
35 let flags
= fcntl_getfl(fd
)?
;
36 let fd_for_dir
= openat(fd
, cstr
!("."), flags
| OFlags
::CLOEXEC
, Mode
::empty())?
;
48 pub fn rewind(&mut self) {
49 self.pos
= self.buf
.len();
53 /// `readdir(self)`, where `None` means the end of the directory.
54 pub fn read(&mut self) -> Option
<io
::Result
<DirEntry
>> {
55 if let Some(next
) = self.next
.take() {
56 match crate::backend
::fs
::syscalls
::_seek(self.fd
.as_fd(), next
as i64, SEEK_SET
) {
58 Err(err
) => return Some(Err(err
)),
62 // Compute linux_dirent64 field offsets.
63 let z
= linux_dirent64
{
68 d_name
: Default
::default(),
70 let base
= as_ptr(&z
) as usize;
71 let offsetof_d_reclen
= (as_ptr(&z
.d_reclen
) as usize) - base
;
72 let offsetof_d_name
= (as_ptr(&z
.d_name
) as usize) - base
;
73 let offsetof_d_ino
= (as_ptr(&z
.d_ino
) as usize) - base
;
74 let offsetof_d_type
= (as_ptr(&z
.d_type
) as usize) - base
;
76 // Test if we need more entries, and if so, read more.
77 if self.buf
.len() - self.pos
< size_of
::<linux_dirent64
>() {
78 match self.read_more()?
{
80 Err(e
) => return Some(Err(e
)),
84 // We successfully read an entry. Extract the fields.
87 // Do an unaligned u16 load.
88 let d_reclen
= u16::from_ne_bytes([
89 self.buf
[pos
+ offsetof_d_reclen
],
90 self.buf
[pos
+ offsetof_d_reclen
+ 1],
92 assert
!(self.buf
.len() - pos
>= d_reclen
as usize);
93 self.pos
+= d_reclen
as usize;
95 // Read the NUL-terminated name from the `d_name` field. Without
96 // `unsafe`, we need to scan for the NUL twice: once to obtain a size
97 // for the slice, and then once within `CStr::from_bytes_with_nul`.
98 let name_start
= pos
+ offsetof_d_name
;
99 let name_len
= self.buf
[name_start
..]
101 .position(|x
| *x
== b'
\0'
)
104 CStr
::from_bytes_with_nul(&self.buf
[name_start
..name_start
+ name_len
+ 1]).unwrap();
105 let name
= name
.to_owned();
106 assert
!(name
.as_bytes().len() <= self.buf
.len() - name_start
);
108 // Do an unaligned u64 load.
109 let d_ino
= u64::from_ne_bytes([
110 self.buf
[pos
+ offsetof_d_ino
],
111 self.buf
[pos
+ offsetof_d_ino
+ 1],
112 self.buf
[pos
+ offsetof_d_ino
+ 2],
113 self.buf
[pos
+ offsetof_d_ino
+ 3],
114 self.buf
[pos
+ offsetof_d_ino
+ 4],
115 self.buf
[pos
+ offsetof_d_ino
+ 5],
116 self.buf
[pos
+ offsetof_d_ino
+ 6],
117 self.buf
[pos
+ offsetof_d_ino
+ 7],
120 let d_type
= self.buf
[pos
+ offsetof_d_type
];
122 // Check that our types correspond to the `linux_dirent64` types.
123 let _
= linux_dirent64
{
128 d_name
: Default
::default(),
138 fn read_more(&mut self) -> Option
<io
::Result
<()>> {
139 let og_len
= self.buf
.len();
140 // Capacity increment currently chosen by wild guess.
142 .resize(self.buf
.capacity() + 32 * size_of
::<linux_dirent64
>(), 0);
143 let nread
= match crate::backend
::fs
::syscalls
::getdents(self.fd
.as_fd(), &mut self.buf
) {
146 self.buf
.resize(og_len
, 0);
147 return Some(Err(err
));
150 self.buf
.resize(nread
, 0);
161 pub fn stat(&self) -> io
::Result
<Stat
> {
167 pub fn statfs(&self) -> io
::Result
<StatFs
> {
173 pub fn statvfs(&self) -> io
::Result
<StatVfs
> {
179 pub fn chdir(&self) -> io
::Result
<()> {
184 impl Iterator
for Dir
{
185 type Item
= io
::Result
<DirEntry
>;
188 fn next(&mut self) -> Option
<Self::Item
> {
193 impl fmt
::Debug
for Dir
{
194 fn fmt(&self, f
: &mut fmt
::Formatter
<'_
>) -> fmt
::Result
{
195 f
.debug_struct("Dir").field("fd", &self.fd
).finish()
201 pub struct DirEntry
{
208 /// Returns the file name of this directory entry.
210 pub fn file_name(&self) -> &CStr
{
214 /// Returns the type of this directory entry.
216 pub fn file_type(&self) -> FileType
{
217 FileType
::from_dirent_d_type(self.d_type
)
220 /// Return the inode number of this directory entry.
222 pub fn ino(&self) -> u64 {