|
15 | 15 | // SPDX-License-Identifier: Apache-2.0
|
16 | 16 |
|
17 | 17 | use std::num::NonZeroU64;
|
| 18 | +use std::os::unix::ffi::OsStrExt; |
18 | 19 | use std::sync::mpsc;
|
19 | 20 | use std::{ffi, panic};
|
20 | 21 |
|
@@ -70,7 +71,6 @@ impl fuse::FuseHandlers for TestFS {
|
70 | 71 | respond: impl for<'a> fuse::Respond<fuse::ReaddirResponse<'a>>,
|
71 | 72 | ) {
|
72 | 73 | self.requests.send(format!("{:#?}", request)).unwrap();
|
73 |
| - //self.requests.send(format!("{:#?}", request)); |
74 | 74 |
|
75 | 75 | let mut cursor: u64 = match request.cursor() {
|
76 | 76 | Some(x) => x.into(),
|
@@ -144,152 +144,203 @@ fn readdir() {
|
144 | 144 | assert!(!dir_p.is_null());
|
145 | 145 |
|
146 | 146 | let next_dirent = |expect| {
|
147 |
| - let mut entry = libc::dirent { |
148 |
| - d_ino: 0, |
149 |
| - d_off: 0, |
150 |
| - d_reclen: 0, |
151 |
| - d_type: 0, |
152 |
| - d_name: [0; 256], |
153 |
| - }; |
154 |
| - let mut result = std::ptr::null_mut(); |
155 |
| - let rc = unsafe { libc::readdir_r(dir_p, &mut entry, &mut result) }; |
156 |
| - assert_eq!(rc, 0); |
157 |
| - if let Some(diff) = diff_dirent(&expect, &entry) { |
| 147 | + let entry = unsafe { libc::readdir(dir_p) }; |
| 148 | + assert!(!entry.is_null()); |
| 149 | + if let Some(diff) = diff_dirent(expect, unsafe { &*entry }) { |
158 | 150 | println!("{}", diff);
|
159 | 151 | assert!(false);
|
160 | 152 | }
|
161 | 153 | };
|
162 | 154 |
|
163 |
| - next_dirent(libc::dirent { |
| 155 | + next_dirent(dirent { |
164 | 156 | d_ino: 10,
|
165 | 157 | d_off: 1,
|
166 | 158 | d_reclen: 32,
|
167 | 159 | d_type: libc::DT_REG,
|
| 160 | + #[cfg(target_os = "freebsd")] |
| 161 | + d_namlen: 7, |
168 | 162 | d_name: dirent_name_new(b"entry_a"),
|
169 | 163 | });
|
170 | 164 | let pos = unsafe { libc::telldir(dir_p) };
|
171 |
| - next_dirent(libc::dirent { |
| 165 | + next_dirent(dirent { |
172 | 166 | d_ino: 11,
|
173 | 167 | d_off: 2,
|
174 | 168 | d_reclen: 32,
|
175 | 169 | d_type: libc::DT_LNK,
|
| 170 | + #[cfg(target_os = "freebsd")] |
| 171 | + d_namlen: 7, |
176 | 172 | d_name: dirent_name_new(b"entry_b"),
|
177 | 173 | });
|
178 | 174 | unsafe {
|
179 | 175 | libc::seekdir(dir_p, pos)
|
180 | 176 | };
|
181 |
| - next_dirent(libc::dirent { |
| 177 | + next_dirent(dirent { |
182 | 178 | d_ino: 11,
|
183 | 179 | d_off: 2,
|
184 | 180 | d_reclen: 32,
|
185 | 181 | d_type: libc::DT_LNK,
|
| 182 | + #[cfg(target_os = "freebsd")] |
| 183 | + d_namlen: 7, |
186 | 184 | d_name: dirent_name_new(b"entry_b"),
|
187 | 185 | });
|
188 |
| - next_dirent(libc::dirent { |
| 186 | + next_dirent(dirent { |
189 | 187 | d_ino: 12,
|
190 | 188 | d_off: 3,
|
191 | 189 | d_reclen: 32,
|
192 | 190 | d_type: libc::DT_DIR,
|
| 191 | + #[cfg(target_os = "freebsd")] |
| 192 | + d_namlen: 7, |
193 | 193 | d_name: dirent_name_new(b"entry_c"),
|
194 | 194 | });
|
195 | 195 |
|
196 | 196 | unsafe {
|
197 | 197 | libc::closedir(dir_p)
|
198 | 198 | };
|
199 | 199 | });
|
200 |
| - assert_eq!(requests.len(), 3); |
201 | 200 |
|
202 |
| - let expect = r#"ReaddirRequest { |
| 201 | + #[cfg(target_os = "linux")] |
| 202 | + { |
| 203 | + assert_eq!(requests.len(), 3); |
| 204 | + |
| 205 | + let expect = r#"ReaddirRequest { |
203 | 206 | node_id: 2,
|
204 | 207 | size: 4096,
|
205 | 208 | cursor: None,
|
206 | 209 | handle: 12345,
|
207 | 210 | opendir_flags: 0x00018000,
|
208 | 211 | }"#;
|
209 |
| - if let Some(diff) = diff_str(expect, &requests[0]) { |
210 |
| - println!("{}", diff); |
211 |
| - assert!(false); |
212 |
| - } |
| 212 | + if let Some(diff) = diff_str(expect, &requests[0]) { |
| 213 | + println!("{}", diff); |
| 214 | + assert!(false); |
| 215 | + } |
213 | 216 |
|
214 |
| - let expect = r#"ReaddirRequest { |
| 217 | + let expect = r#"ReaddirRequest { |
215 | 218 | node_id: 2,
|
216 | 219 | size: 4096,
|
217 | 220 | cursor: Some(1),
|
218 | 221 | handle: 12345,
|
219 | 222 | opendir_flags: 0x00018000,
|
220 | 223 | }"#;
|
221 |
| - if let Some(diff) = diff_str(expect, &requests[1]) { |
222 |
| - println!("{}", diff); |
223 |
| - assert!(false); |
224 |
| - } |
| 224 | + if let Some(diff) = diff_str(expect, &requests[1]) { |
| 225 | + println!("{}", diff); |
| 226 | + assert!(false); |
| 227 | + } |
225 | 228 |
|
226 |
| - let expect = r#"ReaddirRequest { |
| 229 | + let expect = r#"ReaddirRequest { |
227 | 230 | node_id: 2,
|
228 | 231 | size: 4096,
|
229 | 232 | cursor: Some(2),
|
230 | 233 | handle: 12345,
|
231 | 234 | opendir_flags: 0x00018000,
|
232 | 235 | }"#;
|
233 |
| - if let Some(diff) = diff_str(expect, &requests[2]) { |
234 |
| - println!("{}", diff); |
235 |
| - assert!(false); |
| 236 | + if let Some(diff) = diff_str(expect, &requests[2]) { |
| 237 | + println!("{}", diff); |
| 238 | + assert!(false); |
| 239 | + } |
| 240 | + } |
| 241 | + |
| 242 | + #[cfg(target_os = "freebsd")] |
| 243 | + { |
| 244 | + assert_eq!(requests.len(), 2); |
| 245 | + |
| 246 | + let expect = r#"ReaddirRequest { |
| 247 | + node_id: 2, |
| 248 | + size: 4096, |
| 249 | + cursor: None, |
| 250 | + handle: 12345, |
| 251 | + opendir_flags: 0x00000000, |
| 252 | +}"#; |
| 253 | + if let Some(diff) = diff_str(expect, &requests[0]) { |
| 254 | + println!("{}", diff); |
| 255 | + assert!(false); |
| 256 | + } |
| 257 | + |
| 258 | + let expect = r#"ReaddirRequest { |
| 259 | + node_id: 2, |
| 260 | + size: 4096, |
| 261 | + cursor: Some(2), |
| 262 | + handle: 12345, |
| 263 | + opendir_flags: 0x00000000, |
| 264 | +}"#; |
| 265 | + if let Some(diff) = diff_str(expect, &requests[1]) { |
| 266 | + println!("{}", diff); |
| 267 | + assert!(false); |
| 268 | + } |
236 | 269 | }
|
237 | 270 | }
|
238 | 271 |
|
239 |
| -#[derive(Debug)] |
240 | 272 | #[allow(non_camel_case_types)]
|
241 | 273 | struct dirent<'a> {
|
242 | 274 | d_ino: libc::ino_t,
|
243 | 275 | d_off: libc::off_t,
|
244 | 276 | d_reclen: libc::c_ushort,
|
245 |
| - d_type: String, |
246 |
| - d_name: &'a ffi::CStr, |
| 277 | + d_type: u8, |
| 278 | + #[cfg(target_os = "freebsd")] |
| 279 | + d_namlen: u16, |
| 280 | + d_name: &'a ffi::OsStr, |
247 | 281 | }
|
248 | 282 |
|
249 |
| -fn diff_dirent(expect: &libc::dirent, got: &libc::dirent) -> Option<String> { |
250 |
| - let expect = format!( |
251 |
| - "{:#?}", |
252 |
| - &dirent { |
253 |
| - d_ino: expect.d_ino, |
254 |
| - d_off: expect.d_off, |
255 |
| - d_reclen: expect.d_reclen, |
256 |
| - d_type: dirent_type_name(expect), |
257 |
| - d_name: dirent_name(expect), |
258 |
| - } |
259 |
| - ); |
| 283 | +impl std::fmt::Debug for dirent<'_> { |
| 284 | + fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result { |
| 285 | + let d_type = dirent_type_name(self); |
| 286 | + let mut s = fmt.debug_struct("dirent"); |
| 287 | + #[cfg(target_os = "linux")] |
| 288 | + s.field("d_ino", &self.d_ino); |
| 289 | + #[cfg(target_os = "freebsd")] |
| 290 | + s.field("d_fileno", &self.d_ino); |
| 291 | + s.field("d_off", &self.d_off); |
| 292 | + s.field("d_reclen", &self.d_reclen); |
| 293 | + s.field("d_type", &format_args!("{}", &d_type)); |
| 294 | + #[cfg(target_os = "freebsd")] |
| 295 | + s.field("d_namlen", &self.d_namlen); |
| 296 | + s.field("d_name", &self.d_name); |
| 297 | + s.finish() |
| 298 | + } |
| 299 | +} |
| 300 | + |
| 301 | +#[allow(unused_mut)] |
| 302 | +fn diff_dirent(mut expect: dirent, got: &libc::dirent) -> Option<String> { |
| 303 | + // https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=253411 |
| 304 | + #[cfg(target_os = "freebsd")] |
| 305 | + { |
| 306 | + expect.d_off = 0; |
| 307 | + } |
| 308 | + |
| 309 | + let expect = format!("{:#?}", &expect); |
260 | 310 | let got = format!(
|
261 | 311 | "{:#?}",
|
262 | 312 | dirent {
|
| 313 | + #[cfg(target_os = "linux")] |
263 | 314 | d_ino: got.d_ino,
|
| 315 | + #[cfg(target_os = "freebsd")] |
| 316 | + d_ino: got.d_fileno, |
264 | 317 | d_off: got.d_off,
|
265 | 318 | d_reclen: got.d_reclen,
|
266 |
| - d_type: dirent_type_name(got), |
| 319 | + d_type: got.d_type, |
| 320 | + #[cfg(target_os = "freebsd")] |
| 321 | + d_namlen: got.d_namlen, |
267 | 322 | d_name: dirent_name(got),
|
268 | 323 | }
|
269 | 324 | );
|
270 | 325 | diff_str(&expect, &got)
|
271 | 326 | }
|
272 | 327 |
|
273 |
| -fn dirent_name(dirent: &libc::dirent) -> &ffi::CStr { |
| 328 | +fn dirent_name(dirent: &libc::dirent) -> &ffi::OsStr { |
274 | 329 | let bytes: &[u8] = unsafe { std::mem::transmute(&dirent.d_name as &[i8]) };
|
275 | 330 | for (ii, byte) in bytes.iter().enumerate() {
|
276 | 331 | if *byte == 0 {
|
277 |
| - let (cstr, _) = bytes.split_at(ii + 1); |
278 |
| - return ffi::CStr::from_bytes_with_nul(cstr).unwrap(); |
| 332 | + let (name, _) = bytes.split_at(ii); |
| 333 | + return ffi::OsStr::from_bytes(name); |
279 | 334 | }
|
280 | 335 | }
|
281 | 336 | panic!("no NUL in dirent d_name")
|
282 | 337 | }
|
283 | 338 |
|
284 |
| -fn dirent_name_new(name: &[u8]) -> [i8; 256] { |
285 |
| - let mut buf = [0i8; 256]; |
286 |
| - let buf_u8: &mut [u8] = |
287 |
| - unsafe { std::mem::transmute(&mut buf as &mut [i8]) }; |
288 |
| - buf_u8[..name.len()].copy_from_slice(name); |
289 |
| - buf |
| 339 | +fn dirent_name_new(name: &[u8]) -> &ffi::OsStr { |
| 340 | + ffi::OsStr::from_bytes(name) |
290 | 341 | }
|
291 | 342 |
|
292 |
| -fn dirent_type_name(dirent: &libc::dirent) -> String { |
| 343 | +fn dirent_type_name(dirent: &dirent) -> String { |
293 | 344 | match dirent.d_type {
|
294 | 345 | libc::DT_BLK => "DT_BLK".to_string(),
|
295 | 346 | libc::DT_CHR => "DT_CHR".to_string(),
|
|
0 commit comments