fix(savedata): preserve memory on write failure
This commit is contained in:
parent
4764e59c37
commit
c4cfb8e23d
|
|
@ -560,8 +560,8 @@ static int setSaveDataMemory2(const SaveDataMemorySet2* set_param) {
|
|||
}
|
||||
}
|
||||
if (n != 0) {
|
||||
std::fstream f(path, std::ios::binary | std::ios::in | std::ios::out);
|
||||
if (!f) {
|
||||
std::vector<char> memory;
|
||||
if (!read_file_all(path, memory) || memory.size() != size) {
|
||||
return SAVE_DATA_ERROR_INTERNAL;
|
||||
}
|
||||
for (std::uint32_t i = 0; i < n; i++) {
|
||||
|
|
@ -569,11 +569,9 @@ static int setSaveDataMemory2(const SaveDataMemorySet2* set_param) {
|
|||
if (d.buf_size == 0) {
|
||||
continue;
|
||||
}
|
||||
f.seekp(static_cast<std::streamoff>(d.offset));
|
||||
f.write(static_cast<const char*>(d.buf), static_cast<std::streamsize>(d.buf_size));
|
||||
std::memcpy(memory.data() + d.offset, d.buf, d.buf_size);
|
||||
}
|
||||
f.flush();
|
||||
if (!f) {
|
||||
if (!write_file_replace(path, memory)) {
|
||||
return SAVE_DATA_ERROR_INTERNAL;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,12 +1,19 @@
|
|||
#include "SceTypes.hpp"
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <chrono>
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <filesystem>
|
||||
#include <fstream>
|
||||
#include <iterator>
|
||||
#include <limits>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#ifndef _WIN32
|
||||
#include <csignal>
|
||||
#include <sys/resource.h>
|
||||
#endif
|
||||
|
||||
extern "C" {
|
||||
int APS5_VABI sceSaveDataInitialize3(const void*);
|
||||
|
|
@ -14,9 +21,13 @@ int APS5_VABI sceSaveDataTerminate();
|
|||
int APS5_VABI sceSaveDataSetSaveDataMemory2(const SaveDataMemorySet2*);
|
||||
}
|
||||
|
||||
static void Require(bool value) {
|
||||
if (!value) std::abort();
|
||||
static void Check(bool value, int line) {
|
||||
if (!value) {
|
||||
std::fprintf(stderr, "Save-data memory check failed at line %d\n", line);
|
||||
std::abort();
|
||||
}
|
||||
}
|
||||
#define Require(value) Check((value), __LINE__)
|
||||
|
||||
static std::vector<char> Read(const std::filesystem::path& path) {
|
||||
std::ifstream file(path, std::ios::binary);
|
||||
|
|
@ -31,8 +42,14 @@ int main() {
|
|||
Require(std::filesystem::create_directory(root));
|
||||
std::filesystem::current_path(root);
|
||||
const auto path = std::filesystem::path("_sd_mem/u7531/slot0.param");
|
||||
const auto memoryPath = std::filesystem::path("_sd_mem/u7531/slot0.bin");
|
||||
std::filesystem::create_directories(path.parent_path());
|
||||
{ std::ofstream file("_sd_mem/u7531/slot0.bin"); file << "save"; Require(static_cast<bool>(file)); }
|
||||
const std::vector<char> memoryOriginal(32, 's');
|
||||
{
|
||||
std::ofstream file(memoryPath, std::ios::binary);
|
||||
file.write(memoryOriginal.data(), static_cast<std::streamsize>(memoryOriginal.size()));
|
||||
Require(static_cast<bool>(file));
|
||||
}
|
||||
Require(sceSaveDataInitialize3(nullptr) == 0);
|
||||
Require(sceSaveDataInitialize3(nullptr) == 0);
|
||||
Require(sceSaveDataTerminate() == 0);
|
||||
|
|
@ -55,6 +72,49 @@ int main() {
|
|||
Require(Read(path) == std::vector<char>(bytes, bytes + sizeof(param)));
|
||||
set.param = nullptr;
|
||||
Require(sceSaveDataSetSaveDataMemory2(&set) == 0);
|
||||
std::array<char, 8> first{'a', '\0', 'b', 'c', 'd', 'e', 'f', 'g'};
|
||||
std::array<char, 8> second{'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o'};
|
||||
std::array<SaveDataMemoryData, 3> data{{
|
||||
{first.data(), first.size(), 4},
|
||||
{second.data(), second.size(), 24},
|
||||
{nullptr, 0, std::numeric_limits<std::size_t>::max()}
|
||||
}};
|
||||
set.data = data.data();
|
||||
set.data_num = static_cast<std::uint32_t>(data.size());
|
||||
data[1].offset = memoryOriginal.size();
|
||||
Require(sceSaveDataSetSaveDataMemory2(&set) == static_cast<int>(0x809F0000u));
|
||||
Require(Read(memoryPath) == memoryOriginal);
|
||||
data[1].offset = 24;
|
||||
const auto memoryTemporary = memoryPath.string() + ".tmp";
|
||||
Require(std::filesystem::create_directory(memoryTemporary));
|
||||
Require(sceSaveDataSetSaveDataMemory2(&set) == static_cast<int>(0x809F000Bu));
|
||||
Require(Read(memoryPath) == memoryOriginal);
|
||||
Require(!std::filesystem::exists(memoryTemporary));
|
||||
#ifndef _WIN32
|
||||
rlimit previousLimit{};
|
||||
Require(getrlimit(RLIMIT_FSIZE, &previousLimit) == 0);
|
||||
auto writeLimit = previousLimit;
|
||||
writeLimit.rlim_cur = 16;
|
||||
const auto previousHandler = std::signal(SIGXFSZ, SIG_IGN);
|
||||
Require(previousHandler != SIG_ERR);
|
||||
Require(setrlimit(RLIMIT_FSIZE, &writeLimit) == 0);
|
||||
const int writeStatus = sceSaveDataSetSaveDataMemory2(&set);
|
||||
Require(setrlimit(RLIMIT_FSIZE, &previousLimit) == 0);
|
||||
Require(std::signal(SIGXFSZ, previousHandler) != SIG_ERR);
|
||||
Require(writeStatus == static_cast<int>(0x809F000Bu));
|
||||
Require(Read(memoryPath) == memoryOriginal);
|
||||
Require(!std::filesystem::exists(memoryTemporary));
|
||||
#endif
|
||||
Require(sceSaveDataSetSaveDataMemory2(&set) == 0);
|
||||
auto memoryExpected = memoryOriginal;
|
||||
std::copy(first.begin(), first.end(), memoryExpected.begin() + 4);
|
||||
std::copy(second.begin(), second.end(), memoryExpected.begin() + 24);
|
||||
Require(Read(memoryPath) == memoryExpected);
|
||||
first.fill('z');
|
||||
set.data_num = 0;
|
||||
Require(sceSaveDataSetSaveDataMemory2(&set) == 0);
|
||||
std::copy(first.begin(), first.end(), memoryExpected.begin() + 4);
|
||||
Require(Read(memoryPath) == memoryExpected);
|
||||
Require(sceSaveDataTerminate() == 0);
|
||||
std::filesystem::current_path(previous);
|
||||
std::filesystem::remove_all(root);
|
||||
|
|
|
|||
Loading…
Reference in New Issue