2018-12-27 18:50:45 +03:00
|
|
|
|
// Copyright (c) 2014-2018 Zano Project
|
|
|
|
|
|
// Copyright (c) 2014-2018 The Louisdor Project
|
2025-09-25 18:18:41 +01:00
|
|
|
|
// 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.
|
|
|
|
|
|
//
|
|
|
|
|
|
// SPDX‑License‑Identifier: EUPL-1.2
|
|
|
|
|
|
//
|
2018-12-27 18:50:45 +03:00
|
|
|
|
|
|
|
|
|
|
#include "include_base_utils.h"
|
2019-02-16 04:31:57 +03:00
|
|
|
|
#include "zlib_helper.h"
|
2018-12-27 18:50:45 +03:00
|
|
|
|
using namespace epee;
|
|
|
|
|
|
|
|
|
|
|
|
#include "util.h"
|
|
|
|
|
|
#include "currency_core/currency_config.h"
|
2019-08-29 04:37:24 +03:00
|
|
|
|
#include "version.h"
|
2025-03-14 19:15:54 +04:00
|
|
|
|
#define UTF_CPP_CPLUSPLUS 201703L
|
|
|
|
|
|
#include "utf8.h"
|
2018-12-27 18:50:45 +03:00
|
|
|
|
#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
|
|
|
|
|
|
|
2019-06-06 16:21:26 +03:00
|
|
|
|
#include <boost/asio.hpp>
|
2018-12-27 18:50:45 +03:00
|
|
|
|
|
2019-09-24 17:49:04 +03:00
|
|
|
|
#include "string_coding.h"
|
2025-04-30 03:55:13 +03:00
|
|
|
|
#include "command_line.h"
|
2019-09-24 17:49:04 +03:00
|
|
|
|
|
2018-12-27 18:50:45 +03:00
|
|
|
|
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;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2019-08-29 04:37:24 +03:00
|
|
|
|
|
|
|
|
|
|
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
|
2018-12-27 18:50:45 +03:00
|
|
|
|
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
|
2019-09-24 17:49:04 +03:00
|
|
|
|
std::wstring get_special_folder_path_w(int nfolder, bool iscreate)
|
2018-12-27 18:50:45 +03:00
|
|
|
|
{
|
2019-09-24 17:49:04 +03:00
|
|
|
|
wchar_t psz_path[MAX_PATH] = L"";
|
2018-12-27 18:50:45 +03:00
|
|
|
|
|
2019-09-24 17:49:04 +03:00
|
|
|
|
if (SHGetSpecialFolderPathW(NULL, psz_path, nfolder, iscreate))
|
2018-12-27 18:50:45 +03:00
|
|
|
|
{
|
|
|
|
|
|
return psz_path;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2019-09-24 17:49:04 +03:00
|
|
|
|
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));
|
2018-12-27 18:50:45 +03:00
|
|
|
|
}
|
|
|
|
|
|
#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
|
2019-09-24 17:49:04 +03:00
|
|
|
|
config_folder = get_special_folder_path_utf8(CSIDL_APPDATA, true) + "/" + CURRENCY_NAME_SHORT;
|
2018-12-27 18:50:45 +03:00
|
|
|
|
#else
|
2019-09-24 17:49:04 +03:00
|
|
|
|
config_folder = get_special_folder_path_utf8(CSIDL_APPDATA, true) + "/" + CURRENCY_NAME_SHORT + "-x86";
|
2018-12-27 18:50:45 +03:00
|
|
|
|
#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
|
2019-09-24 17:49:04 +03:00
|
|
|
|
wallets_dir = get_special_folder_path_utf8(CSIDL_PERSONAL, true) + "/" + CURRENCY_NAME_BASE;
|
2018-12-27 18:50:45 +03:00
|
|
|
|
#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;
|
2019-09-24 17:49:04 +03:00
|
|
|
|
fs::path fs_path = epee::string_encoding::utf8_to_wstring(path);
|
2018-12-27 18:50:45 +03:00
|
|
|
|
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());
|
|
|
|
|
|
}
|
2019-02-16 03:04:08 +03:00
|
|
|
|
|
|
|
|
|
|
#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());
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2024-09-25 04:03:57 +02:00
|
|
|
|
bool parse_client_version(const std::string& str, int& major, int& minor, int& revision, int& build_number, std::string& commit_id, bool& dirty)
|
2019-10-10 16:22:34 +03:00
|
|
|
|
{
|
2024-09-25 04:03:57 +02:00
|
|
|
|
// "10.101.999.28391"
|
|
|
|
|
|
// "10.101.999.28391[deadbeef31337]"
|
|
|
|
|
|
// "10.101.999.28391[deadbeef31337-dirty]"
|
|
|
|
|
|
// 0123456789012345678901234567890123456
|
2019-10-10 16:22:34 +03:00
|
|
|
|
|
2024-09-25 04:03:57 +02:00
|
|
|
|
if (str.size() == 0)
|
2019-10-10 16:22:34 +03:00
|
|
|
|
return false;
|
|
|
|
|
|
|
2024-09-25 04:03:57 +02:00
|
|
|
|
auto bracket_pos = str.find('[');
|
|
|
|
|
|
if (bracket_pos != std::string::npos)
|
2019-10-10 16:22:34 +03:00
|
|
|
|
{
|
2024-09-25 04:03:57 +02:00
|
|
|
|
if (str[str.size() - 1] != ']')
|
2019-10-10 16:22:34 +03:00
|
|
|
|
return false;
|
2024-09-25 04:03:57 +02:00
|
|
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
|
}
|
2019-10-10 16:22:34 +03:00
|
|
|
|
}
|
|
|
|
|
|
|
2024-09-25 04:03:57 +02:00
|
|
|
|
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;
|
2019-10-10 16:22:34 +03:00
|
|
|
|
|
2024-03-21 10:48:11 +01:00
|
|
|
|
// allow 2.x and greater
|
|
|
|
|
|
if (v_major < 2)
|
2019-10-10 16:22:34 +03:00
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-04-30 03:55:13 +03:00
|
|
|
|
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;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2020-07-11 18:42:59 +02:00
|
|
|
|
//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;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-03-12 19:51:51 +04:00
|
|
|
|
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;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-03-14 14:44:27 +04:00
|
|
|
|
|
2025-03-14 19:15:54 +04:00
|
|
|
|
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;
|
|
|
|
|
|
}
|
2025-03-14 14:44:27 +04:00
|
|
|
|
|
2025-03-14 19:15:54 +04:00
|
|
|
|
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;
|
2025-03-14 14:44:27 +04:00
|
|
|
|
}
|
2025-03-14 19:15:54 +04:00
|
|
|
|
return false;
|
2025-03-14 14:44:27 +04:00
|
|
|
|
}
|
2025-03-12 19:51:51 +04:00
|
|
|
|
|
2025-03-14 19:15:54 +04:00
|
|
|
|
// // 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
|
2025-09-25 18:18:41 +01:00
|
|
|
|
// // Also ensure it<69>s not an overlong encoding (0xC0, 0xC1 are invalid starts)
|
2025-03-14 19:15:54 +04:00
|
|
|
|
// 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;
|
|
|
|
|
|
// }
|
|
|
|
|
|
|
2019-06-06 16:21:26 +03:00
|
|
|
|
} // namespace tools
|