mirror of
https://github.com/dashpay/dash.git
synced 2024-12-27 04:52:59 +01:00
d36a4a4db3
cf02779
Add logging and error handling for file syncing (Wladimir J. van der Laan)
Pull request description:
Add logging and error handling inside, and outside of FileCommit.
Functions such as fsync, fdatasync will return error in case of hardware I/O errors, and ignoring this means it can silently continue through data corruption.
(c.f. https://lwn.net/SubscriberLink/752063/12b232ab5039efbe/)
EINVAL is handled specially to avoid crashing out on (network, fuse) filesystems that don't handle `f[data]sync`.
I checked that the syncing inside leveldb is already generating an I/O error as appropriate.
Tree-SHA512: 64cc9bbedca3ecc97ff4bac0a7b7ac6526a7ed763c66f6786d03ca4f2e9e366e42b152cb908299c060448d98ca39ff03395280bffaca51d592e728aa2516f5dd
147 lines
3.9 KiB
C++
147 lines
3.9 KiB
C++
// Copyright (c) 2009-2010 Satoshi Nakamoto
|
|
// Copyright (c) 2009-2015 The Bitcoin Core developers
|
|
// Distributed under the MIT software license, see the accompanying
|
|
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
|
|
|
#include <addrdb.h>
|
|
|
|
#include <addrman.h>
|
|
#include <chainparams.h>
|
|
#include <clientversion.h>
|
|
#include <hash.h>
|
|
#include <random.h>
|
|
#include <streams.h>
|
|
#include <tinyformat.h>
|
|
#include <util.h>
|
|
|
|
namespace {
|
|
|
|
template <typename Stream, typename Data>
|
|
bool SerializeDB(Stream& stream, const Data& data)
|
|
{
|
|
// Write and commit header, data
|
|
try {
|
|
CHashWriter hasher(SER_DISK, CLIENT_VERSION);
|
|
stream << Params().MessageStart() << data;
|
|
hasher << Params().MessageStart() << data;
|
|
stream << hasher.GetHash();
|
|
} catch (const std::exception& e) {
|
|
return error("%s: Serialize or I/O error - %s", __func__, e.what());
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
template <typename Data>
|
|
bool SerializeFileDB(const std::string& prefix, const fs::path& path, const Data& data)
|
|
{
|
|
// Generate random temporary filename
|
|
unsigned short randv = 0;
|
|
GetRandBytes((unsigned char*)&randv, sizeof(randv));
|
|
std::string tmpfn = strprintf("%s.%04x", prefix, randv);
|
|
|
|
// open temp output file, and associate with CAutoFile
|
|
fs::path pathTmp = GetDataDir() / tmpfn;
|
|
FILE *file = fsbridge::fopen(pathTmp, "wb");
|
|
CAutoFile fileout(file, SER_DISK, CLIENT_VERSION);
|
|
if (fileout.IsNull())
|
|
return error("%s: Failed to open file %s", __func__, pathTmp.string());
|
|
|
|
// Serialize
|
|
if (!SerializeDB(fileout, data)) return false;
|
|
if (!FileCommit(fileout.Get()))
|
|
return error("%s: Failed to flush file %s", __func__, pathTmp.string());
|
|
fileout.fclose();
|
|
|
|
// replace existing file, if any, with new file
|
|
if (!RenameOver(pathTmp, path))
|
|
return error("%s: Rename-into-place failed", __func__);
|
|
|
|
return true;
|
|
}
|
|
|
|
template <typename Stream, typename Data>
|
|
bool DeserializeDB(Stream& stream, Data& data, bool fCheckSum = true)
|
|
{
|
|
try {
|
|
CHashVerifier<Stream> verifier(&stream);
|
|
// de-serialize file header (network specific magic number) and ..
|
|
unsigned char pchMsgTmp[4];
|
|
verifier >> pchMsgTmp;
|
|
// ... verify the network matches ours
|
|
if (memcmp(pchMsgTmp, Params().MessageStart(), sizeof(pchMsgTmp)))
|
|
return error("%s: Invalid network magic number", __func__);
|
|
|
|
// de-serialize data
|
|
verifier >> data;
|
|
|
|
// verify checksum
|
|
if (fCheckSum) {
|
|
uint256 hashTmp;
|
|
stream >> hashTmp;
|
|
if (hashTmp != verifier.GetHash()) {
|
|
return error("%s: Checksum mismatch, data corrupted", __func__);
|
|
}
|
|
}
|
|
}
|
|
catch (const std::exception& e) {
|
|
return error("%s: Deserialize or I/O error - %s", __func__, e.what());
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
template <typename Data>
|
|
bool DeserializeFileDB(const fs::path& path, Data& data)
|
|
{
|
|
// open input file, and associate with CAutoFile
|
|
FILE *file = fsbridge::fopen(path, "rb");
|
|
CAutoFile filein(file, SER_DISK, CLIENT_VERSION);
|
|
if (filein.IsNull())
|
|
return error("%s: Failed to open file %s", __func__, path.string());
|
|
|
|
return DeserializeDB(filein, data);
|
|
}
|
|
|
|
}
|
|
|
|
CBanDB::CBanDB()
|
|
{
|
|
pathBanlist = GetDataDir() / "banlist.dat";
|
|
}
|
|
|
|
bool CBanDB::Write(const banmap_t& banSet)
|
|
{
|
|
return SerializeFileDB("banlist", pathBanlist, banSet);
|
|
}
|
|
|
|
bool CBanDB::Read(banmap_t& banSet)
|
|
{
|
|
return DeserializeFileDB(pathBanlist, banSet);
|
|
}
|
|
|
|
CAddrDB::CAddrDB()
|
|
{
|
|
pathAddr = GetDataDir() / "peers.dat";
|
|
}
|
|
|
|
bool CAddrDB::Write(const CAddrMan& addr)
|
|
{
|
|
return SerializeFileDB("peers", pathAddr, addr);
|
|
}
|
|
|
|
bool CAddrDB::Read(CAddrMan& addr)
|
|
{
|
|
return DeserializeFileDB(pathAddr, addr);
|
|
}
|
|
|
|
bool CAddrDB::Read(CAddrMan& addr, CDataStream& ssPeers)
|
|
{
|
|
bool ret = DeserializeDB(ssPeers, addr, false);
|
|
if (!ret) {
|
|
// Ensure addrman is left in a clean state
|
|
addr.Clear();
|
|
}
|
|
return ret;
|
|
}
|