From 966ff741d18a6ca966181191977b1ce2b882b686 Mon Sep 17 00:00:00 2001 From: psucien Date: Thu, 20 Jun 2024 21:45:58 +0200 Subject: [PATCH] kernel: file_system: gmoralis's dirents implementation --- src/core/file_sys/fs.cpp | 14 ++-- src/core/file_sys/fs.h | 7 +- src/core/libraries/kernel/file_system.cpp | 84 +++++++++++++++++++++-- src/core/libraries/kernel/file_system.h | 10 +++ 4 files changed, 99 insertions(+), 16 deletions(-) diff --git a/src/core/file_sys/fs.cpp b/src/core/file_sys/fs.cpp index c42a0d3e..912c74bf 100644 --- a/src/core/file_sys/fs.cpp +++ b/src/core/file_sys/fs.cpp @@ -28,15 +28,13 @@ void MntPoints::UnmountAll() { std::string MntPoints::GetHostDirectory(const std::string& guest_directory) { std::scoped_lock lock{m_mutex}; for (auto& pair : m_mnt_pairs) { - if (pair.guest_path.starts_with(guest_directory)) { - return pair.host_path + guest_directory; - } - } - // hack for relative path , get app0 and assuming it goes from there - for (auto& pair : m_mnt_pairs) { - if (pair.guest_path.starts_with("/app0")) { + // horrible code but it works :D + int find = guest_directory.find(pair.guest_path); + if (find == 0) { + std::string npath = + guest_directory.substr(pair.guest_path.size(), guest_directory.size() - 1); std::replace(pair.host_path.begin(), pair.host_path.end(), '\\', '/'); - return pair.host_path + guest_directory; + return pair.host_path + npath; } } return ""; diff --git a/src/core/file_sys/fs.h b/src/core/file_sys/fs.h index 7d7b9985..4ba01685 100644 --- a/src/core/file_sys/fs.h +++ b/src/core/file_sys/fs.h @@ -32,13 +32,18 @@ private: std::mutex m_mutex; }; +struct DirEntry { + std::string name; + bool isFile; +}; + struct File { std::atomic_bool is_opened{}; std::atomic_bool is_directory{}; std::string m_host_name; std::string m_guest_name; Common::FS::IOFile f; - // std::vector dirents; + std::vector dirents; u32 dirents_index; std::mutex m_mutex; }; diff --git a/src/core/libraries/kernel/file_system.cpp b/src/core/libraries/kernel/file_system.cpp index 964177b7..53b20b91 100644 --- a/src/core/libraries/kernel/file_system.cpp +++ b/src/core/libraries/kernel/file_system.cpp @@ -11,6 +11,27 @@ namespace Libraries::Kernel { +std::vector GetDirectoryEntries(const std::string& path) { + std::string curpath = path; + if (!curpath.ends_with("/")) { + curpath = std::string(curpath + "/"); + } + std::vector files; + + for (const auto& entry : std::filesystem::directory_iterator(curpath)) { + Core::FileSys::DirEntry e = {}; + if (std::filesystem::is_directory(entry.path().string())) { + e.name = entry.path().filename().string(); + e.isFile = false; + } else { + e.name = entry.path().filename().string(); + e.isFile = true; + } + files.push_back(e); + } + + return files; +} int PS4_SYSV_ABI sceKernelOpen(const char* path, int flags, u16 mode) { LOG_INFO(Kernel_Fs, "path = {} flags = {:#x} mode = {}", path, flags, mode); auto* h = Common::Singleton::Instance(); @@ -34,12 +55,23 @@ int PS4_SYSV_ABI sceKernelOpen(const char* path, int flags, u16 mode) { if (std::string_view{path} == "/dev/console" || std::string_view{path} == "/dev/deci_tty6") { return 2000;//return a high handler // TODO fix me } - + u32 handle = h->CreateHandle(); + auto* file = h->GetFile(handle); if (directory) { - LOG_ERROR(Kernel_Fs, "called on directory"); + file->is_directory = true; + file->m_guest_name = path; + file->m_host_name = mnt->GetHostDirectory(file->m_guest_name); + if (!std::filesystem::is_directory(file->m_host_name)) { // directory doesn't exist + UNREACHABLE(); // not supported yet + } else { + if (create) { + return handle; // dir already exists + } else { + file->dirents = GetDirectoryEntries(file->m_host_name); + file->dirents_index = 0; + } + } } else { - u32 handle = h->CreateHandle(); - auto* file = h->GetFile(handle); file->m_guest_name = path; file->m_host_name = mnt->GetHostFile(file->m_guest_name); if (read) { @@ -61,10 +93,9 @@ int PS4_SYSV_ABI sceKernelOpen(const char* path, int flags, u16 mode) { h->DeleteHandle(handle); return SCE_KERNEL_ERROR_EACCES; } - file->is_opened = true; - return handle; } - return -1; // dummy + file->is_opened = true; + return handle; } int PS4_SYSV_ABI posix_open(const char* path, int flags, /* SceKernelMode*/ u16 mode) { @@ -310,6 +341,43 @@ s32 PS4_SYSV_ABI sceKernelFsync(int fd) { return ORBIS_OK; } +int GetDents(int fd, char* buf, int nbytes, s64* basep) { + // TODO error codes + auto* h = Common::Singleton::Instance(); + auto* file = h->GetFile(fd); + + if (file->dirents_index == file->dirents.size()) { + return 0; + } + + const auto& entry = file->dirents.at(file->dirents_index++); + auto str = entry.name; + auto str_size = str.size() - 1; + static int fileno = 1000; // random + OrbisKernelDirent* sce_ent = (OrbisKernelDirent*)buf; + sce_ent->d_fileno = fileno++; // TODO this should be unique but atm it changes maybe switch to a + // hash or something? + sce_ent->d_reclen = sizeof(OrbisKernelDirent); + sce_ent->d_type = (entry.isFile ? 8 : 4); + sce_ent->d_namlen = str_size; + strncpy(sce_ent->d_name, str.c_str(), ORBIS_MAX_PATH); + sce_ent->d_name[ORBIS_MAX_PATH] = '\0'; + + if (basep != nullptr) { + *basep = file->dirents_index; + } + + return sizeof(OrbisKernelDirent); +} + +int PS4_SYSV_ABI sceKernelGetdents(int fd, char* buf, int nbytes) { + return GetDents(fd, buf, nbytes, nullptr); +} + +int PS4_SYSV_ABI sceKernelGetdirentries(int fd, char* buf, int nbytes, s64* basep) { + return GetDents(fd, buf, nbytes, basep); +} + void fileSystemSymbolsRegister(Core::Loader::SymbolsResolver* sym) { LIB_FUNCTION("1G3lF1Gg1k8", "libkernel", 1, "libkernel", 1, 1, sceKernelOpen); LIB_FUNCTION("wuCroIGjt2g", "libScePosix", 1, "libkernel", 1, 1, posix_open); @@ -333,6 +401,8 @@ void fileSystemSymbolsRegister(Core::Loader::SymbolsResolver* sym) { LIB_FUNCTION("+r3rMFwItV4", "libkernel", 1, "libkernel", 1, 1, sceKernelPread); LIB_FUNCTION("uWyW3v98sU4", "libkernel", 1, "libkernel", 1, 1, sceKernelCheckReachability); LIB_FUNCTION("fTx66l5iWIA", "libkernel", 1, "libkernel", 1, 1, sceKernelFsync); + LIB_FUNCTION("j2AIqSqJP0w", "libkernel", 1, "libkernel", 1, 1, sceKernelGetdents); + LIB_FUNCTION("taRWhTJFTgE", "libkernel", 1, "libkernel", 1, 1, sceKernelGetdirentries); // openOrbis (to check if it is valid out of OpenOrbis LIB_FUNCTION("6c3rCVE-fTU", "libkernel", 1, "libkernel", 1, 1, diff --git a/src/core/libraries/kernel/file_system.h b/src/core/libraries/kernel/file_system.h index c0284310..1174dd86 100644 --- a/src/core/libraries/kernel/file_system.h +++ b/src/core/libraries/kernel/file_system.h @@ -12,6 +12,8 @@ class SymbolsResolver; namespace Libraries::Kernel { +constexpr int ORBIS_MAX_PATH = 255; + struct SceKernelIovec { void* iov_base; std::size_t iov_len; @@ -39,6 +41,14 @@ struct OrbisKernelStat { unsigned int : (8 / 2) * (16 - static_cast(sizeof(OrbisKernelTimespec))); }; +struct OrbisKernelDirent { + u32 d_fileno; /* file number of entry */ + u16 d_reclen; /* length of this record */ + u8 d_type; /* file type, see below */ + u8 d_namlen; /* length of string in d_name */ + char d_name[ORBIS_MAX_PATH + 1]; /* name must be no longer than this */ +}; + // flags for Open constexpr int ORBIS_KERNEL_O_RDONLY = 0x0000; constexpr int ORBIS_KERNEL_O_WRONLY = 0x0001;