From cfd9c6c801f9af711d048a01852e1e533fb47e60 Mon Sep 17 00:00:00 2001 From: Maschell Date: Sun, 24 Mar 2024 11:07:30 +0100 Subject: [PATCH] Improve performance when reading directories --- source/ftpSession.cpp | 114 ++++++++++++++++++++++++++++++------------ 1 file changed, 83 insertions(+), 31 deletions(-) diff --git a/source/ftpSession.cpp b/source/ftpSession.cpp index 94ba4d4..02cdbb3 100644 --- a/source/ftpSession.cpp +++ b/source/ftpSession.cpp @@ -37,6 +37,9 @@ #include #include #include +#ifdef __WIIU__ +#include +#endif #include #include #include @@ -1634,6 +1637,44 @@ void FtpSession::sendResponse (std::string_view const response_) m_responseBuffer.markUsed (response_.size ()); } +#ifdef __WIIU__ +#ifndef FSA_DIRITER_MAGIC +#define FSA_DIRITER_MAGIC 0x77696975 +#endif + +// TODO: make this less hacky. Ideally this should be handled by newlib. +typedef struct +{ + uint32_t magic; + FSADirectoryHandle fd; + FSADirectoryEntry entry_data; + // Some fields are missing here!!!! +} __wut_fsa_dir_incomplete_t; + +extern "C" void __wut_fsa_translate_stat (FSAClientHandle clientHandle, + FSStat *fsStat, + ino_t ino, + struct stat *posStat); + +static bool __wut_fsa_get_stat_from_dir (DIR *dp, struct stat *posStat) +{ + if (dp == NULL || dp->dirData == NULL || dp->dirData->dirStruct == NULL || posStat == NULL) + { + return false; + } + + auto const magic = *(uint32_t *)(dp->dirData->dirStruct); + if (magic == FSA_DIRITER_MAGIC) + { + __wut_fsa_dir_incomplete_t *dir = (__wut_fsa_dir_incomplete_t *)dp->dirData->dirStruct; + __wut_fsa_translate_stat (0, &dir->entry_data.info, 0, posStat); + return true; + } + + return false; +} +#endif + bool FtpSession::listTransfer () { // check if we sent all available data @@ -1690,8 +1731,15 @@ bool FtpSession::listTransfer () // build the path auto const fullPath = buildPath (m_lwd, dent->d_name); struct stat st = {}; - -#ifdef __3DS__ +#ifdef __WIIU__ + auto const dp = static_cast (m_dir); + if (__wut_fsa_get_stat_from_dir (dp, &st)) + { + // success! + } + else + { // fallback to lstat +#elifdef __3DS__ // the sdmc directory entry already has the type and size, so no need to do a slow stat auto const dp = static_cast (m_dir); auto const magic = *reinterpret_cast (dp->dirData->dirStruct); @@ -1738,6 +1786,7 @@ bool FtpSession::listTransfer () } } else + { #endif // lstat the entry if (IOAbstraction::lstat (fullPath.c_str (), &st) != 0) @@ -1747,42 +1796,45 @@ bool FtpSession::listTransfer () setState (State::COMMAND, true, true); return false; #else - // probably archive bit set; list name with dummy stats - std::memset (&st, 0, sizeof (st)); - error ("%s: type %u\n", dent->d_name, dent->d_type); - switch (dent->d_type) - { - case DT_BLK: - st.st_mode = S_IFBLK; - break; + // probably archive bit set; list name with dummy stats + std::memset (&st, 0, sizeof (st)); + error ("%s: type %u\n", dent->d_name, dent->d_type); + switch (dent->d_type) + { + case DT_BLK: + st.st_mode = S_IFBLK; + break; - case DT_CHR: - st.st_mode = S_IFCHR; - break; + case DT_CHR: + st.st_mode = S_IFCHR; + break; - case DT_DIR: - st.st_mode = S_IFDIR; - break; + case DT_DIR: + st.st_mode = S_IFDIR; + break; - case DT_FIFO: - st.st_mode = S_IFIFO; - break; + case DT_FIFO: + st.st_mode = S_IFIFO; + break; - case DT_LNK: - st.st_mode = S_IFLNK; - break; + case DT_LNK: + st.st_mode = S_IFLNK; + break; - case DT_REG: - case DT_UNKNOWN: - st.st_mode = S_IFREG; - break; + case DT_REG: + case DT_UNKNOWN: + st.st_mode = S_IFREG; + break; - case DT_SOCK: - st.st_mode = S_IFSOCK; - break; - } + case DT_SOCK: + st.st_mode = S_IFSOCK; + break; + } #endif } +#if defined(__WIIU__) || defined(__3DS__) + } +#endif auto const path = encodePath (dent->d_name); auto const rc = fillDirent (st, path); @@ -2291,7 +2343,7 @@ void FtpSession::PASV (char const *args_) ephemeralPort = 5001; addr.sin_port = htons (ephemeralPort++); #else - addr.sin_port = htons (0); + addr.sin_port = htons (0); #endif // bind to the address