GCC Code Coverage Report


Directory: cvmfs/
File: cvmfs/catalog_sql.cc
Date: 2026-11-08 02:41:18
Exec Total Coverage
Lines: 464 616 75.3%
Branches: 590 1554 38.0%

Line Branch Exec Source
1 /**
2 * This file is part of the CernVM file system.
3 */
4
5
6 #include "catalog_sql.h"
7
8 #include <cstdlib>
9 #include <cstring>
10
11 #include "catalog.h"
12 #include "globals.h"
13 #include "util/logging.h"
14 #include "util/posix.h"
15 #include "xattr.h"
16
17 using namespace std; // NOLINT
18
19 namespace catalog {
20
21 // Emergency fallback: if CVMFS_NO_IGNORE_LEGACY_BULKHASHES is set, revert to
22 // the old behavior of including bulk hashes for chunked files.
23 bool g_ignore_legacy_bulk_hashes = (getenv("CVMFS_NO_IGNORE_LEGACY_BULKHASHES")
24 == NULL);
25
26 /**
27 * NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE
28 * Always remember to update the legacy catalog migration classes to produce a
29 * compatible catalog structure when updating the schema revisions here!
30 *
31 * Repository rollbacks to an outdated catalog schema is not supported. Have a
32 * look into CVM-252 if that becomes necessary at some point.
33 *
34 * If the statistics counters get modified, the swissknife migration 'stats'
35 * tools needs to be modified, too.
36 * NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE
37 */
38
39 // ChangeLog
40 // 2.5 (Jun 26 2013 - Git: e79baec22c6abd6ddcdf8f8d7d33921027a052ab)
41 // * add (backward compatible) schema revision - see below
42 // * add statistics counters for chunked files
43 // Note: this was retrofitted and needed a catalog migration step
44 //
45 // 2.4 (Aug 15 2012 - Git: 17de8fc782b5b8dc4404dda925627b5ec2b552e1)
46 // 2.3 (Aug 15 2012 - Git: ab77688cdb2f851af3fe983bf3694dc2465e65be)
47 // 2.2 (never existed)
48 // 2.1 (Aug 7 2012 - Git: beba36c12d2b1123ffbb169f865a861e570adc68)
49 // * add 'chunks' table for file chunks
50 // * add 'statistics' table for accumulative counters
51 // * rename 'inode' field to 'hardlinks'
52 // * containing both hardlink group ID and linkcount
53 // * .cvmfscatalog files become first-class entries in the catalogs
54 //
55 // 2.0 (Aug 6 2012 - Git: c8a81ede603e57fbe4324b6ab6bc8c41e3a2fa5f)
56 // * beginning of CernVM-FS 2.1.x branch ('modern' era)
57 //
58 // 1.x (earlier - code base still in SVN)
59 // * pre-historic times
60 // 0.9 (some time 2011, artificial version)
61 // * 1.0 catalogs that lack the SHA-1 value for nested catalogs
62 const float CatalogDatabase::kLatestSchema = 2.5;
63 const float CatalogDatabase::kLatestSupportedSchema = 2.5; // + 1.X (r/o)
64
65 // ChangeLog
66 // 0 --> 1: (Jan 6 2014 - Git: 3667fe7a669d0d65e07275b753a7c6f23fc267df)
67 // * add size column to nested catalog table,
68 // * add schema_revision property
69 // 1 --> 2: (Jan 22 2014 - Git: 85e6680e52cfe56dc1213a5ad74a5cc62fd50ead):
70 // * add xattr column to catalog table
71 // * add self_xattr and subtree_xattr statistics counters
72 // 2 --> 3: (Sep 28 2015 - Git: f4171234b13ea448589820c1524ee52eae141bb4):
73 // * add kFlagFileExternal to entries in catalog table
74 // * add self_external and subtree_external statistics counters
75 // * store compression algorithm in flags
76 // 3 --> 4: (Nov 11 2016 - Git):
77 // * add kFlagDirBindMountpoint
78 // * add kFlagHidden
79 // * add table bind_mountpoints
80 // 4 --> 5: (Dec 07 2017):
81 // * add kFlagFileSpecial (rebranded unused kFlagFileStat)
82 // * add self_special and subtree_special statistics counters
83 // 5 --> 6: (Jul 01 2021):
84 // * Add kFlagDirectIo
85 // 6 --> 7: (Feb 23 2024):
86 // * Store nanosecond timestamps (mtimens column) in catalog table.
87 // The mtimens column has only the nanosecond part of the timestamp
88 // and may be NULL
89 // 7 --> 8: (Sep 30 2025):
90 // * add kFlagBundleTrigger
91 // 8 --> 9: (May 08 2026):
92 // * Add kFlagFileVolatile per-file flag bit (no DDL change)
93 const unsigned CatalogDatabase::kLatestSchemaRevision = 9;
94
95 3004 bool CatalogDatabase::CheckSchemaCompatibility() {
96
2/4
✓ Branch 1 taken 2942 times.
✓ Branch 2 taken 62 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
5946 return !((schema_version() >= 2.0 - kSchemaEpsilon)
97
1/2
✗ Branch 2 not taken.
✓ Branch 3 taken 2942 times.
2942 && (!IsEqualSchema(schema_version(), kLatestSupportedSchema))
98 ✗ && (!IsEqualSchema(schema_version(), 2.4)
99
0/2
✗ Branch 1 not taken.
✗ Branch 2 not taken.
3004 || !IsEqualSchema(kLatestSupportedSchema, 2.5)));
100 }
101
102
103 2020 bool CatalogDatabase::LiveSchemaUpgradeIfNecessary() {
104
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 2020 times.
2020 assert(read_write());
105
106
6/6
✓ Branch 2 taken 1958 times.
✓ Branch 3 taken 62 times.
✓ Branch 5 taken 49 times.
✓ Branch 6 taken 1909 times.
✓ Branch 7 taken 49 times.
✓ Branch 8 taken 1971 times.
2020 if (IsEqualSchema(schema_version(), 2.5) && (schema_revision() == 0)) {
107
1/2
✓ Branch 1 taken 49 times.
✗ Branch 2 not taken.
49 LogCvmfs(kLogCatalog, kLogDebug, "upgrading schema revision (0 --> 1)");
108
109 SqlCatalog sql_upgrade(*this, "ALTER TABLE nested_catalogs "
110
2/4
✓ Branch 2 taken 49 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 49 times.
✗ Branch 6 not taken.
98 "ADD size INTEGER;");
111
2/4
✓ Branch 1 taken 49 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 49 times.
49 if (!sql_upgrade.Execute()) {
112 ✗ LogCvmfs(kLogCatalog, kLogDebug, "failed to upgrade nested_catalogs");
113 ✗ return false;
114 }
115
116 49 set_schema_revision(1);
117
2/4
✓ Branch 1 taken 49 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 49 times.
49 if (!StoreSchemaRevision()) {
118 ✗ LogCvmfs(kLogCatalog, kLogDebug, "failed to upgrade schema revision");
119 ✗ return false;
120 }
121
1/2
✓ Branch 1 taken 49 times.
✗ Branch 2 not taken.
49 }
122
123
6/6
✓ Branch 2 taken 1958 times.
✓ Branch 3 taken 62 times.
✓ Branch 5 taken 98 times.
✓ Branch 6 taken 1860 times.
✓ Branch 7 taken 98 times.
✓ Branch 8 taken 1922 times.
2020 if (IsEqualSchema(schema_version(), 2.5) && (schema_revision() == 1)) {
124
1/2
✓ Branch 1 taken 98 times.
✗ Branch 2 not taken.
98 LogCvmfs(kLogCatalog, kLogDebug, "upgrading schema revision (1 --> 2)");
125
126
2/4
✓ Branch 2 taken 98 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 98 times.
✗ Branch 6 not taken.
196 SqlCatalog sql_upgrade1(*this, "ALTER TABLE catalog ADD xattr BLOB;");
127 SqlCatalog sql_upgrade2(
128 *this,
129
2/4
✓ Branch 2 taken 98 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 98 times.
✗ Branch 6 not taken.
196 "INSERT INTO statistics (counter, value) VALUES ('self_xattr', 0);");
130 SqlCatalog sql_upgrade3(
131 *this,
132
2/4
✓ Branch 2 taken 98 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 98 times.
✗ Branch 6 not taken.
196 "INSERT INTO statistics (counter, value) VALUES ('subtree_xattr', 0);");
133
3/7
✓ Branch 1 taken 98 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 98 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 98 times.
✗ Branch 7 not taken.
196 if (!sql_upgrade1.Execute() || !sql_upgrade2.Execute()
134
4/8
✓ Branch 0 taken 98 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 98 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 98 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 98 times.
196 || !sql_upgrade3.Execute()) {
135 ✗ LogCvmfs(kLogCatalog, kLogDebug, "failed to upgrade catalogs (1 --> 2)");
136 ✗ return false;
137 }
138
139 98 set_schema_revision(2);
140
2/4
✓ Branch 1 taken 98 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 98 times.
98 if (!StoreSchemaRevision()) {
141 ✗ LogCvmfs(kLogCatalog, kLogDebug, "failed to upgrade schema revision");
142 ✗ return false;
143 }
144
3/6
✓ Branch 1 taken 98 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 98 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 98 times.
✗ Branch 8 not taken.
98 }
145
146
6/6
✓ Branch 2 taken 1958 times.
✓ Branch 3 taken 62 times.
✓ Branch 5 taken 98 times.
✓ Branch 6 taken 1860 times.
✓ Branch 7 taken 98 times.
✓ Branch 8 taken 1922 times.
2020 if (IsEqualSchema(schema_version(), 2.5) && (schema_revision() == 2)) {
147
1/2
✓ Branch 1 taken 98 times.
✗ Branch 2 not taken.
98 LogCvmfs(kLogCatalog, kLogDebug, "upgrading schema revision (2 --> 3)");
148
149 SqlCatalog sql_upgrade4(*this,
150 "INSERT INTO statistics (counter, value) VALUES "
151
2/4
✓ Branch 2 taken 98 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 98 times.
✗ Branch 6 not taken.
196 "('self_external', 0);");
152 SqlCatalog sql_upgrade5(*this,
153 "INSERT INTO statistics (counter, value) VALUES "
154
2/4
✓ Branch 2 taken 98 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 98 times.
✗ Branch 6 not taken.
196 "('self_external_file_size', 0);");
155 SqlCatalog sql_upgrade6(*this,
156 "INSERT INTO statistics (counter, value) VALUES "
157
2/4
✓ Branch 2 taken 98 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 98 times.
✗ Branch 6 not taken.
196 "('subtree_external', 0);");
158 SqlCatalog sql_upgrade7(*this,
159 "INSERT INTO statistics (counter, value) VALUES "
160
2/4
✓ Branch 2 taken 98 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 98 times.
✗ Branch 6 not taken.
196 "('subtree_external_file_size', 0);");
161
3/7
✓ Branch 1 taken 98 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 98 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 98 times.
✗ Branch 7 not taken.
196 if (!sql_upgrade4.Execute() || !sql_upgrade5.Execute()
162
6/13
✓ Branch 0 taken 98 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 98 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 98 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✓ Branch 8 taken 98 times.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✓ Branch 11 taken 98 times.
✗ Branch 12 not taken.
✓ Branch 13 taken 98 times.
196 || !sql_upgrade6.Execute() || !sql_upgrade7.Execute()) {
163 ✗ LogCvmfs(kLogCatalog, kLogDebug, "failed to upgrade catalogs (2 --> 3)");
164 ✗ return false;
165 }
166
167 98 set_schema_revision(3);
168
2/4
✓ Branch 1 taken 98 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 98 times.
98 if (!StoreSchemaRevision()) {
169 ✗ LogCvmfs(kLogCatalog, kLogDebug, "failed to upgrade schema revision");
170 ✗ return false;
171 }
172
4/8
✓ Branch 1 taken 98 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 98 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 98 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 98 times.
✗ Branch 11 not taken.
98 }
173
174
6/6
✓ Branch 2 taken 1958 times.
✓ Branch 3 taken 62 times.
✓ Branch 5 taken 98 times.
✓ Branch 6 taken 1860 times.
✓ Branch 7 taken 98 times.
✓ Branch 8 taken 1922 times.
2020 if (IsEqualSchema(schema_version(), 2.5) && (schema_revision() == 3)) {
175
1/2
✓ Branch 1 taken 98 times.
✗ Branch 2 not taken.
98 LogCvmfs(kLogCatalog, kLogDebug, "upgrading schema revision (3 --> 4)");
176
177 SqlCatalog sql_upgrade8(
178 *this,
179 "CREATE TABLE bind_mountpoints (path TEXT, sha1 TEXT, size INTEGER, "
180
2/4
✓ Branch 2 taken 98 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 98 times.
✗ Branch 6 not taken.
196 "CONSTRAINT pk_bind_mountpoints PRIMARY KEY (path));");
181
2/4
✓ Branch 1 taken 98 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 98 times.
98 if (!sql_upgrade8.Execute()) {
182 ✗ LogCvmfs(kLogCatalog, kLogDebug, "failed to upgrade catalogs (3 --> 4)");
183 ✗ return false;
184 }
185
186 98 set_schema_revision(4);
187
2/4
✓ Branch 1 taken 98 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 98 times.
98 if (!StoreSchemaRevision()) {
188 ✗ LogCvmfs(kLogCatalog, kLogDebug, "failed to upgrade schema revision");
189 ✗ return false;
190 }
191
1/2
✓ Branch 1 taken 98 times.
✗ Branch 2 not taken.
98 }
192
193
194
6/6
✓ Branch 2 taken 1958 times.
✓ Branch 3 taken 62 times.
✓ Branch 5 taken 98 times.
✓ Branch 6 taken 1860 times.
✓ Branch 7 taken 98 times.
✓ Branch 8 taken 1922 times.
2020 if (IsEqualSchema(schema_version(), 2.5) && (schema_revision() == 4)) {
195
1/2
✓ Branch 1 taken 98 times.
✗ Branch 2 not taken.
98 LogCvmfs(kLogCatalog, kLogDebug, "upgrading schema revision (4 --> 5)");
196
197 SqlCatalog sql_upgrade9(*this,
198 "INSERT INTO statistics (counter, value) VALUES "
199
2/4
✓ Branch 2 taken 98 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 98 times.
✗ Branch 6 not taken.
196 "('self_special', 0);");
200 SqlCatalog sql_upgrade10(*this,
201 "INSERT INTO statistics (counter, value) VALUES "
202
2/4
✓ Branch 2 taken 98 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 98 times.
✗ Branch 6 not taken.
196 "('subtree_special', 0);");
203
5/11
✓ Branch 1 taken 98 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 98 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 98 times.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✓ Branch 9 taken 98 times.
✗ Branch 10 not taken.
✓ Branch 11 taken 98 times.
98 if (!sql_upgrade9.Execute() || !sql_upgrade10.Execute()) {
204 ✗ LogCvmfs(kLogCatalog, kLogDebug, "failed to upgrade catalogs (4 --> 5)");
205 ✗ return false;
206 }
207
208 98 set_schema_revision(5);
209
2/4
✓ Branch 1 taken 98 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 98 times.
98 if (!StoreSchemaRevision()) {
210 ✗ LogCvmfs(kLogCatalog, kLogDebug, "failed to upgrade schema revision");
211 ✗ return false;
212 }
213
2/4
✓ Branch 1 taken 98 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 98 times.
✗ Branch 5 not taken.
98 }
214
215
216
6/6
✓ Branch 2 taken 1958 times.
✓ Branch 3 taken 62 times.
✓ Branch 5 taken 98 times.
✓ Branch 6 taken 1860 times.
✓ Branch 7 taken 98 times.
✓ Branch 8 taken 1922 times.
2020 if (IsEqualSchema(schema_version(), 2.5) && (schema_revision() == 5)) {
217 98 LogCvmfs(kLogCatalog, kLogDebug, "upgrading schema revision (5 --> 6)");
218
219 98 set_schema_revision(6);
220
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 98 times.
98 if (!StoreSchemaRevision()) {
221 ✗ LogCvmfs(kLogCatalog, kLogDebug, "failed to upgrade schema revision");
222 ✗ return false;
223 }
224 }
225
226
6/6
✓ Branch 2 taken 1958 times.
✓ Branch 3 taken 62 times.
✓ Branch 5 taken 98 times.
✓ Branch 6 taken 1860 times.
✓ Branch 7 taken 98 times.
✓ Branch 8 taken 1922 times.
2020 if (IsEqualSchema(schema_version(), 2.5) && (schema_revision() == 6)) {
227
1/2
✓ Branch 1 taken 98 times.
✗ Branch 2 not taken.
98 LogCvmfs(kLogCatalog, kLogDebug, "upgrading schema revision (6 --> 7)");
228
229
2/4
✓ Branch 2 taken 98 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 98 times.
✗ Branch 6 not taken.
196 SqlCatalog sql_upgrade1(*this, "ALTER TABLE catalog ADD mtimens INTEGER;");
230
2/4
✓ Branch 1 taken 98 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 98 times.
98 if (!sql_upgrade1.Execute()) {
231 ✗ LogCvmfs(kLogCatalog, kLogDebug, "failed to upgrade catalogs (6 --> 7)");
232 ✗ return false;
233 }
234
235 98 set_schema_revision(7);
236
2/4
✓ Branch 1 taken 98 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 98 times.
98 if (!StoreSchemaRevision()) {
237 ✗ LogCvmfs(kLogCatalog, kLogDebug, "failed to upgrade schema revision");
238 ✗ return false;
239 }
240
1/2
✓ Branch 1 taken 98 times.
✗ Branch 2 not taken.
98 }
241
242
6/6
✓ Branch 2 taken 1958 times.
✓ Branch 3 taken 62 times.
✓ Branch 5 taken 98 times.
✓ Branch 6 taken 1860 times.
✓ Branch 7 taken 98 times.
✓ Branch 8 taken 1922 times.
2020 if (IsEqualSchema(schema_version(), 2.5) && (schema_revision() == 7)) {
243 98 LogCvmfs(kLogCatalog, kLogDebug, "upgrading schema revision (7 --> 8)");
244
245 98 set_schema_revision(8);
246
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 98 times.
98 if (!StoreSchemaRevision()) {
247 ✗ LogCvmfs(kLogCatalog, kLogDebug, "failed to upgrade schema revision");
248 ✗ return false;
249 }
250 }
251
252
6/6
✓ Branch 2 taken 1958 times.
✓ Branch 3 taken 62 times.
✓ Branch 5 taken 98 times.
✓ Branch 6 taken 1860 times.
✓ Branch 7 taken 98 times.
✓ Branch 8 taken 1922 times.
2020 if (IsEqualSchema(schema_version(), 2.5) && (schema_revision() == 8)) {
253 98 LogCvmfs(kLogCatalog, kLogDebug, "upgrading schema revision (8 --> 9)");
254
255 // No DDL change: kFlagFileVolatile is encoded in the existing flags column.
256 98 set_schema_revision(9);
257
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 98 times.
98 if (!StoreSchemaRevision()) {
258 ✗ LogCvmfs(kLogCatalog, kLogDebug, "failed to upgrade schema revision");
259 ✗ return false;
260 }
261 }
262
263 2020 return true;
264 }
265
266
267 1956 bool CatalogDatabase::CreateEmptyDatabase() {
268
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1956 times.
1956 assert(read_write());
269
270 // generate the catalog table and index structure
271 const bool retval =
272
4/16
✓ Branch 1 taken 1956 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 1956 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 1956 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 1956 times.
✗ Branch 11 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
✗ Branch 19 not taken.
✗ Branch 20 not taken.
3912 SqlCatalog(*this,
273 "CREATE TABLE catalog "
274 "(md5path_1 INTEGER, md5path_2 INTEGER, parent_1 INTEGER, "
275 "parent_2 INTEGER,"
276 " hardlinks INTEGER, hash BLOB, size INTEGER, mode INTEGER, "
277 "mtime INTEGER,"
278 " mtimens INTEGER, flags INTEGER, name TEXT, symlink TEXT, "
279 "uid INTEGER,"
280 " gid INTEGER, xattr BLOB, "
281 " CONSTRAINT pk_catalog PRIMARY KEY (md5path_1, md5path_2));")
282 3912 .Execute()
283
5/20
✓ Branch 2 taken 1956 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 1956 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✓ Branch 8 taken 1956 times.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✓ Branch 11 taken 1956 times.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✓ Branch 14 taken 1956 times.
✗ Branch 15 not taken.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
✗ Branch 19 not taken.
✗ Branch 20 not taken.
✗ Branch 22 not taken.
✗ Branch 23 not taken.
3912 && SqlCatalog(*this,
284 "CREATE INDEX idx_catalog_parent "
285 "ON catalog (parent_1, parent_2);")
286
2/4
✓ Branch 1 taken 1956 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1956 times.
✗ Branch 4 not taken.
1956 .Execute()
287
5/20
✓ Branch 2 taken 1956 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 1956 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✓ Branch 8 taken 1956 times.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✓ Branch 11 taken 1956 times.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✓ Branch 14 taken 1956 times.
✗ Branch 15 not taken.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
✗ Branch 19 not taken.
✗ Branch 20 not taken.
✗ Branch 22 not taken.
✗ Branch 23 not taken.
3912 && SqlCatalog(*this,
288 "CREATE TABLE chunks "
289 "(md5path_1 INTEGER, md5path_2 INTEGER, offset INTEGER, "
290 "size INTEGER, "
291 " hash BLOB, "
292 " CONSTRAINT pk_chunks PRIMARY KEY (md5path_1, md5path_2, "
293 "offset, size), "
294 " FOREIGN KEY (md5path_1, md5path_2) REFERENCES "
295 " catalog(md5path_1, md5path_2));")
296
2/4
✓ Branch 1 taken 1956 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1956 times.
✗ Branch 4 not taken.
1956 .Execute()
297
5/20
✓ Branch 2 taken 1956 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 1956 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✓ Branch 8 taken 1956 times.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✓ Branch 11 taken 1956 times.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✓ Branch 14 taken 1956 times.
✗ Branch 15 not taken.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
✗ Branch 19 not taken.
✗ Branch 20 not taken.
✗ Branch 22 not taken.
✗ Branch 23 not taken.
3912 && SqlCatalog(*this,
298 "CREATE TABLE nested_catalogs (path TEXT, sha1 TEXT, size "
299 "INTEGER, "
300 "CONSTRAINT pk_nested_catalogs PRIMARY KEY (path));")
301
2/4
✓ Branch 1 taken 1956 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1956 times.
✗ Branch 4 not taken.
1956 .Execute()
302
0/2
✗ Branch 0 not taken.
✗ Branch 1 not taken.
3912 &&
303 // Bind mountpoints and nested catalogs are almost the same. We put them
304 // in separate tables to
305 // - not confuse previous client versions, which would crash on bind
306 // mountpoints
307 // - prevent catalogs referenced as bind mountpoints from being
308 // replicated,
309 // which would cause exhaustive recursive catalog tree walking
310 // - don't walk into bind mountpoints in catalog traversal (e.g. GC)
311
5/19
✓ Branch 2 taken 1956 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 1956 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✓ Branch 8 taken 1956 times.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✓ Branch 11 taken 1956 times.
✗ Branch 12 not taken.
✓ Branch 14 taken 1956 times.
✗ Branch 15 not taken.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
✗ Branch 19 not taken.
✗ Branch 20 not taken.
✗ Branch 22 not taken.
✗ Branch 23 not taken.
3912 SqlCatalog(
312 *this,
313 "CREATE TABLE bind_mountpoints (path TEXT, sha1 TEXT, size INTEGER, "
314 "CONSTRAINT pk_bind_mountpoints PRIMARY KEY (path));")
315
2/4
✓ Branch 1 taken 1956 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1956 times.
✗ Branch 4 not taken.
1956 .Execute()
316
7/24
✓ Branch 2 taken 1956 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1956 times.
✗ Branch 5 not taken.
✗ Branch 7 not taken.
✓ Branch 8 taken 1956 times.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✓ Branch 11 taken 1956 times.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✓ Branch 14 taken 1956 times.
✗ Branch 15 not taken.
✗ Branch 16 not taken.
✓ Branch 17 taken 1956 times.
✗ Branch 18 not taken.
✓ Branch 20 taken 1956 times.
✗ Branch 21 not taken.
✗ Branch 22 not taken.
✗ Branch 23 not taken.
✗ Branch 25 not taken.
✗ Branch 26 not taken.
✗ Branch 28 not taken.
✗ Branch 29 not taken.
9780 && SqlCatalog(*this,
317 "CREATE TABLE statistics (counter TEXT, value INTEGER, "
318 "CONSTRAINT pk_statistics PRIMARY KEY (counter));")
319
3/6
✓ Branch 1 taken 1956 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1956 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 1956 times.
✗ Branch 6 not taken.
3912 .Execute();
320
321
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1956 times.
1956 if (!retval) {
322 ✗ PrintSqlError("failed to create catalog database tables.");
323 }
324
325 1956 return retval;
326 }
327
328
329 1907 bool CatalogDatabase::InsertInitialValues(const std::string &root_path,
330 const bool volatile_content,
331 const std::string &voms_authz,
332 const DirectoryEntry &root_entry) {
333
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1907 times.
1907 assert(read_write());
334 1907 bool retval = false;
335
336 // Path hashes
337
1/2
✓ Branch 2 taken 1907 times.
✗ Branch 3 not taken.
1907 const shash::Md5 root_path_hash = shash::Md5(shash::AsciiPtr(root_path));
338 1907 const shash::Md5 root_parent_hash = (root_path == "")
339 ? shash::Md5()
340 : shash::Md5(shash::AsciiPtr(
341
7/12
✓ Branch 0 taken 1044 times.
✓ Branch 1 taken 863 times.
✓ Branch 3 taken 1044 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 863 times.
✗ Branch 7 not taken.
✓ Branch 10 taken 863 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 863 times.
✓ Branch 13 taken 1044 times.
✗ Branch 15 not taken.
✗ Branch 16 not taken.
1907 GetParentPath(root_path)));
342
343 // Start initial filling transaction
344
1/2
✓ Branch 1 taken 1907 times.
✗ Branch 2 not taken.
1907 retval = BeginTransaction();
345
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1907 times.
1907 if (!retval) {
346 ✗ PrintSqlError("failed to enter initial filling transaction");
347 ✗ return false;
348 }
349
350 // Insert initial values to properties
351
3/6
✓ Branch 2 taken 1907 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 1907 times.
✗ Branch 6 not taken.
✗ Branch 9 not taken.
✓ Branch 10 taken 1907 times.
1907 if (!this->SetProperty("revision", 0)) {
352 ✗ PrintSqlError(
353 "failed to insert default initial values into the newly created "
354 "catalog tables.");
355 ✗ return false;
356 }
357
358
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1907 times.
1907 if (volatile_content) {
359 ✗ if (!this->SetProperty("volatile", 1)) {
360 ✗ PrintSqlError("failed to insert volatile flag into the newly created "
361 "catalog tables.");
362 ✗ return false;
363 }
364 }
365
366
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1907 times.
1907 if (!voms_authz.empty()) {
367 ✗ if (!SetVOMSAuthz(voms_authz)) {
368 ✗ PrintSqlError("failed to insert VOMS authz flag into the newly created "
369 "catalog tables.");
370 ✗ return false;
371 }
372 }
373
374 // Create initial statistics counters
375
1/2
✓ Branch 1 taken 1907 times.
✗ Branch 2 not taken.
1907 catalog::Counters counters;
376
377 // Insert root entry (when given)
378
2/2
✓ Branch 1 taken 1167 times.
✓ Branch 2 taken 740 times.
1907 if (!root_entry.IsNegative()) {
379
1/2
✓ Branch 1 taken 1167 times.
✗ Branch 2 not taken.
1167 SqlDirentInsert sql_insert(*this);
380
1/2
✓ Branch 1 taken 1167 times.
✗ Branch 2 not taken.
1167 retval = sql_insert.BindPathHash(root_path_hash)
381
2/4
✓ Branch 1 taken 1167 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1167 times.
✗ Branch 4 not taken.
1167 && sql_insert.BindParentPathHash(root_parent_hash)
382
5/11
✓ Branch 0 taken 1167 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 1167 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 1167 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✓ Branch 8 taken 1167 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 1167 times.
✗ Branch 11 not taken.
2334 && sql_insert.BindDirent(root_entry) && sql_insert.Execute();
383
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1167 times.
1167 if (!retval) {
384 ✗ PrintSqlError("failed to insert root entry into newly created catalog.");
385 ✗ return false;
386 }
387
388 // account for the created root entry
389 1167 counters.self.directories = 1;
390
1/2
✓ Branch 1 taken 1167 times.
✗ Branch 2 not taken.
1167 }
391
392 // Save initial statistics counters
393
2/4
✓ Branch 1 taken 1907 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 1907 times.
1907 if (!counters.InsertIntoDatabase(*this)) {
394 ✗ PrintSqlError("failed to insert initial catalog statistics counters.");
395 ✗ return false;
396 }
397
398 // Insert root path (when given)
399
2/2
✓ Branch 1 taken 863 times.
✓ Branch 2 taken 1044 times.
1907 if (!root_path.empty()) {
400
4/9
✓ Branch 1 taken 863 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 863 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✓ Branch 8 taken 863 times.
✗ Branch 9 not taken.
✗ Branch 13 not taken.
✓ Branch 14 taken 863 times.
863 if (!this->SetProperty("root_prefix", root_path)) {
401 ✗ PrintSqlError(
402 "failed to store root prefix in the newly created catalog.");
403 ✗ return false;
404 }
405 }
406
407 // Set creation timestamp
408
3/6
✓ Branch 3 taken 1907 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 1907 times.
✗ Branch 7 not taken.
✗ Branch 10 not taken.
✓ Branch 11 taken 1907 times.
1907 if (!this->SetProperty("last_modified", static_cast<uint64_t>(time(NULL)))) {
409 ✗ PrintSqlError("failed to store creation timestamp in the new catalog.");
410 ✗ return false;
411 }
412
413 // Commit initial filling transaction
414
1/2
✓ Branch 1 taken 1907 times.
✗ Branch 2 not taken.
1907 retval = CommitTransaction();
415
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1907 times.
1907 if (!retval) {
416 ✗ PrintSqlError("failed to commit initial filling transaction");
417 ✗ return false;
418 }
419
420 1907 return true;
421 }
422
423
424 ✗ bool CatalogDatabase::SetVOMSAuthz(const std::string &voms_authz) {
425 ✗ return this->SetProperty("voms_authz", voms_authz);
426 }
427
428
429 780 double CatalogDatabase::GetRowIdWasteRatio() const {
430 SqlCatalog rowid_waste_ratio_query(
431 *this,
432 "SELECT 1.0 - CAST(COUNT(*) AS DOUBLE) / MAX(rowid) "
433
2/4
✓ Branch 2 taken 780 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 780 times.
✗ Branch 6 not taken.
1560 "AS ratio FROM catalog;");
434
1/2
✓ Branch 1 taken 780 times.
✗ Branch 2 not taken.
780 const bool retval = rowid_waste_ratio_query.FetchRow();
435
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 780 times.
780 assert(retval);
436
437
1/2
✓ Branch 1 taken 780 times.
✗ Branch 2 not taken.
1560 return rowid_waste_ratio_query.RetrieveDouble(0);
438 780 }
439
440 /**
441 * Cleanup unused database space
442 *
443 * This copies the entire catalog content into a temporary SQLite table, sweeps
444 * the original data from the 'catalog' table and reinserts everything from the
445 * temporary table afterwards. That way the implicit rowid field of 'catalog' is
446 * defragmented.
447 *
448 * Since the 'chunks' table has a foreign key relationship to the 'catalog' we
449 * need to temporarily switch off the foreign key checks. Otherwise the clearing
450 * of the 'catalog' table would fail due to foreign key violations. Note that it
451 * is a NOOP to change the foreign key setting during a transaction!
452 *
453 * Note: VACUUM used to have a similar behaviour but it was dropped from SQLite
454 * at some point. Since we compute client-inodes from the rowIDs, we are
455 * probably one of the few use cases where a defragmented rowID is indeed
456 * beneficial.
457 *
458 * See: http://www.sqlite.org/lang_vacuum.html
459 */
460 200 bool CatalogDatabase::CompactDatabase() const {
461
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 200 times.
200 assert(read_write());
462
463
4/16
✓ Branch 1 taken 200 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 200 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 200 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 200 times.
✗ Branch 11 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
✗ Branch 19 not taken.
✗ Branch 20 not taken.
400 return SqlCatalog(*this, "PRAGMA foreign_keys = OFF;").Execute()
464
2/4
✓ Branch 1 taken 200 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 200 times.
✗ Branch 4 not taken.
200 && BeginTransaction()
465
5/20
✓ Branch 2 taken 200 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 200 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✓ Branch 8 taken 200 times.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✓ Branch 11 taken 200 times.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✓ Branch 14 taken 200 times.
✗ Branch 15 not taken.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
✗ Branch 19 not taken.
✗ Branch 20 not taken.
✗ Branch 22 not taken.
✗ Branch 23 not taken.
400 && SqlCatalog(*this, "CREATE TEMPORARY TABLE duplicate AS "
466 " SELECT * FROM catalog "
467 " ORDER BY rowid ASC;")
468
2/4
✓ Branch 1 taken 200 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 200 times.
✗ Branch 4 not taken.
200 .Execute()
469
7/22
✓ Branch 2 taken 200 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 200 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✓ Branch 8 taken 200 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 200 times.
✗ Branch 11 not taken.
✓ Branch 13 taken 200 times.
✗ Branch 14 not taken.
✓ Branch 16 taken 200 times.
✗ Branch 17 not taken.
✓ Branch 19 taken 200 times.
✗ Branch 20 not taken.
✗ Branch 21 not taken.
✗ Branch 22 not taken.
✗ Branch 24 not taken.
✗ Branch 25 not taken.
✗ Branch 27 not taken.
✗ Branch 28 not taken.
400 && SqlCatalog(*this, "DELETE FROM catalog;").Execute()
470
5/20
✓ Branch 2 taken 200 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 200 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✓ Branch 8 taken 200 times.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✓ Branch 11 taken 200 times.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✓ Branch 14 taken 200 times.
✗ Branch 15 not taken.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
✗ Branch 19 not taken.
✗ Branch 20 not taken.
✗ Branch 22 not taken.
✗ Branch 23 not taken.
400 && SqlCatalog(*this, "INSERT INTO catalog "
471 " SELECT * FROM duplicate "
472 " ORDER BY rowid")
473
2/4
✓ Branch 1 taken 200 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 200 times.
✗ Branch 4 not taken.
200 .Execute()
474
7/22
✓ Branch 2 taken 200 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 200 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✓ Branch 8 taken 200 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 200 times.
✗ Branch 11 not taken.
✓ Branch 13 taken 200 times.
✗ Branch 14 not taken.
✓ Branch 16 taken 200 times.
✗ Branch 17 not taken.
✓ Branch 19 taken 200 times.
✗ Branch 20 not taken.
✗ Branch 21 not taken.
✗ Branch 22 not taken.
✗ Branch 24 not taken.
✗ Branch 25 not taken.
✗ Branch 27 not taken.
✗ Branch 28 not taken.
400 && SqlCatalog(*this, "DROP TABLE duplicate;").Execute()
475
2/4
✓ Branch 1 taken 200 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 200 times.
✗ Branch 4 not taken.
200 && CommitTransaction()
476
10/29
✓ Branch 2 taken 200 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 200 times.
✗ Branch 5 not taken.
✓ Branch 8 taken 200 times.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✓ Branch 11 taken 200 times.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✓ Branch 14 taken 200 times.
✗ Branch 15 not taken.
✓ Branch 16 taken 200 times.
✗ Branch 17 not taken.
✓ Branch 18 taken 200 times.
✗ Branch 19 not taken.
✗ Branch 20 not taken.
✓ Branch 21 taken 200 times.
✗ Branch 22 not taken.
✓ Branch 24 taken 200 times.
✗ Branch 25 not taken.
✓ Branch 27 taken 200 times.
✗ Branch 28 not taken.
✗ Branch 29 not taken.
✗ Branch 30 not taken.
✗ Branch 32 not taken.
✗ Branch 33 not taken.
✗ Branch 35 not taken.
✗ Branch 36 not taken.
800 && SqlCatalog(*this, "PRAGMA foreign_keys = ON;").Execute();
477 }
478
479
480 //------------------------------------------------------------------------------
481
482
483 13925 unsigned SqlDirent::CreateDatabaseFlags(const DirectoryEntry &entry) const {
484 13925 unsigned int database_flags = 0;
485
486
2/2
✓ Branch 1 taken 571 times.
✓ Branch 2 taken 13354 times.
13925 if (entry.IsNestedCatalogRoot())
487 571 database_flags |= kFlagDirNestedRoot;
488
2/2
✓ Branch 1 taken 653 times.
✓ Branch 2 taken 12701 times.
13354 else if (entry.IsNestedCatalogMountpoint())
489 653 database_flags |= kFlagDirNestedMountpoint;
490
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 12701 times.
12701 else if (entry.IsBindMountpoint())
491 ✗ database_flags |= kFlagDirBindMountpoint;
492
493
2/2
✓ Branch 1 taken 7623 times.
✓ Branch 2 taken 6302 times.
13925 if (entry.IsDirectory()) {
494 7623 database_flags |= kFlagDir;
495
2/2
✓ Branch 1 taken 398 times.
✓ Branch 2 taken 5904 times.
6302 } else if (entry.IsLink()) {
496 398 database_flags |= kFlagFile | kFlagLink;
497
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 5904 times.
5904 } else if (entry.IsSpecial()) {
498 ✗ database_flags |= kFlagFile | kFlagFileSpecial;
499 } else {
500 5904 database_flags |= kFlagFile;
501 5904 database_flags |= entry.compression_algorithm() << kFlagPosCompression;
502
2/2
✓ Branch 1 taken 370 times.
✓ Branch 2 taken 5534 times.
5904 if (entry.IsChunkedFile())
503 370 database_flags |= kFlagFileChunk;
504
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 5904 times.
5904 if (entry.IsExternalFile())
505 ✗ database_flags |= kFlagFileExternal;
506
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 5904 times.
5904 if (entry.IsDirectIo())
507 ✗ database_flags |= kFlagDirectIo;
508
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 5904 times.
5904 if (entry.IsBundleTrigger())
509 ✗ database_flags |= kFlagBundleTrigger;
510
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 5904 times.
5904 if (entry.IsVolatile())
511 ✗ database_flags |= kFlagFileVolatile;
512 }
513
514
5/6
✓ Branch 2 taken 8321 times.
✓ Branch 3 taken 5604 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 8321 times.
✓ Branch 7 taken 5604 times.
✓ Branch 8 taken 8321 times.
13925 if (!entry.checksum_ptr()->IsNull() || entry.IsChunkedFile())
515 5604 StoreHashAlgorithm(entry.checksum_ptr()->algorithm, &database_flags);
516
517
2/2
✓ Branch 1 taken 340 times.
✓ Branch 2 taken 13585 times.
13925 if (entry.IsHidden())
518 340 database_flags |= kFlagHidden;
519
520 13925 return database_flags;
521 }
522
523
524 5604 void SqlDirent::StoreHashAlgorithm(const shash::Algorithms algo,
525 unsigned *flags) const {
526
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5604 times.
5604 assert(algo != shash::kAny);
527 // Md5 unusable for content hashes
528 5604 *flags |= (algo - 1) << kFlagPosHash;
529 5604 }
530
531
532 12664 shash::Algorithms SqlDirent::RetrieveHashAlgorithm(const unsigned flags) const {
533 12664 unsigned in_flags = ((7 << kFlagPosHash) & flags) >> kFlagPosHash;
534 // Skip Md5
535 12664 in_flags++;
536
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12664 times.
12664 assert(in_flags < shash::kAny);
537 12664 return static_cast<shash::Algorithms>(in_flags);
538 }
539
540
541 12274 zlib::Algorithms SqlDirent::RetrieveCompressionAlgorithm(
542 const unsigned flags) const {
543 // 3 bits, so use 7 (111) to only pull out the flags we want
544 12274 const unsigned in_flags = ((7 << kFlagPosCompression) & flags)
545 12274 >> kFlagPosCompression;
546 12274 return static_cast<zlib::Algorithms>(in_flags);
547 }
548
549
550 12274 uint32_t SqlDirent::Hardlinks2Linkcount(const uint64_t hardlinks) const {
551 12274 return (hardlinks << 32) >> 32;
552 }
553
554
555 12274 uint32_t SqlDirent::Hardlinks2HardlinkGroup(const uint64_t hardlinks) const {
556 12274 return hardlinks >> 32;
557 }
558
559
560 13925 uint64_t SqlDirent::MakeHardlinks(const uint32_t hardlink_group,
561 const uint32_t linkcount) const {
562
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 13925 times.
13925 assert(linkcount > 0);
563 13925 return (static_cast<uint64_t>(hardlink_group) << 32) | linkcount;
564 }
565
566
567 /**
568 * Expands variant symlinks containing $(VARIABLE) string. Uses the environment
569 * variables of the current process (cvmfs2)
570 */
571 10145 void SqlDirent::ExpandSymlink(LinkString *raw_symlink) const {
572 10145 const char *c = raw_symlink->GetChars();
573 10145 const char *cEnd = c + raw_symlink->GetLength();
574
2/2
✓ Branch 0 taken 1088 times.
✓ Branch 1 taken 10145 times.
11233 for (; c < cEnd; ++c) {
575
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1088 times.
1088 if (*c == '$')
576 ✗ goto expand_symlink;
577 }
578 10145 return;
579
580 ✗ expand_symlink:
581 ✗ LinkString result;
582 ✗ for (c = raw_symlink->GetChars(); c < cEnd; ++c) {
583 ✗ if ((*c == '$') && (c < cEnd - 2) && (*(c + 1) == '(')) {
584 ✗ c += 2;
585 ✗ const char *rpar = c;
586 ✗ while (rpar < cEnd) {
587 ✗ if (*rpar == ')')
588 ✗ goto expand_symlink_getenv;
589 ✗ rpar++;
590 }
591 // right parenthesis missing
592 ✗ result.Append("$(", 2);
593 ✗ result.Append(c, 1);
594 ✗ continue;
595
596 ✗ expand_symlink_getenv:
597 // Check for default value
598 ✗ const char *default_separator = c;
599 ✗ const char *default_value = rpar;
600 ✗ while (default_separator != rpar) {
601 ✗ if ((*default_separator == ':') && (*(default_separator + 1) == '-')) {
602 ✗ default_value = default_separator + 2;
603 ✗ break;
604 }
605 ✗ default_separator++;
606 }
607
608 ✗ const unsigned environ_var_length = default_separator - c;
609 ✗ char environ_var[environ_var_length + 1];
610 ✗ environ_var[environ_var_length] = '\0';
611 ✗ memcpy(environ_var, c, environ_var_length);
612 ✗ const char *environ_value = getenv(environ_var); // Don't free!
613 ✗ if (environ_value) {
614 ✗ result.Append(environ_value, strlen(environ_value));
615 } else {
616 ✗ const unsigned default_length = rpar - default_value;
617 ✗ result.Append(default_value, default_length);
618 }
619 ✗ c = rpar;
620 ✗ continue;
621 }
622 ✗ result.Append(c, 1);
623 }
624 ✗ raw_symlink->Assign(result);
625 ✗ return;
626 }
627
628
629 //------------------------------------------------------------------------------
630
631
632 13925 bool SqlDirentWrite::BindDirentFields(const int hash_idx,
633 const int hardlinks_idx,
634 const int size_idx,
635 const int mode_idx,
636 const int mtime_idx,
637 const int mtimens_idx,
638 const int flags_idx,
639 const int name_idx,
640 const int symlink_idx,
641 const int uid_idx,
642 const int gid_idx,
643 const DirectoryEntry &entry) {
644 13925 const uint64_t hardlinks = MakeHardlinks(entry.hardlink_group_,
645 13925 entry.linkcount_);
646
647 13925 bool result = BindHashBlob(hash_idx, entry.checksum_)
648
1/2
✓ Branch 1 taken 13925 times.
✗ Branch 2 not taken.
13925 && BindInt64(hardlinks_idx, hardlinks)
649
1/2
✓ Branch 1 taken 13925 times.
✗ Branch 2 not taken.
13925 && BindInt64(size_idx, entry.size_)
650
1/2
✓ Branch 1 taken 13925 times.
✗ Branch 2 not taken.
13925 && BindInt(mode_idx, entry.mode_)
651
1/2
✓ Branch 1 taken 13925 times.
✗ Branch 2 not taken.
13925 && BindInt64(uid_idx, entry.uid_)
652
1/2
✓ Branch 1 taken 13925 times.
✗ Branch 2 not taken.
13925 && BindInt64(gid_idx, entry.gid_)
653
1/2
✓ Branch 1 taken 13925 times.
✗ Branch 2 not taken.
13925 && BindInt64(mtime_idx, entry.mtime_)
654
1/2
✓ Branch 2 taken 13925 times.
✗ Branch 3 not taken.
13925 && BindInt(flags_idx, CreateDatabaseFlags(entry))
655
1/2
✓ Branch 2 taken 13925 times.
✗ Branch 3 not taken.
13925 && BindText(name_idx, entry.name_.GetChars(),
656 13925 static_cast<int>(entry.name_.GetLength()))
657
2/4
✓ Branch 0 taken 13925 times.
✗ Branch 1 not taken.
✓ Branch 4 taken 13925 times.
✗ Branch 5 not taken.
27850 && BindText(symlink_idx, entry.symlink_.GetChars(),
658 13925 static_cast<int>(entry.symlink_.GetLength()));
659
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 13925 times.
13925 if (entry.HasMtimeNs()) {
660 ✗ result &= BindInt(mtimens_idx, entry.mtime_ns_);
661 } else {
662 13925 result &= BindNull(mtimens_idx);
663 }
664
665 13925 return result;
666 }
667
668
669 //------------------------------------------------------------------------------
670
671
672 60 SqlListContentHashes::SqlListContentHashes(const CatalogDatabase &database) {
673 static const char *stmt_lt_2_4 = "SELECT hash, flags, 0 "
674 " FROM catalog "
675 " WHERE length(hash) > 0;";
676
677 static const char
678 *stmt_ge_2_4 = "SELECT hash, flags, 0 "
679 " FROM catalog "
680 " WHERE (length(catalog.hash) > 0) AND "
681 " ((flags & 128) = 0) " // kFlagFileExternal
682 "UNION "
683 "SELECT chunks.hash, catalog.flags, 1 "
684 " FROM catalog "
685 " LEFT JOIN chunks "
686 " ON catalog.md5path_1 = chunks.md5path_1 AND "
687 " catalog.md5path_2 = chunks.md5path_2 "
688 " WHERE (catalog.flags & 128) = 0;"; // kFlagFileExternal
689
690
2/2
✓ Branch 1 taken 30 times.
✓ Branch 2 taken 30 times.
60 if (database.schema_version() < 2.4 - CatalogDatabase::kSchemaEpsilon) {
691
2/4
✓ Branch 1 taken 30 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 30 times.
✗ Branch 5 not taken.
30 DeferredInit(database.sqlite_db(), stmt_lt_2_4);
692 } else {
693
2/4
✓ Branch 1 taken 30 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 30 times.
✗ Branch 5 not taken.
30 DeferredInit(database.sqlite_db(), stmt_ge_2_4);
694 }
695 60 }
696
697
698 390 shash::Any SqlListContentHashes::GetHash() const {
699 390 const unsigned int db_flags = RetrieveInt(1);
700 390 const shash::Algorithms hash_algorithm = RetrieveHashAlgorithm(db_flags);
701 390 shash::Any hash = RetrieveHashBlob(0, hash_algorithm);
702
2/2
✓ Branch 1 taken 150 times.
✓ Branch 2 taken 240 times.
390 if (RetrieveInt(2) == 1) {
703 150 hash.suffix = shash::kSuffixPartial;
704 }
705
706 390 return hash;
707 }
708
709
710 //------------------------------------------------------------------------------
711
712 #define DB_FIELDS_LT_V2_1 \
713 "catalog.hash, catalog.inode, catalog.size, " \
714 "catalog.mode, catalog.mtime, catalog.flags, " \
715 "catalog.name, catalog.symlink, catalog.md5path_1, " \
716 "catalog.md5path_2, catalog.parent_1, catalog.parent_2, " \
717 "catalog.rowid"
718 #define DB_FIELDS_GE_V2_1_LT_R2 \
719 "catalog.hash, catalog.hardlinks, catalog.size, " \
720 "catalog.mode, catalog.mtime, catalog.flags, " \
721 "catalog.name, catalog.symlink, catalog.md5path_1, " \
722 "catalog.md5path_2, catalog.parent_1, catalog.parent_2, " \
723 "catalog.rowid, catalog.uid, catalog.gid, " \
724 "0, NULL"
725 #define DB_FIELDS_GE_V2_1_LT_R7 \
726 "catalog.hash, catalog.hardlinks, catalog.size, " \
727 "catalog.mode, catalog.mtime, catalog.flags, " \
728 "catalog.name, catalog.symlink, catalog.md5path_1, " \
729 "catalog.md5path_2, catalog.parent_1, catalog.parent_2, " \
730 "catalog.rowid, catalog.uid, catalog.gid, " \
731 "catalog.xattr IS NOT NULL, NULL"
732 #define DB_FIELDS_GE_V2_1_GE_R7 \
733 "catalog.hash, catalog.hardlinks, catalog.size, " \
734 "catalog.mode, catalog.mtime, catalog.flags, " \
735 "catalog.name, catalog.symlink, catalog.md5path_1, " \
736 "catalog.md5path_2, catalog.parent_1, catalog.parent_2, " \
737 "catalog.rowid, catalog.uid, catalog.gid, " \
738 "catalog.xattr IS NOT NULL, catalog.mtimens"
739
740 #define MAKE_STATEMENT(STMT_TMPL, REV) \
741 static const std::string REV = ReplaceAll(STMT_TMPL, "@DB_FIELDS@", \
742 DB_FIELDS_##REV)
743
744 #define MAKE_STATEMENTS(STMT_TMPL) \
745 MAKE_STATEMENT(STMT_TMPL, LT_V2_1); \
746 MAKE_STATEMENT(STMT_TMPL, GE_V2_1_LT_R2); \
747 MAKE_STATEMENT(STMT_TMPL, GE_V2_1_LT_R7); \
748 MAKE_STATEMENT(STMT_TMPL, GE_V2_1_GE_R7)
749
750 #define DEFERRED_INIT(DB, REV) DeferredInit((DB).sqlite_db(), (REV).c_str())
751
752 #define DEFERRED_INITS(DB) \
753 if ((DB).schema_version() < 2.1 - CatalogDatabase::kSchemaEpsilon) { \
754 DEFERRED_INIT((DB), LT_V2_1); \
755 } else if ((DB).schema_revision() < 2) { \
756 DEFERRED_INIT((DB), GE_V2_1_LT_R2); \
757 } else if ((DB).schema_revision() < 7) { \
758 DEFERRED_INIT((DB), GE_V2_1_LT_R7); \
759 } else { \
760 DEFERRED_INIT((DB), GE_V2_1_GE_R7); \
761 }
762
763
764 ✗ shash::Md5 SqlLookup::GetPathHash() const { return RetrieveMd5(8, 9); }
765
766
767 ✗ shash::Md5 SqlLookup::GetParentPathHash() const { return RetrieveMd5(10, 11); }
768
769
770 /**
771 * This method is a friend of DirectoryEntry.
772 */
773 12274 DirectoryEntry SqlLookup::GetDirent(const Catalog *catalog,
774 const bool expand_symlink) const {
775 12274 DirectoryEntry result;
776
777
1/2
✓ Branch 1 taken 12274 times.
✗ Branch 2 not taken.
12274 const unsigned database_flags = RetrieveInt(5);
778 12274 result.is_nested_catalog_root_ = (database_flags & kFlagDirNestedRoot);
779 12274 result.is_nested_catalog_mountpoint_ = (database_flags
780 12274 & kFlagDirNestedMountpoint);
781
1/2
✓ Branch 1 taken 12274 times.
✗ Branch 2 not taken.
12274 const char *name = reinterpret_cast<const char *>(RetrieveText(6));
782
1/2
✓ Branch 1 taken 12274 times.
✗ Branch 2 not taken.
12274 const char *symlink = reinterpret_cast<const char *>(RetrieveText(7));
783
784 // Retrieve the hardlink information from the hardlinks database field
785
2/4
✓ Branch 1 taken 12274 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 12274 times.
12274 if (catalog->schema() < 2.1 - CatalogDatabase::kSchemaEpsilon) {
786 ✗ result.linkcount_ = 1;
787 ✗ result.hardlink_group_ = 0;
788 ✗ result.inode_ = catalog->GetMangledInode(RetrieveInt64(12), 0);
789 ✗ result.is_chunked_file_ = false;
790 ✗ result.has_xattrs_ = false;
791 ✗ result.checksum_ = RetrieveHashBlob(0, shash::kSha1);
792 ✗ result.uid_ = g_uid;
793 ✗ result.gid_ = g_gid;
794 } else {
795
1/2
✓ Branch 1 taken 12274 times.
✗ Branch 2 not taken.
12274 const uint64_t hardlinks = RetrieveInt64(1);
796 12274 result.linkcount_ = Hardlinks2Linkcount(hardlinks);
797 12274 result.hardlink_group_ = Hardlinks2HardlinkGroup(hardlinks);
798
1/2
✓ Branch 1 taken 12274 times.
✗ Branch 2 not taken.
12274 result.inode_ = catalog->GetMangledInode(RetrieveInt64(12),
799
1/2
✓ Branch 1 taken 12274 times.
✗ Branch 2 not taken.
12274 result.hardlink_group_);
800 12274 result.is_bind_mountpoint_ = (database_flags & kFlagDirBindMountpoint);
801 12274 result.is_chunked_file_ = (database_flags & kFlagFileChunk);
802 12274 result.is_hidden_ = (database_flags & kFlagHidden);
803 12274 result.is_direct_io_ = (database_flags & kFlagDirectIo);
804 12274 result.is_volatile_ = (database_flags & kFlagFileVolatile);
805 12274 result.is_external_file_ = (database_flags & kFlagFileExternal);
806 12274 result.is_bundle_trigger_ = (database_flags & kFlagBundleTrigger);
807
1/2
✓ Branch 1 taken 12274 times.
✗ Branch 2 not taken.
12274 result.has_xattrs_ = RetrieveInt(15) != 0;
808
1/2
✓ Branch 1 taken 12274 times.
✗ Branch 2 not taken.
12274 result.mtime_ns_ = RetrieveNullableInt(16, -1);
809
1/2
✓ Branch 2 taken 12274 times.
✗ Branch 3 not taken.
12274 result.checksum_ = RetrieveHashBlob(0,
810 RetrieveHashAlgorithm(database_flags));
811 12274 result.compression_algorithm_ = RetrieveCompressionAlgorithm(
812 database_flags);
813
814
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12274 times.
12274 if (g_claim_ownership) {
815 ✗ result.uid_ = g_uid;
816 ✗ result.gid_ = g_gid;
817 } else {
818
2/4
✓ Branch 1 taken 12274 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 12274 times.
✗ Branch 5 not taken.
12274 result.uid_ = catalog->MapUid(RetrieveInt64(13));
819
2/4
✓ Branch 1 taken 12274 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 12274 times.
✗ Branch 5 not taken.
12274 result.gid_ = catalog->MapGid(RetrieveInt64(14));
820 }
821 }
822
823
1/2
✓ Branch 1 taken 12274 times.
✗ Branch 2 not taken.
12274 result.mode_ = RetrieveInt(3);
824
1/2
✓ Branch 1 taken 12274 times.
✗ Branch 2 not taken.
12274 result.size_ = RetrieveInt64(2);
825
1/2
✓ Branch 1 taken 12274 times.
✗ Branch 2 not taken.
12274 result.mtime_ = RetrieveInt64(4);
826
1/2
✓ Branch 1 taken 12274 times.
✗ Branch 2 not taken.
12274 result.name_.Assign(name, strlen(name));
827
1/2
✓ Branch 1 taken 12274 times.
✗ Branch 2 not taken.
12274 result.symlink_.Assign(symlink, strlen(symlink));
828
3/4
✓ Branch 0 taken 10145 times.
✓ Branch 1 taken 2129 times.
✓ Branch 2 taken 10145 times.
✗ Branch 3 not taken.
12274 if (expand_symlink && !g_raw_symlinks)
829
1/2
✓ Branch 1 taken 10145 times.
✗ Branch 2 not taken.
10145 ExpandSymlink(&result.symlink_);
830
831
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12274 times.
12274 if (g_world_readable) {
832 ✗ if (S_ISDIR(result.mode_)) {
833 ✗ result.mode_ |= 0555;
834 } else {
835 ✗ result.mode_ |= 0444;
836 }
837 }
838
839 12274 return result;
840 }
841
842
843 //------------------------------------------------------------------------------
844
845
846 2857 SqlListing::SqlListing(const CatalogDatabase &database) {
847
28/62
✓ Branch 0 taken 32 times.
✓ Branch 1 taken 2825 times.
✓ Branch 3 taken 32 times.
✗ Branch 4 not taken.
✓ Branch 7 taken 32 times.
✗ Branch 8 not taken.
✓ Branch 11 taken 32 times.
✗ Branch 12 not taken.
✓ Branch 15 taken 32 times.
✗ Branch 16 not taken.
✓ Branch 18 taken 32 times.
✗ Branch 19 not taken.
✗ Branch 20 not taken.
✗ Branch 21 not taken.
✗ Branch 23 not taken.
✗ Branch 24 not taken.
✓ Branch 28 taken 32 times.
✓ Branch 29 taken 2825 times.
✓ Branch 31 taken 32 times.
✗ Branch 32 not taken.
✓ Branch 35 taken 32 times.
✗ Branch 36 not taken.
✓ Branch 39 taken 32 times.
✗ Branch 40 not taken.
✗ Branch 41 not taken.
✓ Branch 43 taken 32 times.
✗ Branch 44 not taken.
✓ Branch 46 taken 32 times.
✗ Branch 47 not taken.
✓ Branch 56 taken 32 times.
✓ Branch 57 taken 2825 times.
✓ Branch 59 taken 32 times.
✗ Branch 60 not taken.
✗ Branch 61 not taken.
✓ Branch 63 taken 32 times.
✗ Branch 64 not taken.
✓ Branch 67 taken 32 times.
✗ Branch 68 not taken.
✓ Branch 71 taken 32 times.
✗ Branch 72 not taken.
✓ Branch 74 taken 32 times.
✗ Branch 75 not taken.
✓ Branch 84 taken 32 times.
✓ Branch 85 taken 2825 times.
✓ Branch 87 taken 32 times.
✗ Branch 88 not taken.
✓ Branch 91 taken 32 times.
✗ Branch 92 not taken.
✓ Branch 95 taken 32 times.
✗ Branch 96 not taken.
✓ Branch 99 taken 32 times.
✗ Branch 100 not taken.
✓ Branch 102 taken 32 times.
✗ Branch 103 not taken.
✗ Branch 118 not taken.
✗ Branch 119 not taken.
✗ Branch 127 not taken.
✗ Branch 128 not taken.
✗ Branch 136 not taken.
✗ Branch 137 not taken.
✗ Branch 145 not taken.
✗ Branch 146 not taken.
2857 MAKE_STATEMENTS("SELECT @DB_FIELDS@ FROM catalog "
848 "WHERE (parent_1 = :p_1) AND (parent_2 = :p_2);");
849
8/25
✓ Branch 1 taken 62 times.
✓ Branch 2 taken 2795 times.
✓ Branch 5 taken 62 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✓ Branch 8 taken 62 times.
✗ Branch 9 not taken.
✗ Branch 11 not taken.
✓ Branch 12 taken 2795 times.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
✗ Branch 16 not taken.
✗ Branch 18 not taken.
✗ Branch 19 not taken.
✗ Branch 21 not taken.
✓ Branch 22 taken 2795 times.
✗ Branch 25 not taken.
✗ Branch 26 not taken.
✗ Branch 28 not taken.
✗ Branch 29 not taken.
✓ Branch 32 taken 2795 times.
✗ Branch 33 not taken.
✓ Branch 35 taken 2795 times.
✗ Branch 36 not taken.
2857 DEFERRED_INITS(database);
850 2857 }
851
852
853 1529 bool SqlListing::BindPathHash(const struct shash::Md5 &hash) {
854 1529 return BindMd5(1, 2, hash);
855 }
856
857
858 //------------------------------------------------------------------------------
859
860
861 2857 SqlLookupPathHash::SqlLookupPathHash(const CatalogDatabase &database) {
862
28/62
✓ Branch 0 taken 32 times.
✓ Branch 1 taken 2825 times.
✓ Branch 3 taken 32 times.
✗ Branch 4 not taken.
✓ Branch 7 taken 32 times.
✗ Branch 8 not taken.
✓ Branch 11 taken 32 times.
✗ Branch 12 not taken.
✓ Branch 15 taken 32 times.
✗ Branch 16 not taken.
✓ Branch 18 taken 32 times.
✗ Branch 19 not taken.
✗ Branch 20 not taken.
✗ Branch 21 not taken.
✗ Branch 23 not taken.
✗ Branch 24 not taken.
✓ Branch 28 taken 32 times.
✓ Branch 29 taken 2825 times.
✓ Branch 31 taken 32 times.
✗ Branch 32 not taken.
✓ Branch 35 taken 32 times.
✗ Branch 36 not taken.
✓ Branch 39 taken 32 times.
✗ Branch 40 not taken.
✗ Branch 41 not taken.
✓ Branch 43 taken 32 times.
✗ Branch 44 not taken.
✓ Branch 46 taken 32 times.
✗ Branch 47 not taken.
✓ Branch 56 taken 32 times.
✓ Branch 57 taken 2825 times.
✓ Branch 59 taken 32 times.
✗ Branch 60 not taken.
✗ Branch 61 not taken.
✓ Branch 63 taken 32 times.
✗ Branch 64 not taken.
✓ Branch 67 taken 32 times.
✗ Branch 68 not taken.
✓ Branch 71 taken 32 times.
✗ Branch 72 not taken.
✓ Branch 74 taken 32 times.
✗ Branch 75 not taken.
✓ Branch 84 taken 32 times.
✓ Branch 85 taken 2825 times.
✓ Branch 87 taken 32 times.
✗ Branch 88 not taken.
✓ Branch 91 taken 32 times.
✗ Branch 92 not taken.
✓ Branch 95 taken 32 times.
✗ Branch 96 not taken.
✓ Branch 99 taken 32 times.
✗ Branch 100 not taken.
✓ Branch 102 taken 32 times.
✗ Branch 103 not taken.
✗ Branch 118 not taken.
✗ Branch 119 not taken.
✗ Branch 127 not taken.
✗ Branch 128 not taken.
✗ Branch 136 not taken.
✗ Branch 137 not taken.
✗ Branch 145 not taken.
✗ Branch 146 not taken.
2857 MAKE_STATEMENTS("SELECT @DB_FIELDS@ FROM catalog "
863 "WHERE (md5path_1 = :md5_1) AND (md5path_2 = :md5_2);");
864
8/25
✓ Branch 1 taken 62 times.
✓ Branch 2 taken 2795 times.
✓ Branch 5 taken 62 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✓ Branch 8 taken 62 times.
✗ Branch 9 not taken.
✗ Branch 11 not taken.
✓ Branch 12 taken 2795 times.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
✗ Branch 16 not taken.
✗ Branch 18 not taken.
✗ Branch 19 not taken.
✗ Branch 21 not taken.
✓ Branch 22 taken 2795 times.
✗ Branch 25 not taken.
✗ Branch 26 not taken.
✗ Branch 28 not taken.
✗ Branch 29 not taken.
✓ Branch 32 taken 2795 times.
✗ Branch 33 not taken.
✓ Branch 35 taken 2795 times.
✗ Branch 36 not taken.
2857 DEFERRED_INITS(database);
865 2857 }
866
867 9652 bool SqlLookupPathHash::BindPathHash(const struct shash::Md5 &hash) {
868 9652 return BindMd5(1, 2, hash);
869 }
870
871
872 //------------------------------------------------------------------------------
873
874
875 ✗ SqlLookupInode::SqlLookupInode(const CatalogDatabase &database) {
876 ✗ MAKE_STATEMENTS("SELECT @DB_FIELDS@ FROM catalog WHERE rowid = :rowid;");
877 ✗ DEFERRED_INITS(database);
878 }
879
880
881 ✗ bool SqlLookupInode::BindRowId(const uint64_t inode) {
882 ✗ return BindInt64(1, inode);
883 }
884
885
886 //------------------------------------------------------------------------------
887
888
889 ✗ SqlLookupDanglingMountpoints::SqlLookupDanglingMountpoints(
890 ✗ const catalog::CatalogDatabase &database) {
891 ✗ MAKE_STATEMENTS("SELECT DISTINCT @DB_FIELDS@ FROM catalog "
892 "JOIN catalog AS c2 "
893 "ON catalog.md5path_1 = c2.parent_1 AND "
894 " catalog.md5path_2 = c2.parent_2 "
895 "WHERE catalog.flags & :nested_mountpoint_flag");
896 ✗ DEFERRED_INITS(database);
897
898 // this pretty much removes the advantage of a deferred init but the statement
899 // is anyway only used directly.
900 ✗ const bool success = BindInt64(1, SqlDirent::kFlagDirNestedMountpoint);
901 ✗ assert(success);
902 }
903
904
905 //------------------------------------------------------------------------------
906
907
908 1873 SqlDirentTouch::SqlDirentTouch(const CatalogDatabase &database) {
909
2/4
✓ Branch 1 taken 1873 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1873 times.
✗ Branch 5 not taken.
1873 DeferredInit(database.sqlite_db(),
910 "UPDATE catalog "
911 "SET hash = :hash, size = :size, mode = :mode, mtime = :mtime, "
912 // 1 2 3 4
913 "name = :name, symlink = :symlink, uid = :uid, gid = :gid, "
914 "xattr = :xattr, "
915 // 5 6 7 8 9
916 "mtimens = :mtimens "
917 // 10
918 "WHERE (md5path_1 = :md5_1) AND (md5path_2 = :md5_2);");
919 // 11 12
920 1873 }
921
922
923 45 bool SqlDirentTouch::BindDirentBase(const DirectoryEntryBase &entry) {
924
1/2
✓ Branch 2 taken 45 times.
✗ Branch 3 not taken.
90 bool result = BindHashBlob(1, entry.checksum_) && BindInt64(2, entry.size_)
925
2/4
✓ Branch 1 taken 45 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 45 times.
✗ Branch 5 not taken.
45 && BindInt(3, entry.mode_) && BindInt64(4, entry.mtime_)
926
1/2
✓ Branch 3 taken 45 times.
✗ Branch 4 not taken.
45 && BindText(5, entry.name_.GetChars(), entry.name_.GetLength())
927
1/2
✓ Branch 2 taken 45 times.
✗ Branch 3 not taken.
45 && BindText(6, entry.symlink_.GetChars(),
928 45 entry.symlink_.GetLength())
929
3/6
✓ Branch 0 taken 45 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 45 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 45 times.
✗ Branch 7 not taken.
90 && BindInt64(7, entry.uid_) && BindInt64(8, entry.gid_);
930
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 45 times.
45 if (entry.HasMtimeNs()) {
931 ✗ result &= BindInt(10, entry.mtime_ns_);
932 } else {
933 45 result &= BindNull(10);
934 }
935 45 return result;
936 }
937
938
939 45 bool SqlDirentTouch::BindPathHash(const shash::Md5 &hash) {
940 45 return BindMd5(11, 12, hash);
941 }
942
943
944 ✗ bool SqlDirentTouch::BindXattr(const XattrList &xattrs) {
945 unsigned char *packed_xattrs;
946 unsigned size;
947 ✗ xattrs.Serialize(&packed_xattrs, &size);
948 ✗ if (packed_xattrs == NULL)
949 ✗ return BindNull(9);
950 ✗ return BindBlobTransient(9, packed_xattrs, size);
951 }
952
953
954 45 bool SqlDirentTouch::BindXattrEmpty() { return BindNull(9); }
955
956
957 //------------------------------------------------------------------------------
958
959
960 2857 SqlNestedCatalogLookup::SqlNestedCatalogLookup(
961 2857 const CatalogDatabase &database) {
962 // We cannot access nested catalogs where the content hash is missing
963 static const char *stmt_0_9 = "SELECT '', 0 FROM nested_catalogs;";
964 static const char *stmt_2_5_ge_4 =
965 "SELECT sha1, size FROM nested_catalogs WHERE path=:path "
966 "UNION ALL SELECT sha1, size FROM bind_mountpoints WHERE path=:path;";
967 static const char *stmt_2_5_ge_1_lt_4 = "SELECT sha1, size FROM "
968 "nested_catalogs WHERE path=:path;";
969 // Internally converts NULL to 0 for size
970 static const char
971 *stmt_2_5_lt_1 = "SELECT sha1, 0 FROM nested_catalogs WHERE path=:path;";
972
973 2857 if (database.IsEqualSchema(database.schema_version(), 2.5)
974
5/6
✓ Branch 0 taken 2795 times.
✓ Branch 1 taken 62 times.
✓ Branch 3 taken 2795 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 2795 times.
✓ Branch 6 taken 62 times.
2857 && (database.schema_revision() >= 4)) {
975
2/4
✓ Branch 1 taken 2795 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 2795 times.
✗ Branch 5 not taken.
2795 DeferredInit(database.sqlite_db(), stmt_2_5_ge_4);
976 62 } else if (database.IsEqualSchema(database.schema_version(), 2.5)
977
2/6
✗ Branch 0 not taken.
✓ Branch 1 taken 62 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 62 times.
62 && (database.schema_revision() >= 1)) {
978 ✗ DeferredInit(database.sqlite_db(), stmt_2_5_ge_1_lt_4);
979 } else {
980
2/2
✓ Branch 2 taken 30 times.
✓ Branch 3 taken 32 times.
62 if (database.IsEqualSchema(database.schema_version(), 0.9)) {
981
2/4
✓ Branch 1 taken 30 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 30 times.
✗ Branch 5 not taken.
30 DeferredInit(database.sqlite_db(), stmt_0_9);
982 } else {
983
2/4
✓ Branch 1 taken 32 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 32 times.
✗ Branch 5 not taken.
32 DeferredInit(database.sqlite_db(), stmt_2_5_lt_1);
984 }
985 }
986 2857 }
987
988
989 942 bool SqlNestedCatalogLookup::BindSearchPath(const PathString &path) {
990 942 return BindText(1, path.GetChars(), path.GetLength());
991 }
992
993
994 900 shash::Any SqlNestedCatalogLookup::GetContentHash() const {
995
2/4
✓ Branch 2 taken 900 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 900 times.
✗ Branch 6 not taken.
900 const string hash = string(reinterpret_cast<const char *>(RetrieveText(0)));
996 900 return (hash.empty())
997 ? shash::Any(shash::kAny)
998
4/6
✓ Branch 0 taken 454 times.
✓ Branch 1 taken 446 times.
✓ Branch 3 taken 454 times.
✗ Branch 4 not taken.
✓ Branch 7 taken 446 times.
✗ Branch 8 not taken.
1800 : shash::MkFromHexPtr(shash::HexPtr(hash), shash::kSuffixCatalog);
999 900 }
1000
1001
1002 900 uint64_t SqlNestedCatalogLookup::GetSize() const { return RetrieveInt64(1); }
1003
1004
1005 //------------------------------------------------------------------------------
1006
1007
1008 2857 SqlNestedCatalogListing::SqlNestedCatalogListing(
1009 2857 const CatalogDatabase &database) {
1010 // We cannot access nested catalogs where the content hash is missing
1011 static const char *stmt_0_9 = "SELECT '', '', 0 FROM nested_catalogs;";
1012 static const char *stmt_2_5_ge_4 =
1013 "SELECT path, sha1, size FROM nested_catalogs "
1014 "UNION ALL SELECT path, sha1, size FROM bind_mountpoints;";
1015 static const char
1016 *stmt_2_5_ge_1_lt_4 = "SELECT path, sha1, size FROM nested_catalogs;";
1017 // Internally converts NULL to 0 for size
1018 static const char
1019 *stmt_2_5_lt_1 = "SELECT path, sha1, 0 FROM nested_catalogs;";
1020
1021 2857 if (database.IsEqualSchema(database.schema_version(), 2.5)
1022
5/6
✓ Branch 0 taken 2795 times.
✓ Branch 1 taken 62 times.
✓ Branch 3 taken 2795 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 2795 times.
✓ Branch 6 taken 62 times.
2857 && (database.schema_revision() >= 4)) {
1023
2/4
✓ Branch 1 taken 2795 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 2795 times.
✗ Branch 5 not taken.
2795 DeferredInit(database.sqlite_db(), stmt_2_5_ge_4);
1024 62 } else if (database.IsEqualSchema(database.schema_version(), 2.5)
1025
2/6
✗ Branch 0 not taken.
✓ Branch 1 taken 62 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 62 times.
62 && (database.schema_revision() >= 1)) {
1026 ✗ DeferredInit(database.sqlite_db(), stmt_2_5_ge_1_lt_4);
1027 } else {
1028
2/2
✓ Branch 2 taken 30 times.
✓ Branch 3 taken 32 times.
62 if (database.IsEqualSchema(database.schema_version(), 0.9)) {
1029
2/4
✓ Branch 1 taken 30 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 30 times.
✗ Branch 5 not taken.
30 DeferredInit(database.sqlite_db(), stmt_0_9);
1030 } else {
1031
2/4
✓ Branch 1 taken 32 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 32 times.
✗ Branch 5 not taken.
32 DeferredInit(database.sqlite_db(), stmt_2_5_lt_1);
1032 }
1033 }
1034 2857 }
1035
1036
1037 782 PathString SqlNestedCatalogListing::GetPath() const {
1038 782 const char *path = reinterpret_cast<const char *>(RetrieveText(0));
1039 782 return PathString(path, strlen(path));
1040 }
1041
1042
1043 782 shash::Any SqlNestedCatalogListing::GetContentHash() const {
1044
2/4
✓ Branch 2 taken 782 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 782 times.
✗ Branch 6 not taken.
782 const string hash = string(reinterpret_cast<const char *>(RetrieveText(1)));
1045 782 return (hash.empty())
1046 ? shash::Any(shash::kAny)
1047
4/6
✓ Branch 0 taken 204 times.
✓ Branch 1 taken 578 times.
✓ Branch 3 taken 204 times.
✗ Branch 4 not taken.
✓ Branch 7 taken 578 times.
✗ Branch 8 not taken.
1564 : shash::MkFromHexPtr(shash::HexPtr(hash), shash::kSuffixCatalog);
1048 782 }
1049
1050
1051 782 uint64_t SqlNestedCatalogListing::GetSize() const { return RetrieveInt64(2); }
1052
1053
1054 //------------------------------------------------------------------------------
1055
1056
1057 2857 SqlOwnNestedCatalogListing::SqlOwnNestedCatalogListing(
1058 2857 const CatalogDatabase &database) {
1059 // We cannot access nested catalogs where the content hash is missing
1060 static const char *stmt_0_9 = "SELECT '', '', 0 FROM nested_catalogs;";
1061 static const char
1062 *stmt_2_5_ge_1 = "SELECT path, sha1, size FROM nested_catalogs;";
1063 // Internally converts NULL to 0 for size
1064 static const char
1065 *stmt_2_5_lt_1 = "SELECT path, sha1, 0 FROM nested_catalogs;";
1066
1067 2857 if (database.IsEqualSchema(database.schema_version(), 2.5)
1068
5/6
✓ Branch 0 taken 2795 times.
✓ Branch 1 taken 62 times.
✓ Branch 3 taken 2795 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 2795 times.
✓ Branch 6 taken 62 times.
2857 && (database.schema_revision() >= 1)) {
1069
2/4
✓ Branch 1 taken 2795 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 2795 times.
✗ Branch 5 not taken.
2795 DeferredInit(database.sqlite_db(), stmt_2_5_ge_1);
1070 } else {
1071
2/2
✓ Branch 2 taken 30 times.
✓ Branch 3 taken 32 times.
62 if (database.IsEqualSchema(database.schema_version(), 0.9)) {
1072
2/4
✓ Branch 1 taken 30 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 30 times.
✗ Branch 5 not taken.
30 DeferredInit(database.sqlite_db(), stmt_0_9);
1073 } else {
1074
2/4
✓ Branch 1 taken 32 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 32 times.
✗ Branch 5 not taken.
32 DeferredInit(database.sqlite_db(), stmt_2_5_lt_1);
1075 }
1076 }
1077 2857 }
1078
1079
1080 96 PathString SqlOwnNestedCatalogListing::GetPath() const {
1081 96 const char *path = reinterpret_cast<const char *>(RetrieveText(0));
1082 96 return PathString(path, strlen(path));
1083 }
1084
1085
1086 96 shash::Any SqlOwnNestedCatalogListing::GetContentHash() const {
1087
2/4
✓ Branch 2 taken 96 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 96 times.
✗ Branch 6 not taken.
96 const string hash = string(reinterpret_cast<const char *>(RetrieveText(1)));
1088 96 return (hash.empty())
1089 ? shash::Any(shash::kAny)
1090
2/6
✗ Branch 0 not taken.
✓ Branch 1 taken 96 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 7 taken 96 times.
✗ Branch 8 not taken.
192 : shash::MkFromHexPtr(shash::HexPtr(hash), shash::kSuffixCatalog);
1091 96 }
1092
1093
1094 96 uint64_t SqlOwnNestedCatalogListing::GetSize() const {
1095 96 return RetrieveInt64(2);
1096 }
1097
1098
1099 //------------------------------------------------------------------------------
1100
1101
1102 3040 SqlDirentInsert::SqlDirentInsert(const CatalogDatabase &database) {
1103 6080 DeferredInit(
1104
2/4
✓ Branch 1 taken 3040 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 3040 times.
✗ Branch 5 not taken.
3040 database.sqlite_db(),
1105 "INSERT INTO catalog "
1106 "(md5path_1, md5path_2, parent_1, parent_2, hash, hardlinks, size, mode,"
1107 // 1 2 3 4 5 6 7 8
1108 "mtime, flags, name, symlink, uid, gid, xattr, mtimens) "
1109 // 9, 10 11 12 13 14 15 16
1110 "VALUES (:md5_1, :md5_2, :p_1, :p_2, :hash, :links, :size, :mode, :mtime,"
1111 " :flags, :name, :symlink, :uid, :gid, :xattr, :mtimens);");
1112 3040 }
1113
1114
1115 10850 bool SqlDirentInsert::BindPathHash(const shash::Md5 &hash) {
1116 10850 return BindMd5(1, 2, hash);
1117 }
1118
1119
1120 10850 bool SqlDirentInsert::BindParentPathHash(const shash::Md5 &hash) {
1121 10850 return BindMd5(3, 4, hash);
1122 }
1123
1124
1125 10850 bool SqlDirentInsert::BindDirent(const DirectoryEntry &entry) {
1126 10850 return BindDirentFields(5, 6, 7, 8, 9, 16, 10, 11, 12, 13, 14, entry);
1127 }
1128
1129
1130 ✗ bool SqlDirentInsert::BindXattr(const XattrList &xattrs) {
1131 unsigned char *packed_xattrs;
1132 unsigned size;
1133 ✗ xattrs.Serialize(&packed_xattrs, &size);
1134 ✗ if (packed_xattrs == NULL)
1135 ✗ return BindNull(15);
1136 ✗ return BindBlobTransient(15, packed_xattrs, size);
1137 }
1138
1139
1140 9683 bool SqlDirentInsert::BindXattrEmpty() { return BindNull(15); }
1141
1142
1143 //------------------------------------------------------------------------------
1144
1145
1146 1873 SqlDirentUpdate::SqlDirentUpdate(const CatalogDatabase &database) {
1147
2/4
✓ Branch 1 taken 1873 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1873 times.
✗ Branch 5 not taken.
1873 DeferredInit(database.sqlite_db(),
1148 "UPDATE catalog "
1149 "SET hash = :hash, size = :size, mode = :mode, mtime = :mtime, "
1150 // 1 2 3 4
1151 "flags = :flags, name = :name, symlink = :symlink, hardlinks = "
1152 ":hardlinks, "
1153 // 5 6 7 8
1154 "uid = :uid, gid = :gid, mtimens = :mtimens "
1155 // 9 10 11
1156 "WHERE (md5path_1 = :md5_1) AND (md5path_2 = :md5_2);");
1157 // 12 13
1158 1873 }
1159
1160
1161 3075 bool SqlDirentUpdate::BindPathHash(const shash::Md5 &hash) {
1162 3075 return BindMd5(12, 13, hash);
1163 }
1164
1165
1166 3075 bool SqlDirentUpdate::BindDirent(const DirectoryEntry &entry) {
1167 3075 return BindDirentFields(1, 8, 2, 3, 4, 11, 5, 6, 7, 9, 10, entry);
1168 }
1169
1170
1171 //------------------------------------------------------------------------------
1172
1173
1174 1873 SqlDirentUnlink::SqlDirentUnlink(const CatalogDatabase &database) {
1175
2/4
✓ Branch 1 taken 1873 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1873 times.
✗ Branch 5 not taken.
1873 DeferredInit(database.sqlite_db(),
1176 "DELETE FROM catalog "
1177 "WHERE (md5path_1 = :md5_1) AND (md5path_2 = :md5_2);");
1178 1873 }
1179
1180 2021 bool SqlDirentUnlink::BindPathHash(const shash::Md5 &hash) {
1181 2021 return BindMd5(1, 2, hash);
1182 }
1183
1184
1185 //------------------------------------------------------------------------------
1186
1187
1188 1873 SqlIncLinkcount::SqlIncLinkcount(const CatalogDatabase &database) {
1189 // This command changes the linkcount of a whole hardlink group at once!
1190 // We can do this, since the 'hardlinks'-field contains the hardlink group ID
1191 // in the higher 32bit as well as the 'linkcount' in the lower 32bit.
1192 // This field will be equal for all entries belonging to the same hardlink
1193 // group while adding/subtracting small values from it will only effect the
1194 // linkcount in the lower 32bit.
1195 // Take a deep breath!
1196
2/4
✓ Branch 1 taken 1873 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1873 times.
✗ Branch 5 not taken.
1873 DeferredInit(database.sqlite_db(),
1197 "UPDATE catalog SET hardlinks = hardlinks + :delta "
1198 "WHERE hardlinks = (SELECT hardlinks from catalog "
1199 "WHERE md5path_1 = :md5_1 AND md5path_2 = :md5_2);");
1200 1873 }
1201
1202
1203 ✗ bool SqlIncLinkcount::BindPathHash(const shash::Md5 &hash) {
1204 ✗ return BindMd5(2, 3, hash);
1205 }
1206
1207
1208 ✗ bool SqlIncLinkcount::BindDelta(const int delta) { return BindInt(1, delta); }
1209
1210
1211 //------------------------------------------------------------------------------
1212
1213
1214 1873 SqlChunkInsert::SqlChunkInsert(const CatalogDatabase &database) {
1215
2/4
✓ Branch 1 taken 1873 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1873 times.
✗ Branch 5 not taken.
1873 DeferredInit(database.sqlite_db(),
1216 "INSERT INTO chunks (md5path_1, md5path_2, offset, size, hash) "
1217 // 1 2 3 4 5
1218 "VALUES (:md5_1, :md5_2, :offset, :size, :hash);");
1219 1873 }
1220
1221
1222 370 bool SqlChunkInsert::BindPathHash(const shash::Md5 &hash) {
1223 370 return BindMd5(1, 2, hash);
1224 }
1225
1226
1227 370 bool SqlChunkInsert::BindFileChunk(const FileChunk &chunk) {
1228
1/2
✓ Branch 4 taken 370 times.
✗ Branch 5 not taken.
740 return BindInt64(3, chunk.offset()) && BindInt64(4, chunk.size())
1229
2/4
✓ Branch 0 taken 370 times.
✗ Branch 1 not taken.
✓ Branch 4 taken 370 times.
✗ Branch 5 not taken.
740 && BindHashBlob(5, chunk.content_hash());
1230 }
1231
1232
1233 //------------------------------------------------------------------------------
1234
1235
1236 1873 SqlChunksRemove::SqlChunksRemove(const CatalogDatabase &database) {
1237
2/4
✓ Branch 1 taken 1873 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1873 times.
✗ Branch 5 not taken.
1873 DeferredInit(database.sqlite_db(),
1238 "DELETE FROM chunks "
1239 "WHERE (md5path_1 = :md5_1) AND (md5path_2 = :md5_2);");
1240 1873 }
1241
1242
1243 ✗ bool SqlChunksRemove::BindPathHash(const shash::Md5 &hash) {
1244 ✗ return BindMd5(1, 2, hash);
1245 }
1246
1247
1248 //------------------------------------------------------------------------------
1249
1250
1251 2857 SqlChunksListing::SqlChunksListing(const CatalogDatabase &database) {
1252
2/4
✓ Branch 1 taken 2857 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 2857 times.
✗ Branch 5 not taken.
2857 DeferredInit(database.sqlite_db(),
1253 "SELECT offset, size, hash FROM chunks "
1254 // 0 1 2
1255 "WHERE (md5path_1 = :md5_1) AND (md5path_2 = :md5_2) "
1256 // 1 2
1257 "ORDER BY offset ASC;");
1258 2857 }
1259
1260
1261 62 bool SqlChunksListing::BindPathHash(const shash::Md5 &hash) {
1262 62 return BindMd5(1, 2, hash);
1263 }
1264
1265
1266 62 FileChunk SqlChunksListing::GetFileChunk(
1267 const shash::Algorithms interpret_hash_as) const {
1268 return FileChunk(
1269 62 RetrieveHashBlob(2, interpret_hash_as, shash::kSuffixPartial),
1270 62 RetrieveInt64(0),
1271 124 RetrieveInt64(1));
1272 }
1273
1274
1275 //------------------------------------------------------------------------------
1276
1277
1278 1873 SqlChunksCount::SqlChunksCount(const CatalogDatabase &database) {
1279
2/4
✓ Branch 1 taken 1873 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1873 times.
✗ Branch 5 not taken.
1873 DeferredInit(database.sqlite_db(),
1280 "SELECT count(*) FROM chunks "
1281 // 0
1282 "WHERE (md5path_1 = :md5_1) AND (md5path_2 = :md5_2)");
1283 // 1 2
1284 1873 }
1285
1286
1287 ✗ bool SqlChunksCount::BindPathHash(const shash::Md5 &hash) {
1288 ✗ return BindMd5(1, 2, hash);
1289 }
1290
1291
1292 ✗ int SqlChunksCount::GetChunkCount() const { return RetrieveInt64(0); }
1293
1294
1295 //------------------------------------------------------------------------------
1296
1297
1298 1873 SqlMaxHardlinkGroup::SqlMaxHardlinkGroup(const CatalogDatabase &database) {
1299
2/4
✓ Branch 1 taken 1873 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1873 times.
✗ Branch 5 not taken.
1873 DeferredInit(database.sqlite_db(), "SELECT max(hardlinks) FROM catalog;");
1300 1873 }
1301
1302
1303 62 uint32_t SqlMaxHardlinkGroup::GetMaxGroupId() const {
1304 62 return RetrieveInt64(0) >> 32;
1305 }
1306
1307
1308 //------------------------------------------------------------------------------
1309
1310
1311 4130 SqlGetCounter::SqlGetCounter(const CatalogDatabase &database) {
1312 static const char
1313 *stmt_ge_2_4 = "SELECT value from statistics WHERE counter = :counter;";
1314 static const char *stmt_lt_2_4 = "SELECT 0;";
1315
1316
2/2
✓ Branch 1 taken 4068 times.
✓ Branch 2 taken 62 times.
4130 if (database.schema_version() >= 2.4 - CatalogDatabase::kSchemaEpsilon) {
1317 4068 compat_ = false;
1318
2/4
✓ Branch 1 taken 4068 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 4068 times.
✗ Branch 5 not taken.
4068 DeferredInit(database.sqlite_db(), stmt_ge_2_4);
1319 } else {
1320 62 compat_ = true;
1321
2/4
✓ Branch 1 taken 62 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 62 times.
✗ Branch 5 not taken.
62 DeferredInit(database.sqlite_db(), stmt_lt_2_4);
1322 }
1323 4130 }
1324
1325
1326 99120 bool SqlGetCounter::BindCounter(const std::string &counter) {
1327
2/2
✓ Branch 0 taken 1488 times.
✓ Branch 1 taken 97632 times.
99120 if (compat_)
1328 1488 return true;
1329 97632 return BindText(1, counter);
1330 }
1331
1332
1333 99120 uint64_t SqlGetCounter::GetCounter() const {
1334
2/2
✓ Branch 0 taken 1488 times.
✓ Branch 1 taken 97632 times.
99120 if (compat_)
1335 1488 return 0;
1336 97632 return RetrieveInt64(0);
1337 }
1338
1339
1340 //------------------------------------------------------------------------------
1341
1342
1343 1273 SqlUpdateCounter::SqlUpdateCounter(const CatalogDatabase &database) {
1344 2546 DeferredInit(
1345
2/4
✓ Branch 1 taken 1273 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1273 times.
✗ Branch 5 not taken.
1273 database.sqlite_db(),
1346 "UPDATE statistics SET value=value+:val WHERE counter=:counter;");
1347 1273 }
1348
1349
1350 30552 bool SqlUpdateCounter::BindCounter(const std::string &counter) {
1351 30552 return BindText(2, counter);
1352 }
1353
1354
1355 30552 bool SqlUpdateCounter::BindDelta(const int64_t delta) {
1356 30552 return BindInt64(1, delta);
1357 }
1358
1359
1360 //------------------------------------------------------------------------------
1361
1362
1363 1956 SqlCreateCounter::SqlCreateCounter(const CatalogDatabase &database) {
1364
2/4
✓ Branch 1 taken 1956 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1956 times.
✗ Branch 5 not taken.
1956 DeferredInit(database.sqlite_db(),
1365 "INSERT OR REPLACE INTO statistics (counter, value) "
1366 "VALUES (:counter, :value);");
1367 1956 }
1368
1369
1370 46944 bool SqlCreateCounter::BindCounter(const std::string &counter) {
1371 46944 return BindText(1, counter);
1372 }
1373
1374
1375 46944 bool SqlCreateCounter::BindInitialValue(const int64_t value) {
1376 46944 return BindInt64(2, value);
1377 }
1378
1379
1380 //------------------------------------------------------------------------------
1381
1382
1383 2857 SqlAllChunks::SqlAllChunks(const CatalogDatabase &database) {
1384 2857 const int hash_mask = 7 << SqlDirent::kFlagPosHash;
1385
3/6
✓ Branch 1 taken 2857 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 2857 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 2857 times.
✗ Branch 8 not taken.
5714 const string flags2hash = " ((flags&" + StringifyInt(hash_mask) + ") >> "
1386
2/4
✓ Branch 1 taken 2857 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 2857 times.
✗ Branch 5 not taken.
8571 + StringifyInt(SqlDirent::kFlagPosHash)
1387
1/2
✓ Branch 1 taken 2857 times.
✗ Branch 2 not taken.
2857 + ")+1 AS hash_algorithm ";
1388
1389 2857 const int compression_mask = 7 << SqlDirent::kFlagPosCompression;
1390
2/4
✓ Branch 1 taken 2857 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 2857 times.
✗ Branch 5 not taken.
5714 const string flags2compression = " ((flags&" + StringifyInt(compression_mask)
1391
1/2
✓ Branch 1 taken 2857 times.
✗ Branch 2 not taken.
5714 + ") >> "
1392
2/4
✓ Branch 1 taken 2857 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 2857 times.
✗ Branch 5 not taken.
8571 + StringifyInt(
1393 SqlDirent::kFlagPosCompression)
1394
2/4
✓ Branch 1 taken 2857 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 2857 times.
✗ Branch 5 not taken.
5714 + ") " + "AS compression_algorithm ";
1395
1396
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2857 times.
2857 if (!g_ignore_legacy_bulk_hashes)
1397 ✗ LogCvmfs(kLogCatalog, kLogDebug,
1398 "CVMFS_NO_IGNORE_LEGACY_BULKHASHES is set, "
1399 "legacy bulk hashes won't be ignored in catalog operations");
1400
1401 // TODO(reneme): this depends on shash::kSuffix* being a char!
1402 // it should be more generic or replaced entirely
1403 // TODO(reneme): this is practically the same as SqlListContentHashes and
1404 // should be consolidated
1405 string sql = "SELECT DISTINCT hash, "
1406 "CASE WHEN flags & "
1407
3/6
✓ Branch 1 taken 2857 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 2857 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 2857 times.
✗ Branch 8 not taken.
5714 + StringifyInt(SqlDirent::kFlagFile) + " THEN "
1408
4/8
✓ Branch 1 taken 2857 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 2857 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 2857 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 2857 times.
✗ Branch 11 not taken.
11428 + StringifyInt(shash::kSuffixNone) + " " + "WHEN flags & "
1409
3/6
✓ Branch 1 taken 2857 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 2857 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 2857 times.
✗ Branch 8 not taken.
11428 + StringifyInt(SqlDirent::kFlagDir) + " THEN "
1410
3/6
✓ Branch 1 taken 2857 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 2857 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 2857 times.
✗ Branch 8 not taken.
11428 + StringifyInt(shash::kSuffixMicroCatalog) + " END "
1411
4/8
✓ Branch 1 taken 2857 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 2857 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 2857 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 2857 times.
✗ Branch 11 not taken.
5714 + "AS chunk_type, " + flags2hash + "," + flags2compression
1412
1/2
✓ Branch 1 taken 2857 times.
✗ Branch 2 not taken.
5714 + "FROM catalog WHERE (hash IS NOT NULL) AND "
1413 " (flags & "
1414
3/6
✓ Branch 0 taken 2857 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 2857 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 2857 times.
✗ Branch 7 not taken.
8571 + StringifyInt(SqlDirent::kFlagFileExternal
1415 | (g_ignore_legacy_bulk_hashes
1416 ? SqlDirent::kFlagFileChunk
1417 : 0))
1418
1/2
✓ Branch 1 taken 2857 times.
✗ Branch 2 not taken.
2857 + " = 0)";
1419
2/2
✓ Branch 1 taken 2795 times.
✓ Branch 2 taken 62 times.
2857 if (database.schema_version() >= 2.4 - CatalogDatabase::kSchemaEpsilon) {
1420 sql += " UNION "
1421 "SELECT DISTINCT chunks.hash, "
1422
5/10
✓ Branch 1 taken 2795 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 2795 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 2795 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 2795 times.
✗ Branch 11 not taken.
✓ Branch 13 taken 2795 times.
✗ Branch 14 not taken.
5590 + StringifyInt(shash::kSuffixPartial) + ", " + flags2hash + ","
1423
1/2
✓ Branch 1 taken 2795 times.
✗ Branch 2 not taken.
5590 + flags2compression
1424
1/2
✓ Branch 1 taken 2795 times.
✗ Branch 2 not taken.
5590 + "FROM chunks, catalog WHERE "
1425 "chunks.md5path_1=catalog.md5path_1 AND "
1426 "chunks.md5path_2=catalog.md5path_2 AND "
1427 "(catalog.flags & "
1428
4/8
✓ Branch 1 taken 2795 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 2795 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 2795 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 2795 times.
✗ Branch 11 not taken.
8385 + StringifyInt(SqlDirent::kFlagFileExternal) + " = 0)";
1429 }
1430
1/2
✓ Branch 1 taken 2857 times.
✗ Branch 2 not taken.
2857 sql += ";";
1431
2/4
✓ Branch 1 taken 2857 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 2857 times.
✗ Branch 5 not taken.
2857 Init(database.sqlite_db(), sql);
1432 2857 }
1433
1434
1435 60 bool SqlAllChunks::Open() { return true; }
1436
1437
1438 300 bool SqlAllChunks::Next(shash::Any *hash, zlib::Algorithms *compression_alg) {
1439
2/2
✓ Branch 1 taken 60 times.
✓ Branch 2 taken 240 times.
300 if (!FetchRow()) {
1440 60 return false;
1441 }
1442
1443 240 *hash = RetrieveHashBlob(0, static_cast<shash::Algorithms>(RetrieveInt(2)),
1444 240 static_cast<shash::Suffix>(RetrieveInt(1)));
1445 240 *compression_alg = static_cast<zlib::Algorithms>(RetrieveInt(3));
1446 240 return true;
1447 }
1448
1449
1450 60 bool SqlAllChunks::Close() { return Reset(); }
1451
1452
1453 //------------------------------------------------------------------------------
1454
1455
1456 2857 SqlLookupXattrs::SqlLookupXattrs(const CatalogDatabase &database) {
1457
2/4
✓ Branch 1 taken 2857 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 2857 times.
✗ Branch 5 not taken.
2857 DeferredInit(database.sqlite_db(),
1458 "SELECT xattr FROM catalog "
1459 "WHERE (md5path_1 = :md5_1) AND (md5path_2 = :md5_2);");
1460 2857 }
1461
1462
1463 30 bool SqlLookupXattrs::BindPathHash(const shash::Md5 &hash) {
1464 30 return BindMd5(1, 2, hash);
1465 }
1466
1467
1468 30 XattrList SqlLookupXattrs::GetXattrs() {
1469 const unsigned char *packed_xattrs = reinterpret_cast<const unsigned char *>(
1470
1/2
✓ Branch 1 taken 30 times.
✗ Branch 2 not taken.
30 RetrieveBlob(0));
1471
1/2
✓ Branch 0 taken 30 times.
✗ Branch 1 not taken.
30 if (packed_xattrs == NULL)
1472 30 return XattrList();
1473
1474 ✗ const int size = RetrieveBytes(0);
1475 ✗ assert(size >= 0);
1476 const std::unique_ptr<XattrList> xattrs(
1477 ✗ XattrList::Deserialize(packed_xattrs, size));
1478 ✗ if (xattrs.get() == nullptr) {
1479 ✗ LogCvmfs(kLogCatalog, kLogDebug, "corrupted xattr data");
1480 ✗ return XattrList();
1481 }
1482 ✗ return *xattrs;
1483 }
1484
1485 } // namespace catalog
1486