util: detect and warn when using exFAT on macOS
What changed, and why it matters
This commit adds a warning for Bitcoin Core users on macOS who store their data or blocks directory on an exFAT-formatted drive. It does not fix a bug in Bitcoin Core itself, but warns users about a known filesystem reliability issue on macOS that has reportedly caused database corruption and data loss. There is no security vulnerability being exploited by an attacker.
No immediate security patch action required. Operators running Bitcoin Core on macOS should ensure datadir and blocksdir are not located on exFAT volumes. Developers may consider whether similar warnings are warranted on other platforms or whether future filesystem checks should be expanded.
Security signals we found
macOS-only exFAT filesystem detection added
warning emitted during init for datadir/blocksdir on exFAT
documentation references user reports of corruption/data loss on exFAT
no code change to cryptographic, networking, consensus, or wallet logic
Evidence from the diff
The patch introduces a macOS-only filesystem type check using statfs() to detect exFAT. During startup, it checks the configured datadir and blocksdir; if either is on exFAT, it emits an InitWarning advising the user to move the directory to avoid intermittent corruption problems on macOS. It also documents this recommendation in doc/files.md, referencing GitHub issue #31454.
Changed components
src/init.cppsrc/util/fs_helpers.cppsrc/util/fs_helpers.hdoc/files.mdInspect captured patch +61 / −0
diff --git a/doc/files.md b/doc/files.md
index 1e5abdbc..5ef1e492 100644
--- a/doc/files.md
+++ b/doc/files.md
@@ -18,6 +18,8 @@
- [Installed Files](#installed-files)
+- [Filesystem recommendations](#filesystem-recommendations)
+
## Data directory location
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.
- 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`).
+
+## 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.
diff --git a/src/init.cpp b/src/init.cpp
index ac401bb7..2c2e3b77 100644
--- a/src/init.cpp
+++ b/src/init.cpp
@@ -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
const std::string block_notify = args.GetArg("-blocknotify", "");
if (!block_notify.empty()) {
diff --git a/src/util/fs_helpers.cpp b/src/util/fs_helpers.cpp
index be7f1ee5..b5dc1cb3 100644
--- a/src/util/fs_helpers.cpp
+++ b/src/util/fs_helpers.cpp
@@ -30,6 +30,11 @@
#include <shlobj.h>
#endif // WIN32
+#ifdef __APPLE__
+#include <sys/mount.h>
+#include <sys/param.h>
+#endif
+
/** Mutex to protect dir_locks. */
static GlobalMutex cs_dir_locks;
/** 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;
}
}
+
+#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
diff --git a/src/util/fs_helpers.h b/src/util/fs_helpers.h
index 28dd6d97..4d11f828 100644
--- a/src/util/fs_helpers.h
+++ b/src/util/fs_helpers.h
@@ -14,6 +14,23 @@
#include <limits>
#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
* feature analogous to fsync().
Why this scored 28/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.