diff --git a/CMakeLists.txt b/CMakeLists.txt index adede79d..7db7e5b6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -147,7 +147,7 @@ add_executable(shadps4 src/emuTimer.h src/core/hle/libraries/libkernel/time_management.cpp src/core/hle/libraries/libkernel/time_management.h -) + "src/common/io_file.cpp" "src/common/io_file.h") create_target_directory_groups(shadps4) diff --git a/src/common/io_file.cpp b/src/common/io_file.cpp new file mode 100644 index 00000000..86874c08 --- /dev/null +++ b/src/common/io_file.cpp @@ -0,0 +1,138 @@ +#include "io_file.h" + +//#include "helpers.hpp" + +#ifdef _MSC_VER +// 64 bit offsets for MSVC +#define fseeko _fseeki64 +#define ftello _ftelli64 +#define fileno _fileno + +#pragma warning(disable : 4996) +#endif + +#ifndef _CRT_SECURE_NO_WARNINGS +#define _CRT_SECURE_NO_WARNINGS +#endif + +#ifdef WIN32 +#include // For _chsize_s +#else +#include // For ftruncate +#endif + +IOFile::IOFile(const std::filesystem::path& path, const char* permissions) : handle(nullptr) { + open(path, permissions); +} + +bool IOFile::open(const std::filesystem::path& path, const char* permissions) { + const auto str = + path.string(); // For some reason converting paths directly with c_str() doesn't work + return open(str.c_str(), permissions); +} + +bool IOFile::open(const char* filename, const char* permissions) { + // If this IOFile is already bound to an open file descriptor, release the file descriptor + // To avoid leaking it and/or erroneously locking the file + if (isOpen()) { + close(); + } + + handle = std::fopen(filename, permissions); + return isOpen(); +} + +void IOFile::close() { + if (isOpen()) { + fclose(handle); + handle = nullptr; + } +} + +std::pair IOFile::read(void* data, std::size_t length, std::size_t dataSize) { + if (!isOpen()) { + return {false, std::numeric_limits::max()}; + } + + if (length == 0) + return {true, 0}; + return {true, std::fread(data, dataSize, length, handle)}; +} + +std::pair IOFile::write(const void* data, std::size_t length, + std::size_t dataSize) { + if (!isOpen()) { + return {false, std::numeric_limits::max()}; + } + + if (length == 0) { + return {true, 0}; + } else { + return {true, std::fwrite(data, dataSize, length, handle)}; + } +} + +std::pair IOFile::readBytes(void* data, std::size_t count) { + return read(data, count, sizeof(std::uint8_t)); +} +std::pair IOFile::writeBytes(const void* data, std::size_t count) { + return write(data, count, sizeof(std::uint8_t)); +} + +std::optional IOFile::size() { + if (!isOpen()) + return {}; + + std::uint64_t pos = ftello(handle); + if (fseeko(handle, 0, SEEK_END) != 0) { + return {}; + } + + std::uint64_t size = ftello(handle); + if ((size != pos) && (fseeko(handle, pos, SEEK_SET) != 0)) { + return {}; + } + + return size; +} + +bool IOFile::seek(std::int64_t offset, int origin) { + if (!isOpen() || fseeko(handle, offset, origin) != 0) + return false; + + return true; +} + +bool IOFile::flush() { + if (!isOpen() || fflush(handle)) + return false; + + return true; +} + +bool IOFile::rewind() { + return seek(0, SEEK_SET); +} +FILE* IOFile::getHandle() { + return handle; +} + +void IOFile::setAppDataDir(const std::filesystem::path& dir) { + //if (dir == "") + // Helpers::panic("Failed to set app data directory"); + appData = dir; +} + +bool IOFile::setSize(std::uint64_t size) { + if (!isOpen()) + return false; + bool success; + +#ifdef WIN32 + success = _chsize_s(_fileno(handle), size) == 0; +#else + success = ftruncate(fileno(handle), size) == 0; +#endif + fflush(handle); + return success; +} \ No newline at end of file diff --git a/src/common/io_file.h b/src/common/io_file.h new file mode 100644 index 00000000..85f7a78e --- /dev/null +++ b/src/common/io_file.h @@ -0,0 +1,41 @@ +#pragma once +#include +#include +#include + +class IOFile { + FILE* handle = nullptr; + static inline std::filesystem::path appData =""; // Directory for holding app data. AppData on Windows + +public: + IOFile() : handle(nullptr) {} + IOFile(FILE* handle) : handle(handle) {} + IOFile(const std::filesystem::path& path, const char* permissions = "rb"); + + bool isOpen() { + return handle != nullptr; + } + bool open(const std::filesystem::path& path, const char* permissions = "rb"); + bool open(const char* filename, const char* permissions = "rb"); + void close(); + + std::pair read(void* data, std::size_t length, std::size_t dataSize); + std::pair readBytes(void* data, std::size_t count); + + std::pair write(const void* data, std::size_t length, std::size_t dataSize); + std::pair writeBytes(const void* data, std::size_t count); + + std::optional size(); + + bool seek(std::int64_t offset, int origin = SEEK_SET); + bool rewind(); + bool flush(); + FILE* getHandle(); + static void setAppDataDir(const std::filesystem::path& dir); + static std::filesystem::path getAppData() { + return appData; + } + + // Sets the size of the file to "size" and returns whether it succeeded or not + bool setSize(std::uint64_t size); +}; \ No newline at end of file diff --git a/src/core/PS4/HLE/Graphics/video_out.cpp b/src/core/PS4/HLE/Graphics/video_out.cpp index c87c1a87..7fdb2193 100644 --- a/src/core/PS4/HLE/Graphics/video_out.cpp +++ b/src/core/PS4/HLE/Graphics/video_out.cpp @@ -330,5 +330,14 @@ void videoOutRegisterLib(Core::Loader::SymbolsResolver* sym) { LIB_FUNCTION("zgXifHT9ErY", "libSceVideoOut", 1, "libSceVideoOut", 0, 0, sceVideoOutIsFlipPending); LIB_FUNCTION("N5KDtkIjjJ4", "libSceVideoOut", 1, "libSceVideoOut", 0, 0, sceVideoOutUnregisterBuffers); LIB_FUNCTION("uquVH4-Du78", "libSceVideoOut", 1, "libSceVideoOut", 0, 0, sceVideoOutClose); + + // openOrbis appears to have libSceVideoOut_v1 module libSceVideoOut_v1.1 + LIB_FUNCTION("Up36PTk687E", "libSceVideoOut", 1, "libSceVideoOut", 1, 1, sceVideoOutOpen); + LIB_FUNCTION("CBiu4mCE1DA", "libSceVideoOut", 1, "libSceVideoOut", 1, 1, sceVideoOutSetFlipRate); + LIB_FUNCTION("HXzjK9yI30k", "libSceVideoOut", 1, "libSceVideoOut", 1, 1, sceVideoOutAddFlipEvent); + LIB_FUNCTION("i6-sR91Wt-4", "libSceVideoOut", 1, "libSceVideoOut", 1, 1, sceVideoOutSetBufferAttribute); + LIB_FUNCTION("w3BY+tAEiQY", "libSceVideoOut", 1, "libSceVideoOut", 1, 1, sceVideoOutRegisterBuffers); + LIB_FUNCTION("U46NwOiJpys", "libSceVideoOut", 1, "libSceVideoOut", 1, 1, sceVideoOutSubmitFlip); + LIB_FUNCTION("SbU3dwp80lQ", "libSceVideoOut", 1, "libSceVideoOut", 1, 1, sceVideoOutGetFlipStatus); } } // namespace HLE::Libs::Graphics::VideoOut diff --git a/src/core/file_sys/fs.h b/src/core/file_sys/fs.h index 3255cc52..45bf718f 100644 --- a/src/core/file_sys/fs.h +++ b/src/core/file_sys/fs.h @@ -4,6 +4,7 @@ #include #include "common/fs_file.h" +#include namespace Core::FileSys { @@ -32,7 +33,7 @@ struct File { std::atomic_bool isDirectory; std::string m_host_name; std::string m_guest_name; - Common::FS::File f; + IOFile f; //std::vector dirents; u32 dirents_index; std::mutex m_mutex; diff --git a/src/core/hle/libraries/libkernel/file_system.cpp b/src/core/hle/libraries/libkernel/file_system.cpp index 271cf363..57d08cae 100644 --- a/src/core/hle/libraries/libkernel/file_system.cpp +++ b/src/core/hle/libraries/libkernel/file_system.cpp @@ -2,6 +2,9 @@ #include "common/debug.h" #include "core/hle/libraries/libkernel/file_system.h" #include "core/hle/libraries/libs.h" +#include +#include +#include namespace Core::Libraries::LibKernel { @@ -9,10 +12,25 @@ constexpr bool log_file_fs = true; // disable it to disable logging int PS4_SYSV_ABI sceKernelOpen(const char* path, int flags, u16 mode) { LOG_INFO_IF(log_file_fs, "sceKernelOpen path = {} flags = {:#x} mode = {:#x}\n", path, flags, mode); - return 0; + 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 result = file->f.open(file->m_host_name); + if (!result) { + h->deleteHandle(handle); + return SCE_KERNEL_ERROR_EACCES; + } + file->isOpened = true; + return handle; } -int PS4_SYSV_ABI open(const char* path, int flags, /* SceKernelMode*/ u16 mode) { +int PS4_SYSV_ABI posix_open(const char* path, int flags, /* SceKernelMode*/ u16 mode) { LOG_INFO_IF(log_file_fs, "posix open redirect to sceKernelOpen\n"); int result = sceKernelOpen(path, flags, mode); if (result < 0) { @@ -21,9 +39,25 @@ int PS4_SYSV_ABI open(const char* path, int flags, /* SceKernelMode*/ u16 mode) return result; } +size_t PS4_SYSV_ABI _readv(int d, const SceKernelIovec* iov, int iovcnt) { + auto* h = Common::Singleton::Instance(); + auto* file = h->getFile(d); + size_t total_read = 0; + file->m_mutex.lock(); + for (int i = 0; i < iovcnt; i++) { + total_read += file->f.readBytes(iov[i].iov_base,iov[i].iov_len).second; + } + file->m_mutex.unlock(); + return total_read; +} + void fileSystemSymbolsRegister(Loader::SymbolsResolver* sym) { LIB_FUNCTION("1G3lF1Gg1k8", "libkernel", 1, "libkernel", 1, 1, sceKernelOpen); - LIB_FUNCTION("wuCroIGjt2g", "libScePosix", 1, "libkernel", 1, 1, open); + LIB_FUNCTION("wuCroIGjt2g", "libScePosix", 1, "libkernel", 1, 1, posix_open); + LIB_FUNCTION("+WRlkKjZvag", "libkernel", 1, "libkernel", 1, 1, _readv); + + // openOrbis (to check if it is valid out of OpenOrbis + LIB_FUNCTION("6c3rCVE-fTU", "libkernel", 1, "libkernel", 1, 1, posix_open); // _open shoudld be equal to open function } } // namespace Core::Libraries::LibKernel diff --git a/src/core/hle/libraries/libkernel/file_system.h b/src/core/hle/libraries/libkernel/file_system.h index f5be1d1e..8a3ef3bb 100644 --- a/src/core/hle/libraries/libkernel/file_system.h +++ b/src/core/hle/libraries/libkernel/file_system.h @@ -8,9 +8,14 @@ class SymbolsResolver; namespace Core::Libraries::LibKernel { +struct SceKernelIovec { + void *iov_base; + size_t iov_len; +}; + int PS4_SYSV_ABI sceKernelOpen(const char *path, int flags, /* SceKernelMode*/ u16 mode); -int PS4_SYSV_ABI open(const char *path, int flags, /* SceKernelMode*/ u16 mode); +int PS4_SYSV_ABI posix_open(const char *path, int flags, /* SceKernelMode*/ u16 mode); void fileSystemSymbolsRegister(Loader::SymbolsResolver *sym);