GCC Code Coverage Report


Directory: cvmfs/
File: cvmfs/catalog.cc
Date: 2024-04-28 02:33:07
Exec Total Coverage
Lines: 406 435 93.3%
Branches: 323 606 53.3%

Line Branch Exec Source
1 /**
2 * This file is part of the CernVM File System.
3 */
4
5 #include "catalog.h"
6
7 #include <alloca.h>
8 #include <errno.h>
9
10 #include <algorithm>
11 #include <cassert>
12
13 #include "catalog_mgr.h"
14 #include "util/concurrency.h"
15 #include "util/logging.h"
16 #include "util/platform.h"
17 #include "util/smalloc.h"
18
19 using namespace std; // NOLINT
20
21 namespace catalog {
22
23 const shash::Md5 Catalog::kMd5PathEmpty("", 0);
24
25
26 /**
27 * Open a catalog outside the framework of a catalog manager.
28 */
29 20 Catalog* Catalog::AttachFreely(const string &imaginary_mountpoint,
30 const string &file,
31 const shash::Any &catalog_hash,
32 Catalog *parent,
33 const bool is_nested) {
34 Catalog *catalog =
35 20 new Catalog(PathString(imaginary_mountpoint.data(),
36 20 imaginary_mountpoint.length()),
37 catalog_hash,
38 parent,
39
2/4
✓ Branch 1 taken 20 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 20 times.
✗ Branch 5 not taken.
20 is_nested);
40 20 const bool successful_init = catalog->InitStandalone(file);
41
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 19 times.
20 if (!successful_init) {
42
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 delete catalog;
43 1 return NULL;
44 }
45 19 return catalog;
46 }
47
48
49 151 Catalog::Catalog(const PathString &mountpoint,
50 const shash::Any &catalog_hash,
51 Catalog *parent,
52 151 const bool is_nested) :
53 151 catalog_hash_(catalog_hash),
54
1/2
✓ Branch 1 taken 151 times.
✗ Branch 2 not taken.
151 mountpoint_(mountpoint),
55
1/2
✓ Branch 1 taken 151 times.
✗ Branch 2 not taken.
151 is_regular_mountpoint_(mountpoint_ == root_prefix_),
56 151 volatile_flag_(false),
57
3/4
✓ Branch 0 taken 96 times.
✓ Branch 1 taken 55 times.
✓ Branch 2 taken 96 times.
✗ Branch 3 not taken.
151 is_root_(parent == NULL && !is_nested),
58 151 managed_database_(false),
59 151 parent_(parent),
60 151 nested_catalog_cache_dirty_(true),
61 151 voms_authz_status_(kVomsUnknown),
62
1/2
✓ Branch 8 taken 151 times.
✗ Branch 9 not taken.
302 initialized_(false)
63 {
64 151 max_row_id_ = 0;
65 151 inode_annotation_ = NULL;
66 151 lock_ = reinterpret_cast<pthread_mutex_t *>(smalloc(sizeof(pthread_mutex_t)));
67 151 int retval = pthread_mutex_init(lock_, NULL);
68
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 151 times.
151 assert(retval == 0);
69
70 151 database_ = NULL;
71 151 uid_map_ = NULL;
72 151 gid_map_ = NULL;
73 151 sql_listing_ = NULL;
74 151 sql_lookup_md5path_ = NULL;
75 151 sql_lookup_nested_ = NULL;
76 151 sql_list_nested_ = NULL;
77 151 sql_own_list_nested_ = NULL;
78 151 sql_all_chunks_ = NULL;
79 151 sql_chunks_listing_ = NULL;
80 151 sql_lookup_xattrs_ = NULL;
81 151 }
82
83
84 412 Catalog::~Catalog() {
85 298 pthread_mutex_destroy(lock_);
86 298 free(lock_);
87 298 FinalizePreparedStatements();
88
2/2
✓ Branch 0 taken 141 times.
✓ Branch 1 taken 8 times.
298 delete database_;
89 412 }
90
91
92 /**
93 * InitPreparedStatement uses polymorphism in case of a r/w catalog.
94 * FinalizePreparedStatements is called in the destructor where
95 * polymorphism does not work any more and has to be called both in
96 * the WritableCatalog and the Catalog destructor
97 */
98 143 void Catalog::InitPreparedStatements() {
99
1/2
✓ Branch 3 taken 143 times.
✗ Branch 4 not taken.
143 sql_listing_ = new SqlListing(database());
100
1/2
✓ Branch 3 taken 143 times.
✗ Branch 4 not taken.
143 sql_lookup_md5path_ = new SqlLookupPathHash(database());
101
1/2
✓ Branch 3 taken 143 times.
✗ Branch 4 not taken.
143 sql_lookup_nested_ = new SqlNestedCatalogLookup(database());
102
1/2
✓ Branch 3 taken 143 times.
✗ Branch 4 not taken.
143 sql_list_nested_ = new SqlNestedCatalogListing(database());
103
1/2
✓ Branch 3 taken 143 times.
✗ Branch 4 not taken.
143 sql_own_list_nested_ = new SqlOwnNestedCatalogListing(database());
104
1/2
✓ Branch 3 taken 143 times.
✗ Branch 4 not taken.
143 sql_all_chunks_ = new SqlAllChunks(database());
105
1/2
✓ Branch 3 taken 143 times.
✗ Branch 4 not taken.
143 sql_chunks_listing_ = new SqlChunksListing(database());
106
1/2
✓ Branch 3 taken 143 times.
✗ Branch 4 not taken.
143 sql_lookup_xattrs_ = new SqlLookupXattrs(database());
107 143 }
108
109
110 149 void Catalog::FinalizePreparedStatements() {
111
2/2
✓ Branch 0 taken 141 times.
✓ Branch 1 taken 8 times.
149 delete sql_lookup_xattrs_;
112
2/2
✓ Branch 0 taken 141 times.
✓ Branch 1 taken 8 times.
149 delete sql_chunks_listing_;
113
2/2
✓ Branch 0 taken 141 times.
✓ Branch 1 taken 8 times.
149 delete sql_all_chunks_;
114
2/2
✓ Branch 0 taken 141 times.
✓ Branch 1 taken 8 times.
149 delete sql_listing_;
115
2/2
✓ Branch 0 taken 141 times.
✓ Branch 1 taken 8 times.
149 delete sql_lookup_md5path_;
116
2/2
✓ Branch 0 taken 141 times.
✓ Branch 1 taken 8 times.
149 delete sql_lookup_nested_;
117
2/2
✓ Branch 0 taken 141 times.
✓ Branch 1 taken 8 times.
149 delete sql_list_nested_;
118
2/2
✓ Branch 0 taken 141 times.
✓ Branch 1 taken 8 times.
149 delete sql_own_list_nested_;
119 149 }
120
121
122 42 bool Catalog::InitStandalone(const std::string &database_file) {
123
1/2
✓ Branch 1 taken 42 times.
✗ Branch 2 not taken.
42 bool retval = OpenDatabase(database_file);
124
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 41 times.
42 if (!retval) {
125 1 return false;
126 }
127
128 41 InodeRange inode_range;
129 41 inode_range.MakeDummy();
130 41 set_inode_range(inode_range);
131 41 return true;
132 }
133
134
135 218 bool Catalog::ReadCatalogCounters() {
136
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 218 times.
218 assert(database_ != NULL);
137 bool statistics_loaded;
138 218 if (database().schema_version() <
139
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 216 times.
218 CatalogDatabase::kLatestSupportedSchema - CatalogDatabase::kSchemaEpsilon)
140 {
141 statistics_loaded =
142 2 counters_.ReadFromDatabase(database(), LegacyMode::kLegacy);
143
1/2
✗ Branch 2 not taken.
✓ Branch 3 taken 216 times.
216 } else if (database().schema_revision() < 2) {
144 statistics_loaded =
145 counters_.ReadFromDatabase(database(), LegacyMode::kNoXattrs);
146
1/2
✗ Branch 2 not taken.
✓ Branch 3 taken 216 times.
216 } else if (database().schema_revision() < 3) {
147 statistics_loaded =
148 counters_.ReadFromDatabase(database(), LegacyMode::kNoExternals);
149
1/2
✗ Branch 2 not taken.
✓ Branch 3 taken 216 times.
216 } else if (database().schema_revision() < 5) {
150 statistics_loaded =
151 counters_.ReadFromDatabase(database(), LegacyMode::kNoSpecials);
152 } else {
153 216 statistics_loaded = counters_.ReadFromDatabase(database());
154 }
155 218 return statistics_loaded;
156 }
157
158
159 /**
160 * Establishes the database structures and opens the sqlite database file.
161 * @param db_path the absolute path to the database file on local file system
162 * @return true on successful initialization otherwise false
163 */
164 145 bool Catalog::OpenDatabase(const string &db_path) {
165
2/4
✓ Branch 1 taken 145 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 145 times.
✗ Branch 5 not taken.
145 database_ = CatalogDatabase::Open(db_path, DatabaseOpenMode());
166
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 143 times.
145 if (NULL == database_) {
167 2 return false;
168 }
169
170
2/2
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 141 times.
143 if (database_->IsEqualSchema(database_->schema_version(), 1.0)) {
171 // Possible fix-up for database layout lacking the content hash of
172 // nested catalogs
173 2 SqlCatalog sql_has_nested_sha1(database(),
174 "SELECT count(*) FROM sqlite_master "
175
2/4
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 2 times.
✗ Branch 6 not taken.
6 "WHERE type='table' AND name='nested_catalogs' AND sql LIKE '%sha1%';");
176
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 bool retval = sql_has_nested_sha1.FetchRow();
177
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 assert(retval == true);
178
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 bool has_nested_sha1 = sql_has_nested_sha1.RetrieveInt64(0);
179
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2 if (!has_nested_sha1) {
180 1 database_->EnforceSchema(0.9, 0);
181 }
182 2 }
183
184
1/2
✓ Branch 1 taken 143 times.
✗ Branch 2 not taken.
143 InitPreparedStatements();
185
186 // Set the database file ownership if requested
187
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 137 times.
143 if (managed_database_) {
188
1/2
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
6 database_->TakeFileOwnership();
189 }
190
191 // Find out the maximum row id of this database file
192
2/4
✓ Branch 2 taken 143 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 143 times.
✗ Branch 7 not taken.
286 SqlCatalog sql_max_row_id(database(), "SELECT MAX(rowid) FROM catalog;");
193
2/4
✓ Branch 1 taken 143 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 143 times.
143 if (!sql_max_row_id.FetchRow()) {
194 LogCvmfs(kLogCatalog, kLogDebug,
195 "Cannot retrieve maximal row id for database file %s "
196 "(SqliteErrorcode: %d)",
197 db_path.c_str(), sql_max_row_id.GetLastError());
198 return false;
199 }
200
1/2
✓ Branch 1 taken 143 times.
✗ Branch 2 not taken.
143 max_row_id_ = sql_max_row_id.RetrieveInt64(0);
201
202 // Get root prefix
203
4/6
✓ Branch 2 taken 143 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 143 times.
✗ Branch 6 not taken.
✓ Branch 9 taken 62 times.
✓ Branch 10 taken 81 times.
143 if (database_->HasProperty("root_prefix")) {
204 const std::string root_prefix =
205
2/4
✓ Branch 2 taken 62 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 62 times.
✗ Branch 6 not taken.
124 database_->GetProperty<std::string>("root_prefix");
206
1/2
✓ Branch 3 taken 62 times.
✗ Branch 4 not taken.
62 root_prefix_.Assign(root_prefix.data(), root_prefix.size());
207
1/2
✓ Branch 3 taken 62 times.
✗ Branch 4 not taken.
62 LogCvmfs(kLogCatalog, kLogDebug,
208 "found root prefix %s in root catalog file %s",
209 root_prefix_.c_str(), db_path.c_str());
210
1/2
✓ Branch 1 taken 62 times.
✗ Branch 2 not taken.
62 is_regular_mountpoint_ = (root_prefix_ == mountpoint_);
211 62 } else {
212
1/2
✓ Branch 2 taken 81 times.
✗ Branch 3 not taken.
81 LogCvmfs(kLogCatalog, kLogDebug,
213 "no root prefix for root catalog file %s", db_path.c_str());
214 }
215
216 // Get volatile content flag
217
2/4
✓ Branch 1 taken 143 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 143 times.
✗ Branch 5 not taken.
143 volatile_flag_ = database_->GetPropertyDefault<bool>("volatile",
218 143 volatile_flag_);
219
220 // Read Catalog Counter Statistics
221
2/4
✓ Branch 1 taken 143 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 143 times.
143 if (!ReadCatalogCounters()) {
222 LogCvmfs(kLogCatalog, kLogStderr,
223 "failed to load statistics counters for catalog %s (file %s)",
224 mountpoint_.c_str(), db_path.c_str());
225 return false;
226 }
227
228
2/2
✓ Branch 1 taken 55 times.
✓ Branch 2 taken 88 times.
143 if (HasParent()) {
229
1/2
✓ Branch 1 taken 55 times.
✗ Branch 2 not taken.
55 parent_->AddChild(this);
230 }
231
232 143 initialized_ = true;
233 143 return true;
234 143 }
235
236
237 /**
238 * Removes the mountpoint and prepends the root prefix to path
239 */
240 633 shash::Md5 Catalog::NormalizePath(const PathString &path) const {
241
2/2
✓ Branch 0 taken 625 times.
✓ Branch 1 taken 8 times.
633 if (is_regular_mountpoint_)
242
1/2
✓ Branch 3 taken 625 times.
✗ Branch 4 not taken.
625 return shash::Md5(path.GetChars(), path.GetLength());
243
244
1/2
✗ Branch 2 not taken.
✓ Branch 3 taken 8 times.
8 assert(path.GetLength() >= mountpoint_.GetLength());
245 // Piecewise hash calculation: root_prefix plus tail of path
246
1/2
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
8 shash::Any result(shash::kMd5);
247
1/2
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
8 shash::ContextPtr ctx(shash::kMd5);
248 8 ctx.buffer = alloca(ctx.size);
249
1/2
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
8 shash::Init(ctx);
250
1/2
✓ Branch 2 taken 8 times.
✗ Branch 3 not taken.
16 shash::Update(
251 8 reinterpret_cast<const unsigned char *>(root_prefix_.GetChars()),
252 root_prefix_.GetLength(),
253 ctx);
254 16 shash::Update(
255 8 reinterpret_cast<const unsigned char *>(path.GetChars()) +
256
1/2
✓ Branch 2 taken 8 times.
✗ Branch 3 not taken.
8 mountpoint_.GetLength(),
257 8 path.GetLength() - mountpoint_.GetLength(),
258 ctx);
259
1/2
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
8 shash::Final(ctx, &result);
260
1/2
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
8 return result.CastToMd5();
261 }
262
263
264 /**
265 * Same as NormalizePath but returns a PathString instead of an Md5 hash.
266 */
267 56 PathString Catalog::NormalizePath2(const PathString &path) const {
268
2/2
✓ Branch 0 taken 52 times.
✓ Branch 1 taken 4 times.
56 if (is_regular_mountpoint_)
269
1/2
✓ Branch 1 taken 52 times.
✗ Branch 2 not taken.
52 return path;
270
271
1/2
✗ Branch 2 not taken.
✓ Branch 3 taken 4 times.
4 assert(path.GetLength() >= mountpoint_.GetLength());
272
1/2
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
4 PathString result = root_prefix_;
273
1/2
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
4 PathString suffix = path.Suffix(mountpoint_.GetLength());
274
1/2
✓ Branch 3 taken 4 times.
✗ Branch 4 not taken.
4 result.Append(suffix.GetChars(), suffix.GetLength());
275
1/2
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
4 return result;
276 4 }
277
278
279 /**
280 * The opposite of NormalizePath: from a full path remove the root prefix and
281 * add the catalogs current mountpoint. Needed for normalized paths from the
282 * SQlite tables, such as nested catalog entry points.
283 */
284 57 PathString Catalog::PlantPath(const PathString &path) const {
285
2/2
✓ Branch 0 taken 53 times.
✓ Branch 1 taken 4 times.
57 if (is_regular_mountpoint_)
286
1/2
✓ Branch 1 taken 53 times.
✗ Branch 2 not taken.
53 return path;
287
288
1/2
✗ Branch 2 not taken.
✓ Branch 3 taken 4 times.
4 assert(path.GetLength() >= root_prefix_.GetLength());
289
1/2
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
4 PathString result = mountpoint_;
290
1/2
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
4 PathString suffix = path.Suffix(root_prefix_.GetLength());
291
1/2
✓ Branch 3 taken 4 times.
✗ Branch 4 not taken.
4 result.Append(suffix.GetChars(), suffix.GetLength());
292
1/2
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
4 return result;
293 4 }
294
295
296 /**
297 * Performs a lookup on this Catalog for a given MD5 path hash.
298 * @param md5path the MD5 hash of the searched path
299 * @param expand_symlink indicates if variables in symlink should be resolved
300 * @param dirent will be set to the found DirectoryEntry
301 * @return true if DirectoryEntry was successfully found, false otherwise
302 */
303 561 bool Catalog::LookupEntry(const shash::Md5 &md5path, const bool expand_symlink,
304 DirectoryEntry *dirent) const
305 {
306
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 561 times.
561 assert(IsInitialized());
307
308 561 MutexLockGuard m(lock_);
309
1/2
✓ Branch 1 taken 561 times.
✗ Branch 2 not taken.
561 sql_lookup_md5path_->BindPathHash(md5path);
310
1/2
✓ Branch 1 taken 561 times.
✗ Branch 2 not taken.
561 bool found = sql_lookup_md5path_->FetchRow();
311
3/4
✓ Branch 0 taken 541 times.
✓ Branch 1 taken 20 times.
✓ Branch 2 taken 541 times.
✗ Branch 3 not taken.
561 if (found && (dirent != NULL)) {
312
2/4
✓ Branch 1 taken 541 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 541 times.
✗ Branch 5 not taken.
541 *dirent = sql_lookup_md5path_->GetDirent(this, expand_symlink);
313
1/2
✓ Branch 1 taken 541 times.
✗ Branch 2 not taken.
541 FixTransitionPoint(md5path, dirent);
314 }
315
1/2
✓ Branch 1 taken 561 times.
✗ Branch 2 not taken.
561 sql_lookup_md5path_->Reset();
316
317 561 return found;
318 561 }
319
320
321 /**
322 * Performs a lookup on this Catalog for a given MD5 path hash.
323 * @param md5path the MD5 hash of the searched path
324 * @param dirent will be set to the found DirectoryEntry
325 * @return true if DirectoryEntry was successfully found, false otherwise
326 */
327 560 bool Catalog::LookupMd5Path(const shash::Md5 &md5path,
328 DirectoryEntry *dirent) const
329 {
330 560 return LookupEntry(md5path, true, dirent);
331 }
332
333
334 1 bool Catalog::LookupRawSymlink(const PathString &path,
335 LinkString *raw_symlink) const
336 {
337
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 DirectoryEntry dirent;
338
2/4
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
1 bool result = (LookupEntry(NormalizePath(path), false, &dirent));
339
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (result)
340
2/4
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
1 raw_symlink->Assign(dirent.symlink());
341 1 return result;
342 1 }
343
344
345 1 bool Catalog::LookupXattrsMd5Path(
346 const shash::Md5 &md5path,
347 XattrList *xattrs) const
348 {
349
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
1 assert(IsInitialized());
350
351 1 MutexLockGuard m(lock_);
352
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 sql_lookup_xattrs_->BindPathHash(md5path);
353
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 bool found = sql_lookup_xattrs_->FetchRow();
354
2/4
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
1 if (found && (xattrs != NULL)) {
355
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 *xattrs = sql_lookup_xattrs_->GetXattrs();
356 }
357
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 sql_lookup_xattrs_->Reset();
358
359 1 return found;
360 1 }
361
362
363 /**
364 * Perform a listing of the directory with the given MD5 path hash.
365 * @param path_hash the MD5 hash of the path of the directory to list
366 * @param listing will be set to the resulting DirectoryEntryList
367 * @return true on successful listing, false otherwise
368 */
369 5 bool Catalog::ListingMd5PathStat(const shash::Md5 &md5path,
370 StatEntryList *listing) const
371 {
372
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 5 times.
5 assert(IsInitialized());
373
374
1/2
✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
5 DirectoryEntry dirent;
375
1/2
✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
5 StatEntry entry;
376
377 5 MutexLockGuard m(lock_);
378
1/2
✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
5 sql_listing_->BindPathHash(md5path);
379
3/4
✓ Branch 1 taken 17 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 12 times.
✓ Branch 4 taken 5 times.
17 while (sql_listing_->FetchRow()) {
380
2/4
✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 12 times.
✗ Branch 5 not taken.
12 dirent = sql_listing_->GetDirent(this);
381
2/2
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 11 times.
12 if (dirent.IsHidden())
382 1 continue;
383
1/2
✓ Branch 1 taken 11 times.
✗ Branch 2 not taken.
11 FixTransitionPoint(md5path, &dirent);
384
2/4
✓ Branch 1 taken 11 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 11 times.
✗ Branch 5 not taken.
11 entry.name = dirent.name();
385
1/2
✓ Branch 1 taken 11 times.
✗ Branch 2 not taken.
11 entry.info = dirent.GetStatStructure();
386
1/2
✓ Branch 1 taken 11 times.
✗ Branch 2 not taken.
11 listing->PushBack(entry);
387 }
388
1/2
✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
5 sql_listing_->Reset();
389
390 5 return true;
391 5 }
392
393
394 /**
395 * Perform a listing of the directory with the given MD5 path hash.
396 * Returns only struct stat values
397 * @param path_hash the MD5 hash of the path of the directory to list
398 * @param listing will be set to the resulting DirectoryEntryList
399 * @param expand_symlink defines if magic symlinks should be resolved
400 * @return true on successful listing, false otherwise
401 */
402 83 bool Catalog::ListingMd5Path(const shash::Md5 &md5path,
403 DirectoryEntryList *listing,
404 const bool expand_symlink) const
405 {
406
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 83 times.
83 assert(IsInitialized());
407
408 83 MutexLockGuard m(lock_);
409
410
1/2
✓ Branch 1 taken 83 times.
✗ Branch 2 not taken.
83 sql_listing_->BindPathHash(md5path);
411
3/4
✓ Branch 1 taken 237 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 154 times.
✓ Branch 4 taken 83 times.
237 while (sql_listing_->FetchRow()) {
412
1/2
✓ Branch 1 taken 154 times.
✗ Branch 2 not taken.
154 DirectoryEntry dirent = sql_listing_->GetDirent(this, expand_symlink);
413
1/2
✓ Branch 1 taken 154 times.
✗ Branch 2 not taken.
154 FixTransitionPoint(md5path, &dirent);
414
1/2
✓ Branch 1 taken 154 times.
✗ Branch 2 not taken.
154 listing->push_back(dirent);
415 154 }
416
1/2
✓ Branch 1 taken 83 times.
✗ Branch 2 not taken.
83 sql_listing_->Reset();
417
418 83 return true;
419 83 }
420
421
422 2 bool Catalog::AllChunksBegin() {
423 2 return sql_all_chunks_->Open();
424 }
425
426
427 11 bool Catalog::AllChunksNext(shash::Any *hash, zlib::Algorithms *compression_alg)
428 {
429 11 return sql_all_chunks_->Next(hash, compression_alg);
430 }
431
432
433 2 bool Catalog::AllChunksEnd() {
434 2 return sql_all_chunks_->Close();
435 }
436
437
438 /**
439 * Hash algorithm is given by the unchunked file.
440 * Could be figured out by a join but it is faster if the user of this
441 * method tells us.
442 */
443 1 bool Catalog::ListMd5PathChunks(const shash::Md5 &md5path,
444 const shash::Algorithms interpret_hashes_as,
445 FileChunkList *chunks) const
446 {
447
2/4
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
1 assert(IsInitialized() && chunks->IsEmpty());
448
449 1 MutexLockGuard m(lock_);
450
451
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 sql_chunks_listing_->BindPathHash(md5path);
452
3/4
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
✓ Branch 4 taken 1 times.
2 while (sql_chunks_listing_->FetchRow()) {
453
2/4
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
1 chunks->PushBack(sql_chunks_listing_->GetFileChunk(interpret_hashes_as));
454 }
455
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 sql_chunks_listing_->Reset();
456
457 1 return true;
458 1 }
459
460
461 /**
462 * Only used by the garbage collection
463 */
464 2 const Catalog::HashVector& Catalog::GetReferencedObjects() const {
465
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
2 if (!referenced_hashes_.empty()) {
466 return referenced_hashes_;
467 }
468
469 // retrieve all referenced content hashes of both files and file chunks
470
1/2
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
2 SqlListContentHashes list_content_hashes(database());
471
3/4
✓ Branch 1 taken 15 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 13 times.
✓ Branch 4 taken 2 times.
15 while (list_content_hashes.FetchRow()) {
472
2/4
✓ Branch 1 taken 13 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 13 times.
✗ Branch 5 not taken.
13 referenced_hashes_.push_back(list_content_hashes.GetHash());
473 }
474
475 2 return referenced_hashes_;
476 2 }
477
478
479 86 void Catalog::TakeDatabaseFileOwnership() {
480 86 managed_database_ = true;
481
2/2
✓ Branch 0 taken 80 times.
✓ Branch 1 taken 6 times.
86 if (NULL != database_) {
482 80 database_->TakeFileOwnership();
483 }
484 86 }
485
486
487 1 void Catalog::DropDatabaseFileOwnership() {
488 1 managed_database_ = false;
489
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (NULL != database_) {
490 1 database_->DropFileOwnership();
491 }
492 1 }
493
494
495 21 uint64_t Catalog::GetTTL() const {
496 21 MutexLockGuard m(lock_);
497
2/4
✓ Branch 3 taken 21 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 21 times.
✗ Branch 7 not taken.
42 return database().GetPropertyDefault<uint64_t>("TTL", kDefaultTTL);
498 21 }
499
500
501 bool Catalog::HasExplicitTTL() const {
502 MutexLockGuard m(lock_);
503 return database().HasProperty("TTL");
504 }
505
506
507 57 bool Catalog::GetVOMSAuthz(string *authz) const {
508 bool result;
509 57 MutexLockGuard m(lock_);
510
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 57 times.
57 if (voms_authz_status_ == kVomsPresent) {
511 if (authz) {*authz = voms_authz_;}
512 result = true;
513
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 57 times.
57 } else if (voms_authz_status_ == kVomsNone) {
514 result = false;
515 } else {
516
3/6
✓ Branch 3 taken 57 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 57 times.
✗ Branch 7 not taken.
✗ Branch 10 not taken.
✓ Branch 11 taken 57 times.
57 if (database().HasProperty("voms_authz")) {
517 voms_authz_ = database().GetProperty<string>("voms_authz");
518 if (authz) {*authz = voms_authz_;}
519 voms_authz_status_ = kVomsPresent;
520 } else {
521 57 voms_authz_status_ = kVomsNone;
522 }
523 57 result = (voms_authz_status_ == kVomsPresent);
524 }
525 57 return result;
526 57 }
527
528 128 uint64_t Catalog::GetRevision() const {
529 128 MutexLockGuard m(lock_);
530
2/4
✓ Branch 3 taken 128 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 128 times.
✗ Branch 7 not taken.
256 return database().GetPropertyDefault<uint64_t>("revision", 0);
531 128 }
532
533 59 uint64_t Catalog::GetLastModified() const {
534
1/2
✓ Branch 2 taken 59 times.
✗ Branch 3 not taken.
59 const std::string prop_name = "last_modified";
535
1/2
✓ Branch 2 taken 59 times.
✗ Branch 3 not taken.
59 return (database().HasProperty(prop_name))
536
2/4
✓ Branch 0 taken 59 times.
✗ Branch 1 not taken.
✓ Branch 4 taken 59 times.
✗ Branch 5 not taken.
59 ? database().GetProperty<int>(prop_name)
537 59 : 0u;
538 59 }
539
540
541 uint64_t Catalog::GetNumChunks() const {
542 return counters_.Get("self_regular") + counters_.Get("self_chunks");
543 }
544
545
546 2 uint64_t Catalog::GetNumEntries() const {
547
1/2
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
2 const string sql = "SELECT count(*) FROM catalog;";
548
549 2 MutexLockGuard m(lock_);
550
1/2
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
2 SqlCatalog stmt(database(), sql);
551
3/6
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 2 times.
✗ Branch 7 not taken.
4 return (stmt.FetchRow()) ? stmt.RetrieveInt64(0) : 0;
552 2 }
553
554
555 2 shash::Any Catalog::GetPreviousRevision() const {
556 2 MutexLockGuard m(lock_);
557 const std::string hash_string =
558
3/6
✓ Branch 3 taken 2 times.
✗ Branch 4 not taken.
✓ Branch 7 taken 2 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 2 times.
✗ Branch 11 not taken.
4 database().GetPropertyDefault<std::string>("previous_revision", "");
559 2 return (!hash_string.empty())
560
1/2
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
1 ? shash::MkFromHexPtr(shash::HexPtr(hash_string), shash::kSuffixCatalog)
561
3/4
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
4 : shash::Any();
562 2 }
563
564
565 1 string Catalog::PrintMemStatistics() const {
566 1 sqlite::MemStatistics stats;
567 {
568 1 MutexLockGuard m(lock_);
569
1/2
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
1 database().GetMemStatistics(&stats);
570 1 }
571
5/10
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 1 times.
✗ Branch 7 not taken.
✓ Branch 10 taken 1 times.
✗ Branch 11 not taken.
✓ Branch 13 taken 1 times.
✗ Branch 14 not taken.
✓ Branch 16 taken 1 times.
✗ Branch 17 not taken.
2 return string(mountpoint().GetChars(), mountpoint().GetLength()) + ": " +
572
3/6
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 1 times.
✗ Branch 8 not taken.
4 StringifyInt(stats.lookaside_slots_used) + " / " +
573
3/6
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 1 times.
✗ Branch 8 not taken.
4 StringifyInt(stats.lookaside_slots_max) + " slots -- " +
574
3/6
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 1 times.
✗ Branch 8 not taken.
4 StringifyInt(stats.lookaside_hit) + " hits, " +
575
3/6
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 1 times.
✗ Branch 8 not taken.
4 StringifyInt(stats.lookaside_miss_size) + " misses-size, " +
576
3/6
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 1 times.
✗ Branch 8 not taken.
4 StringifyInt(stats.lookaside_miss_full) + " misses-full -- " +
577
3/6
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 1 times.
✗ Branch 8 not taken.
4 StringifyInt(stats.page_cache_used / 1024) + " kB pages -- " +
578
3/6
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 1 times.
✗ Branch 8 not taken.
4 StringifyInt(stats.page_cache_hit) + " hits, " +
579
3/6
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 1 times.
✗ Branch 8 not taken.
4 StringifyInt(stats.page_cache_miss) + " misses -- " +
580
3/6
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 1 times.
✗ Branch 8 not taken.
4 StringifyInt(stats.schema_used / 1024) + " kB schema -- " +
581
2/4
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
3 StringifyInt(stats.stmt_used / 1024) + " kB statements";
582 }
583
584
585 /**
586 * Determine the actual inode of a DirectoryEntry.
587 * The first used entry from a hardlink group deterimines the inode of the
588 * others.
589 * @param row_id the row id of a read row in the sqlite database
590 * @param hardlink_group the id of a possibly present hardlink group
591 * @return the assigned inode number
592 */
593 707 inode_t Catalog::GetMangledInode(const uint64_t row_id,
594 const uint64_t hardlink_group) const {
595
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 707 times.
707 assert(IsInitialized());
596
597
2/2
✓ Branch 1 taken 19 times.
✓ Branch 2 taken 688 times.
707 if (inode_range_.IsDummy()) {
598 19 return DirectoryEntry::kInvalidInode;
599 }
600
601 688 inode_t inode = row_id + inode_range_.offset;
602
603 // Hardlinks are encoded in catalog-wide unique hard link group ids.
604 // These ids must be resolved to actual inode relationships at runtime.
605
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 688 times.
688 if (hardlink_group > 0) {
606 HardlinkGroupMap::const_iterator inode_iter =
607 hardlink_groups_.find(hardlink_group);
608
609 // Use cached entry if possible
610 if (inode_iter == hardlink_groups_.end()) {
611 hardlink_groups_[hardlink_group] = inode;
612 } else {
613 inode = inode_iter->second;
614 }
615 }
616
617
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 688 times.
688 if (inode_annotation_) {
618 inode = inode_annotation_->Annotate(inode);
619 }
620
621 688 return inode;
622 }
623
624
625 /**
626 * Get a list of all registered nested catalogs and bind mountpoints in this
627 * catalog.
628 * @return a list of all nested catalog and bind mountpoints.
629 */
630 394 const Catalog::NestedCatalogList& Catalog::ListNestedCatalogs() const {
631 394 MutexLockGuard m(lock_);
632
633
2/2
✓ Branch 0 taken 87 times.
✓ Branch 1 taken 307 times.
394 if (nested_catalog_cache_dirty_) {
634
1/2
✓ Branch 2 taken 87 times.
✗ Branch 3 not taken.
87 LogCvmfs(kLogCatalog, kLogDebug, "refreshing nested catalog cache of '%s'",
635
1/2
✓ Branch 1 taken 87 times.
✗ Branch 2 not taken.
174 mountpoint().c_str());
636
3/4
✓ Branch 1 taken 133 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 46 times.
✓ Branch 4 taken 87 times.
133 while (sql_list_nested_->FetchRow()) {
637
1/2
✓ Branch 1 taken 46 times.
✗ Branch 2 not taken.
46 NestedCatalog nested;
638
3/6
✓ Branch 1 taken 46 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 46 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 46 times.
✗ Branch 8 not taken.
46 nested.mountpoint = PlantPath(sql_list_nested_->GetPath());
639
1/2
✓ Branch 1 taken 46 times.
✗ Branch 2 not taken.
46 nested.hash = sql_list_nested_->GetContentHash();
640
1/2
✓ Branch 1 taken 46 times.
✗ Branch 2 not taken.
46 nested.size = sql_list_nested_->GetSize();
641
1/2
✓ Branch 1 taken 46 times.
✗ Branch 2 not taken.
46 nested_catalog_cache_.push_back(nested);
642 46 }
643
1/2
✓ Branch 1 taken 87 times.
✗ Branch 2 not taken.
87 sql_list_nested_->Reset();
644 87 nested_catalog_cache_dirty_ = false;
645 }
646
647 394 return nested_catalog_cache_;
648 394 }
649
650
651 /**
652 * Get a list of all registered nested catalogs without bind mountpoints. Used
653 * for replication and garbage collection.
654 * @return a list of all nested catalogs.
655 */
656 34 const Catalog::NestedCatalogList Catalog::ListOwnNestedCatalogs() const {
657 34 NestedCatalogList result;
658
659 34 MutexLockGuard m(lock_);
660
661
3/4
✓ Branch 1 taken 39 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 5 times.
✓ Branch 4 taken 34 times.
39 while (sql_own_list_nested_->FetchRow()) {
662
1/2
✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
5 NestedCatalog nested;
663
3/6
✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 5 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 5 times.
✗ Branch 8 not taken.
5 nested.mountpoint = PlantPath(sql_own_list_nested_->GetPath());
664
1/2
✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
5 nested.hash = sql_own_list_nested_->GetContentHash();
665
1/2
✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
5 nested.size = sql_own_list_nested_->GetSize();
666
1/2
✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
5 result.push_back(nested);
667 5 }
668
1/2
✓ Branch 1 taken 34 times.
✗ Branch 2 not taken.
34 sql_own_list_nested_->Reset();
669
670 68 return result;
671 34 }
672
673
674 /**
675 * Drops the nested catalog cache. Usually this is only useful in subclasses
676 * that implement writable catalogs.
677 *
678 * Note: this action is _not_ secured by the catalog's mutex. If serialisation
679 * is required the subclass needs to ensure that.
680 */
681 72 void Catalog::ResetNestedCatalogCacheUnprotected() {
682 72 nested_catalog_cache_.clear();
683 72 nested_catalog_cache_dirty_ = true;
684 72 }
685
686
687 /**
688 * Looks for a specific registered nested catalog based on a path.
689 */
690 50 bool Catalog::FindNested(const PathString &mountpoint,
691 shash::Any *hash, uint64_t *size) const
692 {
693 50 MutexLockGuard m(lock_);
694
1/2
✓ Branch 1 taken 50 times.
✗ Branch 2 not taken.
50 PathString normalized_mountpoint = NormalizePath2(mountpoint);
695
1/2
✓ Branch 1 taken 50 times.
✗ Branch 2 not taken.
50 sql_lookup_nested_->BindSearchPath(normalized_mountpoint);
696
1/2
✓ Branch 1 taken 50 times.
✗ Branch 2 not taken.
50 bool found = sql_lookup_nested_->FetchRow();
697
3/4
✓ Branch 0 taken 48 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 48 times.
✗ Branch 3 not taken.
50 if (found && (hash != NULL)) {
698
1/2
✓ Branch 1 taken 48 times.
✗ Branch 2 not taken.
48 *hash = sql_lookup_nested_->GetContentHash();
699
1/2
✓ Branch 1 taken 48 times.
✗ Branch 2 not taken.
48 *size = sql_lookup_nested_->GetSize();
700 }
701
1/2
✓ Branch 1 taken 50 times.
✗ Branch 2 not taken.
50 sql_lookup_nested_->Reset();
702
703 50 return found;
704 50 }
705
706
707 /**
708 * Sets a new object to do inode annotations (or set to NULL)
709 * The annotation object is not owned by the catalog.
710 */
711 101 void Catalog::SetInodeAnnotation(InodeAnnotation *new_annotation) {
712 101 MutexLockGuard m(lock_);
713 // Since annotated inodes could come back to the catalog in order to
714 // get stripped, exchanging the annotation is not allowed
715
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 101 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
101 assert((inode_annotation_ == NULL) || (inode_annotation_ == new_annotation));
716 101 inode_annotation_ = new_annotation;
717 101 }
718
719
720 101 void Catalog::SetOwnerMaps(const OwnerMap *uid_map, const OwnerMap *gid_map) {
721
2/4
✓ Branch 0 taken 101 times.
✗ Branch 1 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 101 times.
101 uid_map_ = (uid_map && uid_map->HasEffect()) ? uid_map : NULL;
722
2/4
✓ Branch 0 taken 101 times.
✗ Branch 1 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 101 times.
101 gid_map_ = (gid_map && gid_map->HasEffect()) ? gid_map : NULL;
723 101 }
724
725
726 /**
727 * Add a Catalog as child to this Catalog.
728 * @param child the Catalog to define as child
729 */
730 55 void Catalog::AddChild(Catalog *child) {
731
3/7
✓ Branch 1 taken 55 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 55 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 55 times.
55 assert(NULL == FindChild(child->mountpoint()));
732
733 55 MutexLockGuard m(lock_);
734
2/4
✓ Branch 1 taken 55 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 55 times.
✗ Branch 5 not taken.
55 children_[child->mountpoint()] = child;
735 55 child->set_parent(this);
736 55 }
737
738
739 /**
740 * Removes a Catalog from the children list of this Catalog
741 * @param child the Catalog to delete as child
742 */
743 44 void Catalog::RemoveChild(Catalog *child) {
744
3/7
✓ Branch 1 taken 44 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 44 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 44 times.
44 assert(NULL != FindChild(child->mountpoint()));
745
746 44 MutexLockGuard m(lock_);
747 44 child->set_parent(NULL);
748
2/4
✓ Branch 1 taken 44 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 44 times.
✗ Branch 5 not taken.
44 children_.erase(child->mountpoint());
749 44 }
750
751
752 152 CatalogList Catalog::GetChildren() const {
753 152 CatalogList result;
754
755 152 MutexLockGuard m(lock_);
756 304 for (NestedCatalogMap::const_iterator i = children_.begin(),
757
2/2
✓ Branch 3 taken 69 times.
✓ Branch 4 taken 152 times.
373 iEnd = children_.end(); i != iEnd; ++i)
758 {
759
1/2
✓ Branch 2 taken 69 times.
✗ Branch 3 not taken.
69 result.push_back(i->second);
760 }
761
762 304 return result;
763 152 }
764
765
766 /**
767 * Find the nested catalog that serves the given path.
768 * It might be possible that the path is in fact served by a child of the found
769 * nested catalog.
770 * @param path the path to find a best fitting catalog for
771 * @return a pointer to the best fitting child or NULL if it does not fit at all
772 */
773 434 Catalog* Catalog::FindSubtree(const PathString &path) const {
774 // Check if this catalog fits the beginning of the path.
775
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 434 times.
434 if (!path.StartsWith(mountpoint_))
776 return NULL;
777
778
1/2
✓ Branch 2 taken 434 times.
✗ Branch 3 not taken.
434 PathString remaining(path.Suffix(mountpoint_.GetLength()));
779
1/2
✓ Branch 1 taken 434 times.
✗ Branch 2 not taken.
434 remaining.Append("/", 1);
780
781 // now we recombine the path elements successively
782 // in order to find a child which serves a part of the path
783
1/2
✓ Branch 1 taken 434 times.
✗ Branch 2 not taken.
434 PathString path_prefix(mountpoint_);
784 434 Catalog *result = NULL;
785 // Skip the first '/'
786
1/2
✓ Branch 1 taken 434 times.
✗ Branch 2 not taken.
434 path_prefix.Append("/", 1);
787 434 const char *c = remaining.GetChars() + 1;
788
2/2
✓ Branch 1 taken 3893 times.
✓ Branch 2 taken 356 times.
4249 for (unsigned i = 1; i < remaining.GetLength(); ++i, ++c) {
789
2/2
✓ Branch 0 taken 880 times.
✓ Branch 1 taken 3013 times.
3893 if (*c == '/') {
790
1/2
✓ Branch 1 taken 880 times.
✗ Branch 2 not taken.
880 result = FindChild(path_prefix);
791
792 // If we found a child serving a part of the path we can stop searching.
793 // Remaining sub path elements are possibly served by a grand child.
794
2/2
✓ Branch 0 taken 78 times.
✓ Branch 1 taken 802 times.
880 if (result != NULL)
795 78 break;
796 }
797
1/2
✓ Branch 1 taken 3815 times.
✗ Branch 2 not taken.
3815 path_prefix.Append(c, 1);
798 }
799
800 434 return result;
801 434 }
802
803
804 /**
805 * Looks for a child catalog, which is a subset of all registered nested
806 * catalogs.
807 */
808 989 Catalog* Catalog::FindChild(const PathString &mountpoint) const {
809 989 NestedCatalogMap::const_iterator nested_iter;
810
811 989 MutexLockGuard m(lock_);
812
1/2
✓ Branch 1 taken 989 times.
✗ Branch 2 not taken.
989 nested_iter = children_.find(mountpoint);
813 Catalog* result =
814
2/2
✓ Branch 2 taken 865 times.
✓ Branch 3 taken 124 times.
989 (nested_iter == children_.end()) ? NULL : nested_iter->second;
815
816 989 return result;
817 989 }
818
819
820 /**
821 * For the transition points for nested catalogs and bind mountpoints, the inode
822 * is ambiguous. It has to be set to the parent inode because nested catalogs
823 * are lazily loaded.
824 * @param md5path the MD5 hash of the entry to check
825 * @param dirent the DirectoryEntry to perform coherence fixes on
826 */
827 706 void Catalog::FixTransitionPoint(const shash::Md5 &md5path,
828 DirectoryEntry *dirent) const
829 {
830
2/2
✓ Branch 1 taken 536 times.
✓ Branch 2 taken 170 times.
706 if (!HasParent())
831 536 return;
832
833
2/2
✓ Branch 1 taken 20 times.
✓ Branch 2 taken 150 times.
170 if (dirent->IsNestedCatalogRoot()) {
834 // Normal nested catalog
835
1/2
✓ Branch 1 taken 20 times.
✗ Branch 2 not taken.
20 DirectoryEntry parent_dirent;
836
1/2
✓ Branch 1 taken 20 times.
✗ Branch 2 not taken.
20 const bool retval = parent_->LookupMd5Path(md5path, &parent_dirent);
837
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 20 times.
20 assert(retval);
838 20 dirent->set_inode(parent_dirent.inode());
839
1/2
✗ Branch 2 not taken.
✓ Branch 3 taken 150 times.
170 } else if (md5path == kMd5PathEmpty) {
840 // Bind mountpoint
841 DirectoryEntry parent_dirent;
842 const bool retval = parent_->LookupPath(mountpoint_, &parent_dirent);
843 assert(retval);
844 dirent->set_inode(parent_dirent.inode());
845 }
846 }
847
848 } // namespace catalog
849