| 468 | |
| 469 | #[test] |
| 470 | fn dir_iterator_handles_io_errors() { |
| 471 | // create a dir, keep the FD, then delete the dir |
| 472 | let tmp = tempfile::tempdir().unwrap(); |
| 473 | let fd = crate::fs::openat( |
| 474 | crate::fs::CWD, |
| 475 | tmp.path(), |
| 476 | crate::fs::OFlags::RDONLY | crate::fs::OFlags::CLOEXEC, |
| 477 | crate::fs::Mode::empty(), |
| 478 | ) |
| 479 | .unwrap(); |
| 480 | |
| 481 | let file_fd = crate::fs::openat( |
| 482 | &fd, |
| 483 | tmp.path().join("test.txt"), |
| 484 | crate::fs::OFlags::WRONLY | crate::fs::OFlags::CREATE, |
| 485 | crate::fs::Mode::RWXU, |
| 486 | ) |
| 487 | .unwrap(); |
| 488 | |
| 489 | let mut dir = Dir::read_from(&fd).unwrap(); |
| 490 | |
| 491 | // Reach inside the `Dir` and replace its directory with a file, which |
| 492 | // will cause the subsequent `readdir` to fail. |
| 493 | unsafe { |
| 494 | let raw_fd = c::dirfd(dir.libc_dir.as_ptr()); |
| 495 | let mut owned_fd: crate::fd::OwnedFd = crate::fd::FromRawFd::from_raw_fd(raw_fd); |
| 496 | crate::io::dup2(&file_fd, &mut owned_fd).unwrap(); |
| 497 | core::mem::forget(owned_fd); |
| 498 | } |
| 499 | |
| 500 | // FreeBSD and macOS seem to read some directory entries before we call |
| 501 | // `.next()`. |
| 502 | #[cfg(any(apple, freebsdlike))] |
| 503 | { |
| 504 | dir.rewind(); |
| 505 | } |
| 506 | |
| 507 | assert!(matches!(dir.next(), Some(Err(_)))); |
| 508 | assert!(dir.next().is_none()); |
| 509 | } |
| 510 | } |