From 7c9ca8baab0aee26790e6ef4165707c191825883 Mon Sep 17 00:00:00 2001 From: implicitfield <114500360+implicitfield@users.noreply.github.com> Date: Wed, 3 Jan 2024 17:06:51 +0400 Subject: [PATCH] LibCore: Fall back to fstat if readdir doesn't produce a valid file type Per POSIX, It is valid for dirent structures obtained via readdir to not name a valid type. --- Userland/Libraries/LibCore/DirIterator.cpp | 14 ++++++++++++++ Userland/Libraries/LibCore/DirectoryEntry.cpp | 2 +- Userland/Libraries/LibCore/DirectoryEntry.h | 1 + 3 files changed, 16 insertions(+), 1 deletion(-) diff --git a/Userland/Libraries/LibCore/DirIterator.cpp b/Userland/Libraries/LibCore/DirIterator.cpp index 1151bf7b71..ea64c4e38e 100644 --- a/Userland/Libraries/LibCore/DirIterator.cpp +++ b/Userland/Libraries/LibCore/DirIterator.cpp @@ -8,6 +8,8 @@ #include #include #include +#include +#include namespace Core { @@ -60,6 +62,18 @@ bool DirIterator::advance_next() m_next = DirectoryEntry::from_stat(m_dir, *de); #else m_next = DirectoryEntry::from_dirent(*de); + + // dirent structures from readdir aren't guaranteed to contain valid file types, + // as it is possible that the underlying filesystem doesn't keep track of those. + if (m_next->type == DirectoryEntry::Type::Unknown && !m_next->name.is_empty()) { + struct stat statbuf; + if (fstatat(dirfd(m_dir), de->d_name, &statbuf, AT_SYMLINK_NOFOLLOW) < 0) { + m_error = Error::from_errno(errno); + dbgln("DirIteration error: {}", m_error.value()); + return false; + } + m_next->type = DirectoryEntry::directory_entry_type_from_stat(statbuf.st_mode); + } #endif if (m_next->name.is_empty()) diff --git a/Userland/Libraries/LibCore/DirectoryEntry.cpp b/Userland/Libraries/LibCore/DirectoryEntry.cpp index 8790c8ef6a..c0f9391683 100644 --- a/Userland/Libraries/LibCore/DirectoryEntry.cpp +++ b/Userland/Libraries/LibCore/DirectoryEntry.cpp @@ -9,7 +9,7 @@ namespace Core { -static DirectoryEntry::Type directory_entry_type_from_stat(mode_t st_mode) +DirectoryEntry::Type DirectoryEntry::directory_entry_type_from_stat(mode_t st_mode) { switch (st_mode & S_IFMT) { case S_IFIFO: diff --git a/Userland/Libraries/LibCore/DirectoryEntry.h b/Userland/Libraries/LibCore/DirectoryEntry.h index 7244ec83dd..c2927435ce 100644 --- a/Userland/Libraries/LibCore/DirectoryEntry.h +++ b/Userland/Libraries/LibCore/DirectoryEntry.h @@ -28,6 +28,7 @@ struct DirectoryEntry { ByteString name; ino_t inode_number; + static Type directory_entry_type_from_stat(mode_t st_mode); static DirectoryEntry from_dirent(dirent const&); static DirectoryEntry from_stat(DIR*, dirent const&); };