From bd8b3976cca1f4388ef6135dbc1b291f3ca9d089 Mon Sep 17 00:00:00 2001
From: koroal <98806009+koroal@users.noreply.github.com>
Date: Thu, 1 Dec 2022 10:08:15 +0300
Subject: [PATCH 3/4] FIX search_folder_t::search_path relying on d_type

d_type is filesystem-specific and may have the DT_UNKNOWN value.
More portable solution, albeit less performant, is to use fstatat.
fstatat can also follow symlinks, which helps to avoid related problems.
---
 src/simutrans/utils/searchfolder.cc | 19 ++++++++++++++++---
 1 file changed, 16 insertions(+), 3 deletions(-)

diff --git a/src/simutrans/utils/searchfolder.cc b/src/simutrans/utils/searchfolder.cc
index 9e04b04ff..51517819e 100644
--- a/src/simutrans/utils/searchfolder.cc
+++ b/src/simutrans/utils/searchfolder.cc
@@ -8,6 +8,8 @@
 #include <stdlib.h>
 
 #ifndef _WIN32
+#	include <sys/stat.h>
+#	include <sys/types.h>
 #	include <dirent.h>
 #else
 #	ifndef NOMINMAX
@@ -165,27 +167,38 @@ void searchfolder_t::search_path(const std::string path, const std::string name,
 	lookfor = path + ".";
 
 	if (DIR* const dir = opendir(lookfor.c_str())) {
+		int dir_fd = dirfd(dir);
+		if( dir_fd == -1 ) {
+			goto close_dir;
+		}
 		lookfor = name + ext;
 
 		while (dirent const* const entry = readdir(dir)) {
 			if(entry->d_name[0]!='.' || (entry->d_name[1]!='.' && entry->d_name[1]!=0)) {
-				if (entry->d_type == DT_DIR && (search_flags&SF_NOADDONS) && !STRICMP(entry->d_name, "addons")) {
+				struct stat st;
+				if( fstatat(dir_fd, entry->d_name, &st, 0) == -1 ) {
+					continue;
+				}
+				bool is_dir = S_ISDIR(st.st_mode);
+
+				if( is_dir && (search_flags&SF_NOADDONS) && !STRICMP(entry->d_name, "addons") ) {
 					continue;
 				}
 
 				if (only_directories) {
-					if( entry->d_type == DT_DIR  ||  entry->d_type == DT_LNK) {
+					if( is_dir ) {
 						add_entry(path, entry->d_name, prepend_path);
 					}
 				} else if (filename_matches_pattern(entry->d_name, lookfor.c_str())) {
 					add_entry(path, entry->d_name, prepend_path);
 				}
-				if( entry->d_type == DT_DIR && max_depth > 0) {
+				if( is_dir && max_depth > 0 ) {
 					search_path(path + entry->d_name + '/', name, ext, search_flags, max_depth - 1);
 				}
 
 			}
 		}
+close_dir:
 		closedir(dir);
 	}
 #endif
-- 
2.38.1

