GCC Code Coverage Report


Directory: cvmfs/
File: cvmfs/catalog_sql.cc
Date: 2026-04-12 02:41:08
Exec Total Coverage
Lines: 452 598 75.6%
Branches: 574 1536 37.4%

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