| 200 | #[allow(unsafe_code)] |
| 201 | #[allow(clippy::should_implement_trait)] |
| 202 | pub fn next(&mut self) -> Option<io::Result<RawDirEntry<'_>>> { |
| 203 | if self.is_buffer_empty() { |
| 204 | match getdents_uninit(self.fd.as_fd(), self.buf) { |
| 205 | Ok(0) => return None, |
| 206 | Ok(bytes_read) => { |
| 207 | self.initialized = bytes_read; |
| 208 | self.offset = 0; |
| 209 | } |
| 210 | Err(e) => return Some(Err(e)), |
| 211 | } |
| 212 | } |
| 213 | |
| 214 | let dirent_ptr = self.buf[self.offset..].as_ptr(); |
| 215 | // SAFETY: |
| 216 | // - This data is initialized by the check above. |
| 217 | // - Assumption: the kernel will not give us partial structs. |
| 218 | // - Assumption: the kernel uses proper alignment between structs. |
| 219 | // - The starting pointer is aligned (performed in `RawDir::new`). |
| 220 | let dirent = unsafe { &*dirent_ptr.cast::<linux_dirent64>() }; |
| 221 | |
| 222 | self.offset += usize::from(dirent.d_reclen); |
| 223 | |
| 224 | Some(Ok(RawDirEntry { |
| 225 | file_type: dirent.d_type, |
| 226 | inode_number: dirent.d_ino.into(), |
| 227 | next_entry_cookie: dirent.d_off.into(), |
| 228 | // SAFETY: The kernel guarantees a NUL-terminated string. |
| 229 | file_name: unsafe { CStr::from_ptr(dirent.d_name.as_ptr().cast()) }, |
| 230 | })) |
| 231 | } |
| 232 | |
| 233 | /// Returns true if the internal buffer is empty and will be refilled when |
| 234 | /// calling [`next`]. |