v29.4-roots.3 · Commit 4: [PATCH 04/30] wallet: harden database and signing behavior
src/wallet/db.cpp
Before: src/wallet/db.cpp · After: src/wallet/db.cpp
File metadata
index 1c007ba949b3b06c5f7c3f63e44cc82a2acad1a5..4ccd1c1b69a45c536ccd3849375d6a33f52441d0 100644
Download original patch · Release notes
Diff rows 1–99 of 99. Line numbers refer to the original before/after files.
+ Added− RemovedUnmarked lines are context.
Scroll the code area horizontally to read long lines. The two line-number columns refer to before and after.
src/wallet/db.cpp
CHANGED
|
@@ -7,11 +7,13 @@
|
|
|
7
7
|
#include <common/args.h>
|
|
8
8
|
#include <logging.h>
|
|
9
9
|
#include <util/fs.h>
|
|
10
|
+
#include <util/fs_helpers.h>
|
|
10
11
|
#include <wallet/db.h>
|
|
11
12
|
|
|
12
13
|
#include <algorithm>
|
|
13
14
|
#include <exception>
|
|
14
15
|
#include <fstream>
|
|
16
|
+
#include <set>
|
|
15
17
|
#include <string>
|
|
16
18
|
#include <system_error>
|
|
17
19
|
#include <vector>
|
|
@@ -22,23 +24,44 @@ bool operator<(Span<const std::byte> a, BytePrefix b) { return std::ranges::lexi
|
|
|
22
24
|
|
|
23
25
|
std::vector<std::pair<fs::path, std::string>> ListDatabases(const fs::path& wallet_dir)
|
|
24
26
|
{
|
|
27
|
+
const fs::path& data_dir = gArgs.GetDataDirNet();
|
|
28
|
+
const fs::path& blocks_dir = gArgs.GetBlocksDirPath();
|
|
29
|
+
|
|
30
|
+
// Here we place the top level dirs we want to skip in case walletdir is datadir or blocksdir
|
|
31
|
+
// Those directories are referenced in doc/files.md
|
|
32
|
+
const std::set<fs::path> ignore_paths = {
|
|
33
|
+
blocks_dir,
|
|
34
|
+
data_dir / "blktree",
|
|
35
|
+
data_dir / "blocks",
|
|
36
|
+
data_dir / "chainstate",
|
|
37
|
+
data_dir / "coins",
|
|
38
|
+
data_dir / "database",
|
|
39
|
+
data_dir / "indexes",
|
|
40
|
+
data_dir / "regtest",
|
|
41
|
+
data_dir / "signet",
|
|
42
|
+
data_dir / "testnet3"
|
|
43
|
+
};
|
|
44
|
+
|
|
25
45
|
std::vector<std::pair<fs::path, std::string>> paths;
|
|
26
46
|
std::error_code ec;
|
|
27
47
|
|
|
28
48
|
for (auto it = fs::recursive_directory_iterator(wallet_dir, ec); it != fs::recursive_directory_iterator(); it.increment(ec)) {
|
|
29
|
-
if (ec) {
|
|
30
|
-
if (fs::is_directory(*it)) {
|
|
31
|
-
it.disable_recursion_pending();
|
|
32
|
-
LogPrintf("%s: %s %s -- skipping.\n", __func__, ec.message(), fs::PathToString(it->path()));
|
|
33
|
-
} else {
|
|
34
|
-
LogPrintf("%s: %s %s\n", __func__, ec.message(), fs::PathToString(it->path()));
|
|
35
|
-
}
|
|
49
|
+
assert(!ec); // Loop should exit on error.
|
|
50
|
+
|
|
51
|
+
// We don't want to iterate through those special node dirs
|
|
52
|
+
if (ignore_paths.count(it->path())) {
|
|
53
|
+
it.disable_recursion_pending();
|
|
36
54
|
continue;
|
|
37
55
|
}
|
|
38
56
|
|
|
39
57
|
try {
|
|
40
58
|
const fs::path path{it->path().lexically_relative(wallet_dir)};
|
|
41
59
|
|
|
60
|
+
if (IsSymlink(it->path())) {
|
|
61
|
+
LogWarning("Not recursively searching symlink/reparse point at '%s'", fs::PathToString(it->path()));
|
|
62
|
+
it.disable_recursion_pending();
|
|
63
|
+
}
|
|
64
|
+
|
|
42
65
|
if (it->status().type() == fs::file_type::directory) {
|
|
43
66
|
if (IsBDBFile(BDBDataFile(it->path()))) {
|
|
44
67
|
// Found a directory which contains wallet.dat btree file, add it as a wallet with BERKELEY format.
|
|
@@ -65,10 +88,18 @@ std::vector<std::pair<fs::path, std::string>> ListDatabases(const fs::path& wall
|
|
|
65
88
|
}
|
|
66
89
|
}
|
|
67
90
|
} catch (const std::exception& e) {
|
|
68
|
-
LogPrintf("%s: Error scanning %s: %s\n", __func__, fs::PathToString(it->path()), e.what());
|
|
91
|
+
LogWarning("Error while scanning wallet dir item: %s [%s].", e.what(), fs::PathToString(it->path()));
|
|
69
92
|
it.disable_recursion_pending();
|
|
70
93
|
}
|
|
71
94
|
}
|
|
95
|
+
if (ec) {
|
|
96
|
+
// Loop could have exited with an error due to one of:
|
|
97
|
+
// * wallet_dir itself not being scannable.
|
|
98
|
+
// * increment() failure. (Observed on Windows native builds when
|
|
99
|
+
// removing the ACL read permissions of a wallet directory after the
|
|
100
|
+
// process started).
|
|
101
|
+
LogWarning("Error scanning directory entries under %s: %s", fs::PathToString(wallet_dir), ec.message());
|
|
102
|
+
}
|
|
72
103
|
|
|
73
104
|
return paths;
|
|
74
105
|
}
|
|
@@ -100,7 +131,7 @@ bool IsBDBFile(const fs::path& path)
|
|
|
100
131
|
// This check also prevents opening lock files.
|
|
101
132
|
std::error_code ec;
|
|
102
133
|
auto size = fs::file_size(path, ec);
|
|
103
|
-
if (ec) LogPrintf("%s: %s %s\n", __func__, ec.message(), fs::PathToString(path));
|
|
134
|
+
if (ec) LogWarning("Error reading file_size: %s [%s]", ec.message(), fs::PathToString(path));
|
|
104
135
|
if (size < 4096) return false;
|
|
105
136
|
|
|
106
137
|
std::ifstream file{path, std::ios::binary};
|
|
@@ -124,7 +155,7 @@ bool IsSQLiteFile(const fs::path& path)
|
|
|
124
155
|
// A SQLite Database file is at least 512 bytes.
|
|
125
156
|
std::error_code ec;
|
|
126
157
|
auto size = fs::file_size(path, ec);
|
|
127
|
-
if (ec) LogPrintf("%s: %s %s\n", __func__, ec.message(), fs::PathToString(path));
|
|
158
|
+
if (ec) LogWarning("Error reading file_size: %s [%s]", ec.message(), fs::PathToString(path));
|
|
128
159
|
if (size < 512) return false;
|
|
129
160
|
|
|
130
161
|
std::ifstream file{path, std::ios::binary};
|