mirror of
https://github.com/KytyPS5/KytyPS5.git
synced 2026-10-28 13:56:59 +01:00
kernel: allow renaming open save files
This commit is contained in:
@@ -454,6 +454,9 @@ add_executable(event_queue_lifetime_tests EXCLUDE_FROM_ALL
|
|||||||
target_link_libraries(event_queue_lifetime_tests common fmt::fmt)
|
target_link_libraries(event_queue_lifetime_tests common fmt::fmt)
|
||||||
target_include_directories(event_queue_lifetime_tests PRIVATE ${inc_headers})
|
target_include_directories(event_queue_lifetime_tests PRIVATE ${inc_headers})
|
||||||
|
|
||||||
|
add_kyty_full_emulator_test(kernel_file_system_tests
|
||||||
|
"${KYTY_TESTS_DIR}/KernelFileSystemTests.cpp")
|
||||||
|
|
||||||
add_executable(sync_on_address_tests EXCLUDE_FROM_ALL
|
add_executable(sync_on_address_tests EXCLUDE_FROM_ALL
|
||||||
"${KYTY_TESTS_DIR}/SyncOnAddressTests.cpp"
|
"${KYTY_TESTS_DIR}/SyncOnAddressTests.cpp"
|
||||||
"${KYTY_SOURCE_DIR}/kernel/syncOnAddress.cpp"
|
"${KYTY_SOURCE_DIR}/kernel/syncOnAddress.cpp"
|
||||||
@@ -514,6 +517,7 @@ if(BUILD_TESTING)
|
|||||||
add_test(NAME shader_stage_runtime COMMAND $<TARGET_FILE:shader_stage_runtime_tests>)
|
add_test(NAME shader_stage_runtime COMMAND $<TARGET_FILE:shader_stage_runtime_tests>)
|
||||||
add_test(NAME resource_tracking COMMAND $<TARGET_FILE:resource_tracking_tests>)
|
add_test(NAME resource_tracking COMMAND $<TARGET_FILE:resource_tracking_tests>)
|
||||||
add_test(NAME event_queue_lifetime COMMAND $<TARGET_FILE:event_queue_lifetime_tests>)
|
add_test(NAME event_queue_lifetime COMMAND $<TARGET_FILE:event_queue_lifetime_tests>)
|
||||||
|
add_test(NAME kernel_file_system COMMAND $<TARGET_FILE:kernel_file_system_tests>)
|
||||||
add_test(NAME sync_on_address COMMAND $<TARGET_FILE:sync_on_address_tests>)
|
add_test(NAME sync_on_address COMMAND $<TARGET_FILE:sync_on_address_tests>)
|
||||||
add_test(NAME audio_out2_port COMMAND $<TARGET_FILE:audio_out2_port_tests>)
|
add_test(NAME audio_out2_port COMMAND $<TARGET_FILE:audio_out2_port_tests>)
|
||||||
add_test(NAME shader_recompiler_compute COMMAND $<TARGET_FILE:shader_recompiler_compute_tests>)
|
add_test(NAME shader_recompiler_compute COMMAND $<TARGET_FILE:shader_recompiler_compute_tests>)
|
||||||
@@ -567,6 +571,7 @@ if(BUILD_TESTING)
|
|||||||
shader_stage_runtime_tests
|
shader_stage_runtime_tests
|
||||||
resource_tracking_tests
|
resource_tracking_tests
|
||||||
event_queue_lifetime_tests
|
event_queue_lifetime_tests
|
||||||
|
kernel_file_system_tests
|
||||||
sync_on_address_tests
|
sync_on_address_tests
|
||||||
shader_recompiler_compute_tests
|
shader_recompiler_compute_tests
|
||||||
virtual_memory_allocation_tests
|
virtual_memory_allocation_tests
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ public:
|
|||||||
};
|
};
|
||||||
|
|
||||||
MountPoints() { EXIT_NOT_IMPLEMENTED(!Common::Thread::IsMainThread()); }
|
MountPoints() { EXIT_NOT_IMPLEMENTED(!Common::Thread::IsMainThread()); }
|
||||||
virtual ~MountPoints() { KYTY_NOT_IMPLEMENTED; }
|
virtual ~MountPoints() = default;
|
||||||
|
|
||||||
KYTY_CLASS_NO_COPY(MountPoints);
|
KYTY_CLASS_NO_COPY(MountPoints);
|
||||||
|
|
||||||
@@ -76,7 +76,7 @@ struct File {
|
|||||||
class FileDescriptors {
|
class FileDescriptors {
|
||||||
public:
|
public:
|
||||||
FileDescriptors() { EXIT_NOT_IMPLEMENTED(!Common::Thread::IsMainThread()); }
|
FileDescriptors() { EXIT_NOT_IMPLEMENTED(!Common::Thread::IsMainThread()); }
|
||||||
virtual ~FileDescriptors() { KYTY_NOT_IMPLEMENTED; }
|
virtual ~FileDescriptors() = default;
|
||||||
|
|
||||||
KYTY_CLASS_NO_COPY(FileDescriptors);
|
KYTY_CLASS_NO_COPY(FileDescriptors);
|
||||||
|
|
||||||
@@ -193,8 +193,10 @@ void FileDescriptors::CloseAll() {
|
|||||||
Common::LockGuard lock(m_mutex);
|
Common::LockGuard lock(m_mutex);
|
||||||
|
|
||||||
for (auto& f: m_files) {
|
for (auto& f: m_files) {
|
||||||
if (f != nullptr && f->opened) {
|
if (f != nullptr) {
|
||||||
f->f.Close();
|
if (f->opened) {
|
||||||
|
f->f.Close();
|
||||||
|
}
|
||||||
delete f;
|
delete f;
|
||||||
f = nullptr;
|
f = nullptr;
|
||||||
}
|
}
|
||||||
@@ -1054,9 +1056,6 @@ int KYTY_SYSV_ABI KernelRename(const char* from, const char* to) {
|
|||||||
auto real_from = g_mount_points->GetRealFilename(from_path);
|
auto real_from = g_mount_points->GetRealFilename(from_path);
|
||||||
auto real_to = g_mount_points->GetRealFilename(to_path);
|
auto real_to = g_mount_points->GetRealFilename(to_path);
|
||||||
|
|
||||||
EXIT_NOT_IMPLEMENTED(g_files->GetFile(real_from) != nullptr);
|
|
||||||
EXIT_NOT_IMPLEMENTED(g_files->GetFile(real_to) != nullptr);
|
|
||||||
|
|
||||||
if (!Common::File::IsFileExisting(real_from)) {
|
if (!Common::File::IsFileExisting(real_from)) {
|
||||||
return KERNEL_ERROR_ENOENT;
|
return KERNEL_ERROR_ENOENT;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,101 @@
|
|||||||
|
#include "common/emulatorConfig.h"
|
||||||
|
#include "common/file.h"
|
||||||
|
#include "common/logging/log.h"
|
||||||
|
#include "common/subsystems.h"
|
||||||
|
#include "common/threads.h"
|
||||||
|
#include "kernel/fileSystem.h"
|
||||||
|
#include "libs/errno.h"
|
||||||
|
|
||||||
|
#include <chrono>
|
||||||
|
#include <cstdio>
|
||||||
|
#include <cstdlib>
|
||||||
|
#include <cstring>
|
||||||
|
#include <filesystem>
|
||||||
|
#include <string>
|
||||||
|
#include <string_view>
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
namespace FileSystem = Libs::LibKernel::FileSystem;
|
||||||
|
|
||||||
|
void Check(bool value, const char *text) {
|
||||||
|
if (!value) {
|
||||||
|
std::fprintf(stderr, "KernelFileSystemTests: failed: %s\n", text);
|
||||||
|
std::abort();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class TempDirectory {
|
||||||
|
public:
|
||||||
|
TempDirectory() {
|
||||||
|
const auto unique =
|
||||||
|
std::chrono::steady_clock::now().time_since_epoch().count();
|
||||||
|
m_path = std::filesystem::temp_directory_path() /
|
||||||
|
("kyty_kernel_file_system_" + std::to_string(unique));
|
||||||
|
Check(std::filesystem::create_directories(m_path),
|
||||||
|
"create temporary directory");
|
||||||
|
}
|
||||||
|
|
||||||
|
~TempDirectory() {
|
||||||
|
std::error_code error;
|
||||||
|
std::filesystem::remove_all(m_path, error);
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] const std::filesystem::path &Path() const { return m_path; }
|
||||||
|
|
||||||
|
KYTY_CLASS_NO_COPY(TempDirectory);
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::filesystem::path m_path;
|
||||||
|
};
|
||||||
|
|
||||||
|
void CheckSaveRename(const std::filesystem::path &root,
|
||||||
|
std::string_view payload) {
|
||||||
|
constexpr char Source[] = "/savedata0/STEMP000.DAT";
|
||||||
|
constexpr char Target[] = "/savedata0/SDATA000.DAT";
|
||||||
|
constexpr char Suffix[] = "-after-rename";
|
||||||
|
|
||||||
|
const int fd = FileSystem::KernelOpen(Source, 0x601, 0777);
|
||||||
|
Check(fd >= 3, "open temporary save file");
|
||||||
|
Check(FileSystem::KernelWrite(fd, payload.data(), payload.size()) ==
|
||||||
|
payload.size(),
|
||||||
|
"write save payload");
|
||||||
|
Check(FileSystem::KernelRename(Source, Target) == OK,
|
||||||
|
"rename open save file");
|
||||||
|
Check(FileSystem::KernelWrite(fd, Suffix, sizeof(Suffix) - 1) ==
|
||||||
|
sizeof(Suffix) - 1,
|
||||||
|
"write through renamed descriptor");
|
||||||
|
Check(FileSystem::KernelClose(fd) == OK, "close renamed descriptor");
|
||||||
|
|
||||||
|
Common::File result(root / "SDATA000.DAT", Common::File::Mode::Read);
|
||||||
|
Check(!result.IsInvalid(), "open renamed save file");
|
||||||
|
const auto data = result.ReadWholeBuffer();
|
||||||
|
result.Close();
|
||||||
|
const std::string expected = std::string(payload) + Suffix;
|
||||||
|
Check(data.Size() == expected.size(), "renamed save size");
|
||||||
|
Check(std::memcmp(data.GetData(), expected.data(), expected.size()) == 0,
|
||||||
|
"renamed save contents");
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
Common::InitializeThreads();
|
||||||
|
Common::Subsystems subsystems;
|
||||||
|
subsystems.Initialize<Config::Lifecycle>();
|
||||||
|
Config::ConfigOptions options;
|
||||||
|
options.printf_direction = Config::OutputDirection::Silent;
|
||||||
|
Config::Load(options);
|
||||||
|
subsystems.Initialize<Log::Lifecycle>();
|
||||||
|
|
||||||
|
TempDirectory temporary;
|
||||||
|
FileSystem::Initialize();
|
||||||
|
FileSystem::Mount(temporary.Path(), "/savedata0");
|
||||||
|
CheckSaveRename(temporary.Path(), "first-save");
|
||||||
|
CheckSaveRename(temporary.Path(), "replacement-save");
|
||||||
|
FileSystem::Shutdown();
|
||||||
|
subsystems.Destroy();
|
||||||
|
|
||||||
|
std::printf("KernelFileSystemTests: all cases passed\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user