Dont write directly to files but rather write and copy a tmp file

This commit is contained in:
PilzAdam 2013-08-13 19:15:06 +02:00
parent c8930850e3
commit d718b0b34e
9 changed files with 101 additions and 69 deletions

@ -24,6 +24,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include <set> #include <set>
#include "strfnd.h" #include "strfnd.h"
#include "log.h" #include "log.h"
#include "filesys.h"
BanManager::BanManager(const std::string &banfilepath): BanManager::BanManager(const std::string &banfilepath):
m_banfilepath(banfilepath), m_banfilepath(banfilepath),
@ -76,20 +77,20 @@ void BanManager::save()
{ {
JMutexAutoLock lock(m_mutex); JMutexAutoLock lock(m_mutex);
infostream<<"BanManager: saving to "<<m_banfilepath<<std::endl; infostream<<"BanManager: saving to "<<m_banfilepath<<std::endl;
std::ofstream os(m_banfilepath.c_str(), std::ios::binary); std::ostringstream ss(std::ios_base::binary);
if(os.good() == false)
{
infostream<<"BanManager: failed saving to "<<m_banfilepath<<std::endl;
throw SerializationError("BanManager::load(): Couldn't open file");
}
for(std::map<std::string, std::string>::iterator for(std::map<std::string, std::string>::iterator
i = m_ips.begin(); i = m_ips.begin();
i != m_ips.end(); i++) i != m_ips.end(); i++)
{ {
os<<i->first<<"|"<<i->second<<"\n"; ss << i->first << "|" << i->second << "\n";
} }
if(!fs::safeWriteToFile(m_banfilepath, ss.str())) {
infostream<<"BanManager: failed saving to "<<m_banfilepath<<std::endl;
throw SerializationError("BanManager::load(): Couldn't write file");
}
m_modified = false; m_modified = false;
} }

@ -437,13 +437,13 @@ void ServerEnvironment::serializePlayers(const std::string &savedir)
if(player->checkModified()) if(player->checkModified())
{ {
// Open file and serialize // Open file and serialize
std::ofstream os(path.c_str(), std::ios_base::binary); std::ostringstream ss(std::ios_base::binary);
if(os.good() == false) player->serialize(ss);
if(!fs::safeWriteToFile(path, ss.str()))
{ {
infostream<<"Failed to overwrite "<<path<<std::endl; infostream<<"Failed to write "<<path<<std::endl;
continue; continue;
} }
player->serialize(os);
saved_players.insert(player); saved_players.insert(player);
} else { } else {
saved_players.insert(player); saved_players.insert(player);
@ -493,13 +493,13 @@ void ServerEnvironment::serializePlayers(const std::string &savedir)
/*infostream<<"Saving player "<<player->getName()<<" to " /*infostream<<"Saving player "<<player->getName()<<" to "
<<path<<std::endl;*/ <<path<<std::endl;*/
// Open file and serialize // Open file and serialize
std::ofstream os(path.c_str(), std::ios_base::binary); std::ostringstream ss(std::ios_base::binary);
if(os.good() == false) player->serialize(ss);
if(!fs::safeWriteToFile(path, ss.str()))
{ {
infostream<<"Failed to overwrite "<<path<<std::endl; infostream<<"Failed to write "<<path<<std::endl;
continue; continue;
} }
player->serialize(os);
saved_players.insert(player); saved_players.insert(player);
} }
} }
@ -581,19 +581,20 @@ void ServerEnvironment::saveMeta(const std::string &savedir)
std::string path = savedir + "/env_meta.txt"; std::string path = savedir + "/env_meta.txt";
// Open file and serialize // Open file and serialize
std::ofstream os(path.c_str(), std::ios_base::binary); std::ostringstream ss(std::ios_base::binary);
if(os.good() == false)
{
infostream<<"ServerEnvironment::saveMeta(): Failed to open "
<<path<<std::endl;
throw SerializationError("Couldn't save env meta");
}
Settings args; Settings args;
args.setU64("game_time", m_game_time); args.setU64("game_time", m_game_time);
args.setU64("time_of_day", getTimeOfDay()); args.setU64("time_of_day", getTimeOfDay());
args.writeLines(os); args.writeLines(ss);
os<<"EnvArgsEnd\n"; ss<<"EnvArgsEnd\n";
if(!fs::safeWriteToFile(path, ss.str()))
{
infostream<<"ServerEnvironment::saveMeta(): Failed to write "
<<path<<std::endl;
throw SerializationError("Couldn't save env meta");
}
} }
void ServerEnvironment::loadMeta(const std::string &savedir) void ServerEnvironment::loadMeta(const std::string &savedir)

@ -23,6 +23,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
#include <errno.h> #include <errno.h>
#include <sstream>
#include <fstream>
#include "log.h" #include "log.h"
namespace fs namespace fs
@ -684,5 +686,28 @@ std::string RemoveRelativePathComponents(std::string path)
return path.substr(0, pos); return path.substr(0, pos);
} }
bool safeWriteToFile(const std::string &path, const std::string &content)
{
std::string tmp_file = path + ".~mt";
// Write to a tmp file
std::ofstream os(tmp_file.c_str(), std::ios::binary);
if (!os.good())
return false;
os << content;
os.flush();
os.close();
if (os.fail())
return false;
// Copy file
#ifdef _WIN32
remove(path.c_str());
return (rename(tmp_file.c_str(), path.c_str()) == 0);
#else
return (rename(tmp_file.c_str(), path.c_str()) == 0);
#endif
}
} // namespace fs } // namespace fs

@ -98,6 +98,8 @@ std::string RemoveLastPathComponent(std::string path,
// this does not resolve symlinks and check for existence of directories. // this does not resolve symlinks and check for existence of directories.
std::string RemoveRelativePathComponents(std::string path); std::string RemoveRelativePathComponents(std::string path);
bool safeWriteToFile(const std::string &path, const std::string &content);
}//fs }//fs
#endif #endif

@ -3490,20 +3490,21 @@ void ServerMap::saveMapMeta()
createDirs(m_savedir); createDirs(m_savedir);
std::string fullpath = m_savedir + DIR_DELIM + "map_meta.txt"; std::string fullpath = m_savedir + DIR_DELIM + "map_meta.txt";
std::ofstream os(fullpath.c_str(), std::ios_base::binary); std::ostringstream ss(std::ios_base::binary);
if(os.good() == false)
{
infostream<<"ERROR: ServerMap::saveMapMeta(): "
<<"could not open"<<fullpath<<std::endl;
throw FileNotGoodException("Cannot open chunk metadata");
}
Settings params; Settings params;
m_emerge->setParamsToSettings(&params); m_emerge->setParamsToSettings(&params);
params.writeLines(os); params.writeLines(ss);
os<<"[end_of_params]\n"; ss<<"[end_of_params]\n";
if(!fs::safeWriteToFile(fullpath, ss.str()))
{
infostream<<"ERROR: ServerMap::saveMapMeta(): "
<<"could not write "<<fullpath<<std::endl;
throw FileNotGoodException("Cannot save chunk metadata");
}
m_map_metadata_changed = false; m_map_metadata_changed = false;
} }
@ -3574,11 +3575,12 @@ void ServerMap::saveSectorMeta(ServerMapSector *sector)
createDirs(dir); createDirs(dir);
std::string fullpath = dir + DIR_DELIM + "meta"; std::string fullpath = dir + DIR_DELIM + "meta";
std::ofstream o(fullpath.c_str(), std::ios_base::binary); std::ostringstream ss(std::ios_base::binary);
if(o.good() == false)
throw FileNotGoodException("Cannot open sector metafile");
sector->serialize(o, version); sector->serialize(ss, version);
if(!fs::safeWriteToFile(fullpath, ss.str()))
throw FileNotGoodException("Cannot write sector metafile");
sector->differs_from_disk = false; sector->differs_from_disk = false;
} }

@ -36,6 +36,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "mapgen_v6.h" #include "mapgen_v6.h"
#include "mapgen_v7.h" #include "mapgen_v7.h"
#include "util/serialize.h" #include "util/serialize.h"
#include "filesys.h"
FlagDesc flagdesc_mapgen[] = { FlagDesc flagdesc_mapgen[] = {
{"trees", MG_TREES}, {"trees", MG_TREES},
@ -756,24 +757,26 @@ bool DecoSchematic::loadSchematicFile() {
2 - Fixed messy never/always place; 0 probability is now never, 0xFF is always 2 - Fixed messy never/always place; 0 probability is now never, 0xFF is always
*/ */
void DecoSchematic::saveSchematicFile(INodeDefManager *ndef) { void DecoSchematic::saveSchematicFile(INodeDefManager *ndef) {
std::ofstream os(filename.c_str(), std::ios_base::binary); std::ostringstream ss(std::ios_base::binary);
writeU32(os, MTSCHEM_FILE_SIGNATURE); // signature writeU32(ss, MTSCHEM_FILE_SIGNATURE); // signature
writeU16(os, 2); // version writeU16(ss, 2); // version
writeV3S16(os, size); // schematic size writeV3S16(ss, size); // schematic size
std::vector<content_t> usednodes; std::vector<content_t> usednodes;
int nodecount = size.X * size.Y * size.Z; int nodecount = size.X * size.Y * size.Z;
build_nnlist_and_update_ids(schematic, nodecount, &usednodes); build_nnlist_and_update_ids(schematic, nodecount, &usednodes);
u16 numids = usednodes.size(); u16 numids = usednodes.size();
writeU16(os, numids); // name count writeU16(ss, numids); // name count
for (int i = 0; i != numids; i++) for (int i = 0; i != numids; i++)
os << serializeString(ndef->get(usednodes[i]).name); // node names ss << serializeString(ndef->get(usednodes[i]).name); // node names
// compressed bulk node data // compressed bulk node data
MapNode::serializeBulk(os, SER_FMT_VER_HIGHEST_WRITE, schematic, MapNode::serializeBulk(ss, SER_FMT_VER_HIGHEST_WRITE, schematic,
nodecount, 2, 2, true); nodecount, 2, 2, true);
fs::safeWriteToFile(filename, ss.str());
} }

@ -105,13 +105,11 @@ bool deleteEntry (ServerListSpec server)
} }
std::string path = ServerList::getFilePath(); std::string path = ServerList::getFilePath();
std::ofstream stream (path.c_str()); std::ostringstream ss(std::ios_base::binary);
if (stream.is_open()) ss << ServerList::serialize(serverlist);
{ if (!fs::safeWriteToFile(path, ss.str()))
stream<<ServerList::serialize(serverlist);
return true;
}
return false; return false;
return true;
} }
/* /*
@ -128,11 +126,9 @@ bool insert (ServerListSpec server)
serverlist.insert(serverlist.begin(), server); serverlist.insert(serverlist.begin(), server);
std::string path = ServerList::getFilePath(); std::string path = ServerList::getFilePath();
std::ofstream stream (path.c_str()); std::ostringstream ss(std::ios_base::binary);
if (stream.is_open()) ss << ServerList::serialize(serverlist);
{ fs::safeWriteToFile(path, ss.str());
stream<<ServerList::serialize(serverlist);
}
return false; return false;
} }

@ -36,6 +36,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include <list> #include <list>
#include <map> #include <map>
#include <set> #include <set>
#include "filesys.h"
enum ValueType enum ValueType
{ {
@ -308,14 +309,7 @@ public:
// Write stuff back // Write stuff back
{ {
std::ofstream os(filename); std::ostringstream ss(std::ios_base::binary);
if(os.good() == false)
{
errorstream<<"Error opening configuration file"
" for writing: \""
<<filename<<"\""<<std::endl;
return false;
}
/* /*
Write updated stuff Write updated stuff
@ -324,7 +318,7 @@ public:
i = objects.begin(); i = objects.begin();
i != objects.end(); ++i) i != objects.end(); ++i)
{ {
os<<(*i); ss<<(*i);
} }
/* /*
@ -340,7 +334,14 @@ public:
std::string value = i->second; std::string value = i->second;
infostream<<"Adding \""<<name<<"\" = \""<<value<<"\"" infostream<<"Adding \""<<name<<"\" = \""<<value<<"\""
<<std::endl; <<std::endl;
os<<name<<" = "<<value<<"\n"; ss<<name<<" = "<<value<<"\n";
}
if(!fs::safeWriteToFile(filename, ss.str()))
{
errorstream<<"Error writing configuration file: \""
<<filename<<"\""<<std::endl;
return false;
} }
} }

@ -241,8 +241,9 @@ bool initializeWorld(const std::string &path, const std::string &gameid)
if(!fs::PathExists(worldmt_path)){ if(!fs::PathExists(worldmt_path)){
infostream<<"Creating world.mt ("<<worldmt_path<<")"<<std::endl; infostream<<"Creating world.mt ("<<worldmt_path<<")"<<std::endl;
fs::CreateAllDirs(path); fs::CreateAllDirs(path);
std::ofstream of(worldmt_path.c_str(), std::ios::binary); std::ostringstream ss(std::ios_base::binary);
of<<"gameid = "<<gameid<<"\n"; ss<<"gameid = "<<gameid<<"\n";
fs::safeWriteToFile(worldmt_path, ss.str());
} }
return true; return true;
} }