Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion core/libs/prx/libSceSaveData.native/Export.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -463,7 +463,6 @@ static int mount3(const SaveDataMount3* mount, SaveDataMountResult* mount_result
if (mount == nullptr || mount_result == nullptr || mount->dir_name == nullptr) {
throw std::runtime_error("sceSaveDataMount3: null argument");
}
std::memset(mount_result, 0, sizeof(*mount_result));
const bool create = (mount->mount_mode & SAVE_DATA_MOUNT_MODE_CREATE) != 0;
const bool create2 = (mount->mount_mode & SAVE_DATA_MOUNT_MODE_CREATE2) != 0;
const bool rdonly = (mount->mount_mode & SAVE_DATA_MOUNT_MODE_RDONLY) != 0;
Expand Down Expand Up @@ -505,6 +504,7 @@ static int mount3(const SaveDataMount3* mount, SaveDataMountResult* mount_result
// path resolver maps it to the save directory, whose name may be far longer.
const std::string mountPoint = "/savedata" + std::to_string(slot);
AddPathAlias_nid_no_patch(mountPoint.c_str(), std::filesystem::absolute(real_path).string().c_str());
std::memset(mount_result, 0, sizeof(*mount_result));
g_slots[slot].used = true;
g_slots[slot].mount_point = mountPoint;
g_slots[slot].real_path = real_path;
Expand Down
23 changes: 23 additions & 0 deletions core/libs/tests/GuestSaveDataMountStatus.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ namespace {
constexpr std::uint32_t MountReadWrite = 2;
constexpr std::uint32_t MountCreate = 4;
constexpr std::uint32_t MountCreate2 = 32;
constexpr int SaveDataErrorBusy = -2137063421;
constexpr int SaveDataErrorNotFound = -2137063416;

int failures = 0;

Expand All @@ -41,6 +43,26 @@ void MountAndCheck(const char* name, std::uint32_t mode, std::uint32_t expectedS
Check(sceSaveDataUmount2(0, &result.mount_point) == 0, what + ": unmounts");
}

void CheckFailedMountKeepsResult() {
SceSaveDataDirName held{};
std::memcpy(held.data, "held", sizeof("held"));
SaveDataMount3 mount{};
mount.dir_name = &held;
mount.mount_mode = MountReadWrite | MountCreate2;
SaveDataMountResult result{};
Check(sceSaveDataMount3(&mount, &result) == 0, "first mount of a save");
const SaveDataMountResult mounted = result;
Check(sceSaveDataMount3(&mount, &result) == SaveDataErrorBusy, "second mount of a mounted save is BUSY");
Check(std::memcmp(&result, &mounted, sizeof(result)) == 0, "a BUSY mount leaves the result as it was");
SceSaveDataDirName absent{};
std::memcpy(absent.data, "absent", sizeof("absent"));
mount.dir_name = &absent;
mount.mount_mode = MountReadWrite;
Check(sceSaveDataMount3(&mount, &result) == SaveDataErrorNotFound, "open of a missing save is NOT_FOUND");
Check(std::memcmp(&result, &mounted, sizeof(result)) == 0, "a NOT_FOUND mount leaves the result as it was");
Check(sceSaveDataUmount2(0, &result.mount_point) == 0, "the kept mount point unmounts the save");
}

}

int main() {
Expand All @@ -53,6 +75,7 @@ int main() {
MountAndCheck("fresh", MountReadWrite | MountCreate2, 0u, "CREATE2 of an existing save");
MountAndCheck("made", MountReadWrite | MountCreate, 1u, "CREATE of a missing save");
MountAndCheck("made", MountReadWrite, 0u, "open of an existing save");
CheckFailedMountKeepsResult();
std::filesystem::current_path(previous);
std::error_code error;
std::filesystem::remove_all(root, error);
Expand Down
1 change: 1 addition & 0 deletions docs/dev/debt/libSceSaveData.native.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,5 @@
### Functional

- [sceSaveDataDirNameSearch2](../../../core/libs/prx/libSceSaveData.native/Export.cpp) (libSceSaveData.native) runs the same search as `sceSaveDataDirNameSearch` with the same condition and result structures, as [SharpEmu](https://github.com/sharpemu/sharpemu/blob/main/src/SharpEmu.Libs/SaveData/SaveDataExports.cs) does, its only source; what distinguishes it on the console is unknown.
- [sceSaveDataMount3](../../../core/libs/prx/libSceSaveData.native/Export.cpp) (libSceSaveData.native) - a failed mount (BUSY, EXISTS, NOT_FOUND, MOUNT_FULL) leaves the result as it was, as shadPS4 does; not checked on hardware. Animal Well (PPSA22520) depends on it: it checks for its save with a mount it never unmounts, then saves with a second mount of the same directory, ignores its BUSY and keeps using the first mount point for `sceSaveDataPrepare`, its file and `sceSaveDataUmount2`

Loading