AnyPS5/core/libs/tests/GuestKernelSync.cpp

76 lines
3.4 KiB
C++

#include "prx/libc/include/General.hpp"
#include <algorithm>
#include <cstdint>
#include <cstdio>
#include <cstdlib>
#include <filesystem>
#include <fstream>
#ifdef _WIN32
#ifndef NOMINMAX
#define NOMINMAX
#endif
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#endif
extern "C" {
int APS5_VABI sceKernelOpen(const char*, int, unsigned short);
int APS5_VABI sceKernelClose(int);
std::int64_t APS5_VABI sceKernelWrite(int, const void*, std::size_t);
int APS5_VABI sceKernelMkdir(const char*, unsigned short);
int APS5_VABI sceKernelRename(const char*, const char*);
int APS5_VABI sceKernelUnlink(const char*);
int APS5_VABI sceKernelChmod_nid_postfix(const char*, std::uint16_t);
void APS5_VABI sceKernelSync();
void* APS5_VABI fopen_nid_postfix(const char*, const char*);
int APS5_VABI fclose_nid_postfix(void*);
}
static void Check(bool value, int line) {
if (!value) {
std::fprintf(stderr, "Kernel sync check failed at line %d\n", line);
std::abort();
}
}
#define Require(value) Check((value), __LINE__)
static bool Recorded(const char* guest) {
const auto paths = WrittenPaths_nid_no_patch();
return std::find(paths.begin(), paths.end(), ResolvePath_nid_no_patch(guest).lexically_normal()) != paths.end();
}
int main() {
std::filesystem::remove_all("kernel_sync_probe");
Require(sceKernelMkdir("kernel_sync_probe", 0777) == 0);
Require(Recorded("kernel_sync_probe"));
std::ofstream("kernel_sync_probe/existing.bin") << "existing";
const int reader = sceKernelOpen("kernel_sync_probe/existing.bin", 0x0, 0);
Require(reader >= 0 && sceKernelClose(reader) == 0);
void* stream = fopen_nid_postfix("kernel_sync_probe/existing.bin", "r");
Require(stream != nullptr && fclose_nid_postfix(stream) == 0);
Require(!Recorded("kernel_sync_probe/existing.bin"));
stream = fopen_nid_postfix("kernel_sync_probe/existing.bin", "a");
Require(stream != nullptr && fclose_nid_postfix(stream) == 0);
Require(Recorded("kernel_sync_probe/existing.bin"));
const int writer = sceKernelOpen("kernel_sync_probe/data.bin", 0x1 | 0x200 | 0x400, 0644);
Require(writer >= 0 && sceKernelWrite(writer, "data", 4) == 4 && sceKernelClose(writer) == 0);
Require(Recorded("kernel_sync_probe/data.bin"));
Require(sceKernelRename("kernel_sync_probe/data.bin", "kernel_sync_probe/moved.bin") == 0);
Require(Recorded("kernel_sync_probe/moved.bin"));
Require(sceKernelUnlink("kernel_sync_probe/moved.bin") == 0);
sceKernelSync();
Require(!Recorded("kernel_sync_probe/data.bin") && !Recorded("kernel_sync_probe/moved.bin"));
sceKernelSync();
const int locked = sceKernelOpen("kernel_sync_probe/read_only.bin", 0x1 | 0x200, 0644);
Require(locked >= 0 && sceKernelWrite(locked, "data", 4) == 4 && sceKernelClose(locked) == 0);
Require(sceKernelChmod_nid_postfix("kernel_sync_probe/read_only.bin", 0444) == 0);
Require(Recorded("kernel_sync_probe/read_only.bin"));
sceKernelSync();
Require(sceKernelChmod_nid_postfix("kernel_sync_probe/read_only.bin", 0644) == 0);
#ifdef _WIN32
const auto exclusive = CreateFileW(ResolvePath_nid_no_patch("kernel_sync_probe/read_only.bin").c_str(), GENERIC_READ, FILE_SHARE_READ,
nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr);
Require(exclusive != INVALID_HANDLE_VALUE);
sceKernelSync();
CloseHandle(exclusive);
#endif
sceKernelSync();
std::filesystem::remove_all("kernel_sync_probe");
}