123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817 |
- // Copyright (c) 2009-2010 Satoshi Nakamoto
- // Copyright (c) 2009-2014 The Bitcoin Core developers
- // Distributed under the MIT software license, see the accompanying
- // file COPYING or http://www.opensource.org/licenses/mit-license.php.
- #if defined(HAVE_CONFIG_H)
- #include "config/bitcoin-config.h"
- #endif
- #include "util.h"
- #include "chainparamsbase.h"
- #include "random.h"
- #include "serialize.h"
- #include "sync.h"
- #include "utilstrencodings.h"
- #include "utiltime.h"
- #include <stdarg.h>
- #if (defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__DragonFly__))
- #include <pthread.h>
- #include <pthread_np.h>
- #endif
- #ifndef WIN32
- // for posix_fallocate
- #ifdef __linux__
- #ifdef _POSIX_C_SOURCE
- #undef _POSIX_C_SOURCE
- #endif
- #define _POSIX_C_SOURCE 200112L
- #endif // __linux__
- #include <algorithm>
- #include <fcntl.h>
- #include <sys/resource.h>
- #include <sys/stat.h>
- #else
- #ifdef _MSC_VER
- #pragma warning(disable:4786)
- #pragma warning(disable:4804)
- #pragma warning(disable:4805)
- #pragma warning(disable:4717)
- #endif
- #ifdef _WIN32_WINNT
- #undef _WIN32_WINNT
- #endif
- #define _WIN32_WINNT 0x0501
- #ifdef _WIN32_IE
- #undef _WIN32_IE
- #endif
- #define _WIN32_IE 0x0501
- #define WIN32_LEAN_AND_MEAN 1
- #ifndef NOMINMAX
- #define NOMINMAX
- #endif
- #include <io.h> /* for _commit */
- #include <shlobj.h>
- #endif
- #ifdef HAVE_SYS_PRCTL_H
- #include <sys/prctl.h>
- #endif
- #include <boost/algorithm/string/case_conv.hpp> // for to_lower()
- #include <boost/algorithm/string/join.hpp>
- #include <boost/algorithm/string/predicate.hpp> // for startswith() and endswith()
- #include <boost/filesystem.hpp>
- #include <boost/filesystem/fstream.hpp>
- #include <boost/foreach.hpp>
- #include <boost/program_options/detail/config_file.hpp>
- #include <boost/program_options/parsers.hpp>
- #include <boost/thread.hpp>
- #include <openssl/crypto.h>
- #include <openssl/rand.h>
- #include <openssl/conf.h>
- // Work around clang compilation problem in Boost 1.46:
- // /usr/include/boost/program_options/detail/config_file.hpp:163:17: error: call to function 'to_internal' that is neither visible in the template definition nor found by argument-dependent lookup
- // See also: http://stackoverflow.com/questions/10020179/compilation-fail-in-boost-librairies-program-options
- // http://clang.debian.net/status.php?version=3.0&key=CANNOT_FIND_FUNCTION
- namespace boost {
- namespace program_options {
- std::string to_internal(const std::string&);
- }
- } // namespace boost
- using namespace std;
- map<string, string> mapArgs;
- map<string, vector<string> > mapMultiArgs;
- bool fDebug = false;
- bool fPrintToConsole = false;
- bool fPrintToDebugLog = true;
- bool fDaemon = false;
- bool fServer = false;
- string strMiscWarning;
- bool fLogTimestamps = DEFAULT_LOGTIMESTAMPS;
- bool fLogTimeMicros = DEFAULT_LOGTIMEMICROS;
- bool fLogIPs = DEFAULT_LOGIPS;
- std::atomic<bool> fReopenDebugLog(false);
- CTranslationInterface translationInterface;
- /** Init OpenSSL library multithreading support */
- static CCriticalSection** ppmutexOpenSSL;
- void locking_callback(int mode, int i, const char* file, int line) NO_THREAD_SAFETY_ANALYSIS
- {
- if (mode & CRYPTO_LOCK) {
- ENTER_CRITICAL_SECTION(*ppmutexOpenSSL[i]);
- } else {
- LEAVE_CRITICAL_SECTION(*ppmutexOpenSSL[i]);
- }
- }
- // Init
- class CInit
- {
- public:
- CInit()
- {
- // Init OpenSSL library multithreading support
- ppmutexOpenSSL = (CCriticalSection**)OPENSSL_malloc(CRYPTO_num_locks() * sizeof(CCriticalSection*));
- for (int i = 0; i < CRYPTO_num_locks(); i++)
- ppmutexOpenSSL[i] = new CCriticalSection();
- CRYPTO_set_locking_callback(locking_callback);
- // OpenSSL can optionally load a config file which lists optional loadable modules and engines.
- // We don't use them so we don't require the config. However some of our libs may call functions
- // which attempt to load the config file, possibly resulting in an exit() or crash if it is missing
- // or corrupt. Explicitly tell OpenSSL not to try to load the file. The result for our libs will be
- // that the config appears to have been loaded and there are no modules/engines available.
- OPENSSL_no_config();
- #ifdef WIN32
- // Seed OpenSSL PRNG with current contents of the screen
- RAND_screen();
- #endif
- // Seed OpenSSL PRNG with performance counter
- RandAddSeed();
- }
- ~CInit()
- {
- // Securely erase the memory used by the PRNG
- RAND_cleanup();
- // Shutdown OpenSSL library multithreading support
- CRYPTO_set_locking_callback(NULL);
- for (int i = 0; i < CRYPTO_num_locks(); i++)
- delete ppmutexOpenSSL[i];
- OPENSSL_free(ppmutexOpenSSL);
- }
- }
- instance_of_cinit;
- /**
- * LogPrintf() has been broken a couple of times now
- * by well-meaning people adding mutexes in the most straightforward way.
- * It breaks because it may be called by global destructors during shutdown.
- * Since the order of destruction of static/global objects is undefined,
- * defining a mutex as a global object doesn't work (the mutex gets
- * destroyed, and then some later destructor calls OutputDebugStringF,
- * maybe indirectly, and you get a core dump at shutdown trying to lock
- * the mutex).
- */
- static boost::once_flag debugPrintInitFlag = BOOST_ONCE_INIT;
- /**
- * We use boost::call_once() to make sure these are initialized
- * in a thread-safe manner the first time called:
- */
- static FILE* fileout = NULL;
- static boost::mutex* mutexDebugLog = NULL;
- static void DebugPrintInit()
- {
- assert(fileout == NULL);
- assert(mutexDebugLog == NULL);
- boost::filesystem::path pathDebug = GetDataDir() / "debug.log";
- fileout = fopen(pathDebug.string().c_str(), "a");
- if (fileout) setbuf(fileout, NULL); // unbuffered
- mutexDebugLog = new boost::mutex();
- }
- bool LogAcceptCategory(const char* category)
- {
- if (category != NULL)
- {
- if (!fDebug)
- return false;
- // Give each thread quick access to -debug settings.
- // This helps prevent issues debugging global destructors,
- // where mapMultiArgs might be deleted before another
- // global destructor calls LogPrint()
- static boost::thread_specific_ptr<set<string> > ptrCategory;
- if (ptrCategory.get() == NULL)
- {
- const vector<string>& categories = mapMultiArgs["-debug"];
- ptrCategory.reset(new set<string>(categories.begin(), categories.end()));
- // thread_specific_ptr automatically deletes the set when the thread ends.
- }
- const set<string>& setCategories = *ptrCategory.get();
- // if not debugging everything and not debugging specific category, LogPrint does nothing.
- if (setCategories.count(string("")) == 0 &&
- setCategories.count(string(category)) == 0)
- return false;
- }
- return true;
- }
- int LogPrintStr(const std::string &str)
- {
- int ret = 0; // Returns total number of characters written
- if (fPrintToConsole)
- {
- // print to console
- ret = fwrite(str.data(), 1, str.size(), stdout);
- fflush(stdout);
- }
- else if (fPrintToDebugLog && AreBaseParamsConfigured())
- {
- static bool fStartedNewLine = true;
- boost::call_once(&DebugPrintInit, debugPrintInitFlag);
- if (fileout == NULL)
- return ret;
- boost::mutex::scoped_lock scoped_lock(*mutexDebugLog);
- // reopen the log file, if requested
- if (fReopenDebugLog) {
- fReopenDebugLog = false;
- boost::filesystem::path pathDebug = GetDataDir() / "debug.log";
- if (freopen(pathDebug.string().c_str(),"a",fileout) != NULL)
- setbuf(fileout, NULL); // unbuffered
- }
- // Debug print useful for profiling
- if (fLogTimestamps && fStartedNewLine)
- ret += fprintf(fileout, "%s ", DateTimeStrFormat("%Y-%m-%d %H:%M:%S", GetTime()).c_str());
- if (!str.empty() && str[str.size()-1] == '\n')
- fStartedNewLine = true;
- else
- fStartedNewLine = false;
- ret = fwrite(str.data(), 1, str.size(), fileout);
- }
- return ret;
- }
- static void InterpretNegativeSetting(string name, map<string, string>& mapSettingsRet)
- {
- // interpret -nofoo as -foo=0 (and -nofoo=0 as -foo=1) as long as -foo not set
- if (name.find("-no") == 0)
- {
- std::string positive("-");
- positive.append(name.begin()+3, name.end());
- if (mapSettingsRet.count(positive) == 0)
- {
- bool value = !GetBoolArg(name, false);
- mapSettingsRet[positive] = (value ? "1" : "0");
- }
- }
- }
- void ParseParameters(int argc, const char* const argv[])
- {
- mapArgs.clear();
- mapMultiArgs.clear();
- for (int i = 1; i < argc; i++)
- {
- std::string str(argv[i]);
- std::string strValue;
- size_t is_index = str.find('=');
- if (is_index != std::string::npos)
- {
- strValue = str.substr(is_index+1);
- str = str.substr(0, is_index);
- }
- #ifdef WIN32
- boost::to_lower(str);
- if (boost::algorithm::starts_with(str, "/"))
- str = "-" + str.substr(1);
- #endif
- if (str[0] != '-')
- break;
- // Interpret --foo as -foo.
- // If both --foo and -foo are set, the last takes effect.
- if (str.length() > 1 && str[1] == '-')
- str = str.substr(1);
- mapArgs[str] = strValue;
- mapMultiArgs[str].push_back(strValue);
- }
- // New 0.6 features:
- BOOST_FOREACH(const PAIRTYPE(string,string)& entry, mapArgs)
- {
- // interpret -nofoo as -foo=0 (and -nofoo=0 as -foo=1) as long as -foo not set
- InterpretNegativeSetting(entry.first, mapArgs);
- }
- }
- std::string GetArg(const std::string& strArg, const std::string& strDefault)
- {
- if (mapArgs.count(strArg))
- return mapArgs[strArg];
- return strDefault;
- }
- int64_t GetArg(const std::string& strArg, int64_t nDefault)
- {
- if (mapArgs.count(strArg))
- return atoi64(mapArgs[strArg]);
- return nDefault;
- }
- bool GetBoolArg(const std::string& strArg, bool fDefault)
- {
- if (mapArgs.count(strArg))
- {
- if (mapArgs[strArg].empty())
- return true;
- return (atoi(mapArgs[strArg]) != 0);
- }
- return fDefault;
- }
- bool SoftSetArg(const std::string& strArg, const std::string& strValue)
- {
- if (mapArgs.count(strArg))
- return false;
- mapArgs[strArg] = strValue;
- return true;
- }
- bool SoftSetBoolArg(const std::string& strArg, bool fValue)
- {
- if (fValue)
- return SoftSetArg(strArg, std::string("1"));
- else
- return SoftSetArg(strArg, std::string("0"));
- }
- static const int screenWidth = 79;
- static const int optIndent = 2;
- static const int msgIndent = 7;
- std::string HelpMessageGroup(const std::string &message) {
- return std::string(message) + std::string("\n\n");
- }
- std::string HelpMessageOpt(const std::string &option, const std::string &message) {
- return std::string(optIndent,' ') + std::string(option) +
- std::string("\n") + std::string(msgIndent,' ') +
- FormatParagraph(message, screenWidth - msgIndent, msgIndent) +
- std::string("\n\n");
- }
- static std::string FormatException(const std::exception* pex, const char* pszThread)
- {
- #ifdef WIN32
- char pszModule[MAX_PATH] = "";
- GetModuleFileNameA(NULL, pszModule, sizeof(pszModule));
- #else
- const char* pszModule = "Zcash";
- #endif
- if (pex)
- return strprintf(
- "EXCEPTION: %s \n%s \n%s in %s \n", typeid(*pex).name(), pex->what(), pszModule, pszThread);
- else
- return strprintf(
- "UNKNOWN EXCEPTION \n%s in %s \n", pszModule, pszThread);
- }
- void PrintExceptionContinue(const std::exception* pex, const char* pszThread)
- {
- std::string message = FormatException(pex, pszThread);
- LogPrintf("\n\n************************\n%s\n", message);
- fprintf(stderr, "\n\n************************\n%s\n", message.c_str());
- strMiscWarning = message;
- }
- boost::filesystem::path GetDefaultDataDir()
- {
- namespace fs = boost::filesystem;
- // Windows < Vista: C:\Documents and Settings\Username\Application Data\Zcash
- // Windows >= Vista: C:\Users\Username\AppData\Roaming\Zcash
- // Mac: ~/Library/Application Support/Zcash
- // Unix: ~/.zcash
- #ifdef WIN32
- // Windows
- return GetSpecialFolderPath(CSIDL_APPDATA) / "Zcash";
- #else
- fs::path pathRet;
- char* pszHome = getenv("HOME");
- if (pszHome == NULL || strlen(pszHome) == 0)
- pathRet = fs::path("/");
- else
- pathRet = fs::path(pszHome);
- #ifdef MAC_OSX
- // Mac
- pathRet /= "Library/Application Support";
- TryCreateDirectory(pathRet);
- return pathRet / "Zcash";
- #else
- // Unix
- return pathRet / ".zcash";
- #endif
- #endif
- }
- static boost::filesystem::path pathCached;
- static boost::filesystem::path pathCachedNetSpecific;
- static boost::filesystem::path zc_paramsPathCached;
- static CCriticalSection csPathCached;
- static boost::filesystem::path ZC_GetBaseParamsDir()
- {
- // Copied from GetDefaultDataDir and adapter for zcash params.
- namespace fs = boost::filesystem;
- // Windows < Vista: C:\Documents and Settings\Username\Application Data\ZcashParams
- // Windows >= Vista: C:\Users\Username\AppData\Roaming\ZcashParams
- // Mac: ~/Library/Application Support/ZcashParams
- // Unix: ~/.zcash-params
- #ifdef WIN32
- // Windows
- return GetSpecialFolderPath(CSIDL_APPDATA) / "ZcashParams";
- #else
- fs::path pathRet;
- char* pszHome = getenv("HOME");
- if (pszHome == NULL || strlen(pszHome) == 0)
- pathRet = fs::path("/");
- else
- pathRet = fs::path(pszHome);
- #ifdef MAC_OSX
- // Mac
- pathRet /= "Library/Application Support";
- TryCreateDirectory(pathRet);
- return pathRet / "ZcashParams";
- #else
- // Unix
- return pathRet / ".zcash-params";
- #endif
- #endif
- }
- const boost::filesystem::path &ZC_GetParamsDir()
- {
- namespace fs = boost::filesystem;
- LOCK(csPathCached); // Reuse the same lock as upstream.
- fs::path &path = zc_paramsPathCached;
- // This can be called during exceptions by LogPrintf(), so we cache the
- // value so we don't have to do memory allocations after that.
- if (!path.empty())
- return path;
- path = ZC_GetBaseParamsDir();
- return path;
- }
- const boost::filesystem::path &GetDataDir(bool fNetSpecific)
- {
- namespace fs = boost::filesystem;
- LOCK(csPathCached);
- fs::path &path = fNetSpecific ? pathCachedNetSpecific : pathCached;
- // This can be called during exceptions by LogPrintf(), so we cache the
- // value so we don't have to do memory allocations after that.
- if (!path.empty())
- return path;
- if (mapArgs.count("-datadir")) {
- path = fs::system_complete(mapArgs["-datadir"]);
- if (!fs::is_directory(path)) {
- path = "";
- return path;
- }
- } else {
- path = GetDefaultDataDir();
- }
- if (fNetSpecific)
- path /= BaseParams().DataDir();
- fs::create_directories(path);
- return path;
- }
- void ClearDatadirCache()
- {
- pathCached = boost::filesystem::path();
- pathCachedNetSpecific = boost::filesystem::path();
- }
- boost::filesystem::path GetConfigFile()
- {
- boost::filesystem::path pathConfigFile(GetArg("-conf", "zcash.conf"));
- if (!pathConfigFile.is_complete())
- pathConfigFile = GetDataDir(false) / pathConfigFile;
- return pathConfigFile;
- }
- void ReadConfigFile(map<string, string>& mapSettingsRet,
- map<string, vector<string> >& mapMultiSettingsRet)
- {
- boost::filesystem::ifstream streamConfig(GetConfigFile());
- if (!streamConfig.good())
- return; // No zcash.conf file is OK
- set<string> setOptions;
- setOptions.insert("*");
- for (boost::program_options::detail::config_file_iterator it(streamConfig, setOptions), end; it != end; ++it)
- {
- // Don't overwrite existing settings so command line settings override zcash.conf
- string strKey = string("-") + it->string_key;
- if (mapSettingsRet.count(strKey) == 0)
- {
- mapSettingsRet[strKey] = it->value[0];
- // interpret nofoo=1 as foo=0 (and nofoo=0 as foo=1) as long as foo not set)
- InterpretNegativeSetting(strKey, mapSettingsRet);
- }
- mapMultiSettingsRet[strKey].push_back(it->value[0]);
- }
- // If datadir is changed in .conf file:
- ClearDatadirCache();
- }
- #ifndef WIN32
- boost::filesystem::path GetPidFile()
- {
- boost::filesystem::path pathPidFile(GetArg("-pid", "zcashd.pid"));
- if (!pathPidFile.is_complete()) pathPidFile = GetDataDir() / pathPidFile;
- return pathPidFile;
- }
- void CreatePidFile(const boost::filesystem::path &path, pid_t pid)
- {
- FILE* file = fopen(path.string().c_str(), "w");
- if (file)
- {
- fprintf(file, "%d\n", pid);
- fclose(file);
- }
- }
- #endif
- bool RenameOver(boost::filesystem::path src, boost::filesystem::path dest)
- {
- #ifdef WIN32
- return MoveFileExA(src.string().c_str(), dest.string().c_str(),
- MOVEFILE_REPLACE_EXISTING) != 0;
- #else
- int rc = std::rename(src.string().c_str(), dest.string().c_str());
- return (rc == 0);
- #endif /* WIN32 */
- }
- /**
- * Ignores exceptions thrown by Boost's create_directory if the requested directory exists.
- * Specifically handles case where path p exists, but it wasn't possible for the user to
- * write to the parent directory.
- */
- bool TryCreateDirectory(const boost::filesystem::path& p)
- {
- try
- {
- return boost::filesystem::create_directory(p);
- } catch (const boost::filesystem::filesystem_error&) {
- if (!boost::filesystem::exists(p) || !boost::filesystem::is_directory(p))
- throw;
- }
- // create_directory didn't create the directory, it had to have existed already
- return false;
- }
- void FileCommit(FILE *fileout)
- {
- fflush(fileout); // harmless if redundantly called
- #ifdef WIN32
- HANDLE hFile = (HANDLE)_get_osfhandle(_fileno(fileout));
- FlushFileBuffers(hFile);
- #else
- #if defined(__linux__) || defined(__NetBSD__)
- fdatasync(fileno(fileout));
- #elif defined(__APPLE__) && defined(F_FULLFSYNC)
- fcntl(fileno(fileout), F_FULLFSYNC, 0);
- #else
- fsync(fileno(fileout));
- #endif
- #endif
- }
- bool TruncateFile(FILE *file, unsigned int length) {
- #if defined(WIN32)
- return _chsize(_fileno(file), length) == 0;
- #else
- return ftruncate(fileno(file), length) == 0;
- #endif
- }
- /**
- * this function tries to raise the file descriptor limit to the requested number.
- * It returns the actual file descriptor limit (which may be more or less than nMinFD)
- */
- int RaiseFileDescriptorLimit(int nMinFD) {
- #if defined(WIN32)
- return 2048;
- #else
- struct rlimit limitFD;
- if (getrlimit(RLIMIT_NOFILE, &limitFD) != -1) {
- if (limitFD.rlim_cur < (rlim_t)nMinFD) {
- limitFD.rlim_cur = nMinFD;
- if (limitFD.rlim_cur > limitFD.rlim_max)
- limitFD.rlim_cur = limitFD.rlim_max;
- setrlimit(RLIMIT_NOFILE, &limitFD);
- getrlimit(RLIMIT_NOFILE, &limitFD);
- }
- return limitFD.rlim_cur;
- }
- return nMinFD; // getrlimit failed, assume it's fine
- #endif
- }
- /**
- * this function tries to make a particular range of a file allocated (corresponding to disk space)
- * it is advisory, and the range specified in the arguments will never contain live data
- */
- void AllocateFileRange(FILE *file, unsigned int offset, unsigned int length) {
- #if defined(WIN32)
- // Windows-specific version
- HANDLE hFile = (HANDLE)_get_osfhandle(_fileno(file));
- LARGE_INTEGER nFileSize;
- int64_t nEndPos = (int64_t)offset + length;
- nFileSize.u.LowPart = nEndPos & 0xFFFFFFFF;
- nFileSize.u.HighPart = nEndPos >> 32;
- SetFilePointerEx(hFile, nFileSize, 0, FILE_BEGIN);
- SetEndOfFile(hFile);
- #elif defined(MAC_OSX)
- // OSX specific version
- fstore_t fst;
- fst.fst_flags = F_ALLOCATECONTIG;
- fst.fst_posmode = F_PEOFPOSMODE;
- fst.fst_offset = 0;
- fst.fst_length = (off_t)offset + length;
- fst.fst_bytesalloc = 0;
- if (fcntl(fileno(file), F_PREALLOCATE, &fst) == -1) {
- fst.fst_flags = F_ALLOCATEALL;
- fcntl(fileno(file), F_PREALLOCATE, &fst);
- }
- ftruncate(fileno(file), fst.fst_length);
- #elif defined(__linux__)
- // Version using posix_fallocate
- off_t nEndPos = (off_t)offset + length;
- posix_fallocate(fileno(file), 0, nEndPos);
- #else
- // Fallback version
- // TODO: just write one byte per block
- static const char buf[65536] = {};
- fseek(file, offset, SEEK_SET);
- while (length > 0) {
- unsigned int now = 65536;
- if (length < now)
- now = length;
- fwrite(buf, 1, now, file); // allowed to fail; this function is advisory anyway
- length -= now;
- }
- #endif
- }
- void ShrinkDebugFile()
- {
- // Scroll debug.log if it's getting too big
- boost::filesystem::path pathLog = GetDataDir() / "debug.log";
- FILE* file = fopen(pathLog.string().c_str(), "r");
- if (file && boost::filesystem::file_size(pathLog) > 10 * 1000000)
- {
- // Restart the file with some of the end
- std::vector <char> vch(200000,0);
- fseek(file, -((long)vch.size()), SEEK_END);
- int nBytes = fread(begin_ptr(vch), 1, vch.size(), file);
- fclose(file);
- file = fopen(pathLog.string().c_str(), "w");
- if (file)
- {
- fwrite(begin_ptr(vch), 1, nBytes, file);
- fclose(file);
- }
- }
- else if (file != NULL)
- fclose(file);
- }
- #ifdef WIN32
- boost::filesystem::path GetSpecialFolderPath(int nFolder, bool fCreate)
- {
- namespace fs = boost::filesystem;
- char pszPath[MAX_PATH] = "";
- if(SHGetSpecialFolderPathA(NULL, pszPath, nFolder, fCreate))
- {
- return fs::path(pszPath);
- }
- LogPrintf("SHGetSpecialFolderPathA() failed, could not obtain requested path.\n");
- return fs::path("");
- }
- #endif
- boost::filesystem::path GetTempPath() {
- #if BOOST_FILESYSTEM_VERSION == 3
- return boost::filesystem::temp_directory_path();
- #else
- // TODO: remove when we don't support filesystem v2 anymore
- boost::filesystem::path path;
- #ifdef WIN32
- char pszPath[MAX_PATH] = "";
- if (GetTempPathA(MAX_PATH, pszPath))
- path = boost::filesystem::path(pszPath);
- #else
- path = boost::filesystem::path("/tmp");
- #endif
- if (path.empty() || !boost::filesystem::is_directory(path)) {
- LogPrintf("GetTempPath(): failed to find temp path\n");
- return boost::filesystem::path("");
- }
- return path;
- #endif
- }
- void runCommand(std::string strCommand)
- {
- int nErr = ::system(strCommand.c_str());
- if (nErr)
- LogPrintf("runCommand error: system(%s) returned %d\n", strCommand, nErr);
- }
- void RenameThread(const char* name)
- {
- #if defined(PR_SET_NAME)
- // Only the first 15 characters are used (16 - NUL terminator)
- ::prctl(PR_SET_NAME, name, 0, 0, 0);
- #elif (defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__DragonFly__))
- pthread_set_name_np(pthread_self(), name);
- #elif defined(MAC_OSX)
- pthread_setname_np(name);
- #else
- // Prevent warnings for unused parameters...
- (void)name;
- #endif
- }
- void SetupEnvironment()
- {
- // On most POSIX systems (e.g. Linux, but not BSD) the environment's locale
- // may be invalid, in which case the "C" locale is used as fallback.
- #if !defined(WIN32) && !defined(MAC_OSX) && !defined(__FreeBSD__) && !defined(__OpenBSD__)
- try {
- std::locale(""); // Raises a runtime error if current locale is invalid
- } catch (const std::runtime_error&) {
- setenv("LC_ALL", "C", 1);
- }
- #endif
- // The path locale is lazy initialized and to avoid deinitialization errors
- // in multithreading environments, it is set explicitly by the main thread.
- // 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.
- std::locale loc = boost::filesystem::path::imbue(std::locale::classic());
- boost::filesystem::path::imbue(loc);
- }
- void SetThreadPriority(int nPriority)
- {
- #ifdef WIN32
- SetThreadPriority(GetCurrentThread(), nPriority);
- #else // WIN32
- #ifdef PRIO_THREAD
- setpriority(PRIO_THREAD, 0, nPriority);
- #else // PRIO_THREAD
- setpriority(PRIO_PROCESS, 0, nPriority);
- #endif // PRIO_THREAD
- #endif // WIN32
- }
|