Core: Handle relative paths for saves, screenshots, etc consistently (fixes #2826)

This commit is contained in:
Vicki Pfau 2023-03-16 23:37:54 -07:00
parent cd0b5193cb
commit fc35395ab8
5 changed files with 69 additions and 15 deletions

View File

@ -28,6 +28,7 @@ Other fixes:
- Scripting: Fix receiving packets for client sockets - Scripting: Fix receiving packets for client sockets
- Scripting: Fix empty receive calls returning unknown error on Windows - Scripting: Fix empty receive calls returning unknown error on Windows
Misc: Misc:
- Core: Handle relative paths for saves, screenshots, etc consistently (fixes mgba.io/i/2826)
- GB Serialize: Add missing savestate support for MBC6 and NT (newer) - GB Serialize: Add missing savestate support for MBC6 and NT (newer)
- GBA: Improve detection of valid ELF ROMs - GBA: Improve detection of valid ELF ROMs
- Qt: Include wayland QPA in AppImage (fixes mgba.io/i/2796) - Qt: Include wayland QPA in AppImage (fixes mgba.io/i/2796)

View File

@ -338,6 +338,8 @@ find_function(popcount32)
find_function(futimens) find_function(futimens)
find_function(futimes) find_function(futimes)
find_function(realpath)
if(ANDROID AND ANDROID_NDK_MAJOR GREATER 13) if(ANDROID AND ANDROID_NDK_MAJOR GREATER 13)
find_function(localtime_r) find_function(localtime_r)
set(HAVE_STRTOF_L ON) set(HAVE_STRTOF_L ON)

View File

@ -100,6 +100,9 @@ struct VFile* VFileFromFILE(FILE* file);
void separatePath(const char* path, char* dirname, char* basename, char* extension); void separatePath(const char* path, char* dirname, char* basename, char* extension);
bool isAbsolute(const char* path);
void makeAbsolute(const char* path, const char* base, char* out);
struct VFile* VDirFindFirst(struct VDir* dir, bool (*filter)(struct VFile*)); struct VFile* VDirFindFirst(struct VDir* dir, bool (*filter)(struct VFile*));
struct VFile* VDirFindNextAvailable(struct VDir*, const char* basename, const char* infix, const char* suffix, int mode); struct VFile* VDirFindNextAvailable(struct VDir*, const char* basename, const char* infix, const char* suffix, int mode);

View File

@ -116,10 +116,15 @@ struct VFile* mDirectorySetOpenSuffix(struct mDirectorySet* dirs, struct VDir* d
} }
void mDirectorySetMapOptions(struct mDirectorySet* dirs, const struct mCoreOptions* opts) { void mDirectorySetMapOptions(struct mDirectorySet* dirs, const struct mCoreOptions* opts) {
char abspath[PATH_MAX + 1];
char configDir[PATH_MAX + 1];
mCoreConfigDirectory(configDir, sizeof(configDir));
if (opts->savegamePath) { if (opts->savegamePath) {
struct VDir* dir = VDirOpen(opts->savegamePath); makeAbsolute(opts->savegamePath, configDir, abspath);
if (!dir && VDirCreate(opts->savegamePath)) { struct VDir* dir = VDirOpen(abspath);
dir = VDirOpen(opts->savegamePath); if (!dir && VDirCreate(abspath)) {
dir = VDirOpen(abspath);
} }
if (dir) { if (dir) {
if (dirs->save && dirs->save != dirs->base) { if (dirs->save && dirs->save != dirs->base) {
@ -130,9 +135,10 @@ void mDirectorySetMapOptions(struct mDirectorySet* dirs, const struct mCoreOptio
} }
if (opts->savestatePath) { if (opts->savestatePath) {
struct VDir* dir = VDirOpen(opts->savestatePath); makeAbsolute(opts->savestatePath, configDir, abspath);
if (!dir && VDirCreate(opts->savestatePath)) { struct VDir* dir = VDirOpen(abspath);
dir = VDirOpen(opts->savestatePath); if (!dir && VDirCreate(abspath)) {
dir = VDirOpen(abspath);
} }
if (dir) { if (dir) {
if (dirs->state && dirs->state != dirs->base) { if (dirs->state && dirs->state != dirs->base) {
@ -143,9 +149,10 @@ void mDirectorySetMapOptions(struct mDirectorySet* dirs, const struct mCoreOptio
} }
if (opts->screenshotPath) { if (opts->screenshotPath) {
struct VDir* dir = VDirOpen(opts->screenshotPath); makeAbsolute(opts->screenshotPath, configDir, abspath);
if (!dir && VDirCreate(opts->screenshotPath)) { struct VDir* dir = VDirOpen(abspath);
dir = VDirOpen(opts->screenshotPath); if (!dir && VDirCreate(abspath)) {
dir = VDirOpen(abspath);
} }
if (dir) { if (dir) {
if (dirs->screenshot && dirs->screenshot != dirs->base) { if (dirs->screenshot && dirs->screenshot != dirs->base) {
@ -156,9 +163,10 @@ void mDirectorySetMapOptions(struct mDirectorySet* dirs, const struct mCoreOptio
} }
if (opts->patchPath) { if (opts->patchPath) {
struct VDir* dir = VDirOpen(opts->patchPath); makeAbsolute(opts->patchPath, configDir, abspath);
if (!dir && VDirCreate(opts->patchPath)) { struct VDir* dir = VDirOpen(abspath);
dir = VDirOpen(opts->patchPath); if (!dir && VDirCreate(abspath)) {
dir = VDirOpen(abspath);
} }
if (dir) { if (dir) {
if (dirs->patch && dirs->patch != dirs->base) { if (dirs->patch && dirs->patch != dirs->base) {
@ -169,9 +177,10 @@ void mDirectorySetMapOptions(struct mDirectorySet* dirs, const struct mCoreOptio
} }
if (opts->cheatsPath) { if (opts->cheatsPath) {
struct VDir* dir = VDirOpen(opts->cheatsPath); makeAbsolute(opts->cheatsPath, configDir, abspath);
if (!dir && VDirCreate(opts->cheatsPath)) { struct VDir* dir = VDirOpen(abspath);
dir = VDirOpen(opts->cheatsPath); if (!dir && VDirCreate(abspath)) {
dir = VDirOpen(abspath);
} }
if (dir) { if (dir) {
if (dirs->cheats && dirs->cheats != dirs->base) { if (dirs->cheats && dirs->cheats != dirs->base) {

View File

@ -13,6 +13,10 @@
#ifdef __3DS__ #ifdef __3DS__
#include <mgba-util/platform/3ds/3ds-vfs.h> #include <mgba-util/platform/3ds/3ds-vfs.h>
#endif #endif
#ifdef _WIN32
#include <shlwapi.h>
#include <windows.h>
#endif
struct VFile* VFileOpen(const char* path, int flags) { struct VFile* VFileOpen(const char* path, int flags) {
#ifdef USE_VFS_FILE #ifdef USE_VFS_FILE
@ -207,6 +211,41 @@ void separatePath(const char* path, char* dirname, char* basename, char* extensi
} }
} }
bool isAbsolute(const char* path) {
// XXX: Is this robust?
#ifdef _WIN32
WCHAR wpath[PATH_MAX];
MultiByteToWideChar(CP_UTF8, 0, path, -1, wpath, PATH_MAX);
return !PathIsRelativeW(wpath);
#else
return path[0] == '/';
#endif
}
void makeAbsolute(const char* path, const char* base, char* out) {
if (isAbsolute(path)) {
strncpy(out, path, PATH_MAX);
return;
}
char buf[PATH_MAX];
snprintf(buf, sizeof(buf), "%s" PATH_SEP "%s", base, path);
#ifdef _WIN32
WCHAR wbuf[PATH_MAX];
WCHAR wout[PATH_MAX];
MultiByteToWideChar(CP_UTF8, 0, buf, -1, wbuf, PATH_MAX);
if (GetFullPathNameW(wbuf, PATH_MAX, wout, NULL)) {
WideCharToMultiByte(CP_UTF8, 0, wout, -1, out, PATH_MAX, 0, 0);
return;
}
#elif defined(HAVE_REALPATH)
if (realpath(buf, out)) {
return;
}
#endif
strncpy(out, buf, PATH_MAX);
}
struct VFile* VDirFindFirst(struct VDir* dir, bool (*filter)(struct VFile*)) { struct VFile* VDirFindFirst(struct VDir* dir, bool (*filter)(struct VFile*)) {
dir->rewind(dir); dir->rewind(dir);
struct VDirEntry* dirent = dir->listNext(dir); struct VDirEntry* dirent = dir->listNext(dir);