Skip to content

Commit d718b0b

Browse files
committedAug 13, 2013
Dont write directly to files but rather write and copy a tmp file
1 parent c893085 commit d718b0b

9 files changed

+101
-69
lines changed
 

‎src/ban.cpp

+9-8
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
2424
#include <set>
2525
#include "strfnd.h"
2626
#include "log.h"
27+
#include "filesys.h"
2728

2829
BanManager::BanManager(const std::string &banfilepath):
2930
m_banfilepath(banfilepath),
@@ -76,20 +77,20 @@ void BanManager::save()
7677
{
7778
JMutexAutoLock lock(m_mutex);
7879
infostream<<"BanManager: saving to "<<m_banfilepath<<std::endl;
79-
std::ofstream os(m_banfilepath.c_str(), std::ios::binary);
80-
81-
if(os.good() == false)
82-
{
83-
infostream<<"BanManager: failed saving to "<<m_banfilepath<<std::endl;
84-
throw SerializationError("BanManager::load(): Couldn't open file");
85-
}
80+
std::ostringstream ss(std::ios_base::binary);
8681

8782
for(std::map<std::string, std::string>::iterator
8883
i = m_ips.begin();
8984
i != m_ips.end(); i++)
9085
{
91-
os<<i->first<<"|"<<i->second<<"\n";
86+
ss << i->first << "|" << i->second << "\n";
9287
}
88+
89+
if(!fs::safeWriteToFile(m_banfilepath, ss.str())) {
90+
infostream<<"BanManager: failed saving to "<<m_banfilepath<<std::endl;
91+
throw SerializationError("BanManager::load(): Couldn't write file");
92+
}
93+
9394
m_modified = false;
9495
}
9596

‎src/environment.cpp

+18-17
Original file line numberDiff line numberDiff line change
@@ -437,13 +437,13 @@ void ServerEnvironment::serializePlayers(const std::string &savedir)
437437
if(player->checkModified())
438438
{
439439
// Open file and serialize
440-
std::ofstream os(path.c_str(), std::ios_base::binary);
441-
if(os.good() == false)
440+
std::ostringstream ss(std::ios_base::binary);
441+
player->serialize(ss);
442+
if(!fs::safeWriteToFile(path, ss.str()))
442443
{
443-
infostream<<"Failed to overwrite "<<path<<std::endl;
444+
infostream<<"Failed to write "<<path<<std::endl;
444445
continue;
445446
}
446-
player->serialize(os);
447447
saved_players.insert(player);
448448
} else {
449449
saved_players.insert(player);
@@ -493,13 +493,13 @@ void ServerEnvironment::serializePlayers(const std::string &savedir)
493493
/*infostream<<"Saving player "<<player->getName()<<" to "
494494
<<path<<std::endl;*/
495495
// Open file and serialize
496-
std::ofstream os(path.c_str(), std::ios_base::binary);
497-
if(os.good() == false)
496+
std::ostringstream ss(std::ios_base::binary);
497+
player->serialize(ss);
498+
if(!fs::safeWriteToFile(path, ss.str()))
498499
{
499-
infostream<<"Failed to overwrite "<<path<<std::endl;
500+
infostream<<"Failed to write "<<path<<std::endl;
500501
continue;
501502
}
502-
player->serialize(os);
503503
saved_players.insert(player);
504504
}
505505
}
@@ -581,19 +581,20 @@ void ServerEnvironment::saveMeta(const std::string &savedir)
581581
std::string path = savedir + "/env_meta.txt";
582582

583583
// Open file and serialize
584-
std::ofstream os(path.c_str(), std::ios_base::binary);
585-
if(os.good() == false)
586-
{
587-
infostream<<"ServerEnvironment::saveMeta(): Failed to open "
588-
<<path<<std::endl;
589-
throw SerializationError("Couldn't save env meta");
590-
}
584+
std::ostringstream ss(std::ios_base::binary);
591585

592586
Settings args;
593587
args.setU64("game_time", m_game_time);
594588
args.setU64("time_of_day", getTimeOfDay());
595-
args.writeLines(os);
596-
os<<"EnvArgsEnd\n";
589+
args.writeLines(ss);
590+
ss<<"EnvArgsEnd\n";
591+
592+
if(!fs::safeWriteToFile(path, ss.str()))
593+
{
594+
infostream<<"ServerEnvironment::saveMeta(): Failed to write "
595+
<<path<<std::endl;
596+
throw SerializationError("Couldn't save env meta");
597+
}
597598
}
598599

599600
void ServerEnvironment::loadMeta(const std::string &savedir)

‎src/filesys.cpp

+25
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
2323
#include <stdio.h>
2424
#include <string.h>
2525
#include <errno.h>
26+
#include <sstream>
27+
#include <fstream>
2628
#include "log.h"
2729

2830
namespace fs
@@ -684,5 +686,28 @@ std::string RemoveRelativePathComponents(std::string path)
684686
return path.substr(0, pos);
685687
}
686688

689+
bool safeWriteToFile(const std::string &path, const std::string &content)
690+
{
691+
std::string tmp_file = path + ".~mt";
692+
693+
// Write to a tmp file
694+
std::ofstream os(tmp_file.c_str(), std::ios::binary);
695+
if (!os.good())
696+
return false;
697+
os << content;
698+
os.flush();
699+
os.close();
700+
if (os.fail())
701+
return false;
702+
703+
// Copy file
704+
#ifdef _WIN32
705+
remove(path.c_str());
706+
return (rename(tmp_file.c_str(), path.c_str()) == 0);
707+
#else
708+
return (rename(tmp_file.c_str(), path.c_str()) == 0);
709+
#endif
710+
}
711+
687712
} // namespace fs
688713

‎src/filesys.h

+2
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,8 @@ std::string RemoveLastPathComponent(std::string path,
9898
// this does not resolve symlinks and check for existence of directories.
9999
std::string RemoveRelativePathComponents(std::string path);
100100

101+
bool safeWriteToFile(const std::string &path, const std::string &content);
102+
101103
}//fs
102104

103105
#endif

‎src/map.cpp

+15-13
Original file line numberDiff line numberDiff line change
@@ -3490,20 +3490,21 @@ void ServerMap::saveMapMeta()
34903490
createDirs(m_savedir);
34913491

34923492
std::string fullpath = m_savedir + DIR_DELIM + "map_meta.txt";
3493-
std::ofstream os(fullpath.c_str(), std::ios_base::binary);
3494-
if(os.good() == false)
3495-
{
3496-
infostream<<"ERROR: ServerMap::saveMapMeta(): "
3497-
<<"could not open"<<fullpath<<std::endl;
3498-
throw FileNotGoodException("Cannot open chunk metadata");
3499-
}
3493+
std::ostringstream ss(std::ios_base::binary);
35003494

35013495
Settings params;
35023496

35033497
m_emerge->setParamsToSettings(&params);
3504-
params.writeLines(os);
3498+
params.writeLines(ss);
35053499

3506-
os<<"[end_of_params]\n";
3500+
ss<<"[end_of_params]\n";
3501+
3502+
if(!fs::safeWriteToFile(fullpath, ss.str()))
3503+
{
3504+
infostream<<"ERROR: ServerMap::saveMapMeta(): "
3505+
<<"could not write "<<fullpath<<std::endl;
3506+
throw FileNotGoodException("Cannot save chunk metadata");
3507+
}
35073508

35083509
m_map_metadata_changed = false;
35093510
}
@@ -3574,11 +3575,12 @@ void ServerMap::saveSectorMeta(ServerMapSector *sector)
35743575
createDirs(dir);
35753576

35763577
std::string fullpath = dir + DIR_DELIM + "meta";
3577-
std::ofstream o(fullpath.c_str(), std::ios_base::binary);
3578-
if(o.good() == false)
3579-
throw FileNotGoodException("Cannot open sector metafile");
3578+
std::ostringstream ss(std::ios_base::binary);
3579+
3580+
sector->serialize(ss, version);
35803581

3581-
sector->serialize(o, version);
3582+
if(!fs::safeWriteToFile(fullpath, ss.str()))
3583+
throw FileNotGoodException("Cannot write sector metafile");
35823584

35833585
sector->differs_from_disk = false;
35843586
}

‎src/mapgen.cpp

+10-7
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
3636
#include "mapgen_v6.h"
3737
#include "mapgen_v7.h"
3838
#include "util/serialize.h"
39+
#include "filesys.h"
3940

4041
FlagDesc flagdesc_mapgen[] = {
4142
{"trees", MG_TREES},
@@ -756,24 +757,26 @@ bool DecoSchematic::loadSchematicFile() {
756757
2 - Fixed messy never/always place; 0 probability is now never, 0xFF is always
757758
*/
758759
void DecoSchematic::saveSchematicFile(INodeDefManager *ndef) {
759-
std::ofstream os(filename.c_str(), std::ios_base::binary);
760+
std::ostringstream ss(std::ios_base::binary);
760761

761-
writeU32(os, MTSCHEM_FILE_SIGNATURE); // signature
762-
writeU16(os, 2); // version
763-
writeV3S16(os, size); // schematic size
762+
writeU32(ss, MTSCHEM_FILE_SIGNATURE); // signature
763+
writeU16(ss, 2); // version
764+
writeV3S16(ss, size); // schematic size
764765

765766
std::vector<content_t> usednodes;
766767
int nodecount = size.X * size.Y * size.Z;
767768
build_nnlist_and_update_ids(schematic, nodecount, &usednodes);
768769

769770
u16 numids = usednodes.size();
770-
writeU16(os, numids); // name count
771+
writeU16(ss, numids); // name count
771772
for (int i = 0; i != numids; i++)
772-
os << serializeString(ndef->get(usednodes[i]).name); // node names
773+
ss << serializeString(ndef->get(usednodes[i]).name); // node names
773774

774775
// compressed bulk node data
775-
MapNode::serializeBulk(os, SER_FMT_VER_HIGHEST_WRITE, schematic,
776+
MapNode::serializeBulk(ss, SER_FMT_VER_HIGHEST_WRITE, schematic,
776777
nodecount, 2, 2, true);
778+
779+
fs::safeWriteToFile(filename, ss.str());
777780
}
778781

779782

‎src/serverlist.cpp

+8-12
Original file line numberDiff line numberDiff line change
@@ -105,13 +105,11 @@ bool deleteEntry (ServerListSpec server)
105105
}
106106

107107
std::string path = ServerList::getFilePath();
108-
std::ofstream stream (path.c_str());
109-
if (stream.is_open())
110-
{
111-
stream<<ServerList::serialize(serverlist);
112-
return true;
113-
}
114-
return false;
108+
std::ostringstream ss(std::ios_base::binary);
109+
ss << ServerList::serialize(serverlist);
110+
if (!fs::safeWriteToFile(path, ss.str()))
111+
return false;
112+
return true;
115113
}
116114

117115
/*
@@ -128,11 +126,9 @@ bool insert (ServerListSpec server)
128126
serverlist.insert(serverlist.begin(), server);
129127

130128
std::string path = ServerList::getFilePath();
131-
std::ofstream stream (path.c_str());
132-
if (stream.is_open())
133-
{
134-
stream<<ServerList::serialize(serverlist);
135-
}
129+
std::ostringstream ss(std::ios_base::binary);
130+
ss << ServerList::serialize(serverlist);
131+
fs::safeWriteToFile(path, ss.str());
136132

137133
return false;
138134
}

‎src/settings.h

+11-10
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
3636
#include <list>
3737
#include <map>
3838
#include <set>
39+
#include "filesys.h"
3940

4041
enum ValueType
4142
{
@@ -308,14 +309,7 @@ class Settings
308309

309310
// Write stuff back
310311
{
311-
std::ofstream os(filename);
312-
if(os.good() == false)
313-
{
314-
errorstream<<"Error opening configuration file"
315-
" for writing: \""
316-
<<filename<<"\""<<std::endl;
317-
return false;
318-
}
312+
std::ostringstream ss(std::ios_base::binary);
319313

320314
/*
321315
Write updated stuff
@@ -324,7 +318,7 @@ class Settings
324318
i = objects.begin();
325319
i != objects.end(); ++i)
326320
{
327-
os<<(*i);
321+
ss<<(*i);
328322
}
329323

330324
/*
@@ -340,7 +334,14 @@ class Settings
340334
std::string value = i->second;
341335
infostream<<"Adding \""<<name<<"\" = \""<<value<<"\""
342336
<<std::endl;
343-
os<<name<<" = "<<value<<"\n";
337+
ss<<name<<" = "<<value<<"\n";
338+
}
339+
340+
if(!fs::safeWriteToFile(filename, ss.str()))
341+
{
342+
errorstream<<"Error writing configuration file: \""
343+
<<filename<<"\""<<std::endl;
344+
return false;
344345
}
345346
}
346347

‎src/subgame.cpp

+3-2
Original file line numberDiff line numberDiff line change
@@ -241,8 +241,9 @@ bool initializeWorld(const std::string &path, const std::string &gameid)
241241
if(!fs::PathExists(worldmt_path)){
242242
infostream<<"Creating world.mt ("<<worldmt_path<<")"<<std::endl;
243243
fs::CreateAllDirs(path);
244-
std::ofstream of(worldmt_path.c_str(), std::ios::binary);
245-
of<<"gameid = "<<gameid<<"\n";
244+
std::ostringstream ss(std::ios_base::binary);
245+
ss<<"gameid = "<<gameid<<"\n";
246+
fs::safeWriteToFile(worldmt_path, ss.str());
246247
}
247248
return true;
248249
}

0 commit comments

Comments
 (0)
Please sign in to comment.