Safe FFI Wrapper
Rust has great support for calling functions through a foreign function interface (FFI). We will use this to build a safe wrapper for the libc functions you would use from C to read the filenames of a directory.
You will want to consult the manual pages:
You will also want to browse the std::ffi module, particular for CStr and CString types which are used to hold NUL-terminated strings coming from C. The Nomicon also has a very useful chapter about FFI.
Copy the code below to <https://play.rust-lang.org/> and fill in the missing functions and methods:
1. // TODO: remove this when you're done with your implementation.
2. #![allow(unused_imports, unused_variables, dead_code)]
4. mod ffi {
5. use std::os::raw::{c_char, c_int, c_long, c_ulong, c_ushort};
7. // Opaque type. See https://doc.rust-lang.org/nomicon/ffi.html.
8. #[repr(C)]
9. pub struct DIR {
10. _data: [u8; 0],
11. _marker: core::marker::PhantomData<(*mut u8, core::marker::PhantomPinned)>,
12. }
14. // Layout as per readdir(3) and definitions in /usr/include/x86_64-linux-gnu.
15. #[repr(C)]
16. pub struct dirent {
17. pub d_ino: c_long,
18. pub d_off: c_ulong,
19. pub d_reclen: c_ushort,
20. pub d_type: c_char,
21. pub d_name: [c_char; 256],
22. }
24. extern "C" {
25. pub fn opendir(s: *const c_char) -> *mut DIR;
26. pub fn readdir(s: *mut DIR) -> *const dirent;
27. pub fn closedir(s: *mut DIR) -> c_int;
28. }
29. }
31. use std::ffi::{CStr, CString, OsStr, OsString};
32. use std::os::unix::ffi::OsStrExt;
34. #[derive(Debug)]
35. struct DirectoryIterator {
36. path: CString,
37. dir: *mut ffi::DIR,
38. }
40. impl DirectoryIterator {
41. fn new(path: &str) -> Result<DirectoryIterator, String> {
42. // Call opendir and return a Ok value if that worked,
43. // otherwise return Err with a message.
44. unimplemented!()
45. }
46. }
48. impl Iterator for DirectoryIterator {
49. type Item = OsString;
50. fn next(&mut self) -> Option<OsString> {
51. // Keep calling readdir until we get a NULL pointer back.
52. unimplemented!()
53. }
54. }
56. impl Drop for DirectoryIterator {
57. fn drop(&mut self) {
58. // Call closedir as needed.
59. unimplemented!()
60. }
61. }
63. fn main() -> Result<(), String> {
64. let iter = DirectoryIterator::new(".")?;
65. println!("files: {:#?}", iter.collect::<Vec<_>>());
66. Ok(())
67. }
