util: detect and warn when using exFAT on macOS

exFAT is known to cause corruption on macOS. See #28552.

Therefore we should warn when using this fs format for either the blocks
or data directories on macOS.

Co-authored-by: l0rinc <pap.lorinc@gmail.com>
This commit is contained in:
willcl-arkandl0rinc authored and will committed 2025-08-08 19:21:06 +01:00
1 parent 2bb06bcaf2
commit db3228042b
4 files changed
+61

No files matched your search

+7
View File
@@ -18,6 +18,8 @@
- [Installed Files](#installed-files) - [Installed Files](#installed-files)
- [Filesystem recommendations](#filesystem-recommendations)
## Data directory location ## Data directory location
The data directory is the default location where the Bitcoin Core files are stored. The data directory is the default location where the Bitcoin Core files are stored.
@@ -160,3 +162,8 @@ This table describes the files installed by Bitcoin Core across different platfo
- *Italicized* files are only installed in source builds if relevant CMake options are enabled. They are not included in binary releases. - *Italicized* files are only installed in source builds if relevant CMake options are enabled. They are not included in binary releases.
- README and bitcoin.conf files are included in binary releases but not installed in source builds. - README and bitcoin.conf files are included in binary releases but not installed in source builds.
- On Windows, binaries have a `.exe` suffix (e.g., `bitcoin-cli.exe`). - On Windows, binaries have a `.exe` suffix (e.g., `bitcoin-cli.exe`).
## Filesystem recommendations
When choosing a filesystem for the data directory (`datadir`) or blocks directory (`blocksdir`) on **macOS**,the `exFAT` filesystem should be avoided.
There have been multiple reports of database corruption and data loss when using this filesystem with Bitcoin Core, see [Issue #31454](https://github.com/bitcoin/bitcoin/issues/31454) for more details.
+20
View File
@@ -1866,6 +1866,26 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
} }
} }
#ifdef __APPLE__
auto check_and_warn_fs{[&](const fs::path& path, std::string_view desc) {
const auto path_desc{strprintf("%s (\"%s\")", desc, fs::PathToString(path))};
switch (GetFilesystemType(path)) {
case FSType::EXFAT:
InitWarning(strprintf(_("The %s path uses exFAT, which is known to have intermittent corruption problems on macOS. "
"Move this directory to a different filesystem to avoid data loss."), path_desc));
break;
case FSType::ERROR:
LogInfo("Failed to detect filesystem type for %s", path_desc);
break;
case FSType::OTHER:
break;
}
}};
check_and_warn_fs(args.GetDataDirNet(), "data directory");
check_and_warn_fs(args.GetBlocksDirPath(), "blocks directory");
#endif
#if HAVE_SYSTEM #if HAVE_SYSTEM
const std::string block_notify = args.GetArg("-blocknotify", ""); const std::string block_notify = args.GetArg("-blocknotify", "");
if (!block_notify.empty()) { if (!block_notify.empty()) {
+17
View File
@@ -30,6 +30,11 @@
#include <shlobj.h> #include <shlobj.h>
#endif // WIN32 #endif // WIN32
#ifdef __APPLE__
#include <sys/mount.h>
#include <sys/param.h>
#endif
/** Mutex to protect dir_locks. */ /** Mutex to protect dir_locks. */
static GlobalMutex cs_dir_locks; static GlobalMutex cs_dir_locks;
/** A map that contains all the currently held directory locks. After /** A map that contains all the currently held directory locks. After
@@ -298,3 +303,15 @@ std::optional<fs::perms> InterpretPermString(const std::string& s)
return std::nullopt; return std::nullopt;
} }
} }
#ifdef __APPLE__
FSType GetFilesystemType(const fs::path& path)
{
if (struct statfs fs_info; statfs(path.c_str(), &fs_info)) {
return FSType::ERROR;
} else if (std::string_view{fs_info.f_fstypename} == "exfat") {
return FSType::EXFAT;
}
return FSType::OTHER;
}
#endif
+17
View File
@@ -14,6 +14,23 @@
#include <limits> #include <limits>
#include <optional> #include <optional>
#ifdef __APPLE__
enum class FSType {
EXFAT,
OTHER,
ERROR
};
/**
* Detect filesystem type for a given path.
* Currently identifies exFAT filesystems which cause issues on macOS.
*
* @param[in] path The directory path to check
* @return FSType enum indicating the filesystem type
*/
FSType GetFilesystemType(const fs::path& path);
#endif
/** /**
* Ensure file contents are fully committed to disk, using a platform-specific * Ensure file contents are fully committed to disk, using a platform-specific
* feature analogous to fsync(). * feature analogous to fsync().