XDG home directory support
This commit is contained in:
parent
da4f9bd13d
commit
0ebf1df742
32
README.md
32
README.md
|
|
@ -202,6 +202,31 @@ set using command line arguments:
|
|||
ioquake3 +set cl_renderer opengl2 +set r_preferOpenGLES 1
|
||||
|
||||
|
||||
# Filesystem
|
||||
|
||||
Compared to the original release, user configuration and data files are stored
|
||||
in more modern locations. If you want a different behaviour a specific path
|
||||
can be provided by adding `+set fs_homepath <path>` to the command line.
|
||||
|
||||
### Windows
|
||||
|
||||
`C:\Users\<username>\AppData\Roaming\Quake3`
|
||||
|
||||
### macOS
|
||||
|
||||
`/Users/<username>/Library/Application Support/Quake3`
|
||||
|
||||
### Linux
|
||||
|
||||
`/home/<username>/.config/Quake3` Configuration files.
|
||||
`/home/<username>/.local/share/Quake3` Data files (pk3s etc.).
|
||||
`/home/<username>/.local/state/Quake3` Other internal runtime files.
|
||||
|
||||
These directories correspond to the Free Desktop XDG Base Directory
|
||||
Specification. The original release used `/home/.q3a`. This will be used if
|
||||
present, however in this case a prompt will be shown suggesting migration to
|
||||
the above locations, if desired.
|
||||
|
||||
# Console
|
||||
|
||||
## New cvars
|
||||
|
|
@ -480,9 +505,8 @@ binary must not detect any original quake3 game pak files. If this
|
|||
condition is met, the game will set com_standalone to 1 and is then running
|
||||
in stand alone mode.
|
||||
|
||||
If you want the engine to use a different directory in your homepath than
|
||||
e.g. "Quake3" on Windows or ".q3a" on Linux, then set a new name at startup
|
||||
by adding
|
||||
If you want the engine to use a different directory in your homepaths than
|
||||
"Quake3" then set a new name at startup by adding
|
||||
|
||||
+set com_homepath <homedirname>
|
||||
|
||||
|
|
@ -496,7 +520,7 @@ matching game name.
|
|||
|
||||
Example line:
|
||||
|
||||
+set com_basegame basefoo +set com_homepath .foo
|
||||
+set com_basegame basefoo +set com_homepath foo
|
||||
+set com_gamename foo
|
||||
|
||||
If you really changed parts that would make vanilla ioquake3 incompatible with
|
||||
|
|
|
|||
|
|
@ -71,7 +71,7 @@ void Log_Open(char *filename)
|
|||
botimport.Print(PRT_ERROR, "log file %s is already opened\n", logfile.filename);
|
||||
return;
|
||||
} //end if
|
||||
ospath = FS_BuildOSPath(Cvar_VariableString("fs_homepath"), Cvar_VariableString("fs_game"), filename);
|
||||
ospath = FS_BuildOSPath(Cvar_VariableString("fs_homestatepath"), Cvar_VariableString("fs_game"), filename);
|
||||
logfile.fp = fopen(ospath, "wb");
|
||||
if (!logfile.fp)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -335,10 +335,10 @@ qboolean CL_OpenAVIForWriting( const char *fileName )
|
|||
return qfalse;
|
||||
}
|
||||
|
||||
if( ( afd.f = FS_FOpenFileWrite( fileName ) ) <= 0 )
|
||||
if( ( afd.f = FS_FOpenFileWrite_HomeData( fileName ) ) <= 0 )
|
||||
return qfalse;
|
||||
|
||||
if( ( afd.idxF = FS_FOpenFileWrite(
|
||||
if( ( afd.idxF = FS_FOpenFileWrite_HomeData(
|
||||
va( "%s" INDEX_FILE_EXTENSION, fileName ) ) ) <= 0 )
|
||||
{
|
||||
FS_FCloseFile( afd.f );
|
||||
|
|
@ -635,7 +635,7 @@ qboolean CL_CloseAVI( void )
|
|||
FS_FCloseFile( afd.idxF );
|
||||
|
||||
// Remove temp index file
|
||||
FS_HomeRemove( idxFileName );
|
||||
FS_Remove_HomeData( idxFileName );
|
||||
|
||||
// Write the real header
|
||||
FS_Seek( afd.f, 0, FS_SEEK_SET );
|
||||
|
|
|
|||
|
|
@ -201,7 +201,7 @@ void Con_Dump_f (void)
|
|||
return;
|
||||
}
|
||||
|
||||
f = FS_FOpenFileWrite( filename );
|
||||
f = FS_FOpenFileWrite_HomeData( filename );
|
||||
if (!f)
|
||||
{
|
||||
Com_Printf ("ERROR: couldn't open %s.\n", filename);
|
||||
|
|
|
|||
|
|
@ -1577,7 +1577,7 @@ void CL_SaveConsoleHistory( void )
|
|||
|
||||
consoleSaveBufferSize = strlen( consoleSaveBuffer );
|
||||
|
||||
f = FS_FOpenFileWrite( CONSOLE_HISTORY_FILE );
|
||||
f = FS_FOpenFileWrite_HomeState( CONSOLE_HISTORY_FILE );
|
||||
if( !f )
|
||||
{
|
||||
Com_Printf( "Couldn't write %s.\n", CONSOLE_HISTORY_FILE );
|
||||
|
|
|
|||
|
|
@ -742,7 +742,7 @@ void CL_Record_f( void ) {
|
|||
#endif
|
||||
Com_sprintf(name, sizeof(name), "demos/%s.%s%d", demoName, DEMOEXT, com_protocol->integer);
|
||||
|
||||
if (!FS_FileExists(name))
|
||||
if (!FS_FileExists_HomeData(name))
|
||||
break; // file doesn't exist
|
||||
}
|
||||
}
|
||||
|
|
@ -750,7 +750,7 @@ void CL_Record_f( void ) {
|
|||
// open the demo file
|
||||
|
||||
Com_Printf ("recording to %s.\n", name);
|
||||
clc.demofile = FS_FOpenFileWrite( name );
|
||||
clc.demofile = FS_FOpenFileWrite_HomeData( name );
|
||||
if ( !clc.demofile ) {
|
||||
Com_Printf ("ERROR: couldn't open.\n");
|
||||
return;
|
||||
|
|
@ -903,7 +903,7 @@ void CL_DemoCompleted( void )
|
|||
else
|
||||
numFrames = clc.timeDemoFrames - 1;
|
||||
|
||||
f = FS_FOpenFileWrite( cl_timedemoLog->string );
|
||||
f = FS_FOpenFileWrite_HomeData( cl_timedemoLog->string );
|
||||
if( f )
|
||||
{
|
||||
FS_Printf( f, "# %s", buffer );
|
||||
|
|
@ -2197,7 +2197,7 @@ static void CL_BeginHttpDownload( const char *remoteURL ) {
|
|||
CL_HTTP_BeginDownload(remoteURL);
|
||||
Q_strncpyz(clc.downloadURL, remoteURL, sizeof(clc.downloadURL));
|
||||
|
||||
clc.download = FS_BaseDir_FOpenFileWrite(clc.downloadTempName);
|
||||
clc.download = FS_BaseDir_FOpenFileWrite_HomeData(clc.downloadTempName);
|
||||
if(!clc.download) {
|
||||
Com_Error(ERR_DROP, "CL_BeginHTTPDownload: failed to open "
|
||||
"%s for writing", clc.downloadTempName);
|
||||
|
|
@ -2233,7 +2233,7 @@ void CL_NextDownload(void)
|
|||
// A download has finished, check whether this matches a referenced checksum
|
||||
if(*clc.downloadName)
|
||||
{
|
||||
char *zippath = FS_BaseDir_BuildOSPath(Cvar_VariableString("fs_homepath"), clc.downloadName);
|
||||
char *zippath = FS_BaseDir_BuildOSPath(Cvar_VariableString("fs_homedatapath"), clc.downloadName);
|
||||
|
||||
if(!FS_CompareZipChecksum(zippath))
|
||||
Com_Error(ERR_DROP, "Incorrect checksum for file: %s", clc.downloadName);
|
||||
|
|
@ -2977,7 +2977,7 @@ void CL_Frame ( int msec ) {
|
|||
clc.download = 0;
|
||||
}
|
||||
|
||||
FS_BaseDir_Rename(clc.downloadTempName, clc.downloadName, qfalse);
|
||||
FS_BaseDir_Rename_HomeData(clc.downloadTempName, clc.downloadName, qfalse);
|
||||
clc.downloadRestart = qtrue;
|
||||
CL_NextDownload();
|
||||
}
|
||||
|
|
@ -3307,7 +3307,7 @@ void CL_InitRef( void ) {
|
|||
ri.FS_FreeFileList = FS_FreeFileList;
|
||||
ri.FS_ListFiles = FS_ListFiles;
|
||||
ri.FS_FileIsInPAK = FS_FileIsInPAK;
|
||||
ri.FS_FileExists = FS_FileExists;
|
||||
ri.FS_FileExists = FS_FileExists_HomeData;
|
||||
ri.Cvar_Get = Cvar_Get;
|
||||
ri.Cvar_Set = Cvar_Set;
|
||||
ri.Cvar_SetValue = Cvar_SetValue;
|
||||
|
|
@ -3418,7 +3418,7 @@ void CL_Video_f( void )
|
|||
Com_sprintf( filename, MAX_OSPATH, "videos/video%d%d%d%d.avi",
|
||||
a, b, c, d );
|
||||
|
||||
if( !FS_FileExists( filename ) )
|
||||
if( !FS_FileExists_HomeData( filename ) )
|
||||
break; // file doesn't exist
|
||||
}
|
||||
|
||||
|
|
@ -3471,7 +3471,7 @@ static void CL_GenerateQKey(void)
|
|||
Com_Printf( "QKEY building random string\n" );
|
||||
Com_RandomBytes( buff, sizeof(buff) );
|
||||
|
||||
f = FS_BaseDir_FOpenFileWrite( QKEY_FILE );
|
||||
f = FS_BaseDir_FOpenFileWrite_HomeState( QKEY_FILE );
|
||||
if( !f ) {
|
||||
Com_Printf( "QKEY could not open %s for write\n",
|
||||
QKEY_FILE );
|
||||
|
|
|
|||
|
|
@ -608,7 +608,7 @@ void CL_ParseDownload ( msg_t *msg ) {
|
|||
// open the file if not opened yet
|
||||
if (!clc.download)
|
||||
{
|
||||
clc.download = FS_BaseDir_FOpenFileWrite( clc.downloadTempName );
|
||||
clc.download = FS_BaseDir_FOpenFileWrite_HomeData( clc.downloadTempName );
|
||||
|
||||
if (!clc.download) {
|
||||
Com_Printf( "Could not create %s\n", clc.downloadTempName );
|
||||
|
|
@ -635,7 +635,7 @@ void CL_ParseDownload ( msg_t *msg ) {
|
|||
clc.download = 0;
|
||||
|
||||
// rename the file
|
||||
FS_BaseDir_Rename ( clc.downloadTempName, clc.downloadName, qfalse );
|
||||
FS_BaseDir_Rename_HomeData ( clc.downloadTempName, clc.downloadName, qfalse );
|
||||
}
|
||||
|
||||
// send intentions now
|
||||
|
|
|
|||
|
|
@ -74,7 +74,7 @@ LAN_SaveServersToCache
|
|||
*/
|
||||
void LAN_SaveServersToCache( void ) {
|
||||
int size;
|
||||
fileHandle_t fileOut = FS_BaseDir_FOpenFileWrite("servercache.dat");
|
||||
fileHandle_t fileOut = FS_BaseDir_FOpenFileWrite_HomeState("servercache.dat");
|
||||
FS_Write(&cls.numglobalservers, sizeof(int), fileOut);
|
||||
FS_Write(&cls.numfavoriteservers, sizeof(int), fileOut);
|
||||
size = sizeof(cls.globalServers) + sizeof(cls.favoriteServers);
|
||||
|
|
|
|||
|
|
@ -205,7 +205,7 @@ void QDECL Com_Printf( const char *fmt, ... ) {
|
|||
time( &aclock );
|
||||
newtime = localtime( &aclock );
|
||||
|
||||
logfile = FS_FOpenFileWrite( "qconsole.log" );
|
||||
logfile = FS_FOpenFileWrite_HomeData( "qconsole.log" );
|
||||
|
||||
if(logfile)
|
||||
{
|
||||
|
|
@ -1921,8 +1921,8 @@ void Com_InitJournaling( void ) {
|
|||
|
||||
if ( com_journal->integer == 1 ) {
|
||||
Com_Printf( "Journaling events\n");
|
||||
com_journalFile = FS_FOpenFileWrite( "journal.dat" );
|
||||
com_journalDataFile = FS_FOpenFileWrite( "journaldata.dat" );
|
||||
com_journalFile = FS_FOpenFileWrite_HomeState( "journal.dat" );
|
||||
com_journalDataFile = FS_FOpenFileWrite_HomeState( "journaldata.dat" );
|
||||
} else if ( com_journal->integer == 2 ) {
|
||||
Com_Printf( "Replaying journaled events\n");
|
||||
FS_FOpenFileRead( "journal.dat", &com_journalFile, qtrue );
|
||||
|
|
@ -2547,7 +2547,7 @@ static void Com_WriteCDKey( const char *filename, const char *ikey ) {
|
|||
#ifndef _WIN32
|
||||
savedumask = umask(0077);
|
||||
#endif
|
||||
f = FS_BaseDir_FOpenFileWrite( fbuffer );
|
||||
f = FS_BaseDir_FOpenFileWrite_HomeState( fbuffer );
|
||||
if ( !f ) {
|
||||
Com_Printf ("Couldn't write CD key to %s.\n", fbuffer );
|
||||
goto out;
|
||||
|
|
@ -2921,7 +2921,7 @@ void Com_ReadFromPipe( void )
|
|||
void Com_WriteConfigToFile( const char *filename ) {
|
||||
fileHandle_t f;
|
||||
|
||||
f = FS_FOpenFileWrite( filename );
|
||||
f = FS_FOpenFileWrite_HomeConfig( filename );
|
||||
if ( !f ) {
|
||||
Com_Printf ("Couldn't write %s.\n", filename );
|
||||
return;
|
||||
|
|
@ -3293,7 +3293,7 @@ void Com_Shutdown (void) {
|
|||
|
||||
if( pipefile ) {
|
||||
FS_FCloseFile( pipefile );
|
||||
FS_HomeRemove( com_pipefile->string );
|
||||
FS_Remove_HomeData( com_pipefile->string );
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -246,7 +246,9 @@ typedef struct searchpath_s {
|
|||
|
||||
static char fs_gamedir[MAX_OSPATH]; // this will be a single file name with no separators
|
||||
static cvar_t *fs_debug;
|
||||
static cvar_t *fs_homepath;
|
||||
static cvar_t *fs_homeconfigpath;
|
||||
static cvar_t *fs_homedatapath;
|
||||
static cvar_t *fs_homestatepath;
|
||||
|
||||
static cvar_t *fs_apppath;
|
||||
static cvar_t *fs_steampath;
|
||||
|
|
@ -609,14 +611,14 @@ void FS_Remove( const char *osPath ) {
|
|||
|
||||
/*
|
||||
===========
|
||||
FS_HomeRemove
|
||||
FS_Remove_HomeData
|
||||
|
||||
===========
|
||||
*/
|
||||
void FS_HomeRemove( const char *homePath ) {
|
||||
void FS_Remove_HomeData( const char *homePath ) {
|
||||
FS_CheckFilenameIsMutable( homePath, __func__ );
|
||||
|
||||
remove( FS_BuildOSPath( fs_homepath->string,
|
||||
remove( FS_BuildOSPath( fs_homedatapath->string,
|
||||
fs_gamedir, homePath ) );
|
||||
}
|
||||
|
||||
|
|
@ -644,7 +646,7 @@ qboolean FS_FileInPathExists(const char *testpath)
|
|||
|
||||
/*
|
||||
================
|
||||
FS_FileExists
|
||||
FS_FileExists_HomeData
|
||||
|
||||
Tests if the file exists in the current gamedir, this DOES NOT
|
||||
search the paths. This is to determine if opening a file to write
|
||||
|
|
@ -652,21 +654,21 @@ search the paths. This is to determine if opening a file to write
|
|||
NOTE TTimo: this goes with FS_FOpenFileWrite for opening the file afterwards
|
||||
================
|
||||
*/
|
||||
qboolean FS_FileExists(const char *file)
|
||||
qboolean FS_FileExists_HomeData(const char *file)
|
||||
{
|
||||
return FS_FileInPathExists(FS_BuildOSPath(fs_homepath->string, fs_gamedir, file));
|
||||
return FS_FileInPathExists(FS_BuildOSPath(fs_homedatapath->string, fs_gamedir, file));
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
FS_BaseDir_FileExists
|
||||
FS_BaseDir_FileExists_HomeData
|
||||
|
||||
Tests if the file exists
|
||||
================
|
||||
*/
|
||||
qboolean FS_BaseDir_FileExists( const char *file )
|
||||
static qboolean FS_BaseDir_FileExists_HomeData( const char *file )
|
||||
{
|
||||
return FS_FileInPathExists(FS_BaseDir_BuildOSPath(fs_homepath->string, file));
|
||||
return FS_FileInPathExists(FS_BaseDir_BuildOSPath(fs_homedatapath->string, file));
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -708,13 +710,32 @@ static fileHandle_t FS_OSPath_FOpenFileWrite( const char *ospath, const char *fi
|
|||
|
||||
/*
|
||||
===========
|
||||
FS_BaseDir_FOpenFileWrite
|
||||
|
||||
FS_BaseDir_FOpenFileWrite_HomeConfig
|
||||
===========
|
||||
*/
|
||||
fileHandle_t FS_BaseDir_FOpenFileWrite( const char *filename ) {
|
||||
fileHandle_t FS_BaseDir_FOpenFileWrite_HomeConfig( const char *filename ) {
|
||||
return FS_OSPath_FOpenFileWrite(
|
||||
FS_BaseDir_BuildOSPath(fs_homepath->string, filename), filename);
|
||||
FS_BaseDir_BuildOSPath(fs_homeconfigpath->string, filename), filename);
|
||||
}
|
||||
|
||||
/*
|
||||
===========
|
||||
FS_BaseDir_FOpenFileWrite_HomeData
|
||||
===========
|
||||
*/
|
||||
fileHandle_t FS_BaseDir_FOpenFileWrite_HomeData( const char *filename ) {
|
||||
return FS_OSPath_FOpenFileWrite(
|
||||
FS_BaseDir_BuildOSPath(fs_homedatapath->string, filename), filename);
|
||||
}
|
||||
|
||||
/*
|
||||
===========
|
||||
FS_BaseDir_FOpenFileWrite_HomeState
|
||||
===========
|
||||
*/
|
||||
fileHandle_t FS_BaseDir_FOpenFileWrite_HomeState( const char *filename ) {
|
||||
return FS_OSPath_FOpenFileWrite(
|
||||
FS_BaseDir_BuildOSPath(fs_homestatepath->string, filename), filename);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -776,11 +797,11 @@ long FS_BaseDir_FOpenFileRead(const char *filename, fileHandle_t *fp)
|
|||
|
||||
/*
|
||||
===========
|
||||
FS_BaseDir_Rename
|
||||
FS_BaseDir_Rename_HomeData
|
||||
|
||||
===========
|
||||
*/
|
||||
void FS_BaseDir_Rename( const char *from, const char *to, qboolean safe ) {
|
||||
void FS_BaseDir_Rename_HomeData( const char *from, const char *to, qboolean safe ) {
|
||||
char *from_ospath, *to_ospath;
|
||||
|
||||
if ( !fs_searchpaths ) {
|
||||
|
|
@ -790,11 +811,11 @@ void FS_BaseDir_Rename( const char *from, const char *to, qboolean safe ) {
|
|||
// don't let sound stutter
|
||||
S_ClearSoundBuffer();
|
||||
|
||||
from_ospath = FS_BaseDir_BuildOSPath( fs_homepath->string, from );
|
||||
to_ospath = FS_BaseDir_BuildOSPath( fs_homepath->string, to );
|
||||
from_ospath = FS_BaseDir_BuildOSPath( fs_homedatapath->string, from );
|
||||
to_ospath = FS_BaseDir_BuildOSPath( fs_homedatapath->string, to );
|
||||
|
||||
if ( fs_debug->integer ) {
|
||||
Com_Printf( "FS_BaseDir_Rename: %s --> %s\n", from_ospath, to_ospath );
|
||||
Com_Printf( "FS_BaseDir_Rename_HomeData: %s --> %s\n", from_ospath, to_ospath );
|
||||
}
|
||||
|
||||
if ( safe ) {
|
||||
|
|
@ -837,22 +858,41 @@ void FS_FCloseFile( fileHandle_t f ) {
|
|||
|
||||
/*
|
||||
===========
|
||||
FS_FOpenFileWrite
|
||||
|
||||
FS_FOpenFileWrite_HomeConfig
|
||||
===========
|
||||
*/
|
||||
fileHandle_t FS_FOpenFileWrite( const char *filename ) {
|
||||
fileHandle_t FS_FOpenFileWrite_HomeConfig( const char *filename ) {
|
||||
return FS_OSPath_FOpenFileWrite(
|
||||
FS_BuildOSPath(fs_homepath->string, fs_gamedir, filename), filename);
|
||||
FS_BuildOSPath(fs_homeconfigpath->string, fs_gamedir, filename), filename);
|
||||
}
|
||||
|
||||
/*
|
||||
===========
|
||||
FS_FOpenFileAppend
|
||||
FS_FOpenFileWrite_HomeData
|
||||
===========
|
||||
*/
|
||||
fileHandle_t FS_FOpenFileWrite_HomeData( const char *filename ) {
|
||||
return FS_OSPath_FOpenFileWrite(
|
||||
FS_BuildOSPath(fs_homedatapath->string, fs_gamedir, filename), filename);
|
||||
}
|
||||
|
||||
/*
|
||||
===========
|
||||
FS_FOpenFileWrite_HomeState
|
||||
===========
|
||||
*/
|
||||
fileHandle_t FS_FOpenFileWrite_HomeState( const char *filename ) {
|
||||
return FS_OSPath_FOpenFileWrite(
|
||||
FS_BuildOSPath(fs_homestatepath->string, fs_gamedir, filename), filename);
|
||||
}
|
||||
|
||||
/*
|
||||
===========
|
||||
FS_FOpenFileAppend_HomeData
|
||||
|
||||
===========
|
||||
*/
|
||||
fileHandle_t FS_FOpenFileAppend( const char *filename ) {
|
||||
fileHandle_t FS_FOpenFileAppend_HomeData( const char *filename ) {
|
||||
char *ospath;
|
||||
fileHandle_t f;
|
||||
|
||||
|
|
@ -868,10 +908,10 @@ fileHandle_t FS_FOpenFileAppend( const char *filename ) {
|
|||
// don't let sound stutter
|
||||
S_ClearSoundBuffer();
|
||||
|
||||
ospath = FS_BuildOSPath( fs_homepath->string, fs_gamedir, filename );
|
||||
ospath = FS_BuildOSPath( fs_homedatapath->string, fs_gamedir, filename );
|
||||
|
||||
if ( fs_debug->integer ) {
|
||||
Com_Printf( "FS_FOpenFileAppend: %s\n", ospath );
|
||||
Com_Printf( "FS_FOpenFileAppend_HomeData: %s\n", ospath );
|
||||
}
|
||||
|
||||
FS_CheckFilenameIsMutable( ospath, __func__ );
|
||||
|
|
@ -911,7 +951,7 @@ fileHandle_t FS_FCreateOpenPipeFile( const char *filename ) {
|
|||
// don't let sound stutter
|
||||
S_ClearSoundBuffer();
|
||||
|
||||
ospath = FS_BuildOSPath( fs_homepath->string, fs_gamedir, filename );
|
||||
ospath = FS_BuildOSPath( fs_homedatapath->string, fs_gamedir, filename );
|
||||
|
||||
if ( fs_debug->integer ) {
|
||||
Com_Printf( "FS_FCreateOpenPipeFile: %s\n", ospath );
|
||||
|
|
@ -1237,7 +1277,7 @@ long FS_FOpenFileReadDir(const char *filename, searchpath_t *search, fileHandle_
|
|||
// if you are using FS_ReadFile to find out if a file exists,
|
||||
// this test can make the search fail although the file is in the directory
|
||||
// I had the problem on https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=8
|
||||
// turned out I used FS_FileExists instead
|
||||
// turned out I used FS_FileExists_HomeData instead
|
||||
if(!unpure && fs_numServerPaks)
|
||||
{
|
||||
if(!FS_IsExt(filename, ".cfg", len) && // for config files
|
||||
|
|
@ -1909,7 +1949,7 @@ void FS_WriteFile( const char *qpath, const void *buffer, int size ) {
|
|||
Com_Error( ERR_FATAL, "FS_WriteFile: NULL parameter" );
|
||||
}
|
||||
|
||||
f = FS_FOpenFileWrite( qpath );
|
||||
f = FS_FOpenFileWrite_HomeData( qpath );
|
||||
if ( !f ) {
|
||||
Com_Printf( "Failed to open %s\n", qpath );
|
||||
return;
|
||||
|
|
@ -3132,7 +3172,7 @@ qboolean FS_ComparePaks( char *neededpaks, int len, qboolean dlstring ) {
|
|||
// Local name
|
||||
Q_strcat( neededpaks, len, "@");
|
||||
// Do we have one with the same name?
|
||||
if ( FS_BaseDir_FileExists( va( "%s.pk3", fs_serverReferencedPakNames[i] ) ) )
|
||||
if ( FS_BaseDir_FileExists_HomeData( va( "%s.pk3", fs_serverReferencedPakNames[i] ) ) )
|
||||
{
|
||||
char st[MAX_ZPATH];
|
||||
// We already have one called this, we need to download it to another name
|
||||
|
|
@ -3159,7 +3199,7 @@ qboolean FS_ComparePaks( char *neededpaks, int len, qboolean dlstring ) {
|
|||
Q_strcat( neededpaks, len, fs_serverReferencedPakNames[i] );
|
||||
Q_strcat( neededpaks, len, ".pk3" );
|
||||
// Do we have one with the same name?
|
||||
if ( FS_BaseDir_FileExists( va( "%s.pk3", fs_serverReferencedPakNames[i] ) ) )
|
||||
if ( FS_BaseDir_FileExists_HomeData( va( "%s.pk3", fs_serverReferencedPakNames[i] ) ) )
|
||||
{
|
||||
Q_strcat( neededpaks, len, " (local file exists with wrong checksum)");
|
||||
}
|
||||
|
|
@ -3302,7 +3342,9 @@ FS_InitPathVars
|
|||
static void FS_InitPathVars( void ) {
|
||||
memset( fs_pathVars, 0, sizeof( fs_pathVars ) );
|
||||
|
||||
FS_AddPathVar( fs_homepath );
|
||||
FS_AddPathVar( fs_homeconfigpath );
|
||||
FS_AddPathVar( fs_homedatapath );
|
||||
FS_AddPathVar( fs_homestatepath );
|
||||
FS_AddPathVar( fs_basepath );
|
||||
FS_AddPathVar( fs_apppath );
|
||||
FS_AddPathVar( fs_steampath );
|
||||
|
|
@ -3317,7 +3359,18 @@ FS_Startup
|
|||
*/
|
||||
static void FS_Startup( const char *gameName )
|
||||
{
|
||||
const char *homePath;
|
||||
cvar_t *fs_homepath = Cvar_Get("fs_homepath", "", CVAR_INIT|CVAR_PROTECTED);
|
||||
const char *configPath = Sys_DefaultHomeConfigPath();
|
||||
const char *dataPath = Sys_DefaultHomeDataPath();
|
||||
const char *statePath = Sys_DefaultHomeStatePath();
|
||||
|
||||
if(*(fs_homepath)->string) {
|
||||
// Setting fs_homepath manually overrides everything else
|
||||
configPath = dataPath = statePath = fs_homepath->string;
|
||||
} else if(!*configPath || !*dataPath || !*statePath) {
|
||||
// #shouldneverhappen; just a sensible fallback
|
||||
configPath = dataPath = statePath = Sys_DefaultInstallPath();
|
||||
}
|
||||
|
||||
Com_Printf( "----- FS_Startup -----\n" );
|
||||
|
||||
|
|
@ -3326,11 +3379,9 @@ static void FS_Startup( const char *gameName )
|
|||
fs_debug = Cvar_Get( "fs_debug", "0", 0 );
|
||||
fs_basepath = Cvar_Get ("fs_basepath", Sys_DefaultInstallPath(), CVAR_INIT|CVAR_PROTECTED );
|
||||
fs_basegame = Cvar_Get ("fs_basegame", "", CVAR_INIT );
|
||||
homePath = Sys_DefaultHomePath();
|
||||
if (!homePath || !homePath[0]) {
|
||||
homePath = fs_basepath->string;
|
||||
}
|
||||
fs_homepath = Cvar_Get ("fs_homepath", homePath, CVAR_INIT|CVAR_PROTECTED );
|
||||
fs_homeconfigpath = Cvar_Get ("fs_homeconfigpath", configPath, CVAR_INIT|CVAR_PROTECTED );
|
||||
fs_homedatapath = Cvar_Get ("fs_homedatapath", dataPath, CVAR_INIT|CVAR_PROTECTED );
|
||||
fs_homestatepath = Cvar_Get ("fs_homestatepath", statePath, CVAR_INIT|CVAR_PROTECTED );
|
||||
fs_gamedirvar = Cvar_Get ("fs_game", "", CVAR_INIT|CVAR_SYSTEMINFO );
|
||||
fs_steampath = Cvar_Get ("fs_steampath", Sys_SteamPath(), CVAR_INIT|CVAR_PROTECTED );
|
||||
fs_gogpath = Cvar_Get ("fs_gogpath", Sys_GogPath(), CVAR_INIT|CVAR_PROTECTED );
|
||||
|
|
@ -3363,9 +3414,9 @@ static void FS_Startup( const char *gameName )
|
|||
Com_Error( ERR_DROP, "Invalid fs_game '%s'", fs_gamedirvar->string );
|
||||
}
|
||||
|
||||
if (fs_homepath->string[0] && Q_stricmp(fs_homepath->string, fs_basepath->string)) {
|
||||
FS_CreatePath ( fs_homepath->string );
|
||||
}
|
||||
FS_CreatePath(fs_homeconfigpath->string);
|
||||
FS_CreatePath(fs_homedatapath->string);
|
||||
FS_CreatePath(fs_homestatepath->string);
|
||||
|
||||
FS_AddGameDirectories(gameName);
|
||||
|
||||
|
|
@ -3639,7 +3690,7 @@ static void FS_CheckPak0( void )
|
|||
#endif
|
||||
|
||||
if(installHome)
|
||||
installPath = fs_homepath->string;
|
||||
installPath = fs_homedatapath->string;
|
||||
else
|
||||
installPath = fs_basepath->string;
|
||||
|
||||
|
|
@ -4059,6 +4110,9 @@ void FS_InitFilesystem( void ) {
|
|||
// has already been initialized
|
||||
Com_StartupVariable("fs_basepath");
|
||||
Com_StartupVariable("fs_homepath");
|
||||
Com_StartupVariable("fs_homeconfigpath");
|
||||
Com_StartupVariable("fs_homedatapath");
|
||||
Com_StartupVariable("fs_homestatepath");
|
||||
Com_StartupVariable("fs_game");
|
||||
|
||||
if(!FS_FilenameCompare(Cvar_VariableString("fs_game"), com_basegame->string))
|
||||
|
|
@ -4201,7 +4255,7 @@ int FS_FOpenFileByMode( const char *qpath, fileHandle_t *f, fsMode_t mode ) {
|
|||
r = FS_FOpenFileRead( qpath, f, qtrue );
|
||||
break;
|
||||
case FS_WRITE:
|
||||
*f = FS_FOpenFileWrite( qpath );
|
||||
*f = FS_FOpenFileWrite_HomeData( qpath );
|
||||
r = 0;
|
||||
if (*f == 0) {
|
||||
r = -1;
|
||||
|
|
@ -4210,7 +4264,7 @@ int FS_FOpenFileByMode( const char *qpath, fileHandle_t *f, fsMode_t mode ) {
|
|||
case FS_APPEND_SYNC:
|
||||
sync = qtrue;
|
||||
case FS_APPEND:
|
||||
*f = FS_FOpenFileAppend( qpath );
|
||||
*f = FS_FOpenFileAppend_HomeData( qpath );
|
||||
r = 0;
|
||||
if (*f == 0) {
|
||||
r = -1;
|
||||
|
|
|
|||
|
|
@ -31,9 +31,8 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|||
#define BASEGAME "foobar"
|
||||
#define CLIENT_WINDOW_TITLE "changeme"
|
||||
#define CLIENT_WINDOW_MIN_TITLE "changeme2"
|
||||
#define HOMEPATH_NAME_UNIX ".foo"
|
||||
#define HOMEPATH_NAME_WIN "FooBar"
|
||||
#define HOMEPATH_NAME_MACOSX HOMEPATH_NAME_WIN
|
||||
#define HOMEPATH_NAME_UNIX_LEGACY ".foo"
|
||||
#define HOMEPATH_NAME "FooBar"
|
||||
#define GAMENAME_FOR_MASTER "foobar" // must NOT contain whitespace
|
||||
#define CINEMATICS_LOGO "foologo.roq"
|
||||
#define CINEMATICS_INTRO "intro.roq"
|
||||
|
|
@ -45,9 +44,8 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|||
#define BASEGAME "baseq3"
|
||||
#define CLIENT_WINDOW_TITLE "ioquake3"
|
||||
#define CLIENT_WINDOW_MIN_TITLE "ioq3"
|
||||
#define HOMEPATH_NAME_UNIX ".q3a"
|
||||
#define HOMEPATH_NAME_WIN "Quake3"
|
||||
#define HOMEPATH_NAME_MACOSX HOMEPATH_NAME_WIN
|
||||
#define HOMEPATH_NAME_UNIX_LEGACY ".q3a"
|
||||
#define HOMEPATH_NAME "Quake3"
|
||||
#define GAMENAME_FOR_MASTER "Quake3Arena"
|
||||
#define CINEMATICS_LOGO "idlogo.RoQ"
|
||||
#define CINEMATICS_INTRO "intro.RoQ"
|
||||
|
|
|
|||
|
|
@ -616,7 +616,7 @@ char **FS_ListFiles( const char *directory, const char *extension, int *numfiles
|
|||
|
||||
void FS_FreeFileList( char **list );
|
||||
|
||||
qboolean FS_FileExists( const char *file );
|
||||
qboolean FS_FileExists_HomeData( const char *file );
|
||||
|
||||
qboolean FS_CreatePath (const char *OSPath);
|
||||
|
||||
|
|
@ -633,14 +633,18 @@ int FS_GetModList( char *listbuf, int bufsize );
|
|||
|
||||
void FS_GetModDescription( const char *modDir, char *description, int descriptionLen );
|
||||
|
||||
fileHandle_t FS_FOpenFileWrite( const char *qpath );
|
||||
fileHandle_t FS_FOpenFileAppend( const char *filename );
|
||||
fileHandle_t FS_FOpenFileWrite_HomeConfig( const char *filename );
|
||||
fileHandle_t FS_FOpenFileWrite_HomeData( const char *filename );
|
||||
fileHandle_t FS_FOpenFileWrite_HomeState( const char *filename );
|
||||
fileHandle_t FS_FOpenFileAppend_HomeData( const char *filename );
|
||||
fileHandle_t FS_FCreateOpenPipeFile( const char *filename );
|
||||
// will properly create any needed paths and deal with seperater character issues
|
||||
|
||||
fileHandle_t FS_BaseDir_FOpenFileWrite( const char *filename );
|
||||
fileHandle_t FS_BaseDir_FOpenFileWrite_HomeConfig( const char *filename );
|
||||
fileHandle_t FS_BaseDir_FOpenFileWrite_HomeData( const char *filename );
|
||||
fileHandle_t FS_BaseDir_FOpenFileWrite_HomeState( const char *filename );
|
||||
long FS_BaseDir_FOpenFileRead( const char *filename, fileHandle_t *fp );
|
||||
void FS_BaseDir_Rename( const char *from, const char *to, qboolean safe );
|
||||
void FS_BaseDir_Rename_HomeData( const char *from, const char *to, qboolean safe );
|
||||
long FS_FOpenFileRead( const char *qpath, fileHandle_t *file, qboolean uniqueFILE );
|
||||
// if uniqueFILE is true, then a new FILE will be fopened even if the file
|
||||
// is found in an already open pak file. If uniqueFILE is false, you must call
|
||||
|
|
@ -725,7 +729,7 @@ qboolean FS_idPak(char *pak, char *base, int numPaks);
|
|||
qboolean FS_ComparePaks( char *neededpaks, int len, qboolean dlstring );
|
||||
|
||||
void FS_Remove( const char *osPath );
|
||||
void FS_HomeRemove( const char *homePath );
|
||||
void FS_Remove_HomeData( const char *homePath );
|
||||
|
||||
void FS_FilenameCompletion( const char *dir, const char *ext, char *filter,
|
||||
qboolean stripExt, void(*callback)(const char *s), qboolean allowNonPureFilesOnDisk );
|
||||
|
|
@ -1122,7 +1126,9 @@ char *Sys_MicrosoftStorePath(void);
|
|||
char *Sys_DefaultAppPath(void);
|
||||
#endif
|
||||
|
||||
char *Sys_DefaultHomePath(void);
|
||||
char *Sys_DefaultHomeConfigPath(void);
|
||||
char *Sys_DefaultHomeDataPath(void);
|
||||
char *Sys_DefaultHomeStatePath(void);
|
||||
const char *Sys_Dirname( char *path );
|
||||
const char *Sys_Basename( char *path );
|
||||
char *Sys_ConsoleInput(void);
|
||||
|
|
|
|||
|
|
@ -333,7 +333,7 @@ static void R_ModeList_f( void )
|
|||
|
||||
NOTE TTimo
|
||||
some thoughts about the screenshots system:
|
||||
screenshots get written in fs_homepath + fs_gamedir
|
||||
screenshots get written in fs_homedatapath + fs_gamedir
|
||||
vanilla q3 .. baseq3/screenshots/ *.tga
|
||||
team arena .. missionpack/screenshots/ *.tga
|
||||
|
||||
|
|
|
|||
|
|
@ -429,7 +429,7 @@ static void R_ModeList_f( void )
|
|||
|
||||
NOTE TTimo
|
||||
some thoughts about the screenshots system:
|
||||
screenshots get written in fs_homepath + fs_gamedir
|
||||
screenshots get written in fs_homedatapath + fs_gamedir
|
||||
vanilla q3 .. baseq3/screenshots/ *.tga
|
||||
team arena .. missionpack/screenshots/ *.tga
|
||||
|
||||
|
|
|
|||
|
|
@ -725,7 +725,7 @@ static void SV_WriteBans(void)
|
|||
|
||||
Com_sprintf(filepath, sizeof(filepath), "%s/%s", FS_GetCurrentGameDir(), sv_banFile->string);
|
||||
|
||||
if((writeto = FS_BaseDir_FOpenFileWrite(filepath)))
|
||||
if((writeto = FS_BaseDir_FOpenFileWrite_HomeState(filepath)))
|
||||
{
|
||||
char writebuf[128];
|
||||
serverBan_t *curban;
|
||||
|
|
|
|||
|
|
@ -181,10 +181,10 @@ Sys_PIDFileName
|
|||
*/
|
||||
static char *Sys_PIDFileName( const char *gamedir )
|
||||
{
|
||||
const char *homePath = Cvar_VariableString( "fs_homepath" );
|
||||
const char *homeStatePath = Cvar_VariableString( "fs_homestatepath" );
|
||||
|
||||
if( *homePath != '\0' )
|
||||
return va( "%s/%s/%s", homePath, gamedir, PID_FILENAME );
|
||||
if( *homeStatePath != '\0' )
|
||||
return va( "%s/%s/%s", homeStatePath, gamedir, PID_FILENAME );
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -112,73 +112,371 @@ static int Sys_Exec( void )
|
|||
}
|
||||
}
|
||||
|
||||
#ifdef __APPLE__
|
||||
|
||||
/*
|
||||
==================
|
||||
Sys_DefaultHomePath
|
||||
==================
|
||||
*/
|
||||
char *Sys_DefaultHomePath(void)
|
||||
static char *Sys_DefaultHomePath(void)
|
||||
{
|
||||
static char homePath[ MAX_OSPATH ] = { 0 };
|
||||
char *p;
|
||||
|
||||
if( !*homePath && com_homepath != NULL )
|
||||
if( !*homePath )
|
||||
{
|
||||
#ifdef __APPLE__
|
||||
if( ( p = getenv( "HOME" ) ) != NULL )
|
||||
{
|
||||
Com_sprintf(homePath, sizeof(homePath), "%s%c", p, PATH_SEP);
|
||||
Com_sprintf( homePath, sizeof(homePath), "%s%c%s",
|
||||
p, PATH_SEP, "Library/Application Support/" );
|
||||
|
||||
Q_strcat(homePath, sizeof(homePath),
|
||||
"Library/Application Support/");
|
||||
|
||||
if(com_homepath->string[0])
|
||||
if( com_homepath && com_homepath->string[0] )
|
||||
Q_strcat(homePath, sizeof(homePath), com_homepath->string);
|
||||
else
|
||||
Q_strcat(homePath, sizeof(homePath), HOMEPATH_NAME_MACOSX);
|
||||
Q_strcat(homePath, sizeof(homePath), HOMEPATH_NAME);
|
||||
}
|
||||
#else
|
||||
if( ( p = getenv( "FLATPAK_ID" ) ) != NULL && *p != '\0' )
|
||||
{
|
||||
if( ( p = getenv( "XDG_DATA_HOME" ) ) != NULL && *p != '\0' )
|
||||
{
|
||||
Com_sprintf(homePath, sizeof(homePath), "%s%c", p, PATH_SEP);
|
||||
}
|
||||
else if( ( p = getenv( "HOME" ) ) != NULL && *p != '\0' )
|
||||
{
|
||||
Com_sprintf(homePath, sizeof(homePath), "%s%c.local%cshare%c", p, PATH_SEP, PATH_SEP, PATH_SEP);
|
||||
}
|
||||
|
||||
if( *homePath )
|
||||
{
|
||||
char *dir;
|
||||
|
||||
if(com_homepath->string[0])
|
||||
dir = com_homepath->string;
|
||||
else
|
||||
dir = HOMEPATH_NAME_UNIX;
|
||||
|
||||
if(dir[0] == '.' && dir[1] != '\0')
|
||||
dir++;
|
||||
|
||||
Q_strcat(homePath, sizeof(homePath), dir);
|
||||
}
|
||||
}
|
||||
else if( ( p = getenv( "HOME" ) ) != NULL )
|
||||
{
|
||||
Com_sprintf(homePath, sizeof(homePath), "%s%c", p, PATH_SEP);
|
||||
|
||||
if(com_homepath->string[0])
|
||||
Q_strcat(homePath, sizeof(homePath), com_homepath->string);
|
||||
else
|
||||
Q_strcat(homePath, sizeof(homePath), HOMEPATH_NAME_UNIX);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
return homePath;
|
||||
}
|
||||
|
||||
char *Sys_DefaultHomeConfigPath(void) { return Sys_DefaultHomePath(); }
|
||||
char *Sys_DefaultHomeDataPath(void) { return Sys_DefaultHomePath(); }
|
||||
char *Sys_DefaultHomeStatePath(void) { return Sys_DefaultHomePath(); }
|
||||
|
||||
#else // __APPLE__
|
||||
|
||||
/*
|
||||
==================
|
||||
Sys_HomeConfigPath
|
||||
==================
|
||||
*/
|
||||
char *Sys_HomeConfigPath(void)
|
||||
{
|
||||
static char homeConfigPath[ MAX_OSPATH ] = { 0 };
|
||||
char *p;
|
||||
|
||||
if( !*homeConfigPath )
|
||||
{
|
||||
if( ( p = getenv( "XDG_CONFIG_HOME" ) ) != NULL && *p != '\0' )
|
||||
Com_sprintf(homeConfigPath, sizeof(homeConfigPath), "%s%c", p, PATH_SEP);
|
||||
else if( ( p = getenv( "HOME" ) ) != NULL && *p != '\0' )
|
||||
Com_sprintf(homeConfigPath, sizeof(homeConfigPath), "%s%c.config%c", p, PATH_SEP, PATH_SEP);
|
||||
|
||||
if( *homeConfigPath )
|
||||
{
|
||||
if( com_homepath && com_homepath->string[0] )
|
||||
Q_strcat(homeConfigPath, sizeof(homeConfigPath), com_homepath->string);
|
||||
else
|
||||
Q_strcat(homeConfigPath, sizeof(homeConfigPath), HOMEPATH_NAME);
|
||||
}
|
||||
}
|
||||
|
||||
return homeConfigPath;
|
||||
}
|
||||
|
||||
/*
|
||||
==================
|
||||
Sys_HomeDataPath
|
||||
==================
|
||||
*/
|
||||
char *Sys_HomeDataPath(void)
|
||||
{
|
||||
static char homeDataPath[ MAX_OSPATH ] = { 0 };
|
||||
char *p;
|
||||
|
||||
if( !*homeDataPath )
|
||||
{
|
||||
if( ( p = getenv( "XDG_DATA_HOME" ) ) != NULL && *p != '\0' )
|
||||
Com_sprintf(homeDataPath, sizeof(homeDataPath), "%s%c", p, PATH_SEP);
|
||||
else if( ( p = getenv( "HOME" ) ) != NULL && *p != '\0' )
|
||||
Com_sprintf(homeDataPath, sizeof(homeDataPath), "%s%c.local%cshare%c", p, PATH_SEP, PATH_SEP, PATH_SEP);
|
||||
|
||||
if( *homeDataPath )
|
||||
{
|
||||
if( com_homepath && com_homepath->string[0] )
|
||||
Q_strcat(homeDataPath, sizeof(homeDataPath), com_homepath->string);
|
||||
else
|
||||
Q_strcat(homeDataPath, sizeof(homeDataPath), HOMEPATH_NAME);
|
||||
}
|
||||
}
|
||||
|
||||
return homeDataPath;
|
||||
}
|
||||
|
||||
/*
|
||||
==================
|
||||
Sys_HomeStatePath
|
||||
==================
|
||||
*/
|
||||
char *Sys_HomeStatePath(void)
|
||||
{
|
||||
static char homeStatePath[ MAX_OSPATH ] = { 0 };
|
||||
char *p;
|
||||
|
||||
if( !*homeStatePath )
|
||||
{
|
||||
if( ( p = getenv( "XDG_STATE_HOME" ) ) != NULL && *p != '\0' )
|
||||
Com_sprintf(homeStatePath, sizeof(homeStatePath), "%s%c", p, PATH_SEP);
|
||||
else if( ( p = getenv( "HOME" ) ) != NULL && *p != '\0' )
|
||||
Com_sprintf(homeStatePath, sizeof(homeStatePath), "%s%c.local%cstate%c", p, PATH_SEP, PATH_SEP, PATH_SEP);
|
||||
|
||||
if( *homeStatePath )
|
||||
{
|
||||
if( com_homepath && com_homepath->string[0] )
|
||||
Q_strcat(homeStatePath, sizeof(homeStatePath), com_homepath->string);
|
||||
else
|
||||
Q_strcat(homeStatePath, sizeof(homeStatePath), HOMEPATH_NAME);
|
||||
}
|
||||
}
|
||||
|
||||
return homeStatePath;
|
||||
}
|
||||
|
||||
/*
|
||||
==================
|
||||
Sys_LegacyHomePath
|
||||
==================
|
||||
*/
|
||||
static char *Sys_LegacyHomePath(void)
|
||||
{
|
||||
static char homePath[ MAX_OSPATH ] = { 0 };
|
||||
char *p;
|
||||
|
||||
if( ( p = getenv( "FLATPAK_ID" ) ) != NULL && *p != '\0' )
|
||||
{
|
||||
// Flatpaks always use XDG
|
||||
return "";
|
||||
}
|
||||
|
||||
if( !*homePath )
|
||||
{
|
||||
if( ( p = getenv( "HOME" ) ) != NULL && *p != '\0' )
|
||||
{
|
||||
Com_sprintf(homePath, sizeof(homePath), "%s%c%s",
|
||||
p, PATH_SEP, HOMEPATH_NAME_UNIX_LEGACY);
|
||||
}
|
||||
}
|
||||
|
||||
return homePath;
|
||||
}
|
||||
|
||||
/*
|
||||
==================
|
||||
Sys_MigrateToXDG
|
||||
==================
|
||||
*/
|
||||
qboolean Sys_MigrateToXDG(void)
|
||||
{
|
||||
const char *scriptTemplate =
|
||||
"#!/bin/sh\n"
|
||||
|
||||
"set -eu\n"
|
||||
|
||||
"legacy_home=\"%s\"\n"
|
||||
"xdg_config_home=\"%s\"\n"
|
||||
"xdg_data_home=\"%s\"\n"
|
||||
"xdg_state_home=\"%s\"\n"
|
||||
|
||||
"xdg_config_pattern=\"*.cfg\"\n"
|
||||
"xdg_data_pattern=\"demos/*.dm_* *.log *.pk3 *.txt \\\n"
|
||||
" screenshots/*.jpg screenshots/*.tga videos/*.avi\"\n"
|
||||
"xdg_state_pattern=\"*.dat q3history q3key\"\n"
|
||||
|
||||
"glob_copy() {\n"
|
||||
" game_dir=${1:+$1/}\n"
|
||||
" dst=\"$2\"\n"
|
||||
" shift 2\n"
|
||||
" for pattern in \"$@\"; do\n"
|
||||
" subdir=$(dirname \"$pattern\")\n"
|
||||
" [ \"$subdir\" = \".\" ] && subdir=\"\"\n"
|
||||
" find \"$legacy_home/$game_dir\" \\\n"
|
||||
" -path \"$legacy_home/$game_dir$pattern\" -type f \\\n"
|
||||
" -exec mkdir -p \"$dst/$game_dir$subdir\" \\; \\\n"
|
||||
" -exec cp -av {} \"$dst/$game_dir$subdir\" \\;\n"
|
||||
" done\n"
|
||||
"}\n"
|
||||
|
||||
"unmatched_copy() {\n"
|
||||
" game_dir=${1:+$1/}\n"
|
||||
" shift\n"
|
||||
" find_args=\"\"\n"
|
||||
" for pattern in \"$@\"; do\n"
|
||||
" find_args=\"$find_args \\\n"
|
||||
" -not -path \\\"$legacy_home/$game_dir$pattern\\\"\"\n"
|
||||
" done\n"
|
||||
" eval \"find '$legacy_home/$game_dir' -type f $find_args\" | \\\n"
|
||||
" while IFS= read -r file; do\n"
|
||||
" dst=\"$xdg_data_home${file#$legacy_home}\"\n"
|
||||
" dst_dir=$(dirname \"$dst\")\n"
|
||||
" mkdir -p \"$dst_dir\"\n"
|
||||
" cp -av \"$file\" \"$dst\"\n"
|
||||
" done\n"
|
||||
"}\n"
|
||||
|
||||
"echo \"Starting XDG migration...\"\n"
|
||||
|
||||
"glob_copy \"\" \"$xdg_state_home\" \"qkey\"\n"
|
||||
|
||||
"for game_dir in \"$legacy_home\"/*; do\n"
|
||||
" [ -d \"$game_dir\" ] || continue\n"
|
||||
" game=$(basename \"$game_dir\")\n"
|
||||
" glob_copy \"$game\" \"$xdg_config_home\" $xdg_config_pattern\n"
|
||||
" glob_copy \"$game\" \"$xdg_data_home\" $xdg_data_pattern\n"
|
||||
" glob_copy \"$game\" \"$xdg_state_home\" $xdg_state_pattern\n"
|
||||
" unmatched_copy \"$game\" \\\n"
|
||||
" $xdg_config_pattern \\\n"
|
||||
" $xdg_data_pattern \\\n"
|
||||
" $xdg_state_pattern\n"
|
||||
"done\n"
|
||||
|
||||
"echo \"XDG migration complete!\"\n";
|
||||
|
||||
char scriptBuffer[2048];
|
||||
int len = Com_sprintf( scriptBuffer, sizeof( scriptBuffer ), scriptTemplate,
|
||||
Sys_LegacyHomePath( ), Sys_HomeConfigPath( ),
|
||||
Sys_HomeDataPath( ), Sys_HomeStatePath( ) );
|
||||
|
||||
if( len < 0 || len >= (int)sizeof( scriptBuffer ) )
|
||||
{
|
||||
Com_Printf( "XDG migration error: substitution failed.\n" );
|
||||
return qfalse;
|
||||
}
|
||||
|
||||
char scriptPath[] = "/tmp/xdgmigrationXXXXXX";
|
||||
int fd = mkstemp( scriptPath );
|
||||
if( fd == -1 )
|
||||
{
|
||||
Com_Printf( "XDG migration error: script creation failed.\n" );
|
||||
return qfalse;
|
||||
}
|
||||
|
||||
if( write( fd, scriptBuffer, len ) != len )
|
||||
{
|
||||
close( fd );
|
||||
unlink( scriptPath );
|
||||
Com_Printf( "XDG migration error: script write failed.\n" );
|
||||
return qfalse;
|
||||
}
|
||||
close( fd );
|
||||
|
||||
if( chmod( scriptPath, 0700 ) == -1 )
|
||||
{
|
||||
unlink( scriptPath );
|
||||
Com_Printf( "XDG migration error: script chmod failed.\n" );
|
||||
return qfalse;
|
||||
}
|
||||
|
||||
Sys_ClearExecBuffer( );
|
||||
Sys_AppendToExecBuffer( scriptPath );
|
||||
int result = Sys_Exec( );
|
||||
unlink( scriptPath );
|
||||
|
||||
return result == 0;
|
||||
}
|
||||
|
||||
/*
|
||||
==================
|
||||
Sys_ShouldUseLegacyHomePath
|
||||
==================
|
||||
*/
|
||||
static qboolean Sys_ShouldUseLegacyHomePath(void)
|
||||
{
|
||||
if( access( Sys_HomeConfigPath( ), F_OK ) == 0 )
|
||||
{
|
||||
// If the XDG config directory exists, prefer XDG layout, regardless
|
||||
return qfalse;
|
||||
}
|
||||
|
||||
if( ( com_homepath && com_homepath->string[0] ) ||
|
||||
Cvar_VariableString( "fs_homepath" )[0] )
|
||||
{
|
||||
// If a custom homepath has been explicity set then
|
||||
// that strongly implies that migration isn't desired
|
||||
return qfalse;
|
||||
}
|
||||
|
||||
const char *legacyHomePath = Sys_LegacyHomePath();
|
||||
|
||||
if( !*legacyHomePath || access( legacyHomePath, F_OK ) != 0 )
|
||||
{
|
||||
// The legacy home path doesn't exist
|
||||
return qfalse;
|
||||
}
|
||||
|
||||
char migrationRefusedPath[ MAX_OSPATH ];
|
||||
Com_sprintf( migrationRefusedPath, sizeof( migrationRefusedPath ),
|
||||
"%s/.xdgMigrationRefused", legacyHomePath );
|
||||
|
||||
// If the user hasn't already refused, ask if they want to migrate
|
||||
if( access( migrationRefusedPath, F_OK ) != 0 )
|
||||
{
|
||||
dialogResult_t result = Sys_Dialog( DT_YES_NO, va(
|
||||
"Modern games and applications store files in "
|
||||
"directories according to the Free Desktop standard. "
|
||||
"Here's what that would look like for %s:\n\n"
|
||||
"Configuration files:\n %s\n\n"
|
||||
"Data files; pk3s, screenshots, logs, demos, etc.:\n %s\n\n"
|
||||
"Internal runtime files:\n %s\n\n"
|
||||
"At the moment all of these files are found here:\n %s\n\n"
|
||||
"Do you want to copy your files to these new directories?",
|
||||
PRODUCT_NAME,
|
||||
Sys_HomeConfigPath( ), Sys_HomeDataPath( ), Sys_HomeStatePath( ),
|
||||
legacyHomePath ),
|
||||
"Home Directory Files Upgrade" );
|
||||
|
||||
if( result == DR_YES )
|
||||
return !Sys_MigrateToXDG( );
|
||||
|
||||
// Guard against asking again in future
|
||||
fclose( fopen( migrationRefusedPath, "w" ) );
|
||||
}
|
||||
|
||||
return qtrue;
|
||||
}
|
||||
|
||||
/*
|
||||
==================
|
||||
Sys_DefaultHomeConfigPath
|
||||
==================
|
||||
*/
|
||||
char *Sys_DefaultHomeConfigPath(void)
|
||||
{
|
||||
if( Sys_ShouldUseLegacyHomePath( ) )
|
||||
return Sys_LegacyHomePath( );
|
||||
|
||||
return Sys_HomeConfigPath( );
|
||||
}
|
||||
|
||||
/*
|
||||
==================
|
||||
Sys_DefaultHomeDataPath
|
||||
==================
|
||||
*/
|
||||
char *Sys_DefaultHomeDataPath(void)
|
||||
{
|
||||
if( Sys_ShouldUseLegacyHomePath( ) )
|
||||
return Sys_LegacyHomePath( );
|
||||
|
||||
return Sys_HomeDataPath( );
|
||||
}
|
||||
|
||||
/*
|
||||
==================
|
||||
Sys_DefaultHomeStatePath
|
||||
==================
|
||||
*/
|
||||
char *Sys_DefaultHomeStatePath(void)
|
||||
{
|
||||
if( Sys_ShouldUseLegacyHomePath( ) )
|
||||
return Sys_LegacyHomePath( );
|
||||
|
||||
return Sys_HomeStatePath( );
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
================
|
||||
Sys_SteamPath
|
||||
|
|
@ -668,10 +966,10 @@ void Sys_ErrorDialog( const char *error )
|
|||
char buffer[ 1024 ];
|
||||
unsigned int size;
|
||||
int f = -1;
|
||||
const char *homepath = Cvar_VariableString( "fs_homepath" );
|
||||
const char *homedatapath = Cvar_VariableString( "fs_homedatapath" );
|
||||
const char *gamedir = Cvar_VariableString( "fs_game" );
|
||||
const char *fileName = "crashlog.txt";
|
||||
char *ospath = FS_BuildOSPath( homepath, gamedir, fileName );
|
||||
char *ospath = FS_BuildOSPath( homedatapath, gamedir, fileName );
|
||||
|
||||
Sys_Print( va( "%s\n", error ) );
|
||||
|
||||
|
|
@ -680,7 +978,7 @@ void Sys_ErrorDialog( const char *error )
|
|||
#endif
|
||||
|
||||
// Make sure the write path for the crashlog exists...
|
||||
if( FS_CreatePath( ospath ) )
|
||||
if( FS_CreatePath( homedatapath ) )
|
||||
{
|
||||
Com_Printf("ERROR: couldn't create path '%s' for crash log.\n", ospath);
|
||||
return;
|
||||
|
|
|
|||
|
|
@ -88,7 +88,7 @@ void Sys_SetFloatEnv(void)
|
|||
Sys_DefaultHomePath
|
||||
================
|
||||
*/
|
||||
char *Sys_DefaultHomePath( void )
|
||||
static char *Sys_DefaultHomePath( void )
|
||||
{
|
||||
static char homePath[ MAX_OSPATH ] = { 0 };
|
||||
|
||||
|
|
@ -108,12 +108,16 @@ char *Sys_DefaultHomePath( void )
|
|||
if(com_homepath->string[0])
|
||||
Q_strcat(homePath, sizeof(homePath), com_homepath->string);
|
||||
else
|
||||
Q_strcat(homePath, sizeof(homePath), HOMEPATH_NAME_WIN);
|
||||
Q_strcat(homePath, sizeof(homePath), HOMEPATH_NAME);
|
||||
}
|
||||
|
||||
return homePath;
|
||||
}
|
||||
|
||||
char *Sys_DefaultHomeConfigPath(void) { return Sys_DefaultHomePath(); }
|
||||
char *Sys_DefaultHomeDataPath(void) { return Sys_DefaultHomePath(); }
|
||||
char *Sys_DefaultHomeStatePath(void) { return Sys_DefaultHomePath(); }
|
||||
|
||||
/*
|
||||
================
|
||||
Sys_SteamPath
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user