From ad6724eebaba4e4578bdabd53abf182bf02f5ddf Mon Sep 17 00:00:00 2001 From: georgemoralis Date: Sun, 5 May 2024 12:43:01 +0300 Subject: [PATCH] improvements in sceKernelOpen, rewrote sceKernelLseek, added sceKernelWrite, added sceKernelMkdir , partial sceKernelStat --- src/core/libraries/kernel/file_system.cpp | 137 ++++++++++++++++++---- src/core/libraries/kernel/file_system.h | 39 ++++++ 2 files changed, 156 insertions(+), 20 deletions(-) diff --git a/src/core/libraries/kernel/file_system.cpp b/src/core/libraries/kernel/file_system.cpp index 2f1e8ef2..1321a1bc 100644 --- a/src/core/libraries/kernel/file_system.cpp +++ b/src/core/libraries/kernel/file_system.cpp @@ -12,25 +12,48 @@ namespace Libraries::Kernel { int PS4_SYSV_ABI sceKernelOpen(const char* path, int flags, u16 mode) { - LOG_INFO(Kernel_Fs, "path = {} flags = {:#x} mode = {:#x}", path, flags, mode); - ASSERT_MSG(flags == 0, "flags!=0 not supported yet"); - ASSERT_MSG(mode == 0, "mode!=0 not supported yet"); + LOG_INFO(Kernel_Fs, "path = {} flags = {:#x} mode = {}", path, flags, mode); auto* h = Common::Singleton::Instance(); auto* mnt = Common::Singleton::Instance(); - // only open files support! - u32 handle = h->CreateHandle(); - auto* file = h->GetFile(handle); - file->m_guest_name = path; - file->m_host_name = mnt->GetHostFile(file->m_guest_name); + bool read = (flags & 0x3) == ORBIS_KERNEL_O_RDONLY; + bool write = (flags & 0x3) == ORBIS_KERNEL_O_WRONLY; + bool rdwr = (flags & 0x3) == ORBIS_KERNEL_O_RDWR; - file->f.Open(file->m_host_name, Common::FS::FileAccessMode::Read); - if (!file->f.IsOpen()) { - h->DeleteHandle(handle); - return SCE_KERNEL_ERROR_EACCES; + bool nonblock = (flags & ORBIS_KERNEL_O_NONBLOCK) != 0; + bool append = (flags & ORBIS_KERNEL_O_APPEND) != 0; + bool fsync = (flags & ORBIS_KERNEL_O_FSYNC) != 0; + bool sync = (flags & ORBIS_KERNEL_O_SYNC) != 0; + bool create = (flags & ORBIS_KERNEL_O_CREAT) != 0; + bool truncate = (flags & ORBIS_KERNEL_O_TRUNC) != 0; + bool excl = (flags & ORBIS_KERNEL_O_EXCL) != 0; + bool dsync = (flags & ORBIS_KERNEL_O_DSYNC) != 0; + bool direct = (flags & ORBIS_KERNEL_O_DIRECT) != 0; + bool directory = (flags & ORBIS_KERNEL_O_DIRECTORY) != 0; + + if (directory) { + UNREACHABLE(); // not supported yet + } else { + // only open files support! + 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) { + file->f.Open(file->m_host_name, Common::FS::FileAccessMode::Read); + } else if (write && create && truncate) { + file->f.Open(file->m_host_name, Common::FS::FileAccessMode::Write); + } else { + UNREACHABLE(); + } + if (!file->f.IsOpen()) { + h->DeleteHandle(handle); + return SCE_KERNEL_ERROR_EACCES; + } + file->is_opened = true; + return handle; } - file->is_opened = true; - return handle; + return -1; // dummy } int PS4_SYSV_ABI posix_open(const char* path, int flags, /* SceKernelMode*/ u16 mode) { @@ -56,6 +79,20 @@ int PS4_SYSV_ABI sceKernelClose(int d) { return SCE_OK; } +size_t PS4_SYSV_ABI sceKernelWrite(int d, void* buf, size_t nbytes) { + if (buf == nullptr) { + return SCE_KERNEL_ERROR_EFAULT; + } + auto* h = Common::Singleton::Instance(); + auto* file = h->GetFile(d); + if (file == nullptr) { + return SCE_KERNEL_ERROR_EBADF; + } + file->m_mutex.lock(); + u32 bytes_write = file->f.WriteRaw(buf, static_cast(nbytes)); + file->m_mutex.unlock(); + return bytes_write; +} size_t PS4_SYSV_ABI _readv(int d, const SceKernelIovec* iov, int iovcnt) { auto* h = Common::Singleton::Instance(); auto* file = h->GetFile(d); @@ -73,18 +110,19 @@ s64 PS4_SYSV_ABI sceKernelLseek(int d, s64 offset, int whence) { auto* file = h->GetFile(d); file->m_mutex.lock(); + Common::FS::SeekOrigin origin; + if (whence == 0) { + origin = Common::FS::SeekOrigin::SetOrigin; + } if (whence == 1) { - offset = static_cast(file->f.Tell()) + offset; - whence = 0; + origin = Common::FS::SeekOrigin::CurrentPosition; } - if (whence == 2) { - offset = static_cast(file->f.GetSize()) + offset; - whence = 0; + origin = Common::FS::SeekOrigin::End; } - file->f.Seek(offset); + file->f.Seek(offset, origin); auto pos = static_cast(file->f.Tell()); file->m_mutex.unlock(); @@ -111,15 +149,74 @@ s64 PS4_SYSV_ABI sceKernelRead(int d, void* buf, size_t nbytes) { return bytes_read; } +int PS4_SYSV_ABI sceKernelMkdir(const char* path, u16 mode) { + LOG_INFO(Kernel_Fs, "path = {} mode = {}", path, mode); + if (path == nullptr) { + return SCE_KERNEL_ERROR_EINVAL; + } + auto* mnt = Common::Singleton::Instance(); + std::string dir_name = mnt->GetHostFile(path); + if (std::filesystem::exists(dir_name)) { + return SCE_KERNEL_ERROR_EEXIST; + } + + if (!std::filesystem::create_directory(dir_name)) { + return SCE_KERNEL_ERROR_EIO; + } + + if (!std::filesystem::exists(dir_name)) { + return SCE_KERNEL_ERROR_ENOENT; + } + return ORBIS_OK; +} + +int PS4_SYSV_ABI sceKernelStat(const char* path, OrbisKernelStat* sb) { + LOG_INFO(Kernel_Fs, "(PARTIAL) path = {}", path); + auto* mnt = Common::Singleton::Instance(); + std::string path_name = mnt->GetHostFile(path); + memset(sb, 0, sizeof(OrbisKernelStat)); + bool is_dir = std::filesystem::is_directory(path_name); + bool is_file = std::filesystem::is_regular_file(path_name); + if (!is_dir && !is_file) { + return ORBIS_KERNEL_ERROR_ENOENT; + } + if (std::filesystem::is_directory(path_name)) { + sb->st_mode = 0000777u | 0040000u; + sb->st_size = 0; + sb->st_blksize = 512; + sb->st_blocks = 0; + // TODO incomplete + } else { + sb->st_mode = 0000777u | 0100000u; + sb->st_size = static_cast(std::filesystem::file_size(path_name)); + sb->st_blksize = 512; + sb->st_blocks = (sb->st_size + 511) / 512; + // TODO incomplete + } + return ORBIS_OK; +} + +int PS4_SYSV_ABI posix_stat(const char* path, OrbisKernelStat* sb) { + int result = sceKernelStat(path, sb); + if (result < 0) { + UNREACHABLE(); // TODO + } + return ORBIS_OK; +} + 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); LIB_FUNCTION("UK2Tl2DWUns", "libkernel", 1, "libkernel", 1, 1, sceKernelClose); + LIB_FUNCTION("4wSze92BhLI", "libkernel", 1, "libkernel", 1, 1, sceKernelWrite); LIB_FUNCTION("+WRlkKjZvag", "libkernel", 1, "libkernel", 1, 1, _readv); LIB_FUNCTION("Oy6IpwgtYOk", "libkernel", 1, "libkernel", 1, 1, lseek); LIB_FUNCTION("oib76F-12fk", "libkernel", 1, "libkernel", 1, 1, sceKernelLseek); LIB_FUNCTION("Cg4srZ6TKbU", "libkernel", 1, "libkernel", 1, 1, sceKernelRead); + LIB_FUNCTION("1-LFLmRFxxM", "libkernel", 1, "libkernel", 1, 1, sceKernelMkdir); + LIB_FUNCTION("eV9wAD2riIA", "libkernel", 1, "libkernel", 1, 1, sceKernelStat); + LIB_FUNCTION("E6ao34wPw+U", "libScePosix", 1, "libkernel", 1, 1, posix_stat); // 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 b0b2e110..865f1b05 100644 --- a/src/core/libraries/kernel/file_system.h +++ b/src/core/libraries/kernel/file_system.h @@ -4,6 +4,7 @@ #pragma once #include "common/types.h" +#include "thread_management.h" namespace Core::Loader { class SymbolsResolver; @@ -16,6 +17,44 @@ struct SceKernelIovec { std::size_t iov_len; }; +struct OrbisKernelStat { + u32 st_dev; + u32 st_ino; + u16 st_mode; + u16 st_nlink; + u32 st_uid; + u32 st_gid; + u32 st_rdev; + SceKernelTimespec st_atim; + SceKernelTimespec st_mtim; + SceKernelTimespec st_ctim; + s64 st_size; + s64 st_blocks; + u32 st_blksize; + u32 st_flags; + u32 st_gen; + s32 st_lspare; + SceKernelTimespec st_birthtim; + unsigned int : (8 / 2) * (16 - static_cast(sizeof(SceKernelTimespec))); + unsigned int : (8 / 2) * (16 - static_cast(sizeof(SceKernelTimespec))); +}; + +// flags for Open +constexpr int ORBIS_KERNEL_O_RDONLY = 0x0000; +constexpr int ORBIS_KERNEL_O_WRONLY = 0x0001; +constexpr int ORBIS_KERNEL_O_RDWR = 0x0002; + +constexpr int ORBIS_KERNEL_O_NONBLOCK = 0x0004; +constexpr int ORBIS_KERNEL_O_APPEND = 0x0008; +constexpr int ORBIS_KERNEL_O_FSYNC = 0x0080; +constexpr int ORBIS_KERNEL_O_SYNC = 0x0080; +constexpr int ORBIS_KERNEL_O_CREAT = 0x0200; +constexpr int ORBIS_KERNEL_O_TRUNC = 0x0400; +constexpr int ORBIS_KERNEL_O_EXCL = 0x0800; +constexpr int ORBIS_KERNEL_O_DSYNC = 0x1000; +constexpr int ORBIS_KERNEL_O_DIRECT = 0x00010000; +constexpr int ORBIS_KERNEL_O_DIRECTORY = 0x00020000; + int PS4_SYSV_ABI sceKernelOpen(const char* path, int flags, /* SceKernelMode*/ u16 mode); int PS4_SYSV_ABI posix_open(const char* path, int flags, /* SceKernelMode*/ u16 mode);