mirror of
https://github.com/mkxp-z/mkxp-z.git
synced 2025-09-10 03:52:55 +02:00
Improve save directory creation algorithm in libretro builds
Before, if the game tried to create a save file, missing parent directories would always be created because they could possibly exist only in the game directory and not in the save directory, and we wouldn't know due to the union mounting of the save and game directories. But this is inconsistent with the behaviour of file creation, where it should fail if parent directories don't exist. The behaviour has been changed to only create parent directories if the parent directories already exist. I know that sounds strange, but if the parent directories exist, it could be that they only exist in the game directory but not the save directory due to the union mounting, so we need to create the parent directories, which will be created in the save directory due to it being set as the write directory in PhysFS.
This commit is contained in:
parent
66256e9156
commit
d71cd242c7
3 changed files with 25 additions and 11 deletions
|
@ -813,7 +813,7 @@ extern "C" u32 w2c_wasi__snapshot__preview1_path_open(wasi_t *wasi, u32 fd, u32
|
|||
write_path_prefix = nullptr;
|
||||
}
|
||||
|
||||
struct FileSystem::File *handle = new FileSystem::File(*mkxp_retro::fs, new_path.c_str(), write_path_prefix, truncate, !exists);
|
||||
struct FileSystem::File *handle = new FileSystem::File(*mkxp_retro::fs, new_path.c_str(), write_path_prefix, truncate, exists);
|
||||
|
||||
// Check for errors opening the read handle and/or write handle
|
||||
if (!handle->is_open() || (needs_write && writable && !handle->is_write_open())) {
|
||||
|
|
|
@ -718,7 +718,17 @@ void FileSystem::openReadRaw(SDL_RWops &ops, const char *filename,
|
|||
#endif // MKXPZ_RETRO
|
||||
|
||||
#ifdef MKXPZ_RETRO
|
||||
FileSystem::File::File(FileSystem &fs, const char *read_path, const char *write_path_prefix, bool truncate, bool mkdir) {
|
||||
static std::string pop_last_path_element(const char *path) {
|
||||
std::string parent(path);
|
||||
size_t last_slash_index = parent.find_last_of('/');
|
||||
if (last_slash_index == std::string::npos) {
|
||||
last_slash_index = 0;
|
||||
}
|
||||
parent = parent.substr(0, last_slash_index);
|
||||
return parent;
|
||||
}
|
||||
|
||||
FileSystem::File::File(FileSystem &fs, const char *read_path, const char *write_path_prefix, bool truncate, unsigned char exists) {
|
||||
_path = fs.normalize(read_path, false, true);
|
||||
|
||||
if (write_path_prefix != nullptr) {
|
||||
|
@ -727,11 +737,15 @@ FileSystem::File::File(FileSystem &fs, const char *read_path, const char *write_
|
|||
if (_path.length() >= prefix_length && !strncmp(_path.c_str(), write_path_prefix, prefix_length)) {
|
||||
const char *suffix = _path.c_str() + prefix_length;
|
||||
|
||||
if (mkdir) {
|
||||
std::string suffix_parent(suffix);
|
||||
size_t last_slash_index = suffix_parent.find_last_of('/');
|
||||
if (last_slash_index != std::string::npos) {
|
||||
suffix_parent = suffix_parent.substr(0, last_slash_index);
|
||||
// If the path doesn't exist but its parent does,
|
||||
// create the parent directory in the PhysFS write directory
|
||||
// since it might only exist in PhysFS's read-only search path
|
||||
if (exists == 0 || (exists != 1 && !PHYSFS_exists(read_path))) {
|
||||
std::string suffix_parent = pop_last_path_element(suffix);
|
||||
if (suffix_parent.empty() || suffix_parent.front() != '/') {
|
||||
suffix_parent = '/' + suffix_parent;
|
||||
}
|
||||
if (suffix_parent != "/" && PHYSFS_exists((write_path_prefix + suffix_parent).c_str())) {
|
||||
PHYSFS_mkdir(suffix_parent.c_str());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -54,12 +54,12 @@ public:
|
|||
PHYSFS_ErrorCode write_error;
|
||||
|
||||
public:
|
||||
// Opens a file using PhysFS. If the file doesn't already exist, it will be created.
|
||||
// Opens a file using PhysFS. If the file doesn't already exist and write_path_prefix is non-null, it will be created.
|
||||
// read_path: Path to open the read handle for the file from.
|
||||
// write_path_prefix: Null to skip opening a write handle for the file, otherwise the write handle will be opened from the path corresponding to read_path with write_path_prefix removed from the beginning.
|
||||
// truncate: Whether or not to delete the contents of the file. Does nothing unless write_path_prefix is non-null.
|
||||
// mkdir: Whether or not to create the parent directories of the file if they don't exist. Does nothing unless write_path_prefix is non-null.
|
||||
File(FileSystem &fs, const char *read_path, const char *write_path_prefix = nullptr, bool truncate = false, bool mkdir = false);
|
||||
// truncate: Whether or not to delete the contents of the file after opening it. Does nothing unless write_path_prefix is non-null.
|
||||
// exists: If you already know whether or not the file you're opening exists, you can set this to 1 if it exists or 0 if it doesn't exist to reduce the amount of file system calls needed. Any values other than 1 or 0 mean you don't know.
|
||||
File(FileSystem &fs, const char *read_path, const char *write_path_prefix = nullptr, bool truncate = false, unsigned char exists = -1);
|
||||
File(const struct File &) = delete;
|
||||
File(struct File &&) noexcept = delete;
|
||||
struct File operator=(const struct File &) = delete;
|
||||
|
|
Loading…
Add table
Reference in a new issue