Skip to content

Commit eb68bb4

Browse files
committed
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.
1 parent ed060e0 commit eb68bb4

File tree

4 files changed

+73
-0
lines changed

4 files changed

+73
-0
lines changed

doc/files.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616

1717
- [Berkeley DB database based wallets](#berkeley-db-database-based-wallets)
1818

19+
- [Filesystem recommendations](#filesystem-recommendations)
20+
1921
- [Notes](#notes)
2022

2123
## Data directory location
@@ -123,6 +125,12 @@ Subdirectory | File(s) | Description
123125
`./` | `wallet.dat` | Personal wallet (a BDB database) with keys and transactions
124126
`./` | `.walletlock` | BDB wallet lock file
125127

128+
## Filesystem recommendations
129+
130+
When choosing a filesystem for the data directory (`datadir`) or blocks directory (`blocksdir`), some filesystems should be avoided:
131+
132+
- **macOS**: The exFAT filesystem should not be used. There have been multiple reports of database and other corruption when using exFAT on macOS for Bitcoin Core. This appears to be due to filesystem-level issues with exFAT on the macOS operating system. See [Issue #31454](https://github.com/bitcoin/bitcoin/issues/31454) for more details.
133+
126134
## Notes
127135

128136
<a name="note1">1</a>. The `/` (slash, U+002F) is used as the platform-independent path component separator in this document.

src/init.cpp

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1841,6 +1841,35 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
18411841
}
18421842
}
18431843

1844+
#ifdef __APPLE__
1845+
// Warn about exFAT filesystem usage on macOS
1846+
std::vector<std::string> exfat_paths;
1847+
std::vector<std::string> error_paths;
1848+
1849+
auto check_fs = [&](const fs::path& path, std::string_view desc) {
1850+
FSType fs_type = GetFilesystemType(path);
1851+
std::string path_desc = strprintf("%s (\"%s\")", desc, fs::PathToString(path));
1852+
if (fs_type == FSType::EXFAT) {
1853+
exfat_paths.push_back(path_desc);
1854+
} else if (fs_type == FSType::ERROR) {
1855+
error_paths.push_back(path_desc);
1856+
}
1857+
};
1858+
1859+
check_fs(args.GetDataDirNet(), "data directory");
1860+
check_fs(args.GetBlocksDirPath(), "blocks directory");
1861+
1862+
if (!exfat_paths.empty()) {
1863+
InitWarning(strprintf(_("The following paths are on exFAT which is known to have intermittent corruption problems on macOS: %s. "
1864+
"Move these directories to a non-exFAT formatted drive to avoid corruption."),
1865+
util::Join(exfat_paths, ", ")));
1866+
}
1867+
1868+
if (!error_paths.empty()) {
1869+
LogInfo("Failed to detect filesystem type for: %s\n", util::Join(error_paths, ", "));
1870+
}
1871+
#endif
1872+
18441873
#if HAVE_SYSTEM
18451874
const std::string block_notify = args.GetArg("-blocknotify", "");
18461875
if (!block_notify.empty()) {

src/util/fs_helpers.cpp

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,11 @@
3030
#include <shlobj.h>
3131
#endif // WIN32
3232

33+
#ifdef __APPLE__
34+
#include <sys/mount.h>
35+
#include <sys/param.h>
36+
#endif
37+
3338
/** Mutex to protect dir_locks. */
3439
static GlobalMutex cs_dir_locks;
3540
/** A map that contains all the currently held directory locks. After
@@ -298,3 +303,17 @@ std::optional<fs::perms> InterpretPermString(const std::string& s)
298303
return std::nullopt;
299304
}
300305
}
306+
307+
#ifdef __APPLE__
308+
FSType GetFilesystemType(const fs::path& path) {
309+
struct statfs fs_info;
310+
if (statfs(path.c_str(), &fs_info) != 0) {
311+
return FSType::ERROR;
312+
}
313+
314+
if (strcmp(fs_info.f_fstypename, "exfat") == 0) {
315+
return FSType::EXFAT;
316+
}
317+
return FSType::OTHER;
318+
}
319+
#endif

src/util/fs_helpers.h

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,23 @@
1414
#include <limits>
1515
#include <optional>
1616

17+
#ifdef __APPLE__
18+
enum class FSType {
19+
EXFAT,
20+
OTHER,
21+
ERROR
22+
};
23+
24+
/**
25+
* Detect filesystem type for a given path.
26+
* Currently identifies exFAT filesystems which cause issues on MacOS.
27+
*
28+
* @param[in] path The directory path to check
29+
* @return FSType enum indicating the filesystem type
30+
*/
31+
FSType GetFilesystemType(const fs::path& path);
32+
#endif
33+
1734
/**
1835
* Ensure file contents are fully committed to disk, using a platform-specific
1936
* feature analogous to fsync().

0 commit comments

Comments
 (0)