mirror of
https://github.com/KytyPS5/KytyPS5.git
synced 2026-10-28 13:56:59 +01:00
savedata: sort directory searches by the requested key
This commit is contained in:
+31
-14
@@ -615,7 +615,12 @@ int KYTY_SYSV_ABI SaveDataDirNameSearch(const SaveDataDirNameSearchCond* cond,
|
|||||||
Common::LockGuard lock(g_mount_mutex);
|
Common::LockGuard lock(g_mount_mutex);
|
||||||
const std::string title_id = cond->title_id != nullptr ? cond->title_id->data : get_title_id();
|
const std::string title_id = cond->title_id != nullptr ? cond->title_id->data : get_title_id();
|
||||||
const auto root = save_user_directory(title_id, cond->user_id);
|
const auto root = save_user_directory(title_id, cond->user_id);
|
||||||
std::vector<std::string> dir_list;
|
struct Found {
|
||||||
|
uint64_t key = 0;
|
||||||
|
std::string name;
|
||||||
|
auto operator<=>(const Found&) const = default;
|
||||||
|
};
|
||||||
|
std::vector<Found> dir_list;
|
||||||
|
|
||||||
if (Common::File::IsDirectoryExisting(root)) {
|
if (Common::File::IsDirectoryExisting(root)) {
|
||||||
for (const auto& entry: Common::File::GetDirEntries(root)) {
|
for (const auto& entry: Common::File::GetDirEntries(root)) {
|
||||||
@@ -625,22 +630,34 @@ int KYTY_SYSV_ABI SaveDataDirNameSearch(const SaveDataDirNameSearchCond* cond,
|
|||||||
if (cond->dir_name == nullptr || cond->dir_name->data[0] == '\0' ||
|
if (cond->dir_name == nullptr || cond->dir_name->data[0] == '\0' ||
|
||||||
dir_name_match(Common::ToLower(entry.name).c_str(),
|
dir_name_match(Common::ToLower(entry.name).c_str(),
|
||||||
Common::ToLower(std::string(cond->dir_name->data)).c_str())) {
|
Common::ToLower(std::string(cond->dir_name->data)).c_str())) {
|
||||||
dir_list.push_back(entry.name);
|
dir_list.push_back({.name = entry.name});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::sort(dir_list.begin(), dir_list.end(), [](const std::string& a, const std::string& b) {
|
// A save whose metadata cannot be read sorts as 0.
|
||||||
return std::strcmp(a.c_str(), b.c_str()) < 0;
|
for (auto& found: dir_list) {
|
||||||
});
|
const auto directory = root / found.name;
|
||||||
|
switch (cond->key) {
|
||||||
if (cond->order == SaveDataSortOrder::Descent) {
|
case SaveDataSortKey::UserParam: {
|
||||||
std::vector<std::string> reversed;
|
SaveDataParam param {};
|
||||||
for (size_t i = dir_list.size(); i > 0; i--) {
|
read_save_param(save_param_path(directory), ¶m);
|
||||||
reversed.push_back(dir_list[i - 1]);
|
found.key = param.user_param;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case SaveDataSortKey::Blocks:
|
||||||
|
case SaveDataSortKey::FreeBlocks: read_save_blocks(directory, &found.key); break;
|
||||||
|
case SaveDataSortKey::Mtime:
|
||||||
|
found.key = static_cast<uint64_t>(newest_save_time(directory));
|
||||||
|
break;
|
||||||
|
default: break;
|
||||||
}
|
}
|
||||||
dir_list = reversed;
|
}
|
||||||
|
// Directory names break ties; descending order reverses both.
|
||||||
|
std::sort(dir_list.begin(), dir_list.end());
|
||||||
|
if (cond->order == SaveDataSortOrder::Descent) {
|
||||||
|
std::reverse(dir_list.begin(), dir_list.end());
|
||||||
}
|
}
|
||||||
|
|
||||||
auto max_count =
|
auto max_count =
|
||||||
@@ -651,9 +668,9 @@ int KYTY_SYSV_ABI SaveDataDirNameSearch(const SaveDataDirNameSearchCond* cond,
|
|||||||
|
|
||||||
for (size_t i = 0; i < max_count; i++) {
|
for (size_t i = 0; i < max_count; i++) {
|
||||||
std::snprintf(result->dir_names[i].data, sizeof(result->dir_names[i].data), "%s",
|
std::snprintf(result->dir_names[i].data, sizeof(result->dir_names[i].data), "%s",
|
||||||
dir_list[i].c_str());
|
dir_list[i].name.c_str());
|
||||||
if (result->params != nullptr) {
|
if (result->params != nullptr) {
|
||||||
const int status = load_save_param(root / dir_list[i], &result->params[i]);
|
const int status = load_save_param(root / dir_list[i].name, &result->params[i]);
|
||||||
if (status != OK) {
|
if (status != OK) {
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
@@ -661,7 +678,7 @@ int KYTY_SYSV_ABI SaveDataDirNameSearch(const SaveDataDirNameSearchCond* cond,
|
|||||||
if (result->infos != nullptr) {
|
if (result->infos != nullptr) {
|
||||||
auto& info = result->infos[i];
|
auto& info = result->infos[i];
|
||||||
info = {};
|
info = {};
|
||||||
const int status = read_save_blocks(root / dir_list[i], &info.blocks);
|
const int status = read_save_blocks(root / dir_list[i].name, &info.blocks);
|
||||||
if (status != OK) {
|
if (status != OK) {
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -660,6 +660,47 @@ void TestClassicSaveParams() {
|
|||||||
CHECK(params[0].mtime == nested_mtime);
|
CHECK(params[0].mtime == nested_mtime);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TestSearchSortKeys() {
|
||||||
|
Reset("SORTED");
|
||||||
|
const std::array names {DirName("alpha"), DirName("bravo"), DirName("charlie")};
|
||||||
|
constexpr std::array<uint64_t, 3> blocks {96, 48, 48};
|
||||||
|
constexpr std::array<uint32_t, 3> user_params {2, 3, 1};
|
||||||
|
constexpr std::array<int, 3> hours_ahead {1, 3, 2};
|
||||||
|
for (size_t i = 0; i < names.size(); i++) {
|
||||||
|
struct SaveDataMount3 mount {};
|
||||||
|
mount.user_id = 1;
|
||||||
|
mount.dir_name = &names[i];
|
||||||
|
mount.mount_mode = 4;
|
||||||
|
mount.blocks = blocks[i];
|
||||||
|
SaveDataMountResult result {};
|
||||||
|
CHECK(SaveDataMount3(&mount, &result) == OK);
|
||||||
|
CHECK(SaveDataSetParam(&result.mount_point, 4, &user_params[i], sizeof(user_params[i])) ==
|
||||||
|
OK);
|
||||||
|
CHECK(SaveDataUmount2(0, &result.mount_point) == OK);
|
||||||
|
fs::last_write_time(fs::path("_SaveData/SORTED") / names[i].data / "sce_sys/param.bin",
|
||||||
|
fs::file_time_type::clock::now() + std::chrono::hours(hours_ahead[i]));
|
||||||
|
}
|
||||||
|
const auto search = [](SaveDataSortKey key, SaveDataSortOrder order) {
|
||||||
|
std::array<SceSaveDataDirName, 3> found {};
|
||||||
|
SaveDataDirNameSearchCond cond {};
|
||||||
|
cond.user_id = 1;
|
||||||
|
cond.key = key;
|
||||||
|
cond.order = order;
|
||||||
|
SaveDataDirNameSearchResult result {};
|
||||||
|
result.dir_names = found.data();
|
||||||
|
result.dir_names_num = found.size();
|
||||||
|
CHECK(SaveDataDirNameSearch(&cond, &result) == OK && result.set_num == 3);
|
||||||
|
return std::string(found[0].data) + " " + found[1].data + " " + found[2].data;
|
||||||
|
};
|
||||||
|
CHECK(search(SaveDataSortKey::DirName, SaveDataSortOrder::Descent) == "charlie bravo alpha");
|
||||||
|
CHECK(search(SaveDataSortKey::UserParam, SaveDataSortOrder::Ascent) == "charlie alpha bravo");
|
||||||
|
CHECK(search(SaveDataSortKey::Blocks, SaveDataSortOrder::Ascent) == "bravo charlie alpha");
|
||||||
|
CHECK(search(SaveDataSortKey::FreeBlocks, SaveDataSortOrder::Descent) == "alpha charlie bravo");
|
||||||
|
CHECK(search(SaveDataSortKey::Mtime, SaveDataSortOrder::Descent) == "bravo charlie alpha");
|
||||||
|
CHECK(fs::remove("_SaveData/SORTED/alpha/sce_sys/blocks.bin"));
|
||||||
|
CHECK(search(SaveDataSortKey::Blocks, SaveDataSortOrder::Ascent) == "alpha bravo charlie");
|
||||||
|
}
|
||||||
|
|
||||||
void RunChild(const fs::path& executable, const char* mode) {
|
void RunChild(const fs::path& executable, const char* mode) {
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
CHECK(_spawnl(_P_WAIT, executable.string().c_str(), executable.string().c_str(), mode,
|
CHECK(_spawnl(_P_WAIT, executable.string().c_str(), executable.string().c_str(), mode,
|
||||||
@@ -706,6 +747,7 @@ int main(int argc, char** argv) {
|
|||||||
TestGuestSaveIsolation();
|
TestGuestSaveIsolation();
|
||||||
TestSaveAllocations();
|
TestSaveAllocations();
|
||||||
TestClassicSaveParams();
|
TestClassicSaveParams();
|
||||||
|
TestSearchSortKeys();
|
||||||
CHECK(SaveDataTerminate() == OK);
|
CHECK(SaveDataTerminate() == OK);
|
||||||
fs::current_path(previous);
|
fs::current_path(previous);
|
||||||
fs::remove_all(temp);
|
fs::remove_all(temp);
|
||||||
|
|||||||
Reference in New Issue
Block a user