Changeset View
Changeset View
Standalone View
Standalone View
src/util.cpp
// Copyright (c) 2009-2010 Satoshi Nakamoto | // Copyright (c) 2009-2010 Satoshi Nakamoto | ||||
// Copyright (c) 2009-2016 The Bitcoin Core developers | // Copyright (c) 2009-2016 The Bitcoin Core developers | ||||
// Distributed under the MIT software license, see the accompanying | // Distributed under the MIT software license, see the accompanying | ||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php. | // file COPYING or http://www.opensource.org/licenses/mit-license.php. | ||||
#if defined(HAVE_CONFIG_H) | #if defined(HAVE_CONFIG_H) | ||||
#include "config/bitcoin-config.h" | #include "config/bitcoin-config.h" | ||||
#endif | #endif | ||||
#include "util.h" | #include "util.h" | ||||
#include "chainparamsbase.h" | #include "chainparamsbase.h" | ||||
#include "fs.h" | |||||
#include "random.h" | #include "random.h" | ||||
#include "serialize.h" | #include "serialize.h" | ||||
#include "sync.h" | #include "sync.h" | ||||
#include "utilstrencodings.h" | #include "utilstrencodings.h" | ||||
#include "utiltime.h" | #include "utiltime.h" | ||||
#include <cstdarg> | #include <cstdarg> | ||||
▲ Show 20 Lines • Show All 53 Lines • ▼ Show 20 Lines | |||||
#ifdef HAVE_MALLOPT_ARENA_MAX | #ifdef HAVE_MALLOPT_ARENA_MAX | ||||
#include <malloc.h> | #include <malloc.h> | ||||
#endif | #endif | ||||
#include <boost/algorithm/string/case_conv.hpp> // for to_lower() | #include <boost/algorithm/string/case_conv.hpp> // for to_lower() | ||||
#include <boost/algorithm/string/join.hpp> | #include <boost/algorithm/string/join.hpp> | ||||
#include <boost/algorithm/string/predicate.hpp> // for startswith() and endswith() | #include <boost/algorithm/string/predicate.hpp> // for startswith() and endswith() | ||||
#include <boost/filesystem.hpp> | |||||
#include <boost/filesystem/fstream.hpp> | #include <boost/filesystem/fstream.hpp> | ||||
#include <boost/program_options/detail/config_file.hpp> | #include <boost/program_options/detail/config_file.hpp> | ||||
#include <boost/program_options/parsers.hpp> | #include <boost/program_options/parsers.hpp> | ||||
#include <boost/thread.hpp> | #include <boost/thread.hpp> | ||||
#include <openssl/conf.h> | #include <openssl/conf.h> | ||||
#include <openssl/rand.h> | #include <openssl/rand.h> | ||||
▲ Show 20 Lines • Show All 100 Lines • ▼ Show 20 Lines | |||||
} | } | ||||
void OpenDebugLog() { | void OpenDebugLog() { | ||||
boost::call_once(&DebugPrintInit, debugPrintInitFlag); | boost::call_once(&DebugPrintInit, debugPrintInitFlag); | ||||
boost::mutex::scoped_lock scoped_lock(*mutexDebugLog); | boost::mutex::scoped_lock scoped_lock(*mutexDebugLog); | ||||
assert(fileout == nullptr); | assert(fileout == nullptr); | ||||
assert(vMsgsBeforeOpenLog); | assert(vMsgsBeforeOpenLog); | ||||
boost::filesystem::path pathDebug = GetDataDir() / "debug.log"; | fs::path pathDebug = GetDataDir() / "debug.log"; | ||||
fileout = fopen(pathDebug.string().c_str(), "a"); | fileout = fsbridge::fopen(pathDebug, "a"); | ||||
if (fileout) { | if (fileout) { | ||||
// Unbuffered. | // Unbuffered. | ||||
setbuf(fileout, nullptr); | setbuf(fileout, nullptr); | ||||
// Dump buffered messages from before we opened the log. | // Dump buffered messages from before we opened the log. | ||||
while (!vMsgsBeforeOpenLog->empty()) { | while (!vMsgsBeforeOpenLog->empty()) { | ||||
FileWriteStr(vMsgsBeforeOpenLog->front(), fileout); | FileWriteStr(vMsgsBeforeOpenLog->front(), fileout); | ||||
vMsgsBeforeOpenLog->pop_front(); | vMsgsBeforeOpenLog->pop_front(); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 82 Lines • ▼ Show 20 Lines | if (fPrintToConsole) { | ||||
if (fileout == nullptr) { | if (fileout == nullptr) { | ||||
assert(vMsgsBeforeOpenLog); | assert(vMsgsBeforeOpenLog); | ||||
ret = strTimestamped.length(); | ret = strTimestamped.length(); | ||||
vMsgsBeforeOpenLog->push_back(strTimestamped); | vMsgsBeforeOpenLog->push_back(strTimestamped); | ||||
} else { | } else { | ||||
// Reopen the log file, if requested. | // Reopen the log file, if requested. | ||||
if (fReopenDebugLog) { | if (fReopenDebugLog) { | ||||
fReopenDebugLog = false; | fReopenDebugLog = false; | ||||
boost::filesystem::path pathDebug = GetDataDir() / "debug.log"; | fs::path pathDebug = GetDataDir() / "debug.log"; | ||||
if (freopen(pathDebug.string().c_str(), "a", fileout) != | if (fsbridge::freopen(pathDebug, "a", fileout) != nullptr) { | ||||
nullptr) { | |||||
// unbuffered. | // unbuffered. | ||||
setbuf(fileout, nullptr); | setbuf(fileout, nullptr); | ||||
} | } | ||||
} | } | ||||
ret = FileWriteStr(strTimestamped, fileout); | ret = FileWriteStr(strTimestamped, fileout); | ||||
} | } | ||||
} | } | ||||
▲ Show 20 Lines • Show All 137 Lines • ▼ Show 20 Lines | |||||
} | } | ||||
void PrintExceptionContinue(const std::exception *pex, const char *pszThread) { | void PrintExceptionContinue(const std::exception *pex, const char *pszThread) { | ||||
std::string message = FormatException(pex, pszThread); | std::string message = FormatException(pex, pszThread); | ||||
LogPrintf("\n\n************************\n%s\n", message); | LogPrintf("\n\n************************\n%s\n", message); | ||||
fprintf(stderr, "\n\n************************\n%s\n", message.c_str()); | fprintf(stderr, "\n\n************************\n%s\n", message.c_str()); | ||||
} | } | ||||
boost::filesystem::path GetDefaultDataDir() { | fs::path GetDefaultDataDir() { | ||||
namespace fs = boost::filesystem; | |||||
// Windows < Vista: C:\Documents and Settings\Username\Application Data\Bitcoin | // Windows < Vista: C:\Documents and Settings\Username\Application Data\Bitcoin | ||||
// Windows >= Vista: C:\Users\Username\AppData\Roaming\Bitcoin | // Windows >= Vista: C:\Users\Username\AppData\Roaming\Bitcoin | ||||
// Mac: ~/Library/Application Support/Bitcoin | // Mac: ~/Library/Application Support/Bitcoin | ||||
// Unix: ~/.bitcoin | // Unix: ~/.bitcoin | ||||
#ifdef WIN32 | #ifdef WIN32 | ||||
// Windows | // Windows | ||||
return GetSpecialFolderPath(CSIDL_APPDATA) / "Bitcoin"; | return GetSpecialFolderPath(CSIDL_APPDATA) / "Bitcoin"; | ||||
#else | #else | ||||
fs::path pathRet; | fs::path pathRet; | ||||
char *pszHome = getenv("HOME"); | char *pszHome = getenv("HOME"); | ||||
if (pszHome == nullptr || strlen(pszHome) == 0) | if (pszHome == nullptr || strlen(pszHome) == 0) | ||||
pathRet = fs::path("/"); | pathRet = fs::path("/"); | ||||
else | else | ||||
pathRet = fs::path(pszHome); | pathRet = fs::path(pszHome); | ||||
#ifdef MAC_OSX | #ifdef MAC_OSX | ||||
// Mac | // Mac | ||||
return pathRet / "Library/Application Support/Bitcoin"; | return pathRet / "Library/Application Support/Bitcoin"; | ||||
#else | #else | ||||
// Unix | // Unix | ||||
return pathRet / ".bitcoin"; | return pathRet / ".bitcoin"; | ||||
#endif | #endif | ||||
#endif | #endif | ||||
} | } | ||||
static boost::filesystem::path pathCached; | static fs::path pathCached; | ||||
static boost::filesystem::path pathCachedNetSpecific; | static fs::path pathCachedNetSpecific; | ||||
static CCriticalSection csPathCached; | static CCriticalSection csPathCached; | ||||
const boost::filesystem::path &GetDataDir(bool fNetSpecific) { | const fs::path &GetDataDir(bool fNetSpecific) { | ||||
namespace fs = boost::filesystem; | |||||
LOCK(csPathCached); | LOCK(csPathCached); | ||||
fs::path &path = fNetSpecific ? pathCachedNetSpecific : pathCached; | fs::path &path = fNetSpecific ? pathCachedNetSpecific : pathCached; | ||||
// This can be called during exceptions by LogPrintf(), so we cache the | // This can be called during exceptions by LogPrintf(), so we cache the | ||||
// value so we don't have to do memory allocations after that. | // value so we don't have to do memory allocations after that. | ||||
if (!path.empty()) return path; | if (!path.empty()) return path; | ||||
Show All 11 Lines | const fs::path &GetDataDir(bool fNetSpecific) { | ||||
fs::create_directories(path); | fs::create_directories(path); | ||||
return path; | return path; | ||||
} | } | ||||
void ClearDatadirCache() { | void ClearDatadirCache() { | ||||
LOCK(csPathCached); | LOCK(csPathCached); | ||||
pathCached = boost::filesystem::path(); | pathCached = fs::path(); | ||||
pathCachedNetSpecific = boost::filesystem::path(); | pathCachedNetSpecific = fs::path(); | ||||
} | } | ||||
boost::filesystem::path GetConfigFile(const std::string &confPath) { | fs::path GetConfigFile(const std::string &confPath) { | ||||
boost::filesystem::path pathConfigFile(confPath); | fs::path pathConfigFile(confPath); | ||||
if (!pathConfigFile.is_complete()) | if (!pathConfigFile.is_complete()) | ||||
pathConfigFile = GetDataDir(false) / pathConfigFile; | pathConfigFile = GetDataDir(false) / pathConfigFile; | ||||
return pathConfigFile; | return pathConfigFile; | ||||
} | } | ||||
void ReadConfigFile(const std::string &confPath) { | void ReadConfigFile(const std::string &confPath) { | ||||
boost::filesystem::ifstream streamConfig(GetConfigFile(confPath)); | fs::ifstream streamConfig(GetConfigFile(confPath)); | ||||
// No bitcoin.conf file is OK | // No bitcoin.conf file is OK | ||||
if (!streamConfig.good()) return; | if (!streamConfig.good()) return; | ||||
{ | { | ||||
LOCK(cs_args); | LOCK(cs_args); | ||||
std::set<std::string> setOptions; | std::set<std::string> setOptions; | ||||
setOptions.insert("*"); | setOptions.insert("*"); | ||||
Show All 11 Lines | if (!streamConfig.good()) return; | ||||
_mapMultiArgs[strKey].push_back(strValue); | _mapMultiArgs[strKey].push_back(strValue); | ||||
} | } | ||||
} | } | ||||
// If datadir is changed in .conf file: | // If datadir is changed in .conf file: | ||||
ClearDatadirCache(); | ClearDatadirCache(); | ||||
} | } | ||||
#ifndef WIN32 | #ifndef WIN32 | ||||
boost::filesystem::path GetPidFile() { | fs::path GetPidFile() { | ||||
boost::filesystem::path pathPidFile(GetArg("-pid", BITCOIN_PID_FILENAME)); | fs::path pathPidFile(GetArg("-pid", BITCOIN_PID_FILENAME)); | ||||
if (!pathPidFile.is_complete()) pathPidFile = GetDataDir() / pathPidFile; | if (!pathPidFile.is_complete()) pathPidFile = GetDataDir() / pathPidFile; | ||||
return pathPidFile; | return pathPidFile; | ||||
} | } | ||||
void CreatePidFile(const boost::filesystem::path &path, pid_t pid) { | void CreatePidFile(const fs::path &path, pid_t pid) { | ||||
FILE *file = fopen(path.string().c_str(), "w"); | FILE *file = fsbridge::fopen(path, "w"); | ||||
if (file) { | if (file) { | ||||
fprintf(file, "%d\n", pid); | fprintf(file, "%d\n", pid); | ||||
fclose(file); | fclose(file); | ||||
} | } | ||||
} | } | ||||
#endif | #endif | ||||
bool RenameOver(boost::filesystem::path src, boost::filesystem::path dest) { | bool RenameOver(fs::path src, fs::path dest) { | ||||
#ifdef WIN32 | #ifdef WIN32 | ||||
return MoveFileExA(src.string().c_str(), dest.string().c_str(), | return MoveFileExA(src.string().c_str(), dest.string().c_str(), | ||||
MOVEFILE_REPLACE_EXISTING) != 0; | MOVEFILE_REPLACE_EXISTING) != 0; | ||||
#else | #else | ||||
int rc = std::rename(src.string().c_str(), dest.string().c_str()); | int rc = std::rename(src.string().c_str(), dest.string().c_str()); | ||||
return (rc == 0); | return (rc == 0); | ||||
#endif /* WIN32 */ | #endif /* WIN32 */ | ||||
} | } | ||||
/** | /** | ||||
* Ignores exceptions thrown by Boost's create_directory if the requested | * Ignores exceptions thrown by Boost's create_directory if the requested | ||||
* directory exists. Specifically handles case where path p exists, but it | * directory exists. Specifically handles case where path p exists, but it | ||||
* wasn't possible for the user to write to the parent directory. | * wasn't possible for the user to write to the parent directory. | ||||
*/ | */ | ||||
bool TryCreateDirectory(const boost::filesystem::path &p) { | bool TryCreateDirectory(const fs::path &p) { | ||||
try { | try { | ||||
return boost::filesystem::create_directory(p); | return fs::create_directory(p); | ||||
} catch (const boost::filesystem::filesystem_error &) { | } catch (const fs::filesystem_error &) { | ||||
if (!boost::filesystem::exists(p) || | if (!fs::exists(p) || !fs::is_directory(p)) { | ||||
!boost::filesystem::is_directory(p)) { | |||||
throw; | throw; | ||||
} | } | ||||
} | } | ||||
// create_directory didn't create the directory, it had to have existed | // create_directory didn't create the directory, it had to have existed | ||||
// already. | // already. | ||||
return false; | return false; | ||||
} | } | ||||
▲ Show 20 Lines • Show All 94 Lines • ▼ Show 20 Lines | #else | ||||
} | } | ||||
#endif | #endif | ||||
} | } | ||||
void ShrinkDebugFile() { | void ShrinkDebugFile() { | ||||
// Amount of debug.log to save at end when shrinking (must fit in memory) | // Amount of debug.log to save at end when shrinking (must fit in memory) | ||||
constexpr size_t RECENT_DEBUG_HISTORY_SIZE = 10 * 1000000; | constexpr size_t RECENT_DEBUG_HISTORY_SIZE = 10 * 1000000; | ||||
// Scroll debug.log if it's getting too big. | // Scroll debug.log if it's getting too big. | ||||
boost::filesystem::path pathLog = GetDataDir() / "debug.log"; | fs::path pathLog = GetDataDir() / "debug.log"; | ||||
FILE *file = fopen(pathLog.string().c_str(), "r"); | FILE *file = fsbridge::fopen(pathLog, "r"); | ||||
// If debug.log file is more than 10% bigger the RECENT_DEBUG_HISTORY_SIZE | // If debug.log file is more than 10% bigger the RECENT_DEBUG_HISTORY_SIZE | ||||
// trim it down by saving only the last RECENT_DEBUG_HISTORY_SIZE bytes. | // trim it down by saving only the last RECENT_DEBUG_HISTORY_SIZE bytes. | ||||
if (file && | if (file && | ||||
boost::filesystem::file_size(pathLog) > | fs::file_size(pathLog) > 11 * (RECENT_DEBUG_HISTORY_SIZE / 10)) { | ||||
11 * (RECENT_DEBUG_HISTORY_SIZE / 10)) { | |||||
// Restart the file with some of the end. | // Restart the file with some of the end. | ||||
std::vector<char> vch(RECENT_DEBUG_HISTORY_SIZE, 0); | std::vector<char> vch(RECENT_DEBUG_HISTORY_SIZE, 0); | ||||
fseek(file, -((long)vch.size()), SEEK_END); | fseek(file, -((long)vch.size()), SEEK_END); | ||||
int nBytes = fread(vch.data(), 1, vch.size(), file); | int nBytes = fread(vch.data(), 1, vch.size(), file); | ||||
fclose(file); | fclose(file); | ||||
file = fopen(pathLog.string().c_str(), "w"); | file = fsbridge::fopen(pathLog, "w"); | ||||
if (file) { | if (file) { | ||||
fwrite(vch.data(), 1, nBytes, file); | fwrite(vch.data(), 1, nBytes, file); | ||||
fclose(file); | fclose(file); | ||||
} | } | ||||
} else if (file != nullptr) | } else if (file != nullptr) | ||||
fclose(file); | fclose(file); | ||||
} | } | ||||
#ifdef WIN32 | #ifdef WIN32 | ||||
boost::filesystem::path GetSpecialFolderPath(int nFolder, bool fCreate) { | fs::path GetSpecialFolderPath(int nFolder, bool fCreate) { | ||||
namespace fs = boost::filesystem; | |||||
char pszPath[MAX_PATH] = ""; | char pszPath[MAX_PATH] = ""; | ||||
if (SHGetSpecialFolderPathA(nullptr, pszPath, nFolder, fCreate)) { | if (SHGetSpecialFolderPathA(nullptr, pszPath, nFolder, fCreate)) { | ||||
return fs::path(pszPath); | return fs::path(pszPath); | ||||
} | } | ||||
LogPrintf( | LogPrintf( | ||||
"SHGetSpecialFolderPathA() failed, could not obtain requested path.\n"); | "SHGetSpecialFolderPathA() failed, could not obtain requested path.\n"); | ||||
▲ Show 20 Lines • Show All 43 Lines • ▼ Show 20 Lines | try { | ||||
std::locale(""); | std::locale(""); | ||||
} catch (const std::runtime_error &) { | } catch (const std::runtime_error &) { | ||||
setenv("LC_ALL", "C", 1); | setenv("LC_ALL", "C", 1); | ||||
} | } | ||||
#endif | #endif | ||||
// The path locale is lazy initialized and to avoid deinitialization errors | // The path locale is lazy initialized and to avoid deinitialization errors | ||||
// in multithreading environments, it is set explicitly by the main thread. | // in multithreading environments, it is set explicitly by the main thread. | ||||
// A dummy locale is used to extract the internal default locale, used by | // A dummy locale is used to extract the internal default locale, used by | ||||
// boost::filesystem::path, which is then used to explicitly imbue the path. | // fs::path, which is then used to explicitly imbue the path. | ||||
std::locale loc = boost::filesystem::path::imbue(std::locale::classic()); | std::locale loc = fs::path::imbue(std::locale::classic()); | ||||
boost::filesystem::path::imbue(loc); | fs::path::imbue(loc); | ||||
} | } | ||||
bool SetupNetworking() { | bool SetupNetworking() { | ||||
#ifdef WIN32 | #ifdef WIN32 | ||||
// Initialize Windows Sockets. | // Initialize Windows Sockets. | ||||
WSADATA wsadata; | WSADATA wsadata; | ||||
int ret = WSAStartup(MAKEWORD(2, 2), &wsadata); | int ret = WSAStartup(MAKEWORD(2, 2), &wsadata); | ||||
if (ret != NO_ERROR || LOBYTE(wsadata.wVersion) != 2 || | if (ret != NO_ERROR || LOBYTE(wsadata.wVersion) != 2 || | ||||
Show All 29 Lines |