feat(kernel): implement file metadata ops and address conversion

This commit is contained in:
asimplestray 2026-09-29 22:27:51 +00:00
parent f881e021a8
commit a4e755ccb1
6 changed files with 75 additions and 33 deletions

View File

@ -281,12 +281,12 @@ if(BUILD_TESTING)
endif()
add_executable(guest_filesystem_tests tests/GuestFilesystem.cpp)
target_include_directories(guest_filesystem_tests PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
target_link_libraries(guest_filesystem_tests PRIVATE libc)
target_link_libraries(guest_filesystem_tests PRIVATE libkernel libc)
configure_windows_unwind(guest_filesystem_tests)
add_test(NAME guest_filesystem COMMAND guest_filesystem_tests)
if(WIN32)
set_tests_properties(guest_filesystem PROPERTIES ENVIRONMENT_MODIFICATION
"PATH=path_list_prepend:$<TARGET_FILE_DIR:libc>")
"PATH=path_list_prepend:$<TARGET_FILE_DIR:libkernel>")
endif()
add_executable(guest_directory_tests tests/GuestDirectory.cpp)
target_include_directories(guest_directory_tests PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})

View File

@ -20,6 +20,7 @@
#include <io.h>
#include <direct.h>
#include <sys/stat.h>
#include <sys/utime.h>
static int NativeRmdir(const std::filesystem::path& path) {
return ::_wrmdir(path.wstring().c_str());
}
@ -33,6 +34,11 @@ static int NativeChmod(const std::filesystem::path& path, int mode) {
static int NativeFtruncate(int descriptor, std::int64_t length) {
return static_cast<int>(::_chsize_s(descriptor, length));
}
static int NativeUtimes(const std::filesystem::path& path, const KernelTimeval* times) {
if (times == nullptr) return ::_wutime(path.wstring().c_str(), nullptr);
struct _utimbuf values{static_cast<time_t>(times[0].tv_sec), static_cast<time_t>(times[1].tv_sec)};
return ::_wutime(path.wstring().c_str(), &values);
}
static int NativeFlock(int descriptor, int operation) {
HANDLE handle = reinterpret_cast<HANDLE>(::_get_osfhandle(descriptor));
if (handle == INVALID_HANDLE_VALUE) {
@ -79,6 +85,7 @@ static std::int64_t NativePwrite(int descriptor, const void* buf, std::size_t nb
#include <unistd.h>
#include <sys/stat.h>
#include <sys/file.h>
#include <sys/time.h>
#include <dirent.h>
#include <sys/syscall.h>
#include <vector>
@ -94,6 +101,12 @@ static int NativeChmod(const std::filesystem::path& path, int mode) {
static int NativeFtruncate(int descriptor, std::int64_t length) {
return ::ftruncate(descriptor, static_cast<off_t>(length));
}
static int NativeUtimes(const std::filesystem::path& path, const KernelTimeval* times) {
if (times == nullptr) return ::utimes(path.c_str(), nullptr);
struct timeval values[2]{{static_cast<time_t>(times[0].tv_sec), static_cast<suseconds_t>(times[0].tv_usec)},
{static_cast<time_t>(times[1].tv_sec), static_cast<suseconds_t>(times[1].tv_usec)}};
return ::utimes(path.c_str(), values);
}
static int NativeFlock(int descriptor, int operation) {
return ::flock(descriptor, operation);
}
@ -180,6 +193,10 @@ int APS5_VABI ftruncate_nid_postfix(int d, int64_t length) {
return 0;
}
int APS5_VABI sceKernelFtruncate(int d, int64_t length) {
return ftruncate_nid_postfix(d, length);
}
int64_t APS5_VABI lseek_nid_postfix(int d, int64_t offset, int whence) {
return static_cast<int64_t>(sceKernelLseek(d, offset, whence));
}
@ -423,23 +440,24 @@ int APS5_VABI rmdir_nid_postfix(const char* path) {
extern "C" {
int APS5_VABI sceKernelChmod_nid_postfix(const char* path, std::uint16_t mode) {
(void)path;
(void)mode;
NotImplemented_nid_no_patch(__func__);
return 0;
return chmod_nid_postfix(path, mode);
}
int APS5_VABI sceKernelTruncate_nid_postfix(const char* path, std::int64_t length) {
(void)path;
(void)length;
NotImplemented_nid_no_patch(__func__);
if (path == nullptr) throw std::invalid_argument("sceKernelTruncate: path is null");
if (length < 0) return SceErrorFromErrno(GUEST_EINVAL);
const auto native = ResolvePath_nid_no_patch(path);
std::error_code error;
if (!std::filesystem::exists(native, error)) return SceErrorFromErrno(GUEST_ENOENT);
std::filesystem::resize_file(native, static_cast<std::uintmax_t>(length), error);
if (error) return SceErrorFromErrno(GUEST_EIO);
return 0;
}
int APS5_VABI sceKernelUtimes_nid_postfix(const char* path, const KernelTimeval* times) {
(void)path;
(void)times;
NotImplemented_nid_no_patch(__func__);
if (path == nullptr) throw std::invalid_argument("sceKernelUtimes: path is null");
const auto native = ResolvePath_nid_no_patch(path);
if (NativeUtimes(native, times) != 0) return SceErrorFromErrno(errno);
return 0;
}

View File

@ -5,6 +5,9 @@
extern "C" {
const char* APS5_VABI __inet_ntop_nid_postfix(int family, const void* source, char* destination, std::uint32_t capacity);
int APS5_VABI __inet_pton_nid_postfix(int family, const char* text, void* destination);
int APS5_VABI accept_nid_postfix(int s, void* addr, uint32_t* addrlen) {
(void)s;
(void)addr;
@ -54,20 +57,11 @@ int64_t APS5_VABI recv_nid_postfix(int s, void* buf, uint64_t len, int flags) {
const char* APS5_VABI inet_ntop_nid_postfix(int af, const void* src, char* dst, uint32_t size) {
(void)af;
(void)src;
(void)dst;
(void)size;
NotImplemented_nid_no_patch(__func__);
return nullptr;
return __inet_ntop_nid_postfix(af, src, dst, size);
}
int APS5_VABI inet_pton_nid_postfix(int af, const char* src, void* dst) {
(void)af;
(void)src;
(void)dst;
NotImplemented_nid_no_patch(__func__);
return 0;
return __inet_pton_nid_postfix(af, src, dst);
}
int APS5_VABI select_nid_postfix(int nfds, void* readfds, void* writefds, void* exceptfds, const void* timeout) {

View File

@ -5,11 +5,6 @@
extern "C" {
int APS5_VABI rename_nid_postfix() {
NotImplemented_nid_no_patch(__func__);
return 0;
}
int APS5_VABI sceCoredumpWriteUserData() {
NotImplemented_nid_no_patch(__func__);
return 0;
@ -35,9 +30,4 @@ int APS5_VABI sceKernelAprResolveFilepathsWithPrefixToIdsForEach() {
return 0;
}
int APS5_VABI sceKernelFtruncate() {
NotImplemented_nid_no_patch(__func__);
return 0;
}
}

View File

@ -7,6 +7,11 @@
extern "C" {
int APS5_VABI remove_nid_postfix(const char*);
int APS5_VABI rename_nid_postfix(const char*, const char*);
int APS5_VABI sceKernelChmod_nid_postfix(const char*, unsigned short);
int APS5_VABI sceKernelFsync(int);
int APS5_VABI sceKernelFtruncate(int, long long);
int APS5_VABI sceKernelTruncate_nid_postfix(const char*, long long);
int APS5_VABI sceKernelUtimes_nid_postfix(const char*, const void*);
int* APS5_VABI __error_nid_postfix();
}
static void Check(bool value, int line) {
@ -41,6 +46,27 @@ int main() {
Require(remove_nid_postfix(file.string().c_str()) == 0);
Require(!std::filesystem::exists(file));
Require(remove_nid_postfix(file.string().c_str()) == -1 && *__error_nid_postfix() == 2);
const auto sized = root / "sized.txt";
{ std::ofstream stream(sized); stream << "0123456789abcdef"; }
Require(sceKernelChmod_nid_postfix(sized.string().c_str(), 0600) == 0);
Require(sceKernelTruncate_nid_postfix(sized.string().c_str(), 6) == 0);
Require(std::filesystem::file_size(sized) == 6);
{ std::ifstream stream(sized); std::string contents; std::getline(stream, contents);
Require(contents == "012345"); }
Require(sceKernelTruncate_nid_postfix((sized / "missing").string().c_str(), 6) == static_cast<int>(0x80020002u));
Require(sceKernelUtimes_nid_postfix(sized.string().c_str(), nullptr) == 0);
std::FILE* native = std::fopen(sized.string().c_str(), "r+b");
Require(native != nullptr);
#ifdef _WIN32
const int descriptor = _fileno(native);
#else
const int descriptor = ::fileno(native);
#endif
Require(descriptor >= 0 && sceKernelFsync(descriptor) == 0);
Require(sceKernelFtruncate(descriptor, 3) == 0);
Require(std::fclose(native) == 0);
Require(std::filesystem::file_size(sized) == 3);
Require(remove_nid_postfix(sized.string().c_str()) == 0);
Require(remove_nid_postfix(root.string().c_str()) == 0);
Require(!std::filesystem::exists(root));
}

View File

@ -16,6 +16,8 @@ int APS5_VABI ioctl_nid_postfix(int, std::uint64_t, void*);
std::int64_t APS5_VABI sendto_nid_postfix(int, const void*, std::uint64_t, int, const void*, std::uint32_t);
std::int64_t APS5_VABI recvfrom_nid_postfix(int, void*, std::uint64_t, int, void*, std::uint32_t*);
int APS5_VABI close_nid_postfix(int);
const char* APS5_VABI inet_ntop_nid_postfix(int, const void*, char*, std::uint32_t);
int APS5_VABI inet_pton_nid_postfix(int, const char*, void*);
int* APS5_VABI __error_nid_postfix();
}
static void Require(bool value) { if (!value) std::abort(); }
@ -65,5 +67,17 @@ int main() {
Require(close_nid_postfix(receiver) == -1 && *__error_nid_postfix() == 9);
Require(ioctl_nid_postfix(receiver, 0x4004667f, &queued) == -1);
Require(close_nid_postfix(sender) == 0);
unsigned char parsed[16]{};
Require(inet_pton_nid_postfix(2, "127.0.0.1", parsed) == 1);
Require(parsed[0] == 127 && parsed[1] == 0 && parsed[2] == 0 && parsed[3] == 1);
char text[64]{};
Require(inet_ntop_nid_postfix(2, parsed, text, sizeof(text)) == text);
Require(std::strcmp(text, "127.0.0.1") == 0);
Require(inet_pton_nid_postfix(28, "::1", parsed) == 1);
Require(inet_ntop_nid_postfix(28, parsed, text, sizeof(text)) == text);
Require(std::strcmp(text, "::1") == 0);
Require(inet_pton_nid_postfix(99, "127.0.0.1", parsed) == -1 && *__error_nid_postfix() == 47);
Require(inet_pton_nid_postfix(2, "not-an-address", parsed) == 0);
Require(inet_ntop_nid_postfix(2, parsed, text, 4) == nullptr && *__error_nid_postfix() == 28);
Require(socket_nid_postfix(2, 1, 0) == -1); // unsupported TCP must not appear to work
}