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.
This commit is contained in:
Yamagi 2021-06-20 18:20:16 +02:00
parent 21483dc1bd
commit c9f7faa7b1
4 changed files with 38 additions and 18 deletions

View file

@ -526,18 +526,21 @@ Sys_RemoveDir(const char *path)
} }
} }
void qboolean
Sys_Realpath(const char *in, char *out, size_t size) Sys_Realpath(const char *in, char *out, size_t size)
{ {
char *converted = realpath(in, NULL); char *converted = realpath(in, NULL);
if (converted == 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); Q_strlcpy(out, converted, size);
free(converted); free(converted);
return true;
} }
/* ================================================================ */ /* ================================================================ */

View file

@ -593,7 +593,7 @@ Sys_RemoveDir(const char *path)
RemoveDirectoryW(wpath); RemoveDirectoryW(wpath);
} }
void qboolean
Sys_Realpath(const char *in, char *out, size_t size) Sys_Realpath(const char *in, char *out, size_t size)
{ {
WCHAR win[MAX_OSPATH] = {0}; WCHAR win[MAX_OSPATH] = {0};
@ -604,10 +604,12 @@ Sys_Realpath(const char *in, char *out, size_t size)
if (wconverted == NULL) 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); WideCharToMultiByte(CP_UTF8, 0, wconverted, -1, out, size, NULL, NULL);
return true
} }
/* ======================================================================= */ /* ======================================================================= */

View file

@ -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}; char dir[MAX_OSPATH] = {0};
// Get the realpath. // 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. // Convert backslashes to forward slashes.
for (int i = 0; i < strlen(dir); i++) for (int i = 0; i < strlen(dir); i++)
@ -1883,36 +1891,43 @@ void FS_AddDirToRawPath (const char *rawdir, qboolean create) {
void FS_BuildRawPath(void) { 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) { if (!is_portable) {
const char *homedir = Sys_GetHomeDir(); const char *homedir = Sys_GetHomeDir();
if (homedir != NULL) { 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(); const char *binarydir = Sys_GetBinaryDir();
if(binarydir[0] != '\0') if(binarydir[0] != '\0')
{ {
FS_AddDirToRawPath(binarydir, false); FS_AddDirToRawPath(binarydir, false, true);
} }
// Add $basedir/ // Add data dir. Required, when the user gives us
FS_AddDirToRawPath(datadir, false); // 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 #ifdef SYSTEMWIDE
FS_AddDirToRawPath(SYSTEMDIR, false); FS_AddDirToRawPath(SYSTEMDIR, false, false);
#endif #endif
// The CD must be the last directory of the path, // The CD must be the last directory of the path,
// otherwise we cannot be sure that the game won't // 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') { 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_rawPath = FS_FreeRawPaths(fs_rawPath, NULL);
fs_baseSearchPaths = NULL; fs_baseSearchPaths = NULL;
} }

View file

@ -825,7 +825,7 @@ void *Sys_GetGameAPI(void *parms);
void Sys_UnloadGame(void); void Sys_UnloadGame(void);
void Sys_GetWorkDir(char *buffer, size_t len); void Sys_GetWorkDir(char *buffer, size_t len);
qboolean Sys_SetWorkDir(char *path); 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) // Windows only (system.c)
#ifdef _WIN32 #ifdef _WIN32