use pid in file names of temporary files

to prevent race conditions with multiple clients running when saving
maps, config on quit, during upgrade
This commit is contained in:
def 2020-02-12 22:39:37 +01:00
parent 5929517941
commit 31ae4c4d5a
9 changed files with 53 additions and 33 deletions

View file

@ -38,4 +38,4 @@ $ ./find_unchanged.py ../spanish.txt
To update all languages:
$ for i in data/languages/*.txt; do scripts/languages/copy_fix.py $i $i.tmp --delete-unused --append-missing && mv $i.tmp $i; done
$ for i in data/languages/*.txt; do scripts/languages/copy_fix.py $i $i.$$.tmp --delete-unused --append-missing && mv $i.$$.tmp $i; done

View file

@ -329,6 +329,7 @@ CClient::CClient() : m_DemoPlayer(&m_SnapshotDelta)
m_MapDetailsSha256 = SHA256_ZEROED;
m_MapDetailsCrc = 0;
str_format(m_aDDNetInfoTmp, sizeof(m_aDDNetInfoTmp), DDNET_INFO ".%d.tmp", pid());
m_pDDNetInfoTask = NULL;
m_aNews[0] = '\0';
@ -1492,11 +1493,21 @@ static void FormatMapDownloadFilename(const char *pName, SHA256_DIGEST *pSha256,
sha256_str(*pSha256, aSha256 + 1, sizeof(aSha256) - 1);
}
str_format(pBuffer, BufferSize, "%s_%08x%s.map%s",
pName,
Crc,
aSha256,
Temp ? ".tmp" : "");
if(Temp)
{
str_format(pBuffer, BufferSize, "%s_%08x%s.map.%d.tmp",
pName,
Crc,
aSha256,
pid());
}
else
{
str_format(pBuffer, BufferSize, "%s_%08x%s.map",
pName,
Crc,
aSha256);
}
}
static CServerCapabilities GetServerCapabilities(int Version, int Flags)
@ -2295,7 +2306,7 @@ void CClient::ResetDDNetInfo()
void CClient::FinishDDNetInfo()
{
ResetDDNetInfo();
m_pStorage->RenameFile(DDNET_INFO_TMP, DDNET_INFO, IStorage::TYPE_SAVE);
m_pStorage->RenameFile(m_aDDNetInfoTmp, DDNET_INFO, IStorage::TYPE_SAVE);
LoadDDNetInfo();
}
@ -4134,7 +4145,7 @@ void CClient::RequestDDNetInfo()
str_append(aUrl, aEscaped, sizeof(aUrl));
}
m_pDDNetInfoTask = std::make_shared<CGetFile>(Storage(), aUrl, DDNET_INFO_TMP, IStorage::TYPE_SAVE, true);
m_pDDNetInfoTask = std::make_shared<CGetFile>(Storage(), aUrl, m_aDDNetInfoTmp, IStorage::TYPE_SAVE, true);
Engine()->AddJob(m_pDDNetInfoTask);
}

View file

@ -166,6 +166,7 @@ class CClient : public IClient, public CDemoPlayer::IListener
int m_MapDetailsCrc;
SHA256_DIGEST m_MapDetailsSha256;
char m_aDDNetInfoTmp[64];
std::shared_ptr<CGetFile> m_pDDNetInfoTask;
// time

View file

@ -86,6 +86,9 @@ CUpdater::CUpdater()
m_State = CLEAN;
m_Percent = 0;
m_Lock = lock_create();
str_format(m_aClientExecTmp, sizeof(m_aClientExecTmp), CLIENT_EXEC ".%d.tmp", pid());
str_format(m_aServerExecTmp, sizeof(m_aServerExecTmp), SERVER_EXEC ".%d.tmp", pid());
}
void CUpdater::Init()
@ -187,16 +190,17 @@ bool CUpdater::ReplaceClient()
{
dbg_msg("updater", "replacing " PLAT_CLIENT_EXEC);
bool Success = true;
char aPath[512];
// Replace running executable by renaming twice...
if(!m_IsWinXP)
{
m_pStorage->RemoveBinaryFile("DDNet.old");
Success &= m_pStorage->RenameBinaryFile(PLAT_CLIENT_EXEC, "DDNet.old");
Success &= m_pStorage->RenameBinaryFile("update/DDNet.tmp", PLAT_CLIENT_EXEC);
m_pStorage->RemoveBinaryFile(CLIENT_EXEC ".old");
Success &= m_pStorage->RenameBinaryFile(PLAT_CLIENT_EXEC, CLIENT_EXEC ".old");
str_format(aPath, sizeof(aPath), "update/%s", m_aClientExecTmp);
Success &= m_pStorage->RenameBinaryFile(aPath, PLAT_CLIENT_EXEC);
}
#if !defined(CONF_FAMILY_WINDOWS)
char aPath[512];
m_pStorage->GetBinaryPath(PLAT_CLIENT_EXEC, aPath, sizeof aPath);
char aBuf[512];
str_format(aBuf, sizeof aBuf, "chmod +x %s", aPath);
@ -213,13 +217,14 @@ bool CUpdater::ReplaceServer()
{
dbg_msg("updater", "replacing " PLAT_SERVER_EXEC);
bool Success = true;
char aPath[512];
//Replace running executable by renaming twice...
m_pStorage->RemoveBinaryFile("DDNet-Server.old");
Success &= m_pStorage->RenameBinaryFile(PLAT_SERVER_EXEC, "DDNet-Server.old");
Success &= m_pStorage->RenameBinaryFile("update/DDNet-Server.tmp", PLAT_SERVER_EXEC);
m_pStorage->RemoveBinaryFile(SERVER_EXEC ".old");
Success &= m_pStorage->RenameBinaryFile(PLAT_SERVER_EXEC, SERVER_EXEC ".old");
str_format(aPath, sizeof(aPath), "update/%s", m_aServerExecTmp);
Success &= m_pStorage->RenameBinaryFile(aPath, PLAT_SERVER_EXEC);
#if !defined(CONF_FAMILY_WINDOWS)
char aPath[512];
m_pStorage->GetBinaryPath(PLAT_SERVER_EXEC, aPath, sizeof aPath);
char aBuf[512];
str_format(aBuf, sizeof aBuf, "chmod +x %s", aPath);
@ -288,13 +293,13 @@ void CUpdater::PerformUpdate()
ParseUpdate();
m_State = DOWNLOADING;
const char *aLastFile;
aLastFile = "";
const char *pLastFile;
pLastFile = "";
for(map<string, bool>::reverse_iterator it = m_FileJobs.rbegin(); it != m_FileJobs.rend(); ++it)
{
if(it->second)
{
aLastFile = it->first.c_str();
pLastFile = it->first.c_str();
break;
}
}
@ -320,7 +325,7 @@ void CUpdater::PerformUpdate()
{
FetchFile(pFile);
}
aLastFile = pFile;
pLastFile = pFile;
}
else
m_pStorage->RemoveBinaryFile(it->first.c_str());
@ -328,16 +333,16 @@ void CUpdater::PerformUpdate()
if(m_ServerUpdate)
{
FetchFile(PLAT_SERVER_DOWN, "DDNet-Server.tmp");
aLastFile = "DDNet-Server.tmp";
FetchFile(PLAT_SERVER_DOWN, m_aServerExecTmp);
pLastFile = m_aServerExecTmp;
}
if(m_ClientUpdate)
{
FetchFile(PLAT_CLIENT_DOWN, "DDNet.tmp");
aLastFile = "DDNet.tmp";
FetchFile(PLAT_CLIENT_DOWN, m_aClientExecTmp);
pLastFile = m_aClientExecTmp;
}
str_copy(m_aLastFile, aLastFile, sizeof(m_aLastFile));
str_copy(m_aLastFile, pLastFile, sizeof(m_aLastFile));
}
void CUpdater::CommitUpdate()
@ -372,7 +377,7 @@ void CUpdater::WinXpRestart()
if(!bhFile)
return;
char bBuf[512];
str_format(bBuf, sizeof(bBuf), ":_R\r\ndel \"DDNet.exe\"\r\nif exist \"DDNet.exe\" goto _R\r\n:_T\r\nmove /y \"update\\DDNet.tmp\" \"DDNet.exe\"\r\nif not exist \"DDNet.exe\" goto _T\r\nstart DDNet.exe\r\ndel \"du.bat\"\r\n");
str_format(bBuf, sizeof(bBuf), ":_R\r\ndel \"" PLAT_CLIENT_EXEC "\"\r\nif exist \"" PLAT_CLIENT_EXEC "\" goto _R\r\n:_T\r\nmove /y \"update\\%s\" \"" PLAT_CLIENT_EXEC "\"\r\nif not exist \"" PLAT_CLIENT_EXEC "\" goto _T\r\nstart " PLAT_CLIENT_EXEC "\r\ndel \"du.bat\"\r\n", m_aClientExecTmp);
io_write(bhFile, bBuf, str_length(bBuf));
io_close(bhFile);
shell_execute(aBuf);

View file

@ -48,6 +48,8 @@ class CUpdater : public IUpdater
char m_aStatus[256];
int m_Percent;
char m_aLastFile[256];
char m_aClientExecTmp[64];
char m_aServerExecTmp[64];
bool m_ClientUpdate;
bool m_ServerUpdate;

View file

@ -8,7 +8,6 @@
#include "kernel.h"
#define DDNET_INFO "ddnet-info.json"
#define DDNET_INFO_TMP DDNET_INFO ".tmp"
/*
Structure: CServerInfo

View file

@ -65,7 +65,10 @@ public:
if(!m_pStorage || !g_Config.m_ClSaveSettings)
return;
m_ConfigFile = m_pStorage->OpenFile(CONFIG_FILE_TMP, IOFLAG_WRITE, IStorage::TYPE_SAVE);
char aConfigFileTmp[64];
str_format(aConfigFileTmp, sizeof(aConfigFileTmp), CONFIG_FILE ".%d.tmp", pid());
m_ConfigFile = m_pStorage->OpenFile(aConfigFileTmp, IOFLAG_WRITE, IStorage::TYPE_SAVE);
if(!m_ConfigFile)
return;
@ -95,12 +98,12 @@ public:
if(m_Failed)
{
dbg_msg("config", "ERROR: writing to " CONFIG_FILE_TMP " failed");
dbg_msg("config", "ERROR: writing to %s failed", aConfigFileTmp);
return;
}
if(!m_pStorage->RenameFile(CONFIG_FILE_TMP, CONFIG_FILE, IStorage::TYPE_SAVE))
dbg_msg("config", "ERROR: renaming " CONFIG_FILE_TMP " to " CONFIG_FILE " failed");
if(!m_pStorage->RenameFile(aConfigFileTmp, CONFIG_FILE, IStorage::TYPE_SAVE))
dbg_msg("config", "ERROR: renaming %s to " CONFIG_FILE " failed", aConfigFileTmp);
}
virtual void RegisterCallback(SAVECALLBACKFUNC pfnFunc, void *pUserData)

View file

@ -4,7 +4,6 @@
#define ENGINE_SHARED_CONFIG_H
#define CONFIG_FILE "settings_ddnet.cfg"
#define CONFIG_FILE_TMP CONFIG_FILE ".tmp"
#define AUTOEXEC_FILE "autoexec.cfg"
#define AUTOEXEC_CLIENT_FILE "autoexec_client.cfg"
#define AUTOEXEC_SERVER_FILE "autoexec_server.cfg"

View file

@ -2874,7 +2874,7 @@ void CGameContext::OnMapChange(char *pNewMapName, int MapNameSize)
char aConfig[128];
char aTemp[128];
str_format(aConfig, sizeof(aConfig), "maps/%s.cfg", g_Config.m_SvMap);
str_format(aTemp, sizeof(aTemp), "%s.temp.%d", pNewMapName, pid());
str_format(aTemp, sizeof(aTemp), "%s.%d.tmp", pNewMapName, pid());
IOHANDLE File = Storage()->OpenFile(aConfig, IOFLAG_READ, IStorage::TYPE_ALL);
if(!File)