Merge bitcoin/bitcoin#31453: util: detect and warn when using exFAT on MacOS

db3228042b util: detect and warn when using exFAT on macOS (willcl-ark)

Pull request description:

  exFAT is known to cause intermittent corruption on MacOS.

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

  See #28552 for more context.

ACKs for top commit:
  l0rinc:
    ACK db3228042b
  marcofleon:
    reACK db3228042b
  ismaelsadeeq:
    reACK db3228042b

Tree-SHA512: e4453a8e24b35c135e4eb0b4e47fe0c80f8b54700f458909c403aa37a0d2979ee165347bcd76e48e4d1ae5d3bae13f50e6afe714e33226a52f907b95df9d3b46
This commit is contained in:
merge-script
2025-08-12 10:23:13 -04:00
4 changed files with 61 additions and 0 deletions

View File

@@ -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.

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
const std::string block_notify = args.GetArg("-blocknotify", "");
if (!block_notify.empty()) {

View File

@@ -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

View File

@@ -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().