#include "IOAbstraction.h" #include #include #include #include #include #include class VirtualDirectory { public: VirtualDirectory (const std::vector &directories) { mDirectories.push_back ("."); mDirectories.push_back (".."); mDirectories.insert (mDirectories.end (), directories.begin (), directories.end ()); mCurIterator = mDirectories.begin (); } [[nodiscard]] const DIR *getAsDir () const { return &mDirPtr; } struct dirent *readdir () { if (mCurIterator == mDirectories.end ()) { return nullptr; } mDir = {}; snprintf (mDir.d_name, sizeof (mDir.d_name), "%s", mCurIterator->c_str ()); mCurIterator++; mDirPtr.position++; return &mDir; } private: DIR mDirPtr = {}; std::vector mDirectories; struct dirent mDir = {}; std::vector::iterator mCurIterator{}; }; std::vector> sOpenVirtualDirectories; std::mutex sOpenVirtualDirectoriesMutex; std::map> sVirtualDirs; template typename std::enable_if>::value, bool>::type remove_first_if (Container &container, Predicate pred) { auto it = container.begin (); while (it != container.end ()) { if (pred (*it)) { container.erase (it); return true; } ++it; } return false; } template bool remove_locked_first_if (std::mutex &mutex, Container &container, Predicate pred) { std::lock_guard lock (mutex); return remove_first_if (container, pred); } static const DIR *getVirtualDir (const std::vector &subDirectories) { auto virtDir = std::make_unique (subDirectories); auto *result = virtDir->getAsDir (); std::lock_guard lock (sOpenVirtualDirectoriesMutex); sOpenVirtualDirectories.push_back (std::move (virtDir)); return result; } std::string IOAbstraction::convertPath (std::string_view inPath) { #ifdef __WIIU__ if (!inPath.starts_with ('/') || inPath.find (':') != std::string::npos) { return std::string (inPath); } std::string path = std::string (inPath); size_t secondSlashPos = path.find ('/', 1); if (secondSlashPos != std::string::npos) { // Extract the substring between the first and second slashes std::string prefix = path.substr (1, secondSlashPos - 1); std::string suffix = path.substr (secondSlashPos); // Concatenate the modified prefix and suffix path = prefix + ":" + suffix; } else { path = std::string (inPath.substr (1)) + ":/"; } return path; #else return std::string (inPath); #endif } int IOAbstraction::closedir (DIR *dirp) { { std::lock_guard lock (sOpenVirtualDirectoriesMutex); if (remove_locked_first_if (sOpenVirtualDirectoriesMutex, sOpenVirtualDirectories, [dirp] (auto &cur) { return cur->getAsDir () == dirp; })) { return 0; } } return ::closedir (dirp); } DIR *IOAbstraction::opendir (const char *dirname) { auto convertedPath = convertPath (dirname); auto *res = ::opendir (convertedPath.c_str ()); if (res == nullptr) { if (sVirtualDirs.count (convertedPath) > 0) { return (DIR *)getVirtualDir (sVirtualDirs[convertedPath]); } } return res; } FILE *IOAbstraction::fopen (const char *_name, const char *_type) { return std::fopen (convertPath (_name).c_str (), _type); } int IOAbstraction::fseek (FILE *f, long pos, int origin) { return std::fseek (f, pos, origin); } size_t IOAbstraction::fread (void *buffer, size_t _size, size_t _n, FILE *f) { return std::fread (buffer, _size, _n, f); } size_t IOAbstraction::fwrite (const void *buffer, size_t _size, size_t _n, FILE *f) { return std::fwrite (buffer, _size, _n, f); } struct dirent *IOAbstraction::readdir (DIR *dirp) { { std::lock_guard lock (sOpenVirtualDirectoriesMutex); auto itr = std::find_if (sOpenVirtualDirectories.begin (), sOpenVirtualDirectories.end (), [dirp] (auto &cur) { return cur->getAsDir () == dirp; }); if (itr != sOpenVirtualDirectories.end ()) { return (*itr)->readdir (); } } return ::readdir (dirp); } int IOAbstraction::stat (const char *path, struct stat *sbuf) { auto convertedPath = convertPath (path); auto r = ::stat (convertedPath.c_str (), sbuf); if (r < 0) { if (sVirtualDirs.contains (convertedPath)) { *sbuf = {}; // TODO: init other values? sbuf->st_mode = _IFDIR; return 0; } } return r; } int IOAbstraction::lstat (const char *path, struct stat *buf) { return IOAbstraction::stat (path, buf); } void IOAbstraction::addVirtualPath (const std::string &virtualPath, const std::vector &subDirectories) { sVirtualDirs.insert (std::make_pair (virtualPath, subDirectories)); } void IOAbstraction::clear () { std::lock_guard lock (sOpenVirtualDirectoriesMutex); sOpenVirtualDirectories.clear (); sVirtualDirs.clear (); } int IOAbstraction::mkdir (const char *path, mode_t mode) { return ::mkdir (convertPath (path).c_str (), mode); } int IOAbstraction::rmdir (const char *path) { return ::rmdir (convertPath (path).c_str ()); } int IOAbstraction::unlink (const char *path) { return ::unlink (convertPath (path).c_str ()); } int IOAbstraction::rename (const char *path, const char *path2) { return ::rename (convertPath (path).c_str (), convertPath (path2).c_str ()); }