Compare commits
27 Commits
main
...
filesystem
Author | SHA1 | Date |
---|---|---|
georgemoralis | 2fa24cc776 | |
georgemoralis | 7a3e4637f4 | |
wheremyfoodat | e35efb55a2 | |
georgemoralis | 1ced777f20 | |
georgemoralis | 76e24202da | |
georgemoralis | 9fb5852f2e | |
georgemoralis | 0dfdefe01b | |
georgemoralis | 128a27a38b | |
georgemoralis | b33fd9d8cb | |
georgemoralis | 81b5434491 | |
georgemoralis | 3bc52fcce3 | |
georgemoralis | c2f18dc7b0 | |
georgemoralis | d4ac82eef2 | |
georgemoralis | 4bd4d2ff53 | |
georgemoralis | f8cc51496d | |
georgemoralis | c6459f35a7 | |
georgemoralis | 365222ee9a | |
georgemoralis | fc14a8a707 | |
georgemoralis | 429d7deb29 | |
georgemoralis | 461215a6f5 | |
georgemoralis | 0f59f4a745 | |
georgemoralis | bd6d635a4b | |
georgemoralis | 961a1a3258 | |
georgemoralis | 3238fff089 | |
georgemoralis | 172fa7df6e | |
georgemoralis | 55a2bfcc29 | |
georgemoralis | bfbe67bc42 |
|
@ -59,6 +59,8 @@ set(SYSTEMSERVICE_SOURCES src/core/hle/libraries/libsystemservice/system_service
|
||||||
|
|
||||||
set(FILESYSTEM_SOURCES src/core/hle/libraries/libkernel/file_system.cpp
|
set(FILESYSTEM_SOURCES src/core/hle/libraries/libkernel/file_system.cpp
|
||||||
src/core/hle/libraries/libkernel/file_system.h
|
src/core/hle/libraries/libkernel/file_system.h
|
||||||
|
src/core/file_sys/fs.cpp
|
||||||
|
src/core/file_sys/fs.h
|
||||||
)
|
)
|
||||||
|
|
||||||
set(HOST_SOURCES src/Emulator/Host/controller.cpp
|
set(HOST_SOURCES src/Emulator/Host/controller.cpp
|
||||||
|
|
|
@ -1,16 +1,14 @@
|
||||||
#include "common/fs_file.h"
|
#include "common/fs_file.h"
|
||||||
|
|
||||||
|
#include <filesystem>
|
||||||
|
|
||||||
namespace Common::FS {
|
namespace Common::FS {
|
||||||
|
|
||||||
File::File() = default;
|
File::File() = default;
|
||||||
|
|
||||||
File::File(const std::string& path, OpenMode mode) {
|
File::File(const std::string& path, OpenMode mode) { open(path, mode); }
|
||||||
open(path, mode);
|
|
||||||
}
|
|
||||||
|
|
||||||
File::~File() {
|
File::~File() { close(); }
|
||||||
close();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool File::open(const std::string& path, OpenMode mode) {
|
bool File::open(const std::string& path, OpenMode mode) {
|
||||||
close();
|
close();
|
||||||
|
@ -24,21 +22,17 @@ bool File::open(const std::string& path, OpenMode mode) {
|
||||||
|
|
||||||
bool File::close() {
|
bool File::close() {
|
||||||
if (!isOpen() || std::fclose(m_file) != 0) [[unlikely]] {
|
if (!isOpen() || std::fclose(m_file) != 0) [[unlikely]] {
|
||||||
m_file = nullptr;
|
m_file = nullptr;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_file = nullptr;
|
m_file = nullptr;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool File::write(std::span<const u08> data) {
|
bool File::write(std::span<const u08> data) { return isOpen() && std::fwrite(data.data(), 1, data.size(), m_file) == data.size(); }
|
||||||
return isOpen() && std::fwrite(data.data(), 1, data.size(), m_file) == data.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool File::read(void* data, u64 size) const {
|
bool File::read(void* data, u64 size) const { return isOpen() && std::fread(data, 1, size, m_file) == size; }
|
||||||
return isOpen() && std::fread(data, 1, size, m_file) == size;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool File::seek(s64 offset, SeekMode mode) {
|
bool File::seek(s64 offset, SeekMode mode) {
|
||||||
#ifdef _WIN64
|
#ifdef _WIN64
|
||||||
|
@ -56,38 +50,61 @@ bool File::seek(s64 offset, SeekMode mode) {
|
||||||
u64 File::tell() const {
|
u64 File::tell() const {
|
||||||
if (isOpen()) [[likely]] {
|
if (isOpen()) [[likely]] {
|
||||||
#ifdef _WIN64
|
#ifdef _WIN64
|
||||||
return _ftelli64(m_file);
|
return _ftelli64(m_file);
|
||||||
#else
|
#else
|
||||||
return ftello64(m_file);
|
return ftello64(m_file);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::vector<DirEntry> File::getDirectoryEntries(const std::string& path) {
|
||||||
|
std::string curpath = path;
|
||||||
|
if (!curpath.ends_with("/")) {
|
||||||
|
curpath = std::string(curpath + "/");
|
||||||
|
}
|
||||||
|
std::vector<DirEntry> files;
|
||||||
|
|
||||||
|
for (const auto& entry : std::filesystem::directory_iterator(curpath)) {
|
||||||
|
DirEntry e = {};
|
||||||
|
if (std::filesystem::is_regular_file(entry.path().string())) {
|
||||||
|
e.name = entry.path().filename().string();
|
||||||
|
e.isFile = true;
|
||||||
|
} else {
|
||||||
|
DirEntry e = {};
|
||||||
|
e.name = entry.path().filename().string() + "/"; // hmmm not sure if it has to be like this...
|
||||||
|
e.isFile = false;
|
||||||
|
}
|
||||||
|
files.push_back(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
return files;
|
||||||
|
}
|
||||||
|
|
||||||
u64 File::getFileSize() {
|
u64 File::getFileSize() {
|
||||||
#ifdef _WIN64
|
#ifdef _WIN64
|
||||||
const u64 pos = _ftelli64(m_file);
|
const u64 pos = _ftelli64(m_file);
|
||||||
if (_fseeki64(m_file, 0, SEEK_END) != 0) {
|
if (_fseeki64(m_file, 0, SEEK_END) != 0) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
const u64 size = _ftelli64(m_file);
|
const u64 size = _ftelli64(m_file);
|
||||||
if (_fseeki64(m_file, pos, SEEK_SET) != 0) {
|
if (_fseeki64(m_file, pos, SEEK_SET) != 0) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
const u64 pos = ftello64(m_file);
|
const u64 pos = ftello64(m_file);
|
||||||
if (fseeko64(m_file, 0, SEEK_END) != 0) {
|
if (fseeko64(m_file, 0, SEEK_END) != 0) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
const u64 size = ftello64(m_file);
|
const u64 size = ftello64(m_file);
|
||||||
if (fseeko64(m_file, pos, SEEK_SET) != 0) {
|
if (fseeko64(m_file, pos, SEEK_SET) != 0) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
return size;
|
return size;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Common::FS
|
} // namespace Common::FS
|
||||||
|
|
|
@ -2,19 +2,15 @@
|
||||||
|
|
||||||
#include <bit>
|
#include <bit>
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
#include <string>
|
|
||||||
#include <span>
|
#include <span>
|
||||||
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "common/types.h"
|
#include "common/types.h"
|
||||||
|
|
||||||
namespace Common::FS {
|
namespace Common::FS {
|
||||||
|
|
||||||
enum class OpenMode : u32 {
|
enum class OpenMode : u32 { Read = 0x1, Write = 0x2, ReadWrite = Read | Write };
|
||||||
Read = 0x1,
|
|
||||||
Write = 0x2,
|
|
||||||
ReadWrite = Read | Write
|
|
||||||
};
|
|
||||||
|
|
||||||
enum class SeekMode : u32 {
|
enum class SeekMode : u32 {
|
||||||
Set,
|
Set,
|
||||||
|
@ -22,6 +18,11 @@ enum class SeekMode : u32 {
|
||||||
End,
|
End,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct DirEntry {
|
||||||
|
std::string name;
|
||||||
|
bool isFile;
|
||||||
|
};
|
||||||
|
|
||||||
class File {
|
class File {
|
||||||
public:
|
public:
|
||||||
File();
|
File();
|
||||||
|
@ -46,39 +47,28 @@ class File {
|
||||||
return read(data.data(), data.size() * sizeof(T));
|
return read(data.data(), data.size() * sizeof(T));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isOpen() const {
|
bool isOpen() const { return m_file != nullptr; }
|
||||||
return m_file != nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
const char* getOpenMode(OpenMode mode) const {
|
const char* getOpenMode(OpenMode mode) const {
|
||||||
switch (mode) {
|
switch (mode) {
|
||||||
case OpenMode::Read:
|
case OpenMode::Read: return "rb";
|
||||||
return "rb";
|
case OpenMode::Write: return "wb";
|
||||||
case OpenMode::Write:
|
case OpenMode::ReadWrite: return "r+b";
|
||||||
return "wb";
|
default: return "r";
|
||||||
case OpenMode::ReadWrite:
|
|
||||||
return "r+b";
|
|
||||||
default:
|
|
||||||
return "r";
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int getSeekMode(SeekMode mode) const {
|
int getSeekMode(SeekMode mode) const {
|
||||||
switch (mode) {
|
switch (mode) {
|
||||||
case SeekMode::Set:
|
case SeekMode::Set: return SEEK_SET;
|
||||||
return SEEK_SET;
|
case SeekMode::Cur: return SEEK_CUR;
|
||||||
case SeekMode::Cur:
|
case SeekMode::End: return SEEK_END;
|
||||||
return SEEK_CUR;
|
default: return SEEK_SET;
|
||||||
case SeekMode::End:
|
|
||||||
return SEEK_END;
|
|
||||||
default:
|
|
||||||
return SEEK_SET;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] std::FILE* fileDescr() const {
|
[[nodiscard]] std::FILE* fileDescr() const { return m_file; }
|
||||||
return m_file;
|
static std::vector<DirEntry> getDirectoryEntries(const std::string& path);
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::FILE* m_file{};
|
std::FILE* m_file{};
|
||||||
|
|
|
@ -1,19 +1,21 @@
|
||||||
#include <cstdio>
|
|
||||||
#include <string>
|
|
||||||
#include <magic_enum.hpp>
|
|
||||||
#include "common/log.h"
|
|
||||||
#include "common/debug.h"
|
|
||||||
#include "core/loader/symbols_resolver.h"
|
|
||||||
#include "core/PS4/HLE/Graphics/video_out.h"
|
#include "core/PS4/HLE/Graphics/video_out.h"
|
||||||
|
|
||||||
|
#include <cstdio>
|
||||||
|
#include <magic_enum.hpp>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include "Objects/video_out_ctx.h"
|
||||||
|
#include "Util/config.h"
|
||||||
|
#include "common/debug.h"
|
||||||
|
#include "common/log.h"
|
||||||
|
#include "common/singleton.h"
|
||||||
#include "core/PS4/GPU/gpu_memory.h"
|
#include "core/PS4/GPU/gpu_memory.h"
|
||||||
#include "core/PS4/GPU/video_out_buffer.h"
|
#include "core/PS4/GPU/video_out_buffer.h"
|
||||||
#include "core/hle/error_codes.h"
|
#include "core/hle/error_codes.h"
|
||||||
#include "core/hle/libraries/libscegnmdriver/libscegnmdriver.h"
|
|
||||||
#include "core/hle/libraries/libs.h"
|
#include "core/hle/libraries/libs.h"
|
||||||
|
#include "core/hle/libraries/libscegnmdriver/libscegnmdriver.h"
|
||||||
#include "core/hle/libraries/libuserservice/usr_mng_codes.h"
|
#include "core/hle/libraries/libuserservice/usr_mng_codes.h"
|
||||||
#include "Util/config.h"
|
#include "core/loader/symbols_resolver.h"
|
||||||
#include "Objects/video_out_ctx.h"
|
|
||||||
#include "common/singleton.h"
|
|
||||||
#include "emulator.h"
|
#include "emulator.h"
|
||||||
#include "graphics_render.h"
|
#include "graphics_render.h"
|
||||||
|
|
||||||
|
@ -222,7 +224,7 @@ s32 PS4_SYSV_ABI sceVideoOutSetFlipRate(s32 handle, s32 rate) {
|
||||||
}
|
}
|
||||||
|
|
||||||
s32 PS4_SYSV_ABI sceVideoOutIsFlipPending(s32 handle) {
|
s32 PS4_SYSV_ABI sceVideoOutIsFlipPending(s32 handle) {
|
||||||
PRINT_FUNCTION_NAME();
|
// PRINT_FUNCTION_NAME();
|
||||||
auto* videoOut = Common::Singleton<HLE::Graphics::Objects::VideoOutCtx>::Instance();
|
auto* videoOut = Common::Singleton<HLE::Graphics::Objects::VideoOutCtx>::Instance();
|
||||||
s32 pending = videoOut->getCtx(handle)->m_flip_status.flipPendingNum;
|
s32 pending = videoOut->getCtx(handle)->m_flip_status.flipPendingNum;
|
||||||
return pending;
|
return pending;
|
||||||
|
@ -234,8 +236,8 @@ s32 PS4_SYSV_ABI sceVideoOutSubmitFlip(s32 handle, s32 bufferIndex, s32 flipMode
|
||||||
auto* ctx = videoOut->getCtx(handle);
|
auto* ctx = videoOut->getCtx(handle);
|
||||||
|
|
||||||
if (flipMode != 1) {
|
if (flipMode != 1) {
|
||||||
// BREAKPOINT(); // only flipmode==1 is supported
|
// BREAKPOINT(); // only flipmode==1 is supported
|
||||||
LOG_TRACE_IF(log_file_videoout, "sceVideoOutSubmitFlip flipmode {}\n", bufferIndex);//openBOR needs 2 but seems to work
|
LOG_TRACE_IF(log_file_videoout, "sceVideoOutSubmitFlip flipmode {}\n", bufferIndex); // openBOR needs 2 but seems to work
|
||||||
}
|
}
|
||||||
if (bufferIndex == -1) {
|
if (bufferIndex == -1) {
|
||||||
BREAKPOINT(); // blank output not supported
|
BREAKPOINT(); // blank output not supported
|
||||||
|
|
|
@ -0,0 +1,77 @@
|
||||||
|
#include "fs.h"
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
|
namespace Core::FileSys {
|
||||||
|
|
||||||
|
constexpr int RESERVED_HANDLES = 3; // First 3 handles are stdin,stdout,stderr
|
||||||
|
|
||||||
|
void MntPoints::mount(const std::string& host_folder, const std::string& guest_folder) {
|
||||||
|
std::scoped_lock lock{m_mutex};
|
||||||
|
|
||||||
|
MntPair pair;
|
||||||
|
pair.host_path = host_folder;
|
||||||
|
pair.guest_path = guest_folder;
|
||||||
|
|
||||||
|
m_mnt_pairs.push_back(pair);
|
||||||
|
}
|
||||||
|
void MntPoints::unmount(const std::string& path) {} // TODO!
|
||||||
|
void MntPoints::unmountAll() {
|
||||||
|
std::scoped_lock lock{m_mutex};
|
||||||
|
m_mnt_pairs.clear();
|
||||||
|
}
|
||||||
|
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")) {
|
||||||
|
std::replace(pair.host_path.begin(), pair.host_path.end(), '\\', '/');
|
||||||
|
return pair.host_path + guest_directory;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
int HandleTable::createHandle() {
|
||||||
|
std::scoped_lock lock{m_mutex};
|
||||||
|
auto* file = new File{};
|
||||||
|
file->isDirectory = false;
|
||||||
|
file->isOpened = false;
|
||||||
|
|
||||||
|
int existingFilesNum = m_files.size();
|
||||||
|
|
||||||
|
for (int index = 0; index < existingFilesNum; index++) {
|
||||||
|
if (m_files.at(index) == nullptr) {
|
||||||
|
m_files[index] = file;
|
||||||
|
return index + RESERVED_HANDLES;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
m_files.push_back(file);
|
||||||
|
|
||||||
|
return m_files.size() + RESERVED_HANDLES - 1;
|
||||||
|
}
|
||||||
|
void HandleTable::deleteHandle(int d) {
|
||||||
|
std::scoped_lock lock{m_mutex};
|
||||||
|
delete m_files.at(d - RESERVED_HANDLES);
|
||||||
|
m_files[d - RESERVED_HANDLES] = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
File* HandleTable::getFile(int d) {
|
||||||
|
std::scoped_lock lock{m_mutex};
|
||||||
|
return m_files.at(d - RESERVED_HANDLES);
|
||||||
|
}
|
||||||
|
File* HandleTable::getFile(const std::string& host_name) {
|
||||||
|
std::scoped_lock lock{m_mutex};
|
||||||
|
for (auto* file : m_files) {
|
||||||
|
if (file != nullptr && file->m_host_name == host_name) {
|
||||||
|
return file;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
} // namespace Core::FileSys
|
|
@ -0,0 +1,52 @@
|
||||||
|
#pragma once
|
||||||
|
#include <mutex>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "common/fs_file.h"
|
||||||
|
|
||||||
|
namespace Core::FileSys {
|
||||||
|
|
||||||
|
class MntPoints {
|
||||||
|
public:
|
||||||
|
struct MntPair {
|
||||||
|
std::string host_path;
|
||||||
|
std::string guest_path; // e.g /app0/
|
||||||
|
};
|
||||||
|
|
||||||
|
MntPoints() = default;
|
||||||
|
virtual ~MntPoints() = default;
|
||||||
|
void mount(const std::string& host_folder, const std::string& guest_folder);
|
||||||
|
void unmount(const std::string& path);
|
||||||
|
void unmountAll();
|
||||||
|
std::string getHostDirectory(const std::string& guest_directory);
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::vector<MntPair> m_mnt_pairs;
|
||||||
|
std::mutex m_mutex;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct File {
|
||||||
|
std::atomic_bool isOpened;
|
||||||
|
std::atomic_bool isDirectory;
|
||||||
|
std::string m_host_name;
|
||||||
|
std::string m_guest_name;
|
||||||
|
Common::FS::File f;
|
||||||
|
std::vector<Common::FS::DirEntry> dirents;
|
||||||
|
u32 dirents_index;
|
||||||
|
};
|
||||||
|
class HandleTable {
|
||||||
|
public:
|
||||||
|
HandleTable() {}
|
||||||
|
virtual ~HandleTable() {}
|
||||||
|
int createHandle();
|
||||||
|
void deleteHandle(int d);
|
||||||
|
File* getFile(int d);
|
||||||
|
File* getFile(const std::string& host_name);
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::vector<File*> m_files;
|
||||||
|
std::mutex m_mutex;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Core::FileSys
|
|
@ -21,3 +21,7 @@ constexpr int SCE_VIDEO_OUT_ERROR_INVALID_EVENT_QUEUE = 0x8029000C; // Invalid
|
||||||
constexpr int SCE_VIDEO_OUT_ERROR_SLOT_OCCUPIED = 0x80290010; // slot already used
|
constexpr int SCE_VIDEO_OUT_ERROR_SLOT_OCCUPIED = 0x80290010; // slot already used
|
||||||
constexpr int SCE_VIDEO_OUT_ERROR_FLIP_QUEUE_FULL = 0x80290012; // flip queue is full
|
constexpr int SCE_VIDEO_OUT_ERROR_FLIP_QUEUE_FULL = 0x80290012; // flip queue is full
|
||||||
constexpr int SCE_VIDEO_OUT_ERROR_INVALID_OPTION = 0x8029001A; // Invalid buffer attribute option
|
constexpr int SCE_VIDEO_OUT_ERROR_INVALID_OPTION = 0x8029001A; // Invalid buffer attribute option
|
||||||
|
|
||||||
|
// filesystem
|
||||||
|
constexpr int SCE_KERNEL_ERROR_ENOTDIR = 0x80020014; // Specified file is not a directory
|
||||||
|
constexpr int SCE_KERNEL_ERROR_EMFILE = 0x80020018; // limit of max descriptors reached
|
||||||
|
|
|
@ -115,6 +115,7 @@ void libcSymbolsRegister(Loader::SymbolsResolver* sym) {
|
||||||
LIB_FUNCTION("DfivPArhucg", "libc", 1, "libc", 1, 1, memcmp);
|
LIB_FUNCTION("DfivPArhucg", "libc", 1, "libc", 1, 1, memcmp);
|
||||||
LIB_FUNCTION("Q3VBxCXhUHs", "libc", 1, "libc", 1, 1, memcpy);
|
LIB_FUNCTION("Q3VBxCXhUHs", "libc", 1, "libc", 1, 1, memcpy);
|
||||||
LIB_FUNCTION("8zTFvBIAIN8", "libc", 1, "libc", 1, 1, memset);
|
LIB_FUNCTION("8zTFvBIAIN8", "libc", 1, "libc", 1, 1, memset);
|
||||||
|
LIB_FUNCTION("viiwFMaNamA", "libc", 1, "libc", 1, 1, strstr);
|
||||||
|
|
||||||
// stdio functions
|
// stdio functions
|
||||||
LIB_FUNCTION("hcuQgD53UxM", "libc", 1, "libc", 1, 1, printf);
|
LIB_FUNCTION("hcuQgD53UxM", "libc", 1, "libc", 1, 1, printf);
|
||||||
|
|
|
@ -1,42 +1,37 @@
|
||||||
#include <cstring>
|
|
||||||
#include "core/hle/libraries/libc/libc_string.h"
|
#include "core/hle/libraries/libc/libc_string.h"
|
||||||
|
|
||||||
|
#include <cstring>
|
||||||
|
#include <common/log.h>
|
||||||
|
|
||||||
namespace Core::Libraries::LibC {
|
namespace Core::Libraries::LibC {
|
||||||
|
|
||||||
int PS4_SYSV_ABI memcmp(const void* s1, const void* s2, size_t n) {
|
constexpr bool log_file_libc = true; // disable it to disable logging
|
||||||
return std::memcmp(s1, s2, n);
|
|
||||||
}
|
|
||||||
|
|
||||||
void* PS4_SYSV_ABI memcpy(void* dest, const void* src, size_t n) {
|
int PS4_SYSV_ABI memcmp(const void* s1, const void* s2, size_t n) { return std::memcmp(s1, s2, n); }
|
||||||
return std::memcpy(dest, src, n);
|
|
||||||
}
|
|
||||||
|
|
||||||
void* PS4_SYSV_ABI memset(void* s, int c, size_t n) {
|
void* PS4_SYSV_ABI memcpy(void* dest, const void* src, size_t n) { return std::memcpy(dest, src, n); }
|
||||||
return std::memset(s, c, n);
|
|
||||||
}
|
|
||||||
|
|
||||||
int PS4_SYSV_ABI strcmp(const char* str1, const char* str2) {
|
void* PS4_SYSV_ABI memset(void* s, int c, size_t n) { return std::memset(s, c, n); }
|
||||||
return std::strcmp(str1, str2);
|
|
||||||
}
|
|
||||||
|
|
||||||
char* PS4_SYSV_ABI strncpy(char* dest, const char* src, size_t count) {
|
int PS4_SYSV_ABI strcmp(const char* str1, const char* str2) { return std::strcmp(str1, str2); }
|
||||||
return std::strncpy(dest, src, count);
|
|
||||||
}
|
|
||||||
|
|
||||||
void* PS4_SYSV_ABI memmove(void* dest, const void* src, std::size_t count) {
|
char* PS4_SYSV_ABI strncpy(char* dest, const char* src, size_t count) { return std::strncpy(dest, src, count); }
|
||||||
return std::memmove(dest, src, count);
|
|
||||||
}
|
void* PS4_SYSV_ABI memmove(void* dest, const void* src, std::size_t count) { return std::memmove(dest, src, count); }
|
||||||
|
|
||||||
char* PS4_SYSV_ABI strcpy(char* dest, const char* src) {
|
char* PS4_SYSV_ABI strcpy(char* dest, const char* src) {
|
||||||
|
LOG_TRACE_IF(log_file_libc, "strcpy dest ={} src ={}", dest, src);
|
||||||
return std::strcpy(dest, src);
|
return std::strcpy(dest, src);
|
||||||
}
|
}
|
||||||
|
|
||||||
char* PS4_SYSV_ABI strcat(char* dest, const char* src) {
|
char* PS4_SYSV_ABI strcat(char* dest, const char* src) {
|
||||||
|
LOG_TRACE_IF(log_file_libc, "strcat dest ={} src ={}", dest, src);
|
||||||
return std::strcat(dest, src);
|
return std::strcat(dest, src);
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t PS4_SYSV_ABI strlen(const char* str) {
|
size_t PS4_SYSV_ABI strlen(const char* str) { return std::strlen(str); }
|
||||||
return std::strlen(str);
|
char* PS4_SYSV_ABI strstr(const char* haystack, const char* needle) {
|
||||||
|
LOG_TRACE_IF(log_file_libc, "strstr haystack ={} needle ={}", haystack, needle);
|
||||||
|
return (char*)std::strstr(haystack, needle);
|
||||||
}
|
}
|
||||||
|
} // namespace Core::Libraries::LibC
|
||||||
} // namespace Core::Libraries::LibC
|
|
||||||
|
|
|
@ -14,5 +14,5 @@ void* PS4_SYSV_ABI memmove(void* dest, const void* src, std::size_t count);
|
||||||
char* PS4_SYSV_ABI strcpy(char* destination, const char* source);
|
char* PS4_SYSV_ABI strcpy(char* destination, const char* source);
|
||||||
char* PS4_SYSV_ABI strcat(char* dest, const char* src);
|
char* PS4_SYSV_ABI strcat(char* dest, const char* src);
|
||||||
size_t PS4_SYSV_ABI strlen(const char* str);
|
size_t PS4_SYSV_ABI strlen(const char* str);
|
||||||
|
char* PS4_SYSV_ABI strstr(const char* haystack, const char* needle);
|
||||||
} // namespace Core::Libraries::LibC
|
} // namespace Core::Libraries::LibC
|
||||||
|
|
|
@ -1,6 +1,12 @@
|
||||||
#include "common/log.h"
|
|
||||||
#include "common/debug.h"
|
|
||||||
#include "core/hle/libraries/libkernel/file_system.h"
|
#include "core/hle/libraries/libkernel/file_system.h"
|
||||||
|
|
||||||
|
#include <filesystem>
|
||||||
|
|
||||||
|
#include "common/debug.h"
|
||||||
|
#include "common/log.h"
|
||||||
|
#include "common/singleton.h"
|
||||||
|
#include "core/file_sys/fs.h"
|
||||||
|
#include "core/hle/error_codes.h"
|
||||||
#include "core/hle/libraries/libs.h"
|
#include "core/hle/libraries/libs.h"
|
||||||
|
|
||||||
namespace Core::Libraries::LibKernel {
|
namespace Core::Libraries::LibKernel {
|
||||||
|
@ -9,10 +15,83 @@ constexpr bool log_file_fs = true; // disable it to disable logging
|
||||||
|
|
||||||
int PS4_SYSV_ABI sceKernelOpen(const char* path, int flags, u16 mode) {
|
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);
|
LOG_INFO_IF(log_file_fs, "sceKernelOpen path = {} flags = {:#x} mode = {:#x}\n", path, flags, mode);
|
||||||
return 0;
|
const bool isDirectory = (flags & SCE_KERNEL_O_DIRECTORY) != 0;
|
||||||
|
const bool create = (flags & SCE_KERNEL_O_CREAT) != 0;
|
||||||
|
|
||||||
|
auto* h = Common::Singleton<Core::FileSys::HandleTable>::Instance();
|
||||||
|
auto* mnt = Common::Singleton<Core::FileSys::MntPoints>::Instance();
|
||||||
|
|
||||||
|
u32 handle = h->createHandle();
|
||||||
|
if (handle >= 2048) { // max descriptor reached
|
||||||
|
return SCE_KERNEL_ERROR_EMFILE;
|
||||||
|
}
|
||||||
|
auto* file = h->getFile(handle);
|
||||||
|
if (isDirectory) {
|
||||||
|
file->isDirectory = 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
|
||||||
|
if (create) { // if we have a create flag create it
|
||||||
|
/* std::error_code e;
|
||||||
|
if (std::filesystem::create_directories(file->m_host_name,e)) {
|
||||||
|
return handle;
|
||||||
|
} else {
|
||||||
|
std::string message =e.message();
|
||||||
|
return SCE_KERNEL_ERROR_ENOTDIR;
|
||||||
|
}
|
||||||
|
return SCE_KERNEL_ERROR_ENOTDIR;*/
|
||||||
|
// there is seems to be a bug with create_directories return false even if the directory creates so don't check until we find
|
||||||
|
// a better solution
|
||||||
|
std::filesystem::create_directories(file->m_host_name);
|
||||||
|
return handle;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (create) {
|
||||||
|
return handle; // directory already exists
|
||||||
|
} else {
|
||||||
|
file->dirents = Common::FS::File::getDirectoryEntries(file->m_host_name);
|
||||||
|
file->dirents_index = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
file->isOpened = true;
|
||||||
|
return handle;
|
||||||
}
|
}
|
||||||
|
|
||||||
int PS4_SYSV_ABI open(const char* path, int flags, /* SceKernelMode*/ u16 mode) {
|
int PS4_SYSV_ABI sceKernelClose(int handle) {
|
||||||
|
LOG_INFO_IF(log_file_fs, "sceKernelClose descriptor = {}\n", handle);
|
||||||
|
auto* h = Common::Singleton<Core::FileSys::HandleTable>::Instance();
|
||||||
|
auto* file = h->getFile(handle);
|
||||||
|
file->isOpened = false;
|
||||||
|
h->deleteHandle(handle);
|
||||||
|
return SCE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PS4_SYSV_ABI sceKernelGetdents(int fd, char* buf, int nbytes) {
|
||||||
|
PRINT_FUNCTION_NAME();
|
||||||
|
// TODO error codes
|
||||||
|
auto* h = Common::Singleton<Core::FileSys::HandleTable>::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
|
||||||
|
SceKernelDirent* sce_ent = (SceKernelDirent*)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(SceKernelDirent);
|
||||||
|
sce_ent->d_type = (entry.isFile ? 8 : 4);
|
||||||
|
sce_ent->d_namlen = str_size;
|
||||||
|
str.copy(sce_ent->d_name, SCE_MAX_PATH);
|
||||||
|
|
||||||
|
return sizeof(SceKernelDirent);
|
||||||
|
}
|
||||||
|
|
||||||
|
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");
|
LOG_INFO_IF(log_file_fs, "posix open redirect to sceKernelOpen\n");
|
||||||
int result = sceKernelOpen(path, flags, mode);
|
int result = sceKernelOpen(path, flags, mode);
|
||||||
if (result < 0) {
|
if (result < 0) {
|
||||||
|
@ -21,9 +100,21 @@ int PS4_SYSV_ABI open(const char* path, int flags, /* SceKernelMode*/ u16 mode)
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void fileSystemSymbolsRegister(Loader::SymbolsResolver* sym) {
|
int PS4_SYSV_ABI posix_close(int handle) {
|
||||||
LIB_FUNCTION("1G3lF1Gg1k8", "libkernel", 1, "libkernel", 1, 1, sceKernelOpen);
|
LOG_INFO_IF(log_file_fs, "posix close redirect to sceKernelClose\n");
|
||||||
LIB_FUNCTION("wuCroIGjt2g", "libScePosix", 1, "libkernel", 1, 1, open);
|
int result = sceKernelClose(handle);
|
||||||
|
if (result < 0) {
|
||||||
|
BREAKPOINT(); // posix calls different only for their return values
|
||||||
|
}
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Core::Libraries::LibKernel
|
void fileSystemSymbolsRegister(Loader::SymbolsResolver* sym) {
|
||||||
|
LIB_FUNCTION("1G3lF1Gg1k8", "libkernel", 1, "libkernel", 1, 1, sceKernelOpen);
|
||||||
|
LIB_FUNCTION("UK2Tl2DWUns", "libkernel", 1, "libkernel", 1, 1, sceKernelClose);
|
||||||
|
LIB_FUNCTION("j2AIqSqJP0w", "libkernel", 1, "libkernel", 1, 1, sceKernelGetdents);
|
||||||
|
LIB_FUNCTION("wuCroIGjt2g", "libScePosix", 1, "libkernel", 1, 1, posix_open);
|
||||||
|
LIB_FUNCTION("bY-PO6JhzhQ", "libScePosix", 1, "libkernel", 1, 1, posix_close);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Core::Libraries::LibKernel
|
||||||
|
|
|
@ -8,10 +8,37 @@ class SymbolsResolver;
|
||||||
|
|
||||||
namespace Core::Libraries::LibKernel {
|
namespace Core::Libraries::LibKernel {
|
||||||
|
|
||||||
int PS4_SYSV_ABI sceKernelOpen(const char *path, int flags, /* SceKernelMode*/ u16 mode);
|
constexpr int SCE_MAX_PATH = 255;
|
||||||
|
|
||||||
int PS4_SYSV_ABI open(const char *path, int flags, /* SceKernelMode*/ u16 mode);
|
struct SceKernelDirent {
|
||||||
|
u32 d_fileno; /* file number of entry */
|
||||||
|
u16 d_reclen; /* length of this record */
|
||||||
|
u08 d_type; /* file type, see below */
|
||||||
|
u08 d_namlen; /* length of string in d_name */
|
||||||
|
char d_name[SCE_MAX_PATH + 1]; /* name must be no longer than this */
|
||||||
|
};
|
||||||
|
|
||||||
|
// Open flags
|
||||||
|
constexpr u32 SCE_KERNEL_O_RDONLY = 0x0000; // Open as read-only
|
||||||
|
constexpr u32 SCE_KERNEL_O_WRONLY = 0x0001; // Open as write-only
|
||||||
|
constexpr u32 SCE_KERNEL_O_RDWR = 0x0002; // Open for reading and writing
|
||||||
|
constexpr u32 SCE_KERNEL_O_NONBLOCK = 0x0004; // Perform non - blocking operation
|
||||||
|
constexpr u32 SCE_KERNEL_O_APPEND = 0x0008; // Write by appending to the end of the file
|
||||||
|
constexpr u32 SCE_KERNEL_O_FSYNC = 0x0080; // Perform synchronized writing
|
||||||
|
constexpr u32 SCE_KERNEL_O_SYNC = 0x0080; // Perform synchronized writing
|
||||||
|
constexpr u32 SCE_KERNEL_O_CREAT = 0x0200; // Create a file(overwrite if it already exists)
|
||||||
|
constexpr u32 SCE_KERNEL_O_TRUNC = 0x0400; // Truncate the file size to 0(discard data if it already exists)
|
||||||
|
constexpr u32 SCE_KERNEL_O_EXCL = 0x0800; // Error will occur if the file to create already exists
|
||||||
|
constexpr u32 SCE_KERNEL_O_DSYNC = 0x1000; // Perform synchronized writing of the file content
|
||||||
|
constexpr u32 SCE_KERNEL_O_DIRECT = 0x00010000; // Use cache as little as possible
|
||||||
|
constexpr u32 SCE_KERNEL_O_DIRECTORY = 0x00020000; // Error will occur if not a directory
|
||||||
|
|
||||||
|
int PS4_SYSV_ABI sceKernelOpen(const char *path, int flags, /* SceKernelMode*/ u16 mode);
|
||||||
|
int PS4_SYSV_ABI sceKernelClose(int handle);
|
||||||
|
int PS4_SYSV_ABI sceKernelGetdents(int fd, char *buf, int nbytes);
|
||||||
|
int PS4_SYSV_ABI posix_open(const char *path, int flags, /* SceKernelMode*/ u16 mode);
|
||||||
|
int PS4_SYSV_ABI posix_close(int handle);
|
||||||
|
|
||||||
void fileSystemSymbolsRegister(Loader::SymbolsResolver *sym);
|
void fileSystemSymbolsRegister(Loader::SymbolsResolver *sym);
|
||||||
|
|
||||||
} // namespace Core::Libraries::LibKernel
|
} // namespace Core::Libraries::LibKernel
|
||||||
|
|
|
@ -14,6 +14,8 @@
|
||||||
#include "core/hle/libraries/libs.h"
|
#include "core/hle/libraries/libs.h"
|
||||||
#include "core/linker.h"
|
#include "core/linker.h"
|
||||||
#include "emuTimer.h"
|
#include "emuTimer.h"
|
||||||
|
#include "core/file_sys/fs.h"
|
||||||
|
#include "common/singleton.h"
|
||||||
|
|
||||||
int main(int argc, char* argv[]) {
|
int main(int argc, char* argv[]) {
|
||||||
if (argc == 1) {
|
if (argc == 1) {
|
||||||
|
@ -29,7 +31,11 @@ int main(int argc, char* argv[]) {
|
||||||
Emulator::emuTimer::start();
|
Emulator::emuTimer::start();
|
||||||
|
|
||||||
// Argument 1 is the path of self file to boot
|
// Argument 1 is the path of self file to boot
|
||||||
const char* const path = argv[1];
|
const char* const path = argv[1]; // argument 1 is the path of self file to boot
|
||||||
|
|
||||||
|
auto* mnt = Common::Singleton<Core::FileSys::MntPoints>::Instance();
|
||||||
|
std::filesystem::path p = std::string(path);
|
||||||
|
mnt->mount(p.parent_path().string(), "/app0");
|
||||||
|
|
||||||
auto linker = Common::Singleton<Core::Linker>::Instance();
|
auto linker = Common::Singleton<Core::Linker>::Instance();
|
||||||
Core::Libraries::InitHLELibs(&linker->getHLESymbols());
|
Core::Libraries::InitHLELibs(&linker->getHLESymbols());
|
||||||
|
|
Loading…
Reference in New Issue