mirror of
https://github.com/boykopovar/AnyPS5.git
synced 2026-10-22 16:43:05 -05:00
SceErrorFromErrno in the libkernel file functions passed host errno values 1-34 through and turned every other value into EIO. Linux numbers EAGAIN 11, which is FreeBSD's EDEADLK, so a read from an empty non-blocking pipe returned SCE_KERNEL_ERROR_EDEADLK, and ENAMETOOLONG, ELOOP, ENOTEMPTY, EDQUOT and EOVERFLOW, whose host values differ from FreeBSD's, all became EIO. Map those host values to the guest's FreeBSD numbers, as SceIoErrorFromErrno in Open.cpp already does for EAGAIN, EDEADLK, EDQUOT and EOVERFLOW. The guest constants the callers pass are all at most 34 and never 11, or GUEST_ENOTEMPTY, so they are unchanged. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Ha6Tsy62AFUyp9a5Mf7vjA
231 lines
11 KiB
C++
231 lines
11 KiB
C++
#include "prx/libc/include/general/VabiMacros.hpp"
|
|
#include "prx/libkernel/File/include/FileFlags.hpp"
|
|
#include <chrono>
|
|
#include <cstddef>
|
|
#include <cstdint>
|
|
#include <cstdio>
|
|
#include <cstdlib>
|
|
#include <cstring>
|
|
#include <filesystem>
|
|
#include <fstream>
|
|
#include <iterator>
|
|
#include <string>
|
|
#ifdef _WIN32
|
|
#include <fcntl.h>
|
|
#include <io.h>
|
|
static int MakePipe(int* ends) { return ::_pipe(ends, 64, _O_BINARY); }
|
|
static int ClosePipe(int end) { return ::_close(end); }
|
|
#else
|
|
#include <fcntl.h>
|
|
#include <unistd.h>
|
|
static int MakePipe(int* ends) { return ::pipe(ends); }
|
|
static int ClosePipe(int end) { return ::close(end); }
|
|
#endif
|
|
|
|
struct GuestIovec {
|
|
void* base;
|
|
std::size_t length;
|
|
};
|
|
|
|
extern "C" {
|
|
int APS5_VABI sceKernelOpen(const char*, int, std::uint16_t);
|
|
int APS5_VABI sceKernelClose(int);
|
|
std::int64_t APS5_VABI sceKernelRead(int, void*, std::size_t);
|
|
std::int64_t APS5_VABI sceKernelPread(int, void*, std::size_t, std::int64_t);
|
|
int APS5_VABI sceKernelLseek(int, std::int64_t, int);
|
|
std::int64_t APS5_VABI sceKernelReadv(int, const GuestIovec*, int);
|
|
std::int64_t APS5_VABI readv_nid_postfix(int, const GuestIovec*, int);
|
|
std::int64_t APS5_VABI writev_nid_postfix(int, const GuestIovec*, int);
|
|
int* APS5_VABI __error_nid_postfix();
|
|
std::int64_t APS5_VABI sceKernelWritev(int, const GuestIovec*, int);
|
|
std::int64_t APS5_VABI sceKernelPreadv(int, const GuestIovec*, int, std::int64_t);
|
|
std::int64_t APS5_VABI sceKernelPwritev(int, const GuestIovec*, int, std::int64_t);
|
|
std::int64_t APS5_VABI preadv_nid_postfix(int, const GuestIovec*, int, std::int64_t);
|
|
std::int64_t APS5_VABI pwritev_nid_postfix(int, const GuestIovec*, int, std::int64_t);
|
|
int* APS5_VABI __error_nid_postfix();
|
|
std::int64_t APS5_VABI sceKernelPread(int, void*, std::size_t, std::int64_t);
|
|
std::int64_t APS5_VABI sceKernelPwrite(int, const void*, std::size_t, std::int64_t);
|
|
int APS5_VABI sceKernelFtruncate(int, std::int64_t);
|
|
}
|
|
|
|
static void Check(bool value, int line) {
|
|
if (!value) {
|
|
std::fprintf(stderr, "File vector check failed at line %d\n", line);
|
|
std::abort();
|
|
}
|
|
}
|
|
#define Require(value) Check((value), __LINE__)
|
|
|
|
static constexpr std::int64_t ErrorEbadf = static_cast<int>(0x80020009u);
|
|
static constexpr std::int64_t ErrorEfault = static_cast<int>(0x8002000Eu);
|
|
static constexpr std::int64_t ErrorEinval = static_cast<int>(0x80020016u);
|
|
static constexpr std::int64_t ErrorEspipe = static_cast<int>(0x8002001Du);
|
|
static constexpr std::int64_t ErrorEagain = static_cast<int>(0x80020023u);
|
|
|
|
static std::string Contents(const std::filesystem::path& path) {
|
|
std::ifstream stream(path, std::ios::binary);
|
|
return std::string(std::istreambuf_iterator<char>(stream), std::istreambuf_iterator<char>());
|
|
}
|
|
|
|
int main() {
|
|
const auto root = std::filesystem::path("anyps5-file-vector-test-" +
|
|
std::to_string(std::chrono::steady_clock::now().time_since_epoch().count()));
|
|
Require(std::filesystem::create_directory(root));
|
|
const auto path = root / "data.bin";
|
|
{ std::ofstream stream(path, std::ios::binary); stream << "0123456789"; }
|
|
|
|
const int file = sceKernelOpen(path.string().c_str(), SCE_KERNEL_O_RDWR, 0);
|
|
Require(file >= 0);
|
|
|
|
char first[3] = {};
|
|
char second[4] = {};
|
|
GuestIovec reads[2] = {{first, sizeof(first)}, {second, sizeof(second)}};
|
|
Require(sceKernelReadv(file, reads, 2) == 7);
|
|
Require(std::memcmp(first, "012", 3) == 0 && std::memcmp(second, "3456", 4) == 0);
|
|
Require(sceKernelLseek(file, 0, 1) == 7);
|
|
Require(sceKernelReadv(file, reads, 2) == 3);
|
|
Require(std::memcmp(first, "789", 3) == 0);
|
|
Require(sceKernelReadv(file, reads, 2) == 0);
|
|
Require(sceKernelLseek(file, 0, 0) == 0);
|
|
Require(readv_nid_postfix(file, reads, 2) == 7);
|
|
Require(std::memcmp(first, "012", 3) == 0 && std::memcmp(second, "3456", 4) == 0);
|
|
Require(sceKernelLseek(file, 0, 1) == 7);
|
|
Require(readv_nid_postfix(file, reads, 2) == 3);
|
|
Require(readv_nid_postfix(file, reads, 2) == 0);
|
|
Require(readv_nid_postfix(file, reads, -1) == -1 && *__error_nid_postfix() == 22);
|
|
Require(writev_nid_postfix(file, nullptr, 1) == -1 && *__error_nid_postfix() == 14);
|
|
|
|
Require(sceKernelPreadv(file, reads, 2, 1) == 7);
|
|
Require(std::memcmp(first, "123", 3) == 0 && std::memcmp(second, "4567", 4) == 0);
|
|
Require(sceKernelLseek(file, 0, 1) == 10);
|
|
Require(sceKernelPreadv(file, reads, 2, 8) == 2);
|
|
Require(std::memcmp(first, "89", 2) == 0);
|
|
|
|
char ab[] = "AB";
|
|
char cde[] = "CDE";
|
|
GuestIovec writes[2] = {{ab, 2}, {cde, 3}};
|
|
Require(sceKernelPwritev(file, writes, 2, 2) == 5);
|
|
Require(sceKernelLseek(file, 0, 1) == 10);
|
|
Require(Contents(path) == "01ABCDE789");
|
|
Require(sceKernelLseek(file, 8, 0) == 8);
|
|
Require(sceKernelWritev(file, writes, 2) == 5);
|
|
Require(sceKernelLseek(file, 0, 1) == 13);
|
|
Require(Contents(path) == "01ABCDE7ABCDE");
|
|
GuestIovec swapped[2] = {{cde, 3}, {ab, 2}};
|
|
Require(sceKernelLseek(file, 8, 0) == 8 && writev_nid_postfix(file, swapped, 2) == 5);
|
|
Require(sceKernelLseek(file, 0, 1) == 13 && Contents(path) == "01ABCDE7CDEAB");
|
|
Require(sceKernelLseek(file, 8, 0) == 8 && writev_nid_postfix(file, writes, 2) == 5);
|
|
Require(Contents(path) == "01ABCDE7ABCDE");
|
|
|
|
GuestIovec gapped[3] = {{first, 2}, {nullptr, 0}, {second, 3}};
|
|
Require(sceKernelPreadv(file, gapped, 3, 0) == 5);
|
|
Require(std::memcmp(first, "01", 2) == 0 && std::memcmp(second, "ABC", 3) == 0);
|
|
Require(sceKernelLseek(file, 2, 0) == 2);
|
|
Require(sceKernelReadv(file, gapped, 3) == 5);
|
|
Require(std::memcmp(first, "AB", 2) == 0 && std::memcmp(second, "CDE", 3) == 0);
|
|
Require(sceKernelLseek(file, 0, 1) == 7);
|
|
|
|
GuestIovec empty[1] = {{nullptr, 0}};
|
|
Require(sceKernelReadv(file, empty, 1) == 0);
|
|
Require(sceKernelReadv(file, reads, 0) == 0);
|
|
Require(sceKernelWritev(file, nullptr, 0) == 0);
|
|
|
|
Require(sceKernelReadv(file, reads, -1) == ErrorEinval);
|
|
Require(sceKernelWritev(file, writes, -1) == ErrorEinval);
|
|
Require(sceKernelPreadv(file, reads, -1, 0) == ErrorEinval);
|
|
Require(sceKernelPwritev(file, writes, -1, 0) == ErrorEinval);
|
|
Require(sceKernelReadv(file, reads, 1025) == ErrorEinval);
|
|
Require(sceKernelWritev(file, writes, 1025) == ErrorEinval);
|
|
Require(sceKernelReadv(file, nullptr, 1) == ErrorEfault);
|
|
Require(sceKernelWritev(file, nullptr, 1) == ErrorEfault);
|
|
Require(sceKernelPreadv(file, nullptr, 1, 0) == ErrorEfault);
|
|
Require(sceKernelPwritev(file, nullptr, 1, 0) == ErrorEfault);
|
|
Require(sceKernelPreadv(file, reads, 2, -1) == ErrorEinval);
|
|
Require(sceKernelPwritev(file, writes, 2, -1) == ErrorEinval);
|
|
Require(Contents(path) == "01ABCDE7ABCDE");
|
|
|
|
Require(sceKernelLseek(file, 4, 0) == 4);
|
|
Require(preadv_nid_postfix(file, reads, 2, 1) == 7);
|
|
Require(std::memcmp(first, "1AB", 3) == 0 && std::memcmp(second, "CDE7", 4) == 0);
|
|
Require(sceKernelLseek(file, 0, 1) == 4);
|
|
Require(preadv_nid_postfix(file, reads, 2, 13) == 0);
|
|
Require(preadv_nid_postfix(file, reads, 2, -1) == -1 && *__error_nid_postfix() == 22);
|
|
Require(preadv_nid_postfix(file, reads, -1, 0) == -1 && *__error_nid_postfix() == 22);
|
|
Require(preadv_nid_postfix(file, nullptr, 1, 0) == -1 && *__error_nid_postfix() == 14);
|
|
Require(pwritev_nid_postfix(file, writes, 2, 8) == 5);
|
|
Require(sceKernelLseek(file, 0, 1) == 4);
|
|
Require(Contents(path) == "01ABCDE7ABCDE");
|
|
char x[] = "X";
|
|
char y[] = "Y";
|
|
GuestIovec marks[2] = {{x, 1}, {y, 1}};
|
|
Require(pwritev_nid_postfix(file, marks, 2, 0) == 2);
|
|
Require(Contents(path) == "XYABCDE7ABCDE");
|
|
char zero[] = "0";
|
|
char one[] = "1";
|
|
GuestIovec restore[2] = {{zero, 1}, {one, 1}};
|
|
Require(pwritev_nid_postfix(file, restore, 2, 0) == 2);
|
|
Require(sceKernelLseek(file, 0, 1) == 4);
|
|
Require(pwritev_nid_postfix(file, writes, 2, -1) == -1 && *__error_nid_postfix() == 22);
|
|
Require(pwritev_nid_postfix(file, nullptr, 1, 0) == -1 && *__error_nid_postfix() == 14);
|
|
|
|
char byte = 0;
|
|
Require(sceKernelPread(file, &byte, 1, 2) == 1 && byte == 'A');
|
|
Require(sceKernelPread(file, nullptr, 0, 0) == 0);
|
|
Require(sceKernelPwrite(file, nullptr, 0, 0) == 0);
|
|
Require(sceKernelPread(file, nullptr, 1, 0) == ErrorEfault);
|
|
Require(sceKernelPwrite(file, nullptr, 1, 0) == ErrorEfault);
|
|
Require(sceKernelPread(file, &byte, 1, -1) == ErrorEinval);
|
|
Require(sceKernelPwrite(file, &byte, 1, -1) == ErrorEinval);
|
|
Require(sceKernelFtruncate(file, -1) == ErrorEinval);
|
|
const int readOnly = sceKernelOpen(path.string().c_str(), SCE_KERNEL_O_RDONLY, 0);
|
|
Require(readOnly >= 0);
|
|
Require(sceKernelPwrite(readOnly, "X", 1, 0) == ErrorEbadf);
|
|
Require(sceKernelFtruncate(readOnly, 0) == ErrorEinval);
|
|
Require(sceKernelClose(readOnly) == 0);
|
|
const int writeOnly = sceKernelOpen(path.string().c_str(), SCE_KERNEL_O_WRONLY, 0);
|
|
Require(writeOnly >= 0);
|
|
Require(sceKernelPread(writeOnly, &byte, 1, 0) == ErrorEbadf);
|
|
Require(sceKernelClose(writeOnly) == 0);
|
|
Require(Contents(path) == "01ABCDE7ABCDE");
|
|
Require(sceKernelFtruncate(file, 5) == 0);
|
|
Require(Contents(path) == "01ABC");
|
|
|
|
Require(sceKernelClose(file) == 0);
|
|
Require(sceKernelReadv(file, reads, 2) == ErrorEbadf);
|
|
Require(sceKernelWritev(file, writes, 2) == ErrorEbadf);
|
|
Require(sceKernelPreadv(file, reads, 2, 0) == ErrorEbadf);
|
|
Require(sceKernelPwritev(file, writes, 2, 0) == ErrorEbadf);
|
|
Require(sceKernelPread(file, &byte, 1, 0) == ErrorEbadf);
|
|
Require(sceKernelPwrite(file, &byte, 1, 0) == ErrorEbadf);
|
|
Require(sceKernelFtruncate(file, 0) == ErrorEbadf);
|
|
|
|
int ends[2] = {};
|
|
Require(MakePipe(ends) == 0);
|
|
char xyz[] = "xyz";
|
|
GuestIovec message[1] = {{xyz, 3}};
|
|
Require(sceKernelWritev(ends[1], message, 1) == 3);
|
|
Require(sceKernelReadv(ends[0], reads, 2) == 3);
|
|
Require(std::memcmp(first, "xyz", 3) == 0);
|
|
Require(sceKernelPreadv(ends[0], reads, 2, 0) == ErrorEspipe);
|
|
Require(sceKernelPwritev(ends[1], message, 1, 0) == ErrorEspipe);
|
|
#ifndef _WIN32
|
|
Require(::fcntl(ends[0], F_SETFL, ::fcntl(ends[0], F_GETFL) | O_NONBLOCK) == 0);
|
|
Require(sceKernelReadv(ends[0], reads, 2) == ErrorEagain);
|
|
Require(readv_nid_postfix(ends[0], reads, 2) == -1 && *__error_nid_postfix() == 35);
|
|
#endif
|
|
Require(ClosePipe(ends[0]) == 0 && ClosePipe(ends[1]) == 0);
|
|
|
|
const int random = sceKernelOpen("/dev/urandom", 0, 0);
|
|
Require(random >= 0);
|
|
unsigned char noise[48]{};
|
|
GuestIovec pieces[2] = {{noise, 16}, {noise + 16, 16}};
|
|
Require(sceKernelReadv(random, pieces, 2) == 32);
|
|
Require(sceKernelPreadv(random, pieces, 1, 1000) == 16);
|
|
Require(sceKernelPread(random, noise + 32, 16, 1000) == 16);
|
|
Require(std::memcmp(noise, noise + 16, 16) != 0 && std::memcmp(noise + 16, noise + 32, 16) != 0);
|
|
Require(sceKernelClose(random) == 0);
|
|
|
|
std::filesystem::remove_all(root);
|
|
return 0;
|
|
}
|