#include "SceTypes.hpp" #include "prx/libc/include/general/VabiMacros.hpp" #include "prx/libkernel/File/include/FileFlags.hpp" #include "prx/libkernel/KernelErrors.hpp" #include #include #include #include #include #include #include #include #include #include extern "C" { int APS5_VABI sceKernelOpen(const char* path, int flags, std::uint16_t mode); int APS5_VABI sceKernelClose(int d); std::int64_t APS5_VABI sceKernelRead(int d, void* buf, std::size_t nbytes); std::int64_t APS5_VABI sceKernelPread(int d, void* buf, std::size_t nbytes, std::int64_t offset); std::int64_t APS5_VABI sceKernelLseek(int d, std::int64_t offset, int whence); } static void Check(bool value, int line) { if (!value) { std::fprintf(stderr, "Positioned race check failed at line %d\n", line); std::abort(); } } #define Require(value) Check((value), __LINE__) int main() { const auto root = std::filesystem::path("anyps5-positioned-race-" + std::to_string(std::chrono::steady_clock::now().time_since_epoch().count())); Require(std::filesystem::create_directory(root)); const auto file = root / "blocks.bin"; constexpr std::int64_t kBlocks = 8; constexpr std::size_t kBlockSize = 4096; { std::ofstream stream(file, std::ios::binary); Require(static_cast(stream)); for (std::int64_t block = 0; block < kBlocks; ++block) { stream << std::string(kBlockSize, static_cast('A' + block)); } } const int fd = sceKernelOpen(file.string().c_str(), SCE_KERNEL_O_RDONLY, 0); Require(fd >= 0); std::array expected{}; expected.fill('A'); std::atomic stop{false}; std::atomic misread{false}; std::array seeked{}; seeked.fill('H'); std::thread seeker([&] { std::array sink{}; while (!stop.load()) { if (sceKernelLseek(fd, (kBlocks - 1) * kBlockSize, 0) != (kBlocks - 1) * kBlockSize) { misread = true; return; } if (sceKernelRead(fd, sink.data(), sink.size()) != static_cast(sink.size()) || std::memcmp(sink.data(), seeked.data(), seeked.size()) != 0) { misread = true; return; } } }); for (int i = 0; i < 5000 && !misread.load(); ++i) { std::array bytes{}; const auto got = sceKernelPread(fd, bytes.data(), bytes.size(), 0); if (got != static_cast(bytes.size()) || std::memcmp(bytes.data(), expected.data(), expected.size()) != 0) { misread = true; } } stop = true; seeker.join(); Require(!misread); Require(sceKernelClose(fd) == 0); Require(std::filesystem::remove_all(root) > 0); }