Improve performance when reading directories

This commit is contained in:
Maschell 2024-03-24 11:07:30 +01:00
parent bfc82df26f
commit d566a7155e

View File

@ -37,6 +37,9 @@
#include <cerrno> #include <cerrno>
#include <chrono> #include <chrono>
#include <cinttypes> #include <cinttypes>
#ifdef __WIIU__
#include <coreinit/filesystem_fsa.h>
#endif
#include <cstdarg> #include <cstdarg>
#include <cstring> #include <cstring>
#include <ctime> #include <ctime>
@ -1634,6 +1637,44 @@ void FtpSession::sendResponse (std::string_view const response_)
m_responseBuffer.markUsed (response_.size ()); 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 () bool FtpSession::listTransfer ()
{ {
// check if we sent all available data // check if we sent all available data
@ -1690,8 +1731,15 @@ bool FtpSession::listTransfer ()
// build the path // build the path
auto const fullPath = buildPath (m_lwd, dent->d_name); auto const fullPath = buildPath (m_lwd, dent->d_name);
struct stat st = {}; struct stat st = {};
#ifdef __WIIU__
#ifdef __3DS__ auto const dp = static_cast<DIR *> (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 // the sdmc directory entry already has the type and size, so no need to do a slow stat
auto const dp = static_cast<DIR *> (m_dir); auto const dp = static_cast<DIR *> (m_dir);
auto const magic = *reinterpret_cast<u32 *> (dp->dirData->dirStruct); auto const magic = *reinterpret_cast<u32 *> (dp->dirData->dirStruct);
@ -1738,6 +1786,7 @@ bool FtpSession::listTransfer ()
} }
} }
else else
{
#endif #endif
// lstat the entry // lstat the entry
if (IOAbstraction::lstat (fullPath.c_str (), &st) != 0) if (IOAbstraction::lstat (fullPath.c_str (), &st) != 0)
@ -1747,42 +1796,45 @@ bool FtpSession::listTransfer ()
setState (State::COMMAND, true, true); setState (State::COMMAND, true, true);
return false; return false;
#else #else
// probably archive bit set; list name with dummy stats // probably archive bit set; list name with dummy stats
std::memset (&st, 0, sizeof (st)); std::memset (&st, 0, sizeof (st));
error ("%s: type %u\n", dent->d_name, dent->d_type); error ("%s: type %u\n", dent->d_name, dent->d_type);
switch (dent->d_type) switch (dent->d_type)
{ {
case DT_BLK: case DT_BLK:
st.st_mode = S_IFBLK; st.st_mode = S_IFBLK;
break; break;
case DT_CHR: case DT_CHR:
st.st_mode = S_IFCHR; st.st_mode = S_IFCHR;
break; break;
case DT_DIR: case DT_DIR:
st.st_mode = S_IFDIR; st.st_mode = S_IFDIR;
break; break;
case DT_FIFO: case DT_FIFO:
st.st_mode = S_IFIFO; st.st_mode = S_IFIFO;
break; break;
case DT_LNK: case DT_LNK:
st.st_mode = S_IFLNK; st.st_mode = S_IFLNK;
break; break;
case DT_REG: case DT_REG:
case DT_UNKNOWN: case DT_UNKNOWN:
st.st_mode = S_IFREG; st.st_mode = S_IFREG;
break; break;
case DT_SOCK: case DT_SOCK:
st.st_mode = S_IFSOCK; st.st_mode = S_IFSOCK;
break; break;
} }
#endif #endif
} }
#if defined(__WIIU__) || defined(__3DS__)
}
#endif
auto const path = encodePath (dent->d_name); auto const path = encodePath (dent->d_name);
auto const rc = fillDirent (st, path); auto const rc = fillDirent (st, path);
@ -2291,7 +2343,7 @@ void FtpSession::PASV (char const *args_)
ephemeralPort = 5001; ephemeralPort = 5001;
addr.sin_port = htons (ephemeralPort++); addr.sin_port = htons (ephemeralPort++);
#else #else
addr.sin_port = htons (0); addr.sin_port = htons (0);
#endif #endif
// bind to the address // bind to the address