1
0
Fork 0
forked from lthn/blockchain
blockchain/src/common/util.cpp
Snider 6a7b6dd2df Refactor config system and move currency_config.h
Moved currency_config.h and related CMake/config files to a new src/config directory, creating a dedicated config CMake target. Updated all includes and build scripts to reference the new config location. Removed obsolete cmake/ChainConfig.cmake and example currency config, and restructured genesis generator and premine wallet logic into the new config system for improved modularity and maintainability.
2025-09-29 19:04:52 +01:00

1061 lines
34 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// Copyright (c) 2014-2018 Zano Project
// Copyright (c) 2014-2018 The Louisdor Project
// Copyright (c) 2012-2013 The Boolberry developers
// Copyright (c) 2017-2025 Lethean (https://lt.hn)
//
// Licensed under the European Union Public Licence (EUPL) version 1.2.
// You may obtain a copy of the licence at:
//
// https://joinup.ec.europa.eu/software/page/eupl/licence-eupl
//
// The EUPL is a copyleft licence that is compatible with the MIT/X11
// licence used by the original projects; the MIT terms are therefore
// considered “grandfathered” under the EUPL for this code.
//
// SPDXLicenseIdentifier: EUPL-1.2
//
#include "include_base_utils.h"
#include "zlib_helper.h"
using namespace epee;
#include "util.h"
#include "config/currency_config.h"
#include "version.h"
#define UTF_CPP_CPLUSPLUS 201703L
#include "utf8.h"
#ifdef WIN32
#include <windows.h>
#include <shlobj.h>
#include <strsafe.h>
#include <lm.h>
#pragma comment(lib, "netapi32.lib")
#else
#include <sys/utsname.h>
#endif
#include <boost/asio.hpp>
#include "string_coding.h"
#include "command_line.h"
namespace tools
{
std::function<void(void)> signal_handler::m_handler;
std::function<void(int, void*)> signal_handler::m_fatal_handler;
#ifdef WIN32
bool GetWinMajorMinorVersion(DWORD& major, DWORD& minor)
{
bool bRetCode = false;
LPBYTE pinfoRawData = 0;
if (NERR_Success == NetWkstaGetInfo(NULL, 100, &pinfoRawData))
{
WKSTA_INFO_100* pworkstationInfo = (WKSTA_INFO_100*)pinfoRawData;
major = pworkstationInfo->wki100_ver_major;
minor = pworkstationInfo->wki100_ver_minor;
::NetApiBufferFree(pinfoRawData);
bRetCode = true;
}
return bRetCode;
}
std::string get_windows_version_display_string()
{
std::string winver;
OSVERSIONINFOEX osver;
SYSTEM_INFO sysInfo;
typedef void(__stdcall *GETSYSTEMINFO) (LPSYSTEM_INFO);
#pragma warning (push)
#pragma warning (disable:4996)
memset(&osver, 0, sizeof(osver));
osver.dwOSVersionInfoSize = sizeof(osver);
GetVersionEx((LPOSVERSIONINFO)&osver);
#pragma warning (pop)
DWORD major = 0;
DWORD minor = 0;
if (GetWinMajorMinorVersion(major, minor))
{
osver.dwMajorVersion = major;
osver.dwMinorVersion = minor;
}
else if (osver.dwMajorVersion == 6 && osver.dwMinorVersion == 2)
{
OSVERSIONINFOEXW osvi;
ULONGLONG cm = 0;
cm = VerSetConditionMask(cm, VER_MINORVERSION, VER_EQUAL);
ZeroMemory(&osvi, sizeof(osvi));
osvi.dwOSVersionInfoSize = sizeof(osvi);
osvi.dwMinorVersion = 3;
if (VerifyVersionInfoW(&osvi, VER_MINORVERSION, cm))
{
osver.dwMinorVersion = 3;
}
}
GETSYSTEMINFO getSysInfo = (GETSYSTEMINFO)GetProcAddress(GetModuleHandleA("kernel32.dll"), "GetNativeSystemInfo");
if (getSysInfo == NULL) getSysInfo = ::GetSystemInfo;
getSysInfo(&sysInfo);
if (osver.dwMajorVersion == 10 && osver.dwMinorVersion >= 0 && osver.wProductType != VER_NT_WORKSTATION) winver = "Windows 10 Server";
else if (osver.dwMajorVersion == 10 && osver.dwMinorVersion >= 0 && osver.wProductType == VER_NT_WORKSTATION) winver = "Windows 10";
else if (osver.dwMajorVersion == 6 && osver.dwMinorVersion == 3 && osver.wProductType != VER_NT_WORKSTATION) winver = "Windows Server 2012 R2";
else if (osver.dwMajorVersion == 6 && osver.dwMinorVersion == 3 && osver.wProductType == VER_NT_WORKSTATION) winver = "Windows 8.1";
else if (osver.dwMajorVersion == 6 && osver.dwMinorVersion == 2 && osver.wProductType != VER_NT_WORKSTATION) winver = "Windows Server 2012";
else if (osver.dwMajorVersion == 6 && osver.dwMinorVersion == 2 && osver.wProductType == VER_NT_WORKSTATION) winver = "Windows 8";
else if (osver.dwMajorVersion == 6 && osver.dwMinorVersion == 1 && osver.wProductType != VER_NT_WORKSTATION) winver = "Windows Server 2008 R2";
else if (osver.dwMajorVersion == 6 && osver.dwMinorVersion == 1 && osver.wProductType == VER_NT_WORKSTATION) winver = "Windows 7";
else if (osver.dwMajorVersion == 6 && osver.dwMinorVersion == 0 && osver.wProductType != VER_NT_WORKSTATION) winver = "Windows Server 2008";
else if (osver.dwMajorVersion == 6 && osver.dwMinorVersion == 0 && osver.wProductType == VER_NT_WORKSTATION) winver = "Windows Vista";
else if (osver.dwMajorVersion == 5 && osver.dwMinorVersion == 2 && osver.wProductType == VER_NT_WORKSTATION
&& sysInfo.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64)
winver = "Windows XP x64";
else if (osver.dwMajorVersion == 5 && osver.dwMinorVersion == 2) winver = "Windows Server 2003";
else if (osver.dwMajorVersion == 5 && osver.dwMinorVersion == 1) winver = "Windows XP";
else if (osver.dwMajorVersion == 5 && osver.dwMinorVersion == 0) winver = "Windows 2000";
else winver = "unknown";
if (osver.wServicePackMajor != 0)
{
std::string sp;
char buf[128] = { 0 };
sp = " Service Pack ";
sprintf_s(buf, sizeof(buf), "%hd", osver.wServicePackMajor);
sp.append(buf);
winver += sp;
}
if (osver.dwMajorVersion >= 6)
{
if (sysInfo.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64)
winver += ", 64-bit";
else if (sysInfo.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_INTEL)
winver += ", 32-bit";
}
winver += "("
+ std::to_string(osver.dwMajorVersion) + ":"
+ std::to_string(osver.dwMinorVersion) + ":"
+ std::to_string(osver.dwBuildNumber) + ":"
+ std::to_string(osver.dwPlatformId) + ":"
+ std::to_string(osver.wServicePackMajor) + ":"
+ std::to_string(osver.wServicePackMinor) + ":"
+ std::to_string(osver.wSuiteMask) + ":"
+ std::to_string(osver.wProductType) + ")";
return winver;
}
std::string get_windows_version_display_string_()
{
typedef void (WINAPI *PGNSI)(LPSYSTEM_INFO);
typedef BOOL (WINAPI *PGPI)(DWORD, DWORD, DWORD, DWORD, PDWORD);
#define BUFSIZE 10000
char pszOS[BUFSIZE] = {0};
OSVERSIONINFOEX osvi;
SYSTEM_INFO si;
PGNSI pGNSI;
PGPI pGPI;
BOOL bOsVersionInfoEx;
DWORD dwType;
ZeroMemory(&si, sizeof(SYSTEM_INFO));
ZeroMemory(&osvi, sizeof(OSVERSIONINFOEX));
osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
bOsVersionInfoEx = GetVersionEx((OSVERSIONINFO*) &osvi);
if(!bOsVersionInfoEx) return pszOS;
// Call GetNativeSystemInfo if supported or GetSystemInfo otherwise.
pGNSI = (PGNSI) GetProcAddress(
GetModuleHandle(TEXT("kernel32.dll")),
"GetNativeSystemInfo");
if(NULL != pGNSI)
pGNSI(&si);
else GetSystemInfo(&si);
if ( VER_PLATFORM_WIN32_NT==osvi.dwPlatformId &&
osvi.dwMajorVersion > 4 )
{
StringCchCopy(pszOS, BUFSIZE, TEXT("Microsoft "));
// Test for the specific product.
if ( osvi.dwMajorVersion == 6 )
{
if( osvi.dwMinorVersion == 0 )
{
if( osvi.wProductType == VER_NT_WORKSTATION )
StringCchCat(pszOS, BUFSIZE, TEXT("Windows Vista "));
else StringCchCat(pszOS, BUFSIZE, TEXT("Windows Server 2008 " ));
}
if ( osvi.dwMinorVersion == 1 )
{
if( osvi.wProductType == VER_NT_WORKSTATION )
StringCchCat(pszOS, BUFSIZE, TEXT("Windows 7 "));
else StringCchCat(pszOS, BUFSIZE, TEXT("Windows Server 2008 R2 " ));
}
pGPI = (PGPI) GetProcAddress(
GetModuleHandle(TEXT("kernel32.dll")),
"GetProductInfo");
pGPI( osvi.dwMajorVersion, osvi.dwMinorVersion, 0, 0, &dwType);
switch( dwType )
{
case PRODUCT_ULTIMATE:
StringCchCat(pszOS, BUFSIZE, TEXT("Ultimate Edition" ));
break;
case PRODUCT_PROFESSIONAL:
StringCchCat(pszOS, BUFSIZE, TEXT("Professional" ));
break;
case PRODUCT_HOME_PREMIUM:
StringCchCat(pszOS, BUFSIZE, TEXT("Home Premium Edition" ));
break;
case PRODUCT_HOME_BASIC:
StringCchCat(pszOS, BUFSIZE, TEXT("Home Basic Edition" ));
break;
case PRODUCT_ENTERPRISE:
StringCchCat(pszOS, BUFSIZE, TEXT("Enterprise Edition" ));
break;
case PRODUCT_BUSINESS:
StringCchCat(pszOS, BUFSIZE, TEXT("Business Edition" ));
break;
case PRODUCT_STARTER:
StringCchCat(pszOS, BUFSIZE, TEXT("Starter Edition" ));
break;
case PRODUCT_CLUSTER_SERVER:
StringCchCat(pszOS, BUFSIZE, TEXT("Cluster Server Edition" ));
break;
case PRODUCT_DATACENTER_SERVER:
StringCchCat(pszOS, BUFSIZE, TEXT("Datacenter Edition" ));
break;
case PRODUCT_DATACENTER_SERVER_CORE:
StringCchCat(pszOS, BUFSIZE, TEXT("Datacenter Edition (core installation)" ));
break;
case PRODUCT_ENTERPRISE_SERVER:
StringCchCat(pszOS, BUFSIZE, TEXT("Enterprise Edition" ));
break;
case PRODUCT_ENTERPRISE_SERVER_CORE:
StringCchCat(pszOS, BUFSIZE, TEXT("Enterprise Edition (core installation)" ));
break;
case PRODUCT_ENTERPRISE_SERVER_IA64:
StringCchCat(pszOS, BUFSIZE, TEXT("Enterprise Edition for Itanium-based Systems" ));
break;
case PRODUCT_SMALLBUSINESS_SERVER:
StringCchCat(pszOS, BUFSIZE, TEXT("Small Business Server" ));
break;
case PRODUCT_SMALLBUSINESS_SERVER_PREMIUM:
StringCchCat(pszOS, BUFSIZE, TEXT("Small Business Server Premium Edition" ));
break;
case PRODUCT_STANDARD_SERVER:
StringCchCat(pszOS, BUFSIZE, TEXT("Standard Edition" ));
break;
case PRODUCT_STANDARD_SERVER_CORE:
StringCchCat(pszOS, BUFSIZE, TEXT("Standard Edition (core installation)" ));
break;
case PRODUCT_WEB_SERVER:
StringCchCat(pszOS, BUFSIZE, TEXT("Web Server Edition" ));
break;
}
}
if ( osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 2 )
{
if( GetSystemMetrics(SM_SERVERR2) )
StringCchCat(pszOS, BUFSIZE, TEXT( "Windows Server 2003 R2, "));
else if ( osvi.wSuiteMask & VER_SUITE_STORAGE_SERVER )
StringCchCat(pszOS, BUFSIZE, TEXT( "Windows Storage Server 2003"));
else if ( osvi.wSuiteMask & VER_SUITE_WH_SERVER )
StringCchCat(pszOS, BUFSIZE, TEXT( "Windows Home Server"));
else if( osvi.wProductType == VER_NT_WORKSTATION &&
si.wProcessorArchitecture==PROCESSOR_ARCHITECTURE_AMD64)
{
StringCchCat(pszOS, BUFSIZE, TEXT( "Windows XP Professional x64 Edition"));
}
else StringCchCat(pszOS, BUFSIZE, TEXT("Windows Server 2003, "));
// Test for the server type.
if ( osvi.wProductType != VER_NT_WORKSTATION )
{
if ( si.wProcessorArchitecture==PROCESSOR_ARCHITECTURE_IA64 )
{
if( osvi.wSuiteMask & VER_SUITE_DATACENTER )
StringCchCat(pszOS, BUFSIZE, TEXT( "Datacenter Edition for Itanium-based Systems" ));
else if( osvi.wSuiteMask & VER_SUITE_ENTERPRISE )
StringCchCat(pszOS, BUFSIZE, TEXT( "Enterprise Edition for Itanium-based Systems" ));
}
else if ( si.wProcessorArchitecture==PROCESSOR_ARCHITECTURE_AMD64 )
{
if( osvi.wSuiteMask & VER_SUITE_DATACENTER )
StringCchCat(pszOS, BUFSIZE, TEXT( "Datacenter x64 Edition" ));
else if( osvi.wSuiteMask & VER_SUITE_ENTERPRISE )
StringCchCat(pszOS, BUFSIZE, TEXT( "Enterprise x64 Edition" ));
else StringCchCat(pszOS, BUFSIZE, TEXT( "Standard x64 Edition" ));
}
else
{
if ( osvi.wSuiteMask & VER_SUITE_COMPUTE_SERVER )
StringCchCat(pszOS, BUFSIZE, TEXT( "Compute Cluster Edition" ));
else if( osvi.wSuiteMask & VER_SUITE_DATACENTER )
StringCchCat(pszOS, BUFSIZE, TEXT( "Datacenter Edition" ));
else if( osvi.wSuiteMask & VER_SUITE_ENTERPRISE )
StringCchCat(pszOS, BUFSIZE, TEXT( "Enterprise Edition" ));
else if ( osvi.wSuiteMask & VER_SUITE_BLADE )
StringCchCat(pszOS, BUFSIZE, TEXT( "Web Edition" ));
else StringCchCat(pszOS, BUFSIZE, TEXT( "Standard Edition" ));
}
}
}
if ( osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 1 )
{
StringCchCat(pszOS, BUFSIZE, TEXT("Windows XP "));
if( osvi.wSuiteMask & VER_SUITE_PERSONAL )
StringCchCat(pszOS, BUFSIZE, TEXT( "Home Edition" ));
else StringCchCat(pszOS, BUFSIZE, TEXT( "Professional" ));
}
if ( osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 0 )
{
StringCchCat(pszOS, BUFSIZE, TEXT("Windows 2000 "));
if ( osvi.wProductType == VER_NT_WORKSTATION )
{
StringCchCat(pszOS, BUFSIZE, TEXT( "Professional" ));
}
else
{
if( osvi.wSuiteMask & VER_SUITE_DATACENTER )
StringCchCat(pszOS, BUFSIZE, TEXT( "Datacenter Server" ));
else if( osvi.wSuiteMask & VER_SUITE_ENTERPRISE )
StringCchCat(pszOS, BUFSIZE, TEXT( "Advanced Server" ));
else StringCchCat(pszOS, BUFSIZE, TEXT( "Server" ));
}
}
// Include service pack (if any) and build number.
if( strlen(osvi.szCSDVersion) > 0 )
{
StringCchCat(pszOS, BUFSIZE, TEXT(" ") );
StringCchCat(pszOS, BUFSIZE, osvi.szCSDVersion);
}
TCHAR buf[80];
StringCchPrintf( buf, 80, TEXT(" (build %d)"), osvi.dwBuildNumber);
StringCchCat(pszOS, BUFSIZE, buf);
if ( osvi.dwMajorVersion >= 6 )
{
if ( si.wProcessorArchitecture==PROCESSOR_ARCHITECTURE_AMD64 )
StringCchCat(pszOS, BUFSIZE, TEXT( ", 64-bit" ));
else if (si.wProcessorArchitecture==PROCESSOR_ARCHITECTURE_INTEL )
StringCchCat(pszOS, BUFSIZE, TEXT(", 32-bit"));
}
return pszOS;
}
else
{
printf( "This sample does not support this version of Windows.\n");
return pszOS;
}
}
void signal_handler::GenerateCrashDump(EXCEPTION_POINTERS *pep /* = NULL*/)
{
SYSTEMTIME sysTime = { 0 };
GetSystemTime(&sysTime);
// get the computer name
char compName[MAX_COMPUTERNAME_LENGTH + 1] = { 0 };
DWORD compNameLen = ARRAYSIZE(compName);
GetComputerNameA(compName, &compNameLen);
// build the filename: APPNAME_COMPUTERNAME_DATE_TIME.DMP
char path[MAX_PATH*10] = { 0 };
std::string folder = epee::log_space::log_singletone::get_default_log_folder();
sprintf_s(path, ARRAYSIZE(path),"%s\\crashdump_" PROJECT_VERSION_LONG "_%s_%04u-%02u-%02u_%02u-%02u-%02u.dmp",
folder.c_str(), compName, sysTime.wYear, sysTime.wMonth, sysTime.wDay,
sysTime.wHour, sysTime.wMinute, sysTime.wSecond);
HANDLE hFile = CreateFileA(path, GENERIC_READ | GENERIC_WRITE,
0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if ((hFile != NULL) && (hFile != INVALID_HANDLE_VALUE))
{
// Create the minidump
MINIDUMP_EXCEPTION_INFORMATION mdei;
mdei.ThreadId = GetCurrentThreadId();
mdei.ExceptionPointers = pep;
mdei.ClientPointers = FALSE;
MINIDUMP_CALLBACK_INFORMATION mci;
mci.CallbackRoutine = (MINIDUMP_CALLBACK_ROUTINE)MyMiniDumpCallback;
mci.CallbackParam = 0;
MINIDUMP_TYPE mdt = (MINIDUMP_TYPE)(MiniDumpWithPrivateReadWriteMemory |
MiniDumpWithDataSegs |
MiniDumpWithHandleData |
MiniDumpWithFullMemoryInfo |
MiniDumpWithThreadInfo |
MiniDumpWithUnloadedModules);
BOOL rv = MiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(),
hFile, mdt, (pep != 0) ? &mdei : 0, 0, &mci);
if (!rv)
{
LOG_ERROR("Minidump file create FAILED(error " << GetLastError() << ") on path: " << path);
}
else
{
LOG_PRINT_L0("Minidump file created on path: " << path);
}
// Close the file
CloseHandle(hFile);
}
else
{
LOG_ERROR("Minidump FAILED to create file (error " << GetLastError() << ") on path: " << path);
}
}
#else // ifdef WIN32
std::string get_nix_version_display_string()
{
utsname un;
if(uname(&un) < 0)
return std::string("*nix: failed to get os version");
return std::string() + un.sysname + " " + un.version + " " + un.release;
}
#endif
std::string get_os_version_string()
{
#ifdef WIN32
return get_windows_version_display_string();
#else
return get_nix_version_display_string();
#endif
}
#ifdef WIN32
std::wstring get_special_folder_path_w(int nfolder, bool iscreate)
{
wchar_t psz_path[MAX_PATH] = L"";
if (SHGetSpecialFolderPathW(NULL, psz_path, nfolder, iscreate))
{
return psz_path;
}
LOG_ERROR("SHGetSpecialFolderPathW(" << nfolder << ", " << iscreate << ") failed, could not obtain requested path.");
return L"";
}
std::string get_special_folder_path_utf8(int nfolder, bool iscreate)
{
return epee::string_encoding::wstring_to_utf8(get_special_folder_path_w(nfolder, iscreate));
}
#endif
std::string get_default_data_dir()
{
//namespace fs = boost::filesystem;
// Windows < Vista: C:\Documents and Settings\Username\Application Data\CURRENCY_NAME_SHORT
// Windows >= Vista: C:\Users\Username\AppData\Roaming\CURRENCY_NAME_SHORT
// Mac: ~/Library/Application Support/CURRENCY_NAME_SHORT
// Unix: ~/.CURRENCY_NAME_SHORT
std::string config_folder;
#ifdef WIN32
// Windows
#ifdef _M_X64
config_folder = get_special_folder_path_utf8(CSIDL_APPDATA, true) + "/" + CURRENCY_NAME_SHORT;
#else
config_folder = get_special_folder_path_utf8(CSIDL_APPDATA, true) + "/" + CURRENCY_NAME_SHORT + "-x86";
#endif
#else
std::string pathRet;
char* pszHome = getenv("HOME");
if (pszHome == NULL || strlen(pszHome) == 0)
pathRet = "/";
else
pathRet = pszHome;
#ifdef __APPLE__
// Mac
pathRet += "/Library/Application Support";
config_folder = (pathRet + "/" + CURRENCY_NAME_SHORT);
#else
// Unix
config_folder = (pathRet + "/." + CURRENCY_NAME_SHORT);
#endif
#endif
return config_folder;
}
std::string get_host_computer_name()
{
char szname[1024] = "";
gethostname(szname, sizeof(szname));
szname[sizeof(szname)-1] = 0; //just to be sure
return szname;
}
std::string get_default_user_dir()
{
//namespace fs = boost::filesystem;
// Windows < Vista: C:\Documents and Settings\Username
// Windows >= Vista: C:\Users\Username\AppData\Roaming\CURRENCY_NAME_SHORT
// Mac: ~/Library/Application Support/CURRENCY_NAME_SHORT
// Unix: ~/.CURRENCY_NAME_SHORT
std::string wallets_dir;
#ifdef WIN32
// Windows
wallets_dir = get_special_folder_path_utf8(CSIDL_PERSONAL, true) + "/" + CURRENCY_NAME_BASE;
#else
std::string pathRet;
char* pszHome = getenv("HOME");
if (pszHome == NULL || strlen(pszHome) == 0)
pathRet = "/";
else
pathRet = pszHome;
wallets_dir = (pathRet + "/" + CURRENCY_NAME_BASE);
#endif
return wallets_dir;
}
std::string get_current_username()
{
#ifdef WIN32
// Windows
const char* psz_username = getenv("USERNAME");
#else
const char* psz_username = getenv("USER");
#endif
if (psz_username == NULL || strlen(psz_username) == 0)
psz_username = "unknown_user";
return std::string(psz_username);
}
bool create_directories_if_necessary(const std::string& path)
{
namespace fs = boost::filesystem;
boost::system::error_code ec;
fs::path fs_path = epee::string_encoding::utf8_to_wstring(path);
if (fs::is_directory(fs_path, ec))
{
return true;
}
bool res = fs::create_directories(fs_path, ec);
if (res)
{
LOG_PRINT_L2("Created directory: " << path);
}
else
{
LOG_PRINT_L2("Can't create directory: " << path << ", err: "<< ec.message());
}
return res;
}
std::error_code replace_file(const std::string& replacement_name, const std::string& replaced_name)
{
int code;
#if defined(WIN32)
// Maximizing chances for success
DWORD attributes = ::GetFileAttributes(replaced_name.c_str());
if (INVALID_FILE_ATTRIBUTES != attributes)
{
::SetFileAttributes(replaced_name.c_str(), attributes & (~FILE_ATTRIBUTE_READONLY));
}
bool ok = 0 != ::MoveFileEx(replacement_name.c_str(), replaced_name.c_str(), MOVEFILE_REPLACE_EXISTING);
code = ok ? 0 : static_cast<int>(::GetLastError());
#else
bool ok = 0 == std::rename(replacement_name.c_str(), replaced_name.c_str());
code = ok ? 0 : errno;
#endif
return std::error_code(code, std::system_category());
}
#define REQUEST_LOG_CHUNK_SIZE_MAX (10 * 1024 * 1024)
bool get_log_chunk_gzipped(uint64_t offset, uint64_t size, std::string& output, std::string& error)
{
if (size > REQUEST_LOG_CHUNK_SIZE_MAX)
{
error = std::string("size is exceeding the limit = ") + epee::string_tools::num_to_string_fast(REQUEST_LOG_CHUNK_SIZE_MAX);
return false;
}
std::string log_filename = epee::log_space::log_singletone::get_actual_log_file_path();
if (std::ifstream log{ log_filename, std::ifstream::ate | std::ifstream::binary })
{
uint64_t file_size = log.tellg();
if (offset >= file_size)
{
error = "offset is out of bounds";
return false;
}
if (offset + size > file_size)
{
error = "offset + size if out of bounds";
return false;
}
if (size != 0)
{
log.seekg(offset);
output.resize(size);
log.read(&output.front(), size);
uint64_t read_bytes = log.gcount();
if (read_bytes != size)
{
error = std::string("read bytes: ") + epee::string_tools::num_to_string_fast(read_bytes);
return false;
}
if (!epee::zlib_helper::pack(output))
{
error = "zlib pack failed";
return false;
}
}
return true;
}
error = std::string("can't open ") + log_filename;
return false;
}
uint64_t get_log_file_size()
{
std::string log_filename = epee::log_space::log_singletone::get_actual_log_file_path();
std::ifstream in(log_filename, std::ifstream::ate | std::ifstream::binary);
return static_cast<uint64_t>(in.tellg());
}
bool parse_client_version(const std::string& str, int& major, int& minor, int& revision, int& build_number, std::string& commit_id, bool& dirty)
{
// "10.101.999.28391"
// "10.101.999.28391[deadbeef31337]"
// "10.101.999.28391[deadbeef31337-dirty]"
// 0123456789012345678901234567890123456
if (str.size() == 0)
return false;
auto bracket_pos = str.find('[');
if (bracket_pos != std::string::npos)
{
if (str[str.size() - 1] != ']')
return false;
commit_id = str.substr(bracket_pos + 1, str.size() - bracket_pos - 2);
auto d_pos = commit_id.find("-dirty");
if (d_pos != std::string::npos)
{
dirty = true;
commit_id.erase(d_pos);
}
}
std::string ver_str = str.substr(0, bracket_pos);
std::vector<std::string> versions;
boost::split(versions, ver_str, boost::is_any_of("."));
if (versions.size() != 4)
return false;
if (!epee::string_tools::string_to_num_fast(versions[0], major))
return false;
if (!epee::string_tools::string_to_num_fast(versions[1], minor))
return false;
if (!epee::string_tools::string_to_num_fast(versions[2], revision))
return false;
if (!epee::string_tools::string_to_num_fast(versions[3], build_number))
return false;
return true;
}
bool parse_client_version_build_number(const std::string& str, int& build_number)
{
int major = -1, minor = -1, revision = -1;
std::string commit_id;
bool dirty = false;
return tools::parse_client_version(str, major, minor, revision, build_number, commit_id, dirty);
}
bool check_remote_client_version(const std::string& client_ver)
{
int v_major = 0, v_minor = 0, v_revision = 0, v_build_number = 0;
std::string commit_id;
bool dirty_flag = false;
if (!parse_client_version(client_ver, v_major, v_minor, v_revision, v_build_number, commit_id, dirty_flag))
return false;
// allow 2.x and greater
if (v_major < 2)
return false;
return true;
}
bool is_non_pruning_mode_enabled(const boost::program_options::variables_map& vm, bool *p_enabled_via_env /* = nullptr */)
{
const char* npm_env = std::getenv("ZANO_NON_PRUNING_MODE");
std::string npm_env_str = boost::algorithm::to_lower_copy(std::string(npm_env ? npm_env : ""));
bool npm_env_enabled = (npm_env_str == "1" || npm_env_str == "on" || npm_env_str == "true");
bool result = (command_line::has_arg(vm, command_line::arg_non_pruning_mode) && command_line::get_arg(vm, command_line::arg_non_pruning_mode)) || npm_env_enabled;
if (result && p_enabled_via_env != nullptr)
*p_enabled_via_env = npm_env_enabled;
return result;
}
//this code was taken from https://stackoverflow.com/a/8594696/5566653
//credits goes to @nijansen: https://stackoverflow.com/users/1056003/nijansen
bool copy_dir( boost::filesystem::path const & source, boost::filesystem::path const & destination)
{
namespace fs = boost::filesystem;
try
{
// Check whether the function call is valid
if (!fs::exists(source) ||!fs::is_directory(source))
{
LOG_ERROR("Source directory " << source.string() << " does not exist or is not a directory.");
return false;
}
if (!fs::exists(destination))
{
if (!fs::create_directory(destination))
{
LOG_ERROR("Unable to create destination directory" << destination.string());
return false;
}
}
// Create the destination directory
}
catch (fs::filesystem_error const & e)
{
LOG_ERROR("Exception: " << e.what());
return false;
}
// Iterate through the source directory
for (fs::directory_iterator file(source); file != fs::directory_iterator(); ++file)
{
try
{
fs::path current(file->path());
if (fs::is_directory(current))
{
// Found directory: Recursion
if (!copy_dir(current, destination / current.filename()))
{
return false;
}
}
else
{
// Found file: Copy
fs::copy_file( current, destination / current.filename());
}
}
catch (fs::filesystem_error const & e)
{
LOG_ERROR("Exception: " << e.what());
}
}
return true;
}
uint64_t get_total_system_memory()
{
#if defined(_WIN32) || defined(_WIN64)
// Windows
MEMORYSTATUSEX status;
status.dwLength = sizeof(status);
if (GlobalMemoryStatusEx(&status)) {
return static_cast<std::uint64_t>(status.ullTotalPhys);
}
return 0;
#elif defined(__APPLE__) || defined(__MACH__) || defined(__linux__) || defined(__unix__)
// POSIX (Linux, macOS, etc.)
// On most Unix-like systems, sysconf(_SC_PHYS_PAGES) and sysconf(_SC_PAGE_SIZE)
// will give total number of pages and page size in bytes.
long pages = sysconf(_SC_PHYS_PAGES);
long page_size = sysconf(_SC_PAGE_SIZE);
if (pages == -1 || page_size == -1) {
return 0;
}
return static_cast<std::uint64_t>(pages) * static_cast<std::uint64_t>(page_size);
#else
// Fallback for other OS
return 0;
#endif
}
std::pair<std::string, std::string> pretty_print_big_nums_to_pair(std::uint64_t num)
{
// 1024-based suffixes
static const char* suffixes[] = { "", "K", "M", "G", "T", "P", "E" };
double count = static_cast<double>(num);
int i = 0;
// Loop until we find the largest suffix that fits
while (count >= 1024.0 && i < (static_cast<int>(sizeof(suffixes) / sizeof(suffixes[0])) - 1))
{
count /= 1024.0;
i++;
}
// Format with 2 decimal places (you can adjust as you like)
std::ostringstream os;
std::pair<std::string, std::string> res;
os << std::fixed << std::setprecision(2) << count;
res.first = os.str();
res.second = suffixes[i];
return res;
}
std::string pretty_print_big_nums(std::uint64_t num)
{
auto pr = pretty_print_big_nums_to_pair(num);
return pr.first + " " + pr.second;
}
bool isUtf8(std::string_view text, size_t* p_invalid_offset)
{
size_t local_invalid = 0;
size_t& invalid = p_invalid_offset ? *p_invalid_offset : local_invalid;
invalid = ::utf8::find_invalid(text);
return invalid == std::string_view::npos;
}
bool sanitize_utf8(std::string& str_to_sanitize)
{
size_t invalid = 0;
if (!isUtf8(str_to_sanitize, &invalid))
{
std::string temp;
utf8::replace_invalid(str_to_sanitize.begin(), str_to_sanitize.end(), back_inserter(temp));
str_to_sanitize.swap(temp);
return true;
}
return false;
}
// // UTF-8 encoding of the Unicode replacement character U+FFFD.
// static const char REPLACEMENT_CHAR_UTF8[] = "\xEF\xBF\xBD";
//
// bool sanitize_utf8(std::string& str_to_sanitize)
// {
// const unsigned char* data = reinterpret_cast<const unsigned char*>(str_to_sanitize.data());
// std::size_t length = str_to_sanitize.size();
// std::size_t i = 0;
//
// std::string sanitized;
// sanitized.reserve(length); // Reserve to avoid repeated allocations
//
// bool changed = false;
//
// while (i < length)
// {
// unsigned char c = data[i];
//
// // 1) ASCII fast path: 0xxxxxxx
// if (c < 0x80)
// {
// sanitized.push_back(static_cast<char>(c));
// i++;
// }
// // 2) 2-byte sequence: 110xxxxx 10xxxxxx
// else if ((c & 0xE0) == 0xC0)
// {
// // Need at least 2 bytes total
// if (i + 1 < length)
// {
// unsigned char c2 = data[i + 1];
// // Valid second byte: 10xxxxxx
// // Also ensure it<69>s not an overlong encoding (0xC0, 0xC1 are invalid starts)
// if ((c2 & 0xC0) == 0x80 && (c & 0xFE) != 0xC0)
// {
// sanitized.push_back(static_cast<char>(c));
// sanitized.push_back(static_cast<char>(c2));
// i += 2;
// }
// else
// {
// sanitized.append(REPLACEMENT_CHAR_UTF8);
// changed = true;
// // Advance by one or two bytes if second byte was somewhat valid
// i += 1 + ((c2 & 0xC0) == 0x80);
// }
// }
// else
// {
// // Truncated 2-byte sequence at the end
// sanitized.append(REPLACEMENT_CHAR_UTF8);
// changed = true;
// i++;
// }
// }
// // 3) 3-byte sequence: 1110xxxx 10xxxxxx 10xxxxxx
// else if ((c & 0xF0) == 0xE0)
// {
// // Need at least 3 bytes total
// if (i + 2 < length)
// {
// unsigned char c2 = data[i + 1];
// unsigned char c3 = data[i + 2];
// if (((c2 & 0xC0) == 0x80) &&
// ((c3 & 0xC0) == 0x80))
// {
// // Combine to form a code point:
// // 1110xxxx 10xxxxxx 10xxxxxx
// // Check for UTF-16 surrogates (invalid in UTF-8)
// unsigned int codepoint = ((c & 0x0F) << 12)
// | ((c2 & 0x3F) << 6)
// | (c3 & 0x3F);
// if (codepoint >= 0xD800 && codepoint <= 0xDFFF)
// {
// // Surrogate half, invalid in UTF-8
// sanitized.append(REPLACEMENT_CHAR_UTF8);
// changed = true;
// }
// else
// {
// // Valid 3-byte sequence
// sanitized.push_back(static_cast<char>(c));
// sanitized.push_back(static_cast<char>(c2));
// sanitized.push_back(static_cast<char>(c3));
// }
// i += 3;
// }
// else
// {
// sanitized.append(REPLACEMENT_CHAR_UTF8);
// changed = true;
// // Advance by how many bytes look valid
// i += 1 + ((c2 & 0xC0) == 0x80) + ((c3 & 0xC0) == 0x80);
// }
// }
// else
// {
// // Truncated 3-byte sequence
// sanitized.append(REPLACEMENT_CHAR_UTF8);
// changed = true;
// i = length; // jump out
// }
// }
// // 4) 4-byte sequence: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
// else if ((c & 0xF8) == 0xF0)
// {
// // Need at least 4 bytes total
// if (i + 3 < length)
// {
// unsigned char c2 = data[i + 1];
// unsigned char c3 = data[i + 2];
// unsigned char c4 = data[i + 3];
// if (((c2 & 0xC0) == 0x80) &&
// ((c3 & 0xC0) == 0x80) &&
// ((c4 & 0xC0) == 0x80))
// {
// // Combine to form a code point:
// // 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
// unsigned int codepoint = ((c & 0x07) << 18)
// | ((c2 & 0x3F) << 12)
// | ((c3 & 0x3F) << 6)
// | (c4 & 0x3F);
// // Max valid code point is 0x10FFFF
// if (codepoint <= 0x10FFFF)
// {
// sanitized.push_back(static_cast<char>(c));
// sanitized.push_back(static_cast<char>(c2));
// sanitized.push_back(static_cast<char>(c3));
// sanitized.push_back(static_cast<char>(c4));
// }
// else
// {
// sanitized.append(REPLACEMENT_CHAR_UTF8);
// changed = true;
// }
// i += 4;
// }
// else
// {
// sanitized.append(REPLACEMENT_CHAR_UTF8);
// changed = true;
// i += 1 + ((c2 & 0xC0) == 0x80) +
// ((c3 & 0xC0) == 0x80) +
// ((c4 & 0xC0) == 0x80);
// }
// }
// else
// {
// // Truncated 4-byte sequence
// sanitized.append(REPLACEMENT_CHAR_UTF8);
// changed = true;
// i = length; // jump out
// }
// }
// else
// {
// // Invalid leading byte (> 0xF4 or some unexpected pattern)
// sanitized.append(REPLACEMENT_CHAR_UTF8);
// changed = true;
// i++;
// }
// }
//
// // Update original string only if changes were made
// if (changed)
// {
// str_to_sanitize = std::move(sanitized);
// return true;
// }
// return false;
// }
} // namespace tools