diff --git a/src/fileio.cpp b/src/fileio.cpp index bcd8a530e0..285d7e471f 100644 --- a/src/fileio.cpp +++ b/src/fileio.cpp @@ -70,8 +70,6 @@ TarFileList _tar_filelist[NUM_SUBDIRS]; typedef std::map TarLinkList; static TarLinkList _tar_linklist[NUM_SUBDIRS]; ///< List of directory links -extern bool FiosIsValidFile(const std::string &path, const struct dirent *ent, struct stat *sb); - /** * Checks whether the given search path is a valid search path * @param sp the search path to check diff --git a/src/fios.cpp b/src/fios.cpp index 91f622f058..dd98cb6699 100644 --- a/src/fios.cpp +++ b/src/fios.cpp @@ -33,8 +33,7 @@ SortingBits _savegame_sort_order = SORT_BY_DATE | SORT_DESCENDING; /* OS-specific functions are taken from their respective files (win32/unix .c) */ extern bool FiosIsRoot(const std::string &path); -extern bool FiosIsValidFile(const std::string &path, const struct dirent *ent, struct stat *sb); -extern bool FiosIsHiddenFile(const struct dirent *ent); +extern bool FiosIsHiddenFile(const std::filesystem::path &path); extern void FiosGetDrives(FileList &file_list); /* get the name of an oldstyle savegame */ @@ -322,48 +321,38 @@ bool FiosFileScanner::AddFile(const std::string &filename, size_t, const std::st */ static void FiosGetFileList(SaveLoadOperation fop, bool show_dirs, FiosGetTypeAndNameProc *callback_proc, Subdirectory subdir, FileList &file_list) { - struct stat sb; - struct dirent *dirent; - DIR *dir; - FiosItem *fios; size_t sort_start; file_list.clear(); assert(_fios_path != nullptr); - /* A parent directory link exists if we are not in the root directory */ - if (show_dirs && !FiosIsRoot(*_fios_path)) { - fios = &file_list.emplace_back(); - fios->type = FIOS_TYPE_PARENT; - fios->mtime = 0; - fios->name = ".."; - SetDParamStr(0, ".."); - fios->title = GetString(STR_SAVELOAD_PARENT_DIRECTORY); - } - - /* Show subdirectories */ - if (show_dirs && (dir = ttd_opendir(_fios_path->c_str())) != nullptr) { - while ((dirent = readdir(dir)) != nullptr) { - std::string d_name = FS2OTTD(dirent->d_name); - - /* found file must be directory, but not '.' or '..' */ - if (FiosIsValidFile(*_fios_path, dirent, &sb) && S_ISDIR(sb.st_mode) && - (!FiosIsHiddenFile(dirent) || StrStartsWithIgnoreCase(PERSONAL_DIR, d_name)) && - d_name != "." && d_name != "..") { - fios = &file_list.emplace_back(); - fios->type = FIOS_TYPE_DIR; - fios->mtime = 0; - fios->name = d_name; - SetDParamStr(0, fios->name + PATHSEP); - fios->title = GetString(STR_SAVELOAD_DIRECTORY); - } - } - closedir(dir); - } - - /* Sort the subdirs always by name, ascending, remember user-sorting order */ if (show_dirs) { + /* A parent directory link exists if we are not in the root directory */ + if (!FiosIsRoot(*_fios_path)) { + FiosItem &fios = file_list.emplace_back(); + fios.type = FIOS_TYPE_PARENT; + fios.mtime = 0; + fios.name = ".."; + SetDParamStr(0, ".."); + fios.title = GetString(STR_SAVELOAD_PARENT_DIRECTORY); + } + + /* Show subdirectories */ + std::error_code error_code; + for (const auto &dir_entry : std::filesystem::directory_iterator(OTTD2FS(*_fios_path), error_code)) { + if (!dir_entry.is_directory()) continue; + if (FiosIsHiddenFile(dir_entry) && dir_entry.path().filename() != PERSONAL_DIR) continue; + + FiosItem &fios = file_list.emplace_back(); + fios.type = FIOS_TYPE_DIR; + fios.mtime = 0; + fios.name = FS2OTTD(dir_entry.path().filename()); + SetDParamStr(0, fios.name + PATHSEP); + fios.title = GetString(STR_SAVELOAD_DIRECTORY); + } + + /* Sort the subdirs always by name, ascending, remember user-sorting order */ SortingBits order = _savegame_sort_order; _savegame_sort_order = SORT_BY_NAME | SORT_ASCENDING; std::sort(file_list.begin(), file_list.end()); diff --git a/src/os/unix/unix.cpp b/src/os/unix/unix.cpp index 2583be3347..b406cbc007 100644 --- a/src/os/unix/unix.cpp +++ b/src/os/unix/unix.cpp @@ -78,18 +78,9 @@ std::optional FiosGetDiskFreeSpace(const std::string &path) return std::nullopt; } -bool FiosIsValidFile(const std::string &path, const struct dirent *ent, struct stat *sb) +bool FiosIsHiddenFile(const std::filesystem::path &path) { - assert(path.back() == PATHSEPCHAR); - if (path.size() > 2) assert(path[path.size() - 2] != PATHSEPCHAR); - std::string filename = fmt::format("{}{}", path, ent->d_name); - - return stat(filename.c_str(), sb) == 0; -} - -bool FiosIsHiddenFile(const struct dirent *ent) -{ - return ent->d_name[0] == '.'; + return path.filename().string().starts_with("."); } #ifdef WITH_ICONV diff --git a/src/os/windows/win32.cpp b/src/os/windows/win32.cpp index 18655c3d42..b956027d52 100644 --- a/src/os/windows/win32.cpp +++ b/src/os/windows/win32.cpp @@ -192,27 +192,15 @@ void FiosGetDrives(FileList &file_list) } } -bool FiosIsValidFile(const std::string &, const struct dirent *ent, struct stat *sb) +bool FiosIsHiddenFile(const std::filesystem::path &path) { - /* hectonanoseconds between Windows and POSIX epoch */ - static const int64_t posix_epoch_hns = 0x019DB1DED53E8000LL; - const WIN32_FIND_DATA *fd = &ent->dir->fd; + UINT sem = SetErrorMode(SEM_FAILCRITICALERRORS); // Disable 'no-disk' message box. - sb->st_size = ((uint64_t) fd->nFileSizeHigh << 32) + fd->nFileSizeLow; - /* UTC FILETIME to seconds-since-1970 UTC - * we just have to subtract POSIX epoch and scale down to units of seconds. - * http://www.gamedev.net/community/forums/topic.asp?topic_id=294070&whichpage=1� - * XXX - not entirely correct, since filetimes on FAT aren't UTC but local, - * this won't entirely be correct, but we use the time only for comparison. */ - sb->st_mtime = (time_t)((*(const uint64_t*)&fd->ftLastWriteTime - posix_epoch_hns) / 1E7); - sb->st_mode = (fd->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)? S_IFDIR : S_IFREG; + DWORD attributes = GetFileAttributes(path.c_str()); - return true; -} + SetErrorMode(sem); // Restore previous setting. -bool FiosIsHiddenFile(const struct dirent *ent) -{ - return (ent->dir->fd.dwFileAttributes & (FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM)) != 0; + return (attributes & (FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM)) != 0; } std::optional FiosGetDiskFreeSpace(const std::string &path)