当前位置:bitcoind.cpp=>main=>AppInit
数据目录
此处的数据目录为比特币中的区块、区块链、交易、交易池、钱包以及P2P网络等数据文件所在目录,该目录涉及我们的比特币核心程序是否可以正确运行,因此其正确设置将是至关重要的。
try
{
.....
}
catch (const std::exception& e) {
PrintExceptionContinue(&e, "AppInit()");
} catch (...) {
PrintExceptionContinue(nullptr, "AppInit()");
}
即如果try中的代码出现异常,则会被catch捕获。下面分析try中的代码。
if (!fs::is_directory(GetDataDir(false)))
{
fprintf(stderr, "Error: Specified data directory \"%s\" does not exist.\n", gArgs.GetArg("-datadir", "").c_str());
return false;
}
try
{
gArgs.ReadConfigFile(gArgs.GetArg("-conf", BITCOIN_CONF_FILENAME));
} catch (const std::exception& e) {
fprintf(stderr,"Error reading configuration file: %s\n", e.what());
return false;
}
// Check for -testnet or -regtest parameter (Params() calls are only valid after this clause)
try {
SelectParams(ChainNameFromCommandLine());
} catch (const std::exception& e) {
fprintf(stderr, "Error: %s\n", e.what());
return false;
}
我们首先看第一行的if语句,在该语句中判断了GetDataDir(false)函数返回的数据路径是否为目录名称,如果不是,则打印指定目录不存在的错误提示信息,并且因为数据目录不正确,而导致比特币核心程序无法正常运行,所以返回false,程序退出。
if语句中fs定义是:namespace fs = boost::filesystem。filesystem库是一种可移植的文件系统操作库,可以跨平台的操作目录、文件等,filesystem库的所有内容定义在boost名字空间的一个下级名字空间里,它叫boost::filesytem。
boost::filesystem::path path("");//初始化
boost::filesystem::is_directory(file_path)//判断file_path是否为目录。
数据目录是否正确的关键在于GetDataDir(false)函数获取的目录信息的正确性。那我们来看GetDataDir函数的具体实现。该函数的实现可以在src/util.cpp中找到。(555lines)
const fs::path &GetDataDir(bool fNetSpecific)
{
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 (gArgs.IsArgSet("-datadir")) {
path = fs::system_complete(gArgs.GetArg("-datadir", ""));
if (!fs::is_directory(path)) {
path = "";
return path;
}
} else {
path = GetDefaultDataDir();
}
if (fNetSpecific)
path /= BaseParams().DataDir();
fs::create_directories(path);
return path;
}
该函数的实现流程图:
函数详解如下:
1. 根据fNetSpecific确定路径类型,网络路径或本地路径,由false可知为本地路径。
2. 如果该路径不为空,则直接返回。
3. 如果参数中包含“-datadir”,则获取参数路径信息:GetArg("-datadir", ""),否则,获取默认的数据路径。
4. 判断是否为网络路径,是则获取Path中的BaseParams.DataDir()目录,该目录定义在该目录的定义在 src/chainparamsbase.h。由false可知这一段代码不会执行。
5. 最后创建该数据目录并返回。
总体来说:
如果有path路径,则直接返回这个路径;
如果没有,则查看参数gArgs中是否设置了路径,如果设置且正确(如果设置的是网络目录,则转换成本地路径),则在本地创建这个路径,并返回路径;如果设置但错误,则清空path,返回空目录;
在AppInit函数中,
if (!fs::is_directory(GetDataDir(false)))
程序中对GetDataDir(false)函数传入的参数为false,即使用本地文件目录,如果未设置“-datadir”参数,程序将执行流程图中的GetDefaultDataDir函数,该函数的实现也位于src/util.cpp中。在该函数中我们可以获得比特币后台进程在Windows、Mac以及unix等操作系统下的默认数据目录。具体如下:
fs::path GetDefaultDataDir()
{
// Windows < Vista: C:\Documents and Settings\Username\Application Data\Bitcoin
// Windows >= Vista: C:\Users\Username\AppData\Roaming\Bitcoin
// Mac: ~/Library/Application Support/Bitcoin
// Unix: ~/.bitcoin
#ifdef WIN32
// Windows
return GetSpecialFolderPath(CSIDL_APPDATA) / "Bitcoin";
#else
fs::path pathRet;
char* pszHome = getenv("HOME");
if (pszHome == nullptr || strlen(pszHome) == 0)
pathRet = fs::path("/");
else
pathRet = fs::path(pszHome);
#ifdef MAC_OSX
// Mac
return pathRet / "Library/Application Support/Bitcoin";
#else
// Unix
return pathRet / ".bitcoin";
#endif
#endif
}
pathCachedNetSpecific、pathCached定义在util.cpp中:(584)
void ClearDatadirCache()
{
LOCK(csPathCached);
pathCached = fs::path();
pathCachedNetSpecific = fs::path();
}
path = fs::system_complete(gArgs.GetArg("-datadir", ""));
转化路径为完整路径。https://link.jianshu.com/?t=https://msdn.microsoft.com/en-us/library/hh874650(v=vs.120).aspx
path /= BaseParams().DataDir();
其中BaseParams函数定义在chainparamsbase.cpp文件。(67)
const CBaseChainParams& BaseParams()
{
assert(globalChainBaseParams);
return *globalChainBaseParams;
}
返回的是*globalChainBaseParams,定义也在这个文件里,(65)
static std::unique_ptr<CBaseChainParams> globalChainBaseParams;
配置文件
完成数据目录的创建后,程序将进入配置文件读取部分。
try
{
gArgs.ReadConfigFile(gArgs.GetArg("-conf", BITCOIN_CONF_FILENAME));
} catch (const std::exception& e) {
fprintf(stderr,"Error reading configuration file: %s\n", e.what());
return false;
}
其中,BITCOIN_CONF_FILENAME定义在src/util.cpp,其值为“bitcoin.conf”,表示配置文件。(90)
const char * const BITCOIN_CONF_FILENAME = "bitcoin.conf";
ReadConfigFile函数,顾名思义,读取配置文件。定义于util.h文件,具体实现于util.cpp. (601)
void ArgsManager::ReadConfigFile(const std::string& confPath)
GetArg函数,在其实现中首先判断是否存在"-conf"参数,如果存在,则使用ParseParmeters中参数解析结果中保存的参数值作为配置文件,否则使用默认的“bitcoin.conf”。
在获得配置文件名后,我们可以来分析ReadConfigFile函数实现。在该函数实现了配置文件中参数与参数值的读取操作,并将读取的参数信息存入mapArgs与_mapMultiArgs中。
函数最后是为防止配置文件中设置了数据目录参数datadir,通过ClearDatadirCache()函数将数据文件路径参数设置为空目录,这样下次进入GetDataDir()时,我们将会根据新的datadir创建数据目录。