• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 #[test]
test_dir()2 fn test_dir() {
3     let t = rustix::fs::openat(
4         rustix::fs::cwd(),
5         rustix::cstr!("."),
6         rustix::fs::OFlags::RDONLY | rustix::fs::OFlags::CLOEXEC,
7         rustix::fs::Mode::empty(),
8     )
9     .unwrap();
10 
11     let mut dir = rustix::fs::Dir::read_from(&t).unwrap();
12 
13     let _file = rustix::fs::openat(
14         &t,
15         rustix::cstr!("Cargo.toml"),
16         rustix::fs::OFlags::RDONLY | rustix::fs::OFlags::CLOEXEC,
17         rustix::fs::Mode::empty(),
18     )
19     .unwrap();
20 
21     // Read the directory entries. We use `while let Some(entry)` so that we
22     // don't consume the `Dir` so that we can run more tests on it.
23     let mut saw_dot = false;
24     let mut saw_dotdot = false;
25     let mut saw_cargo_toml = false;
26     while let Some(entry) = dir.read() {
27         let entry = entry.unwrap();
28         if entry.file_name() == rustix::cstr!(".") {
29             saw_dot = true;
30         } else if entry.file_name() == rustix::cstr!("..") {
31             saw_dotdot = true;
32         } else if entry.file_name() == rustix::cstr!("Cargo.toml") {
33             saw_cargo_toml = true;
34         }
35     }
36     assert!(saw_dot);
37     assert!(saw_dotdot);
38     assert!(saw_cargo_toml);
39 
40     // Rewind the directory so we can iterate over the entries again.
41     dir.rewind();
42 
43     // For what comes next, we don't need `mut` anymore.
44     let dir = dir;
45 
46     // Read the directory entries, again. This time we use `for entry in dir`.
47     let mut saw_dot = false;
48     let mut saw_dotdot = false;
49     let mut saw_cargo_toml = false;
50     for entry in dir {
51         let entry = entry.unwrap();
52         if entry.file_name() == rustix::cstr!(".") {
53             saw_dot = true;
54         } else if entry.file_name() == rustix::cstr!("..") {
55             saw_dotdot = true;
56         } else if entry.file_name() == rustix::cstr!("Cargo.toml") {
57             saw_cargo_toml = true;
58         }
59     }
60     assert!(saw_dot);
61     assert!(saw_dotdot);
62     assert!(saw_cargo_toml);
63 }
64 
65 // Test that `Dir` silently stops iterating if the directory has been removed.
66 //
67 // Except on FreeBSD and macOS, where apparently `readdir` just keeps reading.
68 #[cfg_attr(
69     any(
70         target_os = "macos",
71         target_os = "ios",
72         target_os = "watchos",
73         target_os = "tvos",
74         target_os = "freebsd",
75         target_os = "dragonflybsd"
76     ),
77     ignore
78 )]
79 #[test]
dir_iterator_handles_dir_removal()80 fn dir_iterator_handles_dir_removal() {
81     // create a dir, keep the FD, then delete the dir
82     let tmp = tempfile::tempdir().unwrap();
83     let fd = rustix::fs::openat(
84         rustix::fs::cwd(),
85         tmp.path(),
86         rustix::fs::OFlags::RDONLY | rustix::fs::OFlags::CLOEXEC,
87         rustix::fs::Mode::empty(),
88     )
89     .unwrap();
90 
91     // Drop the `TempDir`, which deletes the directory.
92     drop(tmp);
93 
94     let mut dir = rustix::fs::Dir::read_from(&fd).unwrap();
95     assert!(matches!(dir.next(), None));
96 }
97 
98 // Like `dir_iterator_handles_dir_removal`, but close the directory after
99 // `Dir::read_from`.
100 #[cfg_attr(
101     any(
102         target_os = "macos",
103         target_os = "ios",
104         target_os = "watchos",
105         target_os = "tvos",
106         target_os = "freebsd",
107         target_os = "dragonflybsd"
108     ),
109     ignore
110 )]
111 #[test]
dir_iterator_handles_dir_removal_after_open()112 fn dir_iterator_handles_dir_removal_after_open() {
113     // create a dir, keep the FD, then delete the dir
114     let tmp = tempfile::tempdir().unwrap();
115     let fd = rustix::fs::openat(
116         rustix::fs::cwd(),
117         tmp.path(),
118         rustix::fs::OFlags::RDONLY | rustix::fs::OFlags::CLOEXEC,
119         rustix::fs::Mode::empty(),
120     )
121     .unwrap();
122 
123     let mut dir = rustix::fs::Dir::read_from(&fd).unwrap();
124 
125     // Drop the `TempDir`, which deletes the directory.
126     drop(tmp);
127 
128     assert!(matches!(dir.next(), None));
129 }
130