mirror of
https://github.com/boykopovar/AnyPS5.git
synced 2026-11-04 13:07:32 +00:00
133 lines
5.7 KiB
C++
133 lines
5.7 KiB
C++
#include "AppArchiveFixture.hpp"
|
|
#include "prx/libc/include/Api.hpp"
|
|
#include "prx/libkernel/include/Api.hpp"
|
|
|
|
#include <cstdint>
|
|
#include <cstdio>
|
|
#include <cstdlib>
|
|
#include <cstring>
|
|
#include <filesystem>
|
|
#include <fstream>
|
|
#include <random>
|
|
#include <set>
|
|
#include <string>
|
|
#include <system_error>
|
|
|
|
namespace {
|
|
|
|
constexpr int NoSuchFile = 2;
|
|
constexpr int Fault = 14;
|
|
constexpr int TypeNotFound = -1;
|
|
constexpr int TypeNone = 0;
|
|
constexpr int TypeRegular = 1;
|
|
constexpr int TypeDirectory = 2;
|
|
constexpr int TypeUnknown = 8;
|
|
constexpr int Loop = 62;
|
|
|
|
void Require(bool condition, const char* message) {
|
|
if (condition) return;
|
|
std::fprintf(stderr, "sce v2 filesystem: %s\n", message);
|
|
std::abort();
|
|
}
|
|
|
|
std::string root;
|
|
|
|
std::string At(const char* name) {
|
|
return root + "/" + name;
|
|
}
|
|
|
|
void Write(const std::string& path, std::size_t bytes) {
|
|
std::ofstream file(path, std::ios::binary | std::ios::trunc);
|
|
file << std::string(bytes, 'x');
|
|
}
|
|
|
|
void TestStat() {
|
|
Write(At("file"), 7);
|
|
int perms = -1;
|
|
int error = -1;
|
|
Require(_ZNSt8__sce_v210filesystem5_StatEPKcPNS0_5permsEPi_nid_postfix(At("file").c_str(), &perms, &error) == TypeRegular && error == 0, "regular file");
|
|
FileStat status{};
|
|
Require(stat_nid_postfix(At("file").c_str(), &status) == 0 && perms == (status.st_mode & 07777), "permission bits");
|
|
Require(_ZNSt8__sce_v210filesystem5_StatEPKcPNS0_5permsEPi_nid_postfix(root.c_str(), nullptr, &error) == TypeDirectory && error == 0, "directory");
|
|
perms = 1234;
|
|
Require(_ZNSt8__sce_v210filesystem5_StatEPKcPNS0_5permsEPi_nid_postfix(At("missing").c_str(), &perms, &error) == TypeNotFound && error == NoSuchFile && perms == 1234, "missing path");
|
|
}
|
|
|
|
void TestStatInvalidPath() {
|
|
int perms = 1234;
|
|
int error = -1;
|
|
Require(_ZNSt8__sce_v210filesystem5_StatEPKcPNS0_5permsEPi_nid_postfix(nullptr, &perms, &error) == TypeNone && error == Fault && perms == 1234, "a null path");
|
|
error = -1;
|
|
Require(_ZNSt8__sce_v210filesystem5_StatEPKcPNS0_5permsEPi_nid_postfix("", &perms, &error) == TypeNotFound && error == NoSuchFile && perms == 1234, "an empty path");
|
|
}
|
|
|
|
void TestStatError() {
|
|
const auto loop = At("loop");
|
|
std::error_code failure;
|
|
std::filesystem::create_symlink("loop", loop, failure);
|
|
if (failure) return;
|
|
std::error_code probe;
|
|
(void)std::filesystem::status(loop, probe);
|
|
if (probe != std::errc::too_many_symbolic_link_levels) return;
|
|
int perms = 1234;
|
|
int error = -1;
|
|
Require(_ZNSt8__sce_v210filesystem5_StatEPKcPNS0_5permsEPi_nid_postfix(loop.c_str(), &perms, &error) == TypeNone && error == Loop && perms == 1234, "a symlink loop is not reported as not found");
|
|
}
|
|
|
|
void TestArchivedStat() {
|
|
int perms = -1;
|
|
int error = -1;
|
|
Require(_ZNSt8__sce_v210filesystem5_StatEPKcPNS0_5permsEPi_nid_postfix("/app0/Readme.TXT", &perms, &error) == TypeRegular && error == 0 && perms == 0444, "archived file");
|
|
FileStat status{};
|
|
Require(stat_nid_postfix("/app0/Readme.TXT", &status) == 0 && perms == (status.st_mode & 07777), "archived file permissions");
|
|
perms = -1;
|
|
Require(_ZNSt8__sce_v210filesystem5_StatEPKcPNS0_5permsEPi_nid_postfix("/app0/Data", &perms, &error) == TypeDirectory && error == 0 && perms == 0555, "archived directory");
|
|
Require(stat_nid_postfix("/app0/Data", &status) == 0 && perms == (status.st_mode & 07777), "archived directory permissions");
|
|
}
|
|
|
|
void TestDirectories() {
|
|
std::filesystem::create_directory(At("made"));
|
|
char name[260];
|
|
int error = -1;
|
|
int type = -1;
|
|
Require(_ZNSt8__sce_v210filesystem9_Open_dirERA260_cPKcRiRNS0_9file_typeE_nid_postfix(name, At("made").c_str(), &error, &type) == nullptr && error == 0 && name[0] == '\0', "an empty directory gives no handle");
|
|
Require(_ZNSt8__sce_v210filesystem9_Open_dirERA260_cPKcRiRNS0_9file_typeE_nid_postfix(name, At("missing").c_str(), &error, &type) == nullptr && error == NoSuchFile, "a missing directory");
|
|
Write(At("made/one"), 1);
|
|
Write(At("made/two"), 2);
|
|
void* handle = _ZNSt8__sce_v210filesystem9_Open_dirERA260_cPKcRiRNS0_9file_typeE_nid_postfix(name, At("made").c_str(), &error, &type);
|
|
Require(handle != nullptr && error == 0 && type == TypeUnknown, "open a directory");
|
|
std::set<std::string> names{name};
|
|
type = 0;
|
|
Require(_ZNSt8__sce_v210filesystem9_Read_dirERA260_cPvRNS0_9file_typeE_nid_postfix(name, handle, &type) == name && type == TypeUnknown, "read a directory");
|
|
names.insert(name);
|
|
Require(names == std::set<std::string>{"one", "two"}, "entries without dot entries");
|
|
Require(_ZNSt8__sce_v210filesystem9_Read_dirERA260_cPvRNS0_9file_typeE_nid_postfix(name, handle, &type)[0] == '\0' && type == TypeUnknown, "end of the directory");
|
|
Require(_ZNSt8__sce_v210filesystem10_Close_dirEPv_nid_postfix(handle) == 0, "close a directory");
|
|
}
|
|
|
|
void TestCurrent() {
|
|
char current[260];
|
|
std::memset(current, 0x5a, sizeof(current));
|
|
Require(_ZNSt8__sce_v210filesystem12_Current_getERA260_c_nid_postfix(current), "current directory");
|
|
Require(std::strcmp(current, "/") == 0, "current directory is the sandbox root");
|
|
Require(static_cast<unsigned char>(current[2]) == 0x5a, "current directory writes two bytes");
|
|
}
|
|
|
|
}
|
|
|
|
int main() {
|
|
const auto directory = AppArchiveFixture::EnterFreshRoot("anyps5-sce-v2-filesystem");
|
|
root = ".";
|
|
AppArchiveFixture::WriteArchive(directory / "app0.zar", {{"Readme.TXT", {'r', 'e', 'a', 'd'}}, {"Data/Sub.txt", {'s'}}});
|
|
TestStat();
|
|
TestStatInvalidPath();
|
|
TestStatError();
|
|
TestArchivedStat();
|
|
TestDirectories();
|
|
TestCurrent();
|
|
std::error_code ignored;
|
|
std::filesystem::current_path(std::filesystem::temp_directory_path(), ignored);
|
|
std::filesystem::remove_all(directory, ignored);
|
|
return 0;
|
|
}
|