Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
192 changes: 97 additions & 95 deletions src/wallet/wallet.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5175,127 +5175,129 @@ bool CWallet::BackupWallet(const std::string& strDest)

// This should be called carefully:
// either supply "wallet" (if already loaded) or "strWalletFile" (if wallet wasn't loaded yet)
bool AutoBackupWallet (CWallet* wallet, std::string strWalletFile, std::string& strBackupWarning, std::string& strBackupError)
bool AutoBackupWallet(CWallet* wallet, const std::string& strWalletFile_, std::string& strBackupWarningRet, std::string& strBackupErrorRet)
{
namespace fs = boost::filesystem;

strBackupWarning = strBackupError = "";
strBackupWarningRet = strBackupErrorRet = "";
std::string strWalletFile = "";

if(nWalletBackups > 0)
{
fs::path backupsDir = GetBackupsDir();
if (nWalletBackups <= 0) {
LogPrintf("Automatic wallet backups are disabled!\n");
return false;
}

if (!fs::exists(backupsDir))
{
// Always create backup folder to not confuse the operating system's file browser
LogPrintf("Creating backup folder %s\n", backupsDir.string());
if(!fs::create_directories(backupsDir)) {
// smth is wrong, we shouldn't continue until it's resolved
strBackupError = strprintf(_("Wasn't able to create wallet backup folder %s!"), backupsDir.string());
LogPrintf("%s\n", strBackupError);
nWalletBackups = -1;
return false;
}
} else if (!fs::is_directory(backupsDir)) {
fs::path backupsDir = GetBackupsDir();

if (!fs::exists(backupsDir))
{
// Always create backup folder to not confuse the operating system's file browser
LogPrintf("Creating backup folder %s\n", backupsDir.string());
if(!fs::create_directories(backupsDir)) {
// smth is wrong, we shouldn't continue until it's resolved
strBackupError = strprintf(_("%s is not a valid backup folder!"), backupsDir.string());
LogPrintf("%s\n", strBackupError);
strBackupErrorRet = strprintf(_("Wasn't able to create wallet backup folder %s!"), backupsDir.string());
LogPrintf("%s\n", strBackupErrorRet);
nWalletBackups = -1;
return false;
}
} else if (!fs::is_directory(backupsDir)) {
// smth is wrong, we shouldn't continue until it's resolved
strBackupErrorRet = strprintf(_("%s is not a valid backup folder!"), backupsDir.string());
LogPrintf("%s\n", strBackupErrorRet);
nWalletBackups = -1;
return false;
}

// Create backup of the ...
std::string dateTimeStr = DateTimeStrFormat(".%Y-%m-%d-%H-%M", GetTime());
if (wallet)
// Create backup of the ...
std::string dateTimeStr = DateTimeStrFormat(".%Y-%m-%d-%H-%M", GetTime());
if (wallet)
{
// ... opened wallet
LOCK2(cs_main, wallet->cs_wallet);
strWalletFile = wallet->strWalletFile;
fs::path backupFile = backupsDir / (strWalletFile + dateTimeStr);
if(!wallet->BackupWallet(backupFile.string())) {
strBackupWarningRet = strprintf(_("Failed to create backup %s!"), backupFile.string());
LogPrintf("%s\n", strBackupWarningRet);
nWalletBackups = -1;
return false;
}
// Update nKeysLeftSinceAutoBackup using current external keypool size
wallet->nKeysLeftSinceAutoBackup = wallet->KeypoolCountExternalKeys();
LogPrintf("nKeysLeftSinceAutoBackup: %d\n", wallet->nKeysLeftSinceAutoBackup);
if(wallet->IsLocked(true)) {
strBackupWarningRet = _("Wallet is locked, can't replenish keypool! Automatic backups and mixing are disabled, please unlock your wallet to replenish keypool.");
LogPrintf("%s\n", strBackupWarningRet);
nWalletBackups = -2;
return false;
}
} else {
// ... strWalletFile file
strWalletFile = strWalletFile_;
fs::path sourceFile = GetDataDir() / strWalletFile;
fs::path backupFile = backupsDir / (strWalletFile + dateTimeStr);
sourceFile.make_preferred();
backupFile.make_preferred();
if (fs::exists(backupFile))
{
// ... opened wallet
LOCK2(cs_main, wallet->cs_wallet);
strWalletFile = wallet->strWalletFile;
fs::path backupFile = backupsDir / (strWalletFile + dateTimeStr);
if(!wallet->BackupWallet(backupFile.string())) {
strBackupWarning = strprintf(_("Failed to create backup %s!"), backupFile.string());
LogPrintf("%s\n", strBackupWarning);
strBackupWarningRet = _("Failed to create backup, file already exists! This could happen if you restarted wallet in less than 60 seconds. You can continue if you are ok with this.");
LogPrintf("%s\n", strBackupWarningRet);
return false;
}
if(fs::exists(sourceFile)) {
try {
fs::copy_file(sourceFile, backupFile);
LogPrintf("Creating backup of %s -> %s\n", sourceFile.string(), backupFile.string());
} catch(fs::filesystem_error &error) {
strBackupWarningRet = strprintf(_("Failed to create backup, error: %s"), error.what());
LogPrintf("%s\n", strBackupWarningRet);
nWalletBackups = -1;
return false;
}
// Update nKeysLeftSinceAutoBackup using current external keypool size
wallet->nKeysLeftSinceAutoBackup = wallet->KeypoolCountExternalKeys();
LogPrintf("nKeysLeftSinceAutoBackup: %d\n", wallet->nKeysLeftSinceAutoBackup);
if(wallet->IsLocked(true)) {
strBackupWarning = _("Wallet is locked, can't replenish keypool! Automatic backups and mixing are disabled, please unlock your wallet to replenish keypool.");
LogPrintf("%s\n", strBackupWarning);
nWalletBackups = -2;
return false;
}
} else {
// ... strWalletFile file
fs::path sourceFile = GetDataDir() / strWalletFile;
fs::path backupFile = backupsDir / (strWalletFile + dateTimeStr);
sourceFile.make_preferred();
backupFile.make_preferred();
if (fs::exists(backupFile))
{
strBackupWarning = _("Failed to create backup, file already exists! This could happen if you restarted wallet in less than 60 seconds. You can continue if you are ok with this.");
LogPrintf("%s\n", strBackupWarning);
return false;
}
if(fs::exists(sourceFile)) {
try {
fs::copy_file(sourceFile, backupFile);
LogPrintf("Creating backup of %s -> %s\n", sourceFile.string(), backupFile.string());
} catch(fs::filesystem_error &error) {
strBackupWarning = strprintf(_("Failed to create backup, error: %s"), error.what());
LogPrintf("%s\n", strBackupWarning);
nWalletBackups = -1;
return false;
}
}
}
}

// Keep only the last 10 backups, including the new one of course
typedef std::multimap<std::time_t, fs::path> folder_set_t;
folder_set_t folder_set;
fs::directory_iterator end_iter;
backupsDir.make_preferred();
// Build map of backup files for current(!) wallet sorted by last write time
fs::path currentFile;
for (fs::directory_iterator dir_iter(backupsDir); dir_iter != end_iter; ++dir_iter)
// Keep only the last 10 backups, including the new one of course
typedef std::multimap<std::time_t, fs::path> folder_set_t;
folder_set_t folder_set;
fs::directory_iterator end_iter;
backupsDir.make_preferred();
// Build map of backup files for current(!) wallet sorted by last write time
fs::path currentFile;
for (fs::directory_iterator dir_iter(backupsDir); dir_iter != end_iter; ++dir_iter)
{
// Only check regular files
if ( fs::is_regular_file(dir_iter->status()))
{
// Only check regular files
if ( fs::is_regular_file(dir_iter->status()))
currentFile = dir_iter->path().filename();
// Only add the backups for the current wallet, e.g. wallet.dat.*
if(dir_iter->path().stem().string() == strWalletFile)
{
currentFile = dir_iter->path().filename();
// Only add the backups for the current wallet, e.g. wallet.dat.*
if(dir_iter->path().stem().string() == strWalletFile)
{
folder_set.insert(folder_set_t::value_type(fs::last_write_time(dir_iter->path()), *dir_iter));
}
folder_set.insert(folder_set_t::value_type(fs::last_write_time(dir_iter->path()), *dir_iter));
}
}
}

// Loop backward through backup files and keep the N newest ones (1 <= N <= 10)
int counter = 0;
BOOST_REVERSE_FOREACH(PAIRTYPE(const std::time_t, fs::path) file, folder_set)
// Loop backward through backup files and keep the N newest ones (1 <= N <= 10)
int counter = 0;
BOOST_REVERSE_FOREACH(PAIRTYPE(const std::time_t, fs::path) file, folder_set)
{
counter++;
if (counter > nWalletBackups)
{
counter++;
if (counter > nWalletBackups)
{
// More than nWalletBackups backups: delete oldest one(s)
try {
fs::remove(file.second);
LogPrintf("Old backup deleted: %s\n", file.second);
} catch(fs::filesystem_error &error) {
strBackupWarning = strprintf(_("Failed to delete backup, error: %s"), error.what());
LogPrintf("%s\n", strBackupWarning);
return false;
}
// More than nWalletBackups backups: delete oldest one(s)
try {
fs::remove(file.second);
LogPrintf("Old backup deleted: %s\n", file.second);
} catch(fs::filesystem_error &error) {
strBackupWarningRet = strprintf(_("Failed to delete backup, error: %s"), error.what());
LogPrintf("%s\n", strBackupWarningRet);
return false;
}
}
return true;
}

LogPrintf("Automatic wallet backups are disabled!\n");
return false;
return true;
}

CKeyPool::CKeyPool()
Expand Down
2 changes: 1 addition & 1 deletion src/wallet/wallet.h
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ extern const char * DEFAULT_WALLET_DAT;
//! if set, all keys will be derived by using BIP39/BIP44
static const bool DEFAULT_USE_HD_WALLET = false;

bool AutoBackupWallet (CWallet* wallet, std::string strWalletFile, std::string& strBackupWarning, std::string& strBackupError);
bool AutoBackupWallet (CWallet* wallet, const std::string& strWalletFile_, std::string& strBackupWarningRet, std::string& strBackupErrorRet);

class CBlockIndex;
class CCoinControl;
Expand Down