feat(libs): global shared path resolver in libc

This commit is contained in:
boykopovar 2026-09-13 12:45:50 +03:00
parent f66a8fc5c4
commit 7c44d13b3a
7 changed files with 46 additions and 63 deletions

View File

@ -2,6 +2,7 @@
#define CORE_LIBS_PRX_LIBC_INCLUDE_GENERAL_HPP
#include <stdexcept>
#include <filesystem>
#include "general/LogMacros.hpp"
#include "general/VabiMacros.hpp"
@ -9,6 +10,8 @@
extern "C" void NotImplemented_nid_no_patch(const char* funcName);
extern "C" std::filesystem::path ResolvePath_nid_no_patch(const char* path);
#define APS5_INVALID_ARG_EX throw std::invalid_argument(std::string(__func__) + ": invalid argument")
#endif

View File

@ -14,21 +14,22 @@ extern "C" {
FileStream* APS5_VABI fopen_nid_postfix(const char* filename, const char* mode) {
if (!filename || !mode) throw std::runtime_error(std::string(__func__) + ": " + FOPEN_MSG_NULL_ARG);
std::unique_ptr<std::FILE, decltype(&std::fclose)> handle(std::fopen(filename, mode), std::fclose);
const auto abs_path = std::filesystem::absolute(filename).string();
const std::filesystem::path fpath = ResolvePath_nid_no_patch(filename);
const auto abs_path = fpath.string();
std::unique_ptr<std::FILE, decltype(&std::fclose)> handle(std::fopen(abs_path.c_str(), mode), std::fclose);
if (!handle) {
const auto reason = std::strerror(errno);
const std::filesystem::path fpath(filename);
bool sibling_exists = false;
std::error_code ec;
for (const auto& entry : std::filesystem::directory_iterator(std::filesystem::absolute(fpath.parent_path()), ec)) {
if (!ec && entry.path().stem() == fpath.stem() && entry.path().extension() != fpath.extension()) {
sibling_exists = true;
std::filesystem::path sibling;
for (const auto& entry : std::filesystem::directory_iterator(fpath.parent_path(), ec)) {
if (ec) break;
if (entry.path().stem() == fpath.stem() && entry.path().extension() != fpath.extension()) {
sibling = std::filesystem::absolute(entry.path());
break;
}
}
if (sibling_exists) {
APS5_LOG_OUT("%s: \"%s\": %s", FOPEN_MSG_NOT_FOUND, abs_path.c_str(), reason);
if (!sibling.empty()) {
APS5_LOG_OUT("%s: \"%s\": %s. Sibling: \"%s\"", FOPEN_MSG_NOT_FOUND, abs_path.c_str(), reason, sibling.string().c_str());
return nullptr;
}
throw std::runtime_error(std::string(__func__) + ": " + FOPEN_MSG_OPEN_FAILED + ": \"" + abs_path + "\": " + reason);

View File

@ -1,5 +1,21 @@
#include <stdexcept>
#include <string>
#include <filesystem>
#include "prx/libc/include/General.hpp"
extern "C" std::filesystem::path ResolvePath_nid_no_patch(const char* path) {
if (path == nullptr) {
APS5_INVALID_ARG_EX;
}
std::string s(path);
std::size_t start = 0;
while (start < s.size() && (s[start] == '/' || s[start] == '\\')) {
++start;
}
std::filesystem::path result = std::filesystem::current_path() / std::filesystem::path(s.substr(start));
return result;
}
extern "C" void NotImplemented_nid_no_patch(const char* funcName) {
throw std::runtime_error(std::string(funcName) + " not implemented");

View File

@ -3,7 +3,6 @@ add_library(libkernel SHARED EXCLUDE_FROM_ALL
${CMAKE_CURRENT_SOURCE_DIR}/Equeue/Equeue.cpp
${CMAKE_CURRENT_SOURCE_DIR}/File/src/NativeStat.cpp
${CMAKE_CURRENT_SOURCE_DIR}/File/src/Open.cpp
${CMAKE_CURRENT_SOURCE_DIR}/File/src/Path.cpp
${CMAKE_CURRENT_SOURCE_DIR}/Semaphore/src/Semaphore.cpp
${CMAKE_CURRENT_SOURCE_DIR}/DirectMemory/Export.cpp
${CMAKE_CURRENT_SOURCE_DIR}/DirectMemory/DirectMemory.cpp

View File

@ -1,13 +0,0 @@
#ifndef CORE_LIBS_PRX_LIBKERNEL_FILE_PATH_HPP
#define CORE_LIBS_PRX_LIBKERNEL_FILE_PATH_HPP
#include <filesystem>
namespace File {
std::filesystem::path ResolvePath(const char* path);
}
#endif

View File

@ -1,6 +1,6 @@
#include "prx/libkernel/File/include/FileFlags.hpp"
#include "prx/libkernel/File/include/NativeStat.hpp"
#include "prx/libkernel/File/include/Path.hpp"
#include "prx/libc/include/General.hpp"
#include "prx/libkernel/File/include/File.hpp"
#include "SceTypes.hpp"
@ -88,78 +88,75 @@ static int MapFlags(int sceFlags) {
extern "C" {
int APS5_VABI sceKernelOpen(const char* path, int flags, std::uint16_t mode) {
if (path == nullptr) {
throw std::invalid_argument("sceKernelOpen: path is null");
}
auto native = File::ResolvePath(path);
auto native = ResolvePath_nid_no_patch(path);
int fd = NativeOpen(native, MapFlags(flags), mode);
if (fd < 0) {
throw std::runtime_error("sceKernelOpen: failed to open " + native.string() + ", errno=" + std::to_string(errno));
throw std::runtime_error(std::string(__func__) + ": failed to open " + native.string() + ", errno=" + std::to_string(errno));
}
return fd;
}
int APS5_VABI sceKernelClose(int d) {
if (NativeClose(d) != 0) {
throw std::runtime_error("sceKernelClose: close failed, fd=" + std::to_string(d) + ", errno=" + std::to_string(errno));
throw std::runtime_error(std::string(__func__) + ": close failed, fd=" + std::to_string(d) + ", errno=" + std::to_string(errno));
}
return 0;
}
std::int64_t APS5_VABI sceKernelRead(int d, void* buf, std::size_t nbytes) {
if (buf == nullptr) {
throw std::invalid_argument("sceKernelRead: buf is null");
throw std::invalid_argument(std::string(__func__) + ": buf is null");
}
auto n = NativeRead(d, buf, nbytes);
if (n < 0) {
throw std::runtime_error("sceKernelRead: read failed, fd=" + std::to_string(d) + ", errno=" + std::to_string(errno));
throw std::runtime_error(std::string(__func__) + ": read failed, fd=" + std::to_string(d) + ", errno=" + std::to_string(errno));
}
return static_cast<std::int64_t>(n);
}
std::int64_t APS5_VABI sceKernelWrite(int d, const void* buf, std::size_t nbytes) {
if (buf == nullptr) {
throw std::invalid_argument("sceKernelWrite: buf is null");
throw std::invalid_argument(std::string(__func__) + ": buf is null");
}
auto n = NativeWrite(d, buf, nbytes);
if (n < 0) {
throw std::runtime_error("sceKernelWrite: write failed, fd=" + std::to_string(d) + ", errno=" + std::to_string(errno));
throw std::runtime_error(std::string(__func__) + ": write failed, fd=" + std::to_string(d) + ", errno=" + std::to_string(errno));
}
return static_cast<std::int64_t>(n);
}
int APS5_VABI sceKernelLseek(int d, std::int64_t offset, int whence) {
if (whence < 0 || whence > 2) {
throw std::invalid_argument("sceKernelLseek: invalid whence=" + std::to_string(whence));
throw std::invalid_argument(std::string(__func__) + ": invalid whence=" + std::to_string(whence));
}
std::int64_t result = NativeLseek(d, offset, whence);
if (result < 0) {
throw std::runtime_error("sceKernelLseek: lseek failed, fd=" + std::to_string(d) + ", errno=" + std::to_string(errno));
throw std::runtime_error(std::string(__func__) + ": lseek failed, fd=" + std::to_string(d) + ", errno=" + std::to_string(errno));
}
if (result > static_cast<std::int64_t>(std::numeric_limits<int>::max())) {
throw std::overflow_error("sceKernelLseek: result " + std::to_string(result) + " overflows int return type");
throw std::overflow_error(std::string(__func__) + ": result " + std::to_string(result) + " overflows int return type");
}
return static_cast<int>(result);
}
int APS5_VABI sceKernelStat(const char* path, FileStat* sb) {
if (path == nullptr) {
throw std::invalid_argument("sceKernelStat: path is null");
throw std::invalid_argument(std::string(__func__) + ": path is null");
}
if (sb == nullptr) {
throw std::invalid_argument("sceKernelStat: sb is null");
throw std::invalid_argument(std::string(__func__) + ": sb is null");
}
File::FillFileStat(File::ResolvePath(path), sb);
File::FillFileStat(ResolvePath_nid_no_patch(path), sb);
return 0;
}
int APS5_VABI sceKernelUnlink(const char* path) {
if (path == nullptr) {
throw std::invalid_argument("sceKernelUnlink: path is null");
throw std::invalid_argument(std::string(__func__) + ": path is null");
}
auto native = File::ResolvePath(path);
auto native = ResolvePath_nid_no_patch(path);
if (NativeUnlink(native) != 0) {
throw std::runtime_error("sceKernelUnlink: unlink failed for " + native.string() + ", errno=" + std::to_string(errno));
throw std::runtime_error(std::string(__func__) + ": unlink failed for " + native.string() + ", errno=" + std::to_string(errno));
}
return 0;
}

View File

@ -1,20 +0,0 @@
#include "prx/libkernel/File/include/Path.hpp"
#include <stdexcept>
#include <string>
namespace File {
std::filesystem::path ResolvePath(const char* path) {
if (path == nullptr) {
throw std::invalid_argument("ResolvePath: path is null");
}
std::filesystem::path p(path);
if (p.is_absolute()) {
auto rel = p.relative_path();
return std::filesystem::current_path() / rel;
}
return std::filesystem::current_path() / p;
}
}