From c9f7faa7b1a7d1a303500dae426ed3ba1d5a08f7 Mon Sep 17 00:00:00 2001 From: Yamagi Date: Sun, 20 Jun 2021 18:20:16 +0200 Subject: [PATCH] Add logic to mark search path entries as required or optional. Until 7.45 we supported adding non existent dirs to the search path, 8.00 bails out if it cannot at a dir. It turned out that some users install the binary through their package management (SYSTEMWIDE is set), but use local game data. This case was broken, because the SYSTEMDIR doesn't exist. Fix this by marking the SYSTEMDIR as optional. Closes #724. --- src/backends/unix/system.c | 7 ++++-- src/backends/windows/system.c | 6 +++-- src/common/filesystem.c | 41 ++++++++++++++++++++++++----------- src/common/header/common.h | 2 +- 4 files changed, 38 insertions(+), 18 deletions(-) diff --git a/src/backends/unix/system.c b/src/backends/unix/system.c index 9f241440..d74e1229 100644 --- a/src/backends/unix/system.c +++ b/src/backends/unix/system.c @@ -526,18 +526,21 @@ Sys_RemoveDir(const char *path) } } -void +qboolean Sys_Realpath(const char *in, char *out, size_t size) { char *converted = realpath(in, NULL); if (converted == NULL) { - Com_Error(ERR_FATAL, "Couldn't get realpath for %s\n", in); + Com_Printf("Couldn't get realpath for %s\n", in); + return false; } Q_strlcpy(out, converted, size); free(converted); + + return true; } /* ================================================================ */ diff --git a/src/backends/windows/system.c b/src/backends/windows/system.c index 4a07ec62..c0aab129 100644 --- a/src/backends/windows/system.c +++ b/src/backends/windows/system.c @@ -593,7 +593,7 @@ Sys_RemoveDir(const char *path) RemoveDirectoryW(wpath); } -void +qboolean Sys_Realpath(const char *in, char *out, size_t size) { WCHAR win[MAX_OSPATH] = {0}; @@ -604,10 +604,12 @@ Sys_Realpath(const char *in, char *out, size_t size) if (wconverted == NULL) { - Com_Error(ERR_FATAL, "Couldn't get realpath for %s\n", in); + Com_Printf("Couldn't get realpath for %s\n", in); + return false; } WideCharToMultiByte(CP_UTF8, 0, wconverted, -1, out, size, NULL, NULL); + return true } /* ======================================================================= */ diff --git a/src/common/filesystem.c b/src/common/filesystem.c index 06341b10..486b2a3c 100644 --- a/src/common/filesystem.c +++ b/src/common/filesystem.c @@ -1836,11 +1836,19 @@ const char* FS_GetFilenameForHandle(fileHandle_t f) // -------- -void FS_AddDirToRawPath (const char *rawdir, qboolean create) { +static void FS_AddDirToRawPath (const char *rawdir, qboolean create, qboolean required) { char dir[MAX_OSPATH] = {0}; // Get the realpath. - Sys_Realpath(rawdir, dir, sizeof(dir)); + if (!Sys_Realpath(rawdir, dir, sizeof(dir))) + { + if (required) + { + Com_Error(ERR_FATAL, "Couldn't add required directory %s to search path\n", rawdir); + } + + return; + } // Convert backslashes to forward slashes. for (int i = 0; i < strlen(dir); i++) @@ -1883,36 +1891,43 @@ void FS_AddDirToRawPath (const char *rawdir, qboolean create) { void FS_BuildRawPath(void) { - // Add $HOME/.yq2 (MUST be the last dir!) + // Add $HOME/.yq2, MUST be the last dir! Required, + // otherwise the config cannot be written. if (!is_portable) { const char *homedir = Sys_GetHomeDir(); if (homedir != NULL) { - FS_AddDirToRawPath(homedir, true); + FS_AddDirToRawPath(homedir, true, true); } } - // Add $binarydir + // Add binary dir. Required, because the renderer + // libraries are loaded from it. const char *binarydir = Sys_GetBinaryDir(); if(binarydir[0] != '\0') { - FS_AddDirToRawPath(binarydir, false); + FS_AddDirToRawPath(binarydir, false, true); } - // Add $basedir/ - FS_AddDirToRawPath(datadir, false); + // Add data dir. Required, when the user gives us + // a data dir he expects it in a working state. + FS_AddDirToRawPath(datadir, false, true); - // Add SYSTEMDIR + // Add SYSTEMDIR. Optional, the user may have a + // binary compiled with SYSTEMWIDE (installed from + // packages), but no systemwide game data. #ifdef SYSTEMWIDE - FS_AddDirToRawPath(SYSTEMDIR, false); + FS_AddDirToRawPath(SYSTEMDIR, false, false); #endif // The CD must be the last directory of the path, // otherwise we cannot be sure that the game won't - // stream the videos from the CD. + // stream the videos from the CD. Required, if the + // user sets a CD path, he expects data getting + // read from the CD. if (fs_cddir->string[0] != '\0') { - FS_AddDirToRawPath(fs_cddir->string, false); + FS_AddDirToRawPath(fs_cddir->string, false, true); } } @@ -1977,4 +1992,4 @@ FS_ShutdownFilesystem(void) fs_rawPath = FS_FreeRawPaths(fs_rawPath, NULL); fs_baseSearchPaths = NULL; -} \ No newline at end of file +} diff --git a/src/common/header/common.h b/src/common/header/common.h index 8b47b304..24134095 100644 --- a/src/common/header/common.h +++ b/src/common/header/common.h @@ -825,7 +825,7 @@ void *Sys_GetGameAPI(void *parms); void Sys_UnloadGame(void); void Sys_GetWorkDir(char *buffer, size_t len); qboolean Sys_SetWorkDir(char *path); -void Sys_Realpath(const char *in, char *out, size_t size); +qboolean Sys_Realpath(const char *in, char *out, size_t size); // Windows only (system.c) #ifdef _WIN32