diff --git a/src/backend/libc/fs/dir.rs b/src/backend/libc/fs/dir.rs index 5e9bf6ed5..cb13f05bc 100644 --- a/src/backend/libc/fs/dir.rs +++ b/src/backend/libc/fs/dir.rs @@ -74,6 +74,7 @@ impl Dir { } #[inline] + #[allow(unused_mut)] fn _read_from(fd: BorrowedFd<'_>) -> io::Result { let mut any_errors = false; @@ -85,6 +86,7 @@ impl Dir { let flags = fcntl_getfl(fd)?; let fd_for_dir = match openat(fd, cstr!("."), flags | OFlags::CLOEXEC, Mode::empty()) { Ok(fd) => fd, + #[cfg(not(target_os = "wasi"))] Err(io::Errno::NOENT) => { // If "." doesn't exist, it means the directory was removed. // We treat that as iterating through a directory with no @@ -544,6 +546,20 @@ fn dir_iterator_handles_io_errors() { core::mem::forget(owned_fd); } + // FreeBSD and macOS seem to read some directory entries before we call + // `.next()`. + #[cfg(any( + target_os = "macos", + target_os = "ios", + target_os = "watchos", + target_os = "tvos", + target_os = "freebsd", + target_os = "dragonflybsd" + ))] + { + dir.rewind(); + } + assert!(matches!(dir.next(), Some(Err(_)))); assert!(matches!(dir.next(), None)); } diff --git a/tests/fs/dir.rs b/tests/fs/dir.rs index 06d243ae7..1745dc092 100644 --- a/tests/fs/dir.rs +++ b/tests/fs/dir.rs @@ -62,6 +62,20 @@ fn test_dir() { assert!(saw_cargo_toml); } +// Test that `Dir` silently stops iterating if the directory has been removed. +// +// Except on FreeBSD and macOS, where apparently `readdir` just keeps reading. +#[cfg_attr( + any( + target_os = "macos", + target_os = "ios", + target_os = "watchos", + target_os = "tvos", + target_os = "freebsd", + target_os = "dragonflybsd" + ), + ignore +)] #[test] fn dir_iterator_handles_dir_removal() { // create a dir, keep the FD, then delete the dir @@ -83,6 +97,17 @@ fn dir_iterator_handles_dir_removal() { // Like `dir_iterator_handles_dir_removal`, but close the directory after // `Dir::read_from`. +#[cfg_attr( + any( + target_os = "macos", + target_os = "ios", + target_os = "watchos", + target_os = "tvos", + target_os = "freebsd", + target_os = "dragonflybsd" + ), + ignore +)] #[test] fn dir_iterator_handles_dir_removal_after_open() { // create a dir, keep the FD, then delete the dir