diff --git a/CHANGES b/CHANGES index 72ccd171d..20cf0a4f4 100644 --- a/CHANGES +++ b/CHANGES @@ -53,6 +53,7 @@ Misc: - Qt: Make mute menu option also toggle fast-forward mute (fixes mgba.io/i/1424) - Vita: L2/R2 and L3/R3 can now be mapped on PSTV (fixes mgba.io/i/1292) - mGUI: Remember name and position of last loaded game + - Core: Create game-related paths if they don't exist (fixes mgba.io/i/1446) 0.7.2: (2019-05-25) Emulation fixes: diff --git a/include/mgba-util/vfs.h b/include/mgba-util/vfs.h index f10f3c577..0ac676d5f 100644 --- a/include/mgba-util/vfs.h +++ b/include/mgba-util/vfs.h @@ -91,6 +91,8 @@ struct VDir* VDirOpen7z(const char* path, int flags); struct VDir* VDeviceList(void); #endif +bool VDirCreate(const char* path); + #ifdef USE_VFS_FILE struct VFile* VFileFOpen(const char* path, const char* mode); struct VFile* VFileFromFILE(FILE* file); diff --git a/src/core/directories.c b/src/core/directories.c index 295614a12..e2e2d2c9f 100644 --- a/src/core/directories.c +++ b/src/core/directories.c @@ -173,6 +173,9 @@ struct VFile* mDirectorySetOpenSuffix(struct mDirectorySet* dirs, struct VDir* d void mDirectorySetMapOptions(struct mDirectorySet* dirs, const struct mCoreOptions* opts) { if (opts->savegamePath) { struct VDir* dir = VDirOpen(opts->savegamePath); + if (!dir && VDirCreate(opts->savegamePath)) { + dir = VDirOpen(opts->savegamePath); + } if (dir) { if (dirs->save && dirs->save != dirs->base) { dirs->save->close(dirs->save); @@ -183,6 +186,9 @@ void mDirectorySetMapOptions(struct mDirectorySet* dirs, const struct mCoreOptio if (opts->savestatePath) { struct VDir* dir = VDirOpen(opts->savestatePath); + if (!dir && VDirCreate(opts->savestatePath)) { + dir = VDirOpen(opts->savestatePath); + } if (dir) { if (dirs->state && dirs->state != dirs->base) { dirs->state->close(dirs->state); @@ -193,6 +199,9 @@ void mDirectorySetMapOptions(struct mDirectorySet* dirs, const struct mCoreOptio if (opts->screenshotPath) { struct VDir* dir = VDirOpen(opts->screenshotPath); + if (!dir && VDirCreate(opts->screenshotPath)) { + dir = VDirOpen(opts->screenshotPath); + } if (dir) { if (dirs->screenshot && dirs->screenshot != dirs->base) { dirs->screenshot->close(dirs->screenshot); @@ -203,6 +212,9 @@ void mDirectorySetMapOptions(struct mDirectorySet* dirs, const struct mCoreOptio if (opts->patchPath) { struct VDir* dir = VDirOpen(opts->patchPath); + if (!dir && VDirCreate(opts->patchPath)) { + dir = VDirOpen(opts->patchPath); + } if (dir) { if (dirs->patch && dirs->patch != dirs->base) { dirs->patch->close(dirs->patch); @@ -213,6 +225,9 @@ void mDirectorySetMapOptions(struct mDirectorySet* dirs, const struct mCoreOptio if (opts->cheatsPath) { struct VDir* dir = VDirOpen(opts->cheatsPath); + if (!dir && VDirCreate(opts->cheatsPath)) { + dir = VDirOpen(opts->cheatsPath); + } if (dir) { if (dirs->cheats && dirs->cheats != dirs->base) { dirs->cheats->close(dirs->cheats); diff --git a/src/platform/3ds/3ds-vfs.c b/src/platform/3ds/3ds-vfs.c index 975d63fdf..8f5864745 100644 --- a/src/platform/3ds/3ds-vfs.c +++ b/src/platform/3ds/3ds-vfs.c @@ -310,4 +310,9 @@ static enum VFSType _vd3deType(struct VDirEntry* vde) { } return VFS_FILE; } + +bool VDirCreate(const char* path) { + Result rc = FSUSER_CreateDirectory(sdmcArchive, fsMakePath(PATH_ASCII, path), 0); + return R_SUCCEEDED(rc) || rc == 0xC82044BE; +} #endif diff --git a/src/platform/psp2/sce-vfs.c b/src/platform/psp2/sce-vfs.c index 383847291..c200d8903 100644 --- a/src/platform/psp2/sce-vfs.c +++ b/src/platform/psp2/sce-vfs.c @@ -357,3 +357,9 @@ static enum VFSType _vdlesceType(struct VDirEntry* vde) { UNUSED(vde); return VFS_DIRECTORY; } + +bool VDirCreate(const char* path) { + // TODO: Verify vitasdk explanation of return values + sceIoMkdir(path, 0777); + return true; +} \ No newline at end of file diff --git a/src/platform/windows/vfs-w32.c b/src/platform/windows/vfs-w32.c index 902f937f3..bfa2e30a3 100644 --- a/src/platform/windows/vfs-w32.c +++ b/src/platform/windows/vfs-w32.c @@ -172,3 +172,15 @@ static enum VFSType _vdweType(struct VDirEntry* vde) { } return VFS_FILE; } + +bool VDirCreate(const char* path) { + wchar_t wpath[MAX_PATH]; + MultiByteToWideChar(CP_UTF8, 0, path, -1, wpath, MAX_PATH); + if (CreateDirectoryW(wpath, NULL)) { + return true; + } + if (GetLastError() == ERROR_ALREADY_EXISTS) { + return true; + } + return false; +} \ No newline at end of file diff --git a/src/util/vfs/vfs-dirent.c b/src/util/vfs/vfs-dirent.c index c41c5b728..0cb060e2b 100644 --- a/src/util/vfs/vfs-dirent.c +++ b/src/util/vfs/vfs-dirent.c @@ -8,6 +8,7 @@ #include #include +#include #include static bool _vdClose(struct VDir* vd); @@ -166,3 +167,7 @@ static enum VFSType _vdeType(struct VDirEntry* vde) { return VFS_FILE; #endif } + +bool VDirCreate(const char* path) { + return mkdir(path, 0777) == 0 || errno == EEXIST; +} \ No newline at end of file