#include "prx/libkernel/include/Api.hpp" #include "prx/libc/include/Api.hpp" #include "prx/libc/include/GuestDirectory.hpp" #include "prx/libc/include/General.hpp" #include "SceTypes.hpp" #include #include #include namespace { constexpr std::size_t NameCapacity = 260; constexpr std::size_t CurrentCapacity = 256; constexpr int NoSuchFile = 2; constexpr int Exists = 17; constexpr int NotDirectory = 20; constexpr int Invalid = 22; constexpr int NameTooLong = 63; constexpr std::uint16_t DefaultDirectoryMode = 0777; constexpr std::uint16_t PermissionBits = 07777; enum FileType : int { TypeNotFound = -1, TypeNone = 0, TypeRegular = 1, TypeDirectory = 2, TypeSymlink = 3, TypeBlock = 4, TypeCharacter = 5, TypeFifo = 6, TypeSocket = 7, TypeUnknown = 8, }; int& GuestErrno() { return *__error_nid_postfix(); } int TypeOfMode(std::uint16_t mode) { switch (mode & 0170000) { case 0010000: return TypeFifo; case 0020000: return TypeCharacter; case 0040000: return TypeDirectory; case 0060000: return TypeBlock; case 0100000: return TypeRegular; case 0120000: return TypeSymlink; case 0140000: return TypeSocket; default: return TypeUnknown; } } int StatType(const char* path, int* perms, int* error) { GuestErrno() = 0; FileStat status{}; int type; if (stat_nid_postfix(path, &status) == 0) { GuestErrno() = 0; if (perms) *perms = status.st_mode & PermissionBits; type = TypeOfMode(status.st_mode); } else { const int code = GuestErrno(); type = code == NoSuchFile || code == NotDirectory || code == Invalid || code == NameTooLong ? TypeNotFound : TypeNone; } if (error) *error = GuestErrno(); return type; } void CopyName(char* target, const char* source) { std::size_t length = 0; while (length < NameCapacity - 1 && source[length] != '\0') { target[length] = source[length]; ++length; } target[length] = '\0'; } bool IsDotEntry(const char* name) { return name[0] == '.' && (name[1] == '\0' || (name[1] == '.' && name[2] == '\0')); } } extern "C" { int APS5_VABI _ZNSt10filesystem5_StatEPKcPNS_5permsEPi_nid_postfix(const char* path, int* perms, int* error) { return StatType(path, perms, error); } int APS5_VABI _ZNSt10filesystem6_LstatEPKcPNS_5permsEPi_nid_postfix(const char* path, int* perms, int* error) { return StatType(path, perms, error); } std::uint64_t APS5_VABI _ZNSt10filesystem10_File_sizeEPKcPi_nid_postfix(const char* path, int* error) { FileStat status{}; if (stat_nid_postfix(path, &status) != 0) { if (error) *error = GuestErrno(); return UINT64_MAX; } return static_cast(status.st_size); } int APS5_VABI _ZNSt10filesystem16_Last_write_timeEPKcPlS2__nid_postfix(const char* path, std::int64_t* seconds, std::int64_t* nanoseconds) { FileStat status{}; if (stat_nid_postfix(path, &status) != 0) return GuestErrno(); *seconds = status.st_mtim.tv_sec; *nanoseconds = status.st_mtim.tv_nsec; return 0; } int APS5_VABI _ZNSt10filesystem9_Make_dirEPKcS1__nid_postfix(const char* path, const char* existing) { GuestErrno() = 0; std::uint16_t mode = DefaultDirectoryMode; if (existing) { FileStat status{}; if (stat_nid_postfix(existing, &status) != 0) return -GuestErrno(); mode = status.st_mode; } if (mkdir_nid_postfix(path, mode) == 0) return 1; if (GuestErrno() == Exists) return 0; return -GuestErrno(); } bool APS5_VABI _ZNSt10filesystem11_Remove_dirEPKc_nid_postfix(const char* path) { return rmdir_nid_postfix(path) == 0; } int APS5_VABI _ZNSt10filesystem7_UnlinkEPKc_nid_postfix(const char* path) { GuestErrno() = 0; return unlink_nid_postfix(path) == 0 ? 0 : GuestErrno(); } int APS5_VABI _ZNSt10filesystem6_ChmodEPKcNS_5permsE_nid_postfix(const char* path, int perms) { return chmod_nid_postfix(path, static_cast(perms)); } bool APS5_VABI _ZNSt10filesystem12_Current_getERA260_c_nid_postfix(char* target) { char current[CurrentCapacity]; const bool found = getcwd_nid_postfix(current, sizeof(current)) != nullptr; if (found) CopyName(target, current); else target[0] = '\0'; return found; } char* APS5_VABI _ZNSt10filesystem9_Read_dirERA260_cPvRNS_9file_typeE_nid_postfix(char* target, void* handle, int* type) { *type = TypeUnknown; GuestDirectoryEntry entry{}; GuestDirectoryEntry* result = nullptr; while (readdir_r_nid_postfix(handle, &entry, &result) == 0 && result) { if (IsDotEntry(entry.name)) continue; CopyName(target, entry.name); return target; } target[0] = '\0'; return target; } void* APS5_VABI _ZNSt10filesystem9_Open_dirERA260_cPKcRiRNS_9file_typeE_nid_postfix(char* target, const char* path, int* error, int* type) { GuestErrno() = 0; void* handle = opendir_nid_postfix(path); if (!handle) { *error = GuestErrno(); return nullptr; } *error = 0; _ZNSt10filesystem9_Read_dirERA260_cPvRNS_9file_typeE_nid_postfix(target, handle, type); if (target[0] != '\0') return handle; closedir_nid_postfix(handle); return nullptr; } int APS5_VABI _ZNSt10filesystem10_Close_dirEPv_nid_postfix(void* handle) { return closedir_nid_postfix(handle); } void APS5_VABI _ZNSt10filesystem18_Xfilesystem_errorEPKcSt10error_code_nid_postfix() { NotImplemented_nid_no_patch(__func__); } void APS5_VABI _ZNSt10filesystem18_Xfilesystem_errorEPKcRKNS_4pathESt10error_code_nid_postfix() { NotImplemented_nid_no_patch(__func__); } }