GCC Code Coverage Report


Directory: cvmfs/
File: cvmfs/catalog.h
Date: 2025-06-22 02:36:02
Exec Total Coverage
Lines: 46 53 86.8%
Branches: 17 40 42.5%

Line Branch Exec Source
1 /**
2 * This file is part of the CernVM File System.
3 */
4
5 #ifndef CVMFS_CATALOG_H_
6 #define CVMFS_CATALOG_H_
7
8 #include <pthread.h>
9 #include <stdint.h>
10
11 #include <cassert>
12 #include <map>
13 #include <string>
14 #include <vector>
15
16 #include "catalog_counters.h"
17 #include "catalog_sql.h"
18 #include "crypto/hash.h"
19 #include "directory_entry.h"
20 #include "file_chunk.h"
21 #include "gtest/gtest_prod.h"
22 #include "shortstring.h"
23 #include "sql.h"
24 #include "uid_map.h"
25 #include "xattr.h"
26
27 namespace swissknife {
28 class CommandMigrate;
29 }
30
31 namespace catalog {
32
33 template<class CatalogT>
34 class AbstractCatalogManager;
35
36 class Catalog;
37
38 class Counters;
39
40 typedef std::vector<Catalog *> CatalogList;
41 typedef IntegerMap<uint64_t> OwnerMap; // used to map uid/gid
42
43
44 /**
45 * Every Catalog gets an InodeRange assigned when attached to
46 * a CatalogManager. Inodes are assigned at runtime out of this InodeRange.
47 * An inode is computed by <row ID of entry> + offset
48 */
49 struct InodeRange {
50 uint64_t offset;
51 uint64_t size;
52
53 9639 InodeRange() : offset(0), size(0) { }
54
55 inline bool ContainsInode(const inode_t inode) const {
56 return ((inode > offset) && (inode <= size + offset));
57 }
58
59 519 inline void MakeDummy() { offset = 1; }
60
61 77271 inline bool IsInitialized() const { return offset > 0; }
62
3/4
✓ Branch 1 taken 25073 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 178 times.
✓ Branch 4 taken 24895 times.
25073 inline bool IsDummy() const { return IsInitialized() && size == 0; }
63 };
64
65
66 /**
67 * Allows to define a class that transforms the inode in order to ensure
68 * that inodes are not reused after reloads (catalog or fuse module).
69 * Currently, annotation is used to set an offset starting at the highest
70 * so far issued inode. The implementation is in the catalog manager.
71 */
72 class InodeAnnotation {
73 public:
74 3038 virtual ~InodeAnnotation() { }
75 virtual inode_t Annotate(const inode_t raw_inode) = 0;
76 virtual void IncGeneration(const uint64_t by) = 0;
77 virtual inode_t GetGeneration() = 0;
78 virtual bool ValidInode(const uint64_t inode) = 0;
79 virtual inode_t Strip(const inode_t annotated_inode) = 0;
80 };
81
82
83 /**
84 * This class wraps a catalog database and provides methods
85 * to query for directory entries.
86 * It has a pointer to its parent catalog and its children, thereby creating
87 * a tree structure of nested catalogs.
88 *
89 * Read-only catalog. A sub-class provides read-write access.
90 */
91 class Catalog : SingleCopy {
92 FRIEND_TEST(T_Catalog, NormalizePath);
93 FRIEND_TEST(T_Catalog, PlantPath);
94 friend class swissknife::CommandMigrate; // for catalog version migration
95
96 public:
97 typedef std::vector<shash::Any> HashVector;
98
99 /**
100 * The default TTL should be shorter than the autofs idle unmount time
101 * which is 5 minutes, because the config repo is accessed on every root
102 * catalog refresh and we want to avoid thrashing that mountpoint.
103 */
104 static const uint64_t kDefaultTTL = 240; /**< 4 minutes default TTL */
105
106 /**
107 * Note: is_nested only has an effect if parent == NULL otherwise being
108 * a root catalog is determined by having a parent pointer or not.
109 */
110 Catalog(const PathString &mountpoint,
111 const shash::Any &catalog_hash,
112 Catalog *parent,
113 const bool is_nested = false);
114 virtual ~Catalog();
115
116 static Catalog *AttachFreely(const std::string &imaginary_mountpoint,
117 const std::string &file,
118 const shash::Any &catalog_hash,
119 Catalog *parent = NULL,
120 const bool is_nested = false);
121
122 bool OpenDatabase(const std::string &db_path);
123
124 19358 inline bool LookupPath(const PathString &path, DirectoryEntry *dirent) const {
125
1/2
✓ Branch 2 taken 19358 times.
✗ Branch 3 not taken.
19358 return LookupMd5Path(NormalizePath(path), dirent);
126 }
127 bool LookupRawSymlink(const PathString &path, LinkString *raw_symlink) const;
128 5 bool LookupXattrsPath(const PathString &path, XattrList *xattrs) const {
129
1/2
✓ Branch 2 taken 5 times.
✗ Branch 3 not taken.
5 return LookupXattrsMd5Path(NormalizePath(path), xattrs);
130 }
131
132 3037 inline bool ListingPath(const PathString &path,
133 DirectoryEntryList *listing,
134 const bool expand_symlink = true) const {
135
1/2
✓ Branch 2 taken 3037 times.
✗ Branch 3 not taken.
3037 return ListingMd5Path(NormalizePath(path), listing, expand_symlink);
136 }
137 117 bool ListingPathStat(const PathString &path, StatEntryList *listing) const {
138
1/2
✓ Branch 2 taken 117 times.
✗ Branch 3 not taken.
117 return ListingMd5PathStat(NormalizePath(path), listing);
139 }
140 bool AllChunksBegin();
141 bool AllChunksNext(shash::Any *hash, zlib::Algorithms *compression_alg);
142 bool AllChunksEnd();
143
144 7 inline bool ListPathChunks(const PathString &path,
145 const shash::Algorithms interpret_hashes_as,
146 FileChunkList *chunks) const {
147
1/2
✓ Branch 2 taken 7 times.
✗ Branch 3 not taken.
7 return ListMd5PathChunks(NormalizePath(path), interpret_hashes_as, chunks);
148 }
149
150 CatalogList GetChildren() const;
151 Catalog *FindSubtree(const PathString &path) const;
152 Catalog *FindChild(const PathString &mountpoint) const;
153 void AddChild(Catalog *child);
154 void RemoveChild(Catalog *child);
155
156 const HashVector &GetReferencedObjects() const;
157 void TakeDatabaseFileOwnership();
158 void DropDatabaseFileOwnership();
159 29 bool OwnsDatabaseFile() const {
160
5/6
✓ Branch 0 taken 22 times.
✓ Branch 1 taken 7 times.
✓ Branch 3 taken 10 times.
✓ Branch 4 taken 12 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 17 times.
29 return ((database_ != NULL) && database_->OwnsFile()) || managed_database_;
161 }
162
163 uint64_t GetTTL() const;
164 bool HasExplicitTTL() const;
165 uint64_t GetRevision() const;
166 bool GetVOMSAuthz(std::string *authz) const;
167 uint64_t GetLastModified() const;
168 uint64_t GetNumEntries() const;
169 uint64_t GetNumChunks() const;
170 shash::Any GetPreviousRevision() const;
171 1579 const Counters &GetCounters() const { return counters_; }
172 std::string PrintMemStatistics() const;
173
174 25087 inline float schema() const { return database().schema_version(); }
175 73258 inline PathString mountpoint() const { return mountpoint_; }
176 4897 inline Catalog *parent() const { return parent_; }
177 4027 inline uint64_t max_row_id() const { return max_row_id_; }
178 4019 inline InodeRange inode_range() const { return inode_range_; }
179 4541 inline void set_inode_range(const InodeRange value) { inode_range_ = value; }
180 3774 inline std::string database_path() const { return database_->filename(); }
181 811 inline PathString root_prefix() const { return root_prefix_; }
182 201 inline shash::Any hash() const { return catalog_hash_; }
183 2575 inline bool volatile_flag() const { return volatile_flag_; }
184 131 inline uint64_t revision() const { return GetRevision(); }
185
186 52198 inline bool IsInitialized() const {
187
2/4
✓ Branch 1 taken 52198 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 52198 times.
✗ Branch 4 not taken.
52198 return inode_range_.IsInitialized() && initialized_;
188 }
189 6433 inline bool IsRoot() const { return is_root_; }
190 bool IsAutogenerated() const {
191 DirectoryEntry dirent;
192 assert(IsInitialized());
193 return LookupPath(PathString(mountpoint_.ToString() + "/.cvmfsautocatalog"),
194 &dirent);
195 }
196 35948 inline bool HasParent() const { return parent_ != NULL; }
197 10 inline virtual bool IsWritable() const { return false; }
198
199 typedef struct {
200 PathString mountpoint;
201 shash::Any hash;
202 uint64_t size;
203 } NestedCatalog;
204 typedef std::vector<NestedCatalog> NestedCatalogList;
205 const NestedCatalogList &ListNestedCatalogs() const;
206 const NestedCatalogList ListOwnNestedCatalogs() const;
207 bool FindNested(const PathString &mountpoint, shash::Any *hash,
208 uint64_t *size) const;
209
210 void SetInodeAnnotation(InodeAnnotation *new_annotation);
211 inode_t GetMangledInode(const uint64_t row_id,
212 const uint64_t hardlink_group) const;
213
214 void SetOwnerMaps(const OwnerMap *uid_map, const OwnerMap *gid_map);
215 25073 uint64_t MapUid(const uint64_t uid) const {
216
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 25073 times.
25073 if (uid_map_) {
217 return uid_map_->Map(uid);
218 }
219 25073 return uid;
220 }
221 25073 uint64_t MapGid(const uint64_t gid) const {
222
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 25073 times.
25073 if (gid_map_) {
223 return gid_map_->Map(gid);
224 }
225 25073 return gid;
226 }
227
228 protected:
229 typedef std::map<uint64_t, inode_t> HardlinkGroupMap;
230 mutable HardlinkGroupMap hardlink_groups_;
231
232 pthread_mutex_t *lock_;
233
234 bool InitStandalone(const std::string &database_file);
235 bool ReadCatalogCounters();
236
237 /**
238 * Specifies the SQLite open flags. Overwritten by r/w catalog.
239 */
240 1949 virtual CatalogDatabase::OpenMode DatabaseOpenMode() const {
241 1949 return CatalogDatabase::kOpenReadOnly;
242 }
243
244 virtual void InitPreparedStatements();
245 void FinalizePreparedStatements();
246
247 79 Counters &GetWritableCounters() { return counters_; }
248
249 39100 inline const CatalogDatabase &database() const { return *database_; }
250 121192 inline CatalogDatabase &database() { return *database_; }
251 2975 inline void set_parent(Catalog *catalog) { parent_ = catalog; }
252
253 void ResetNestedCatalogCacheUnprotected();
254
255 bool LookupMd5Path(const shash::Md5 &md5path, DirectoryEntry *dirent) const;
256
257 private:
258 typedef std::map<PathString, Catalog *> NestedCatalogMap;
259
260 /**
261 * The hash of the empty string. Used to identify the root entry of a
262 * repository, which is the child transition point of a bind mountpoint.
263 */
264 static const shash::Md5 kMd5PathEmpty;
265
266 enum VomsAuthzStatus {
267 kVomsUnknown, // Not yet looked up
268 kVomsNone, // No voms_authz key in properties table
269 kVomsPresent, // voms_authz property available
270 };
271
272 shash::Md5 NormalizePath(const PathString &path) const;
273 PathString NormalizePath2(const PathString &path) const;
274 PathString PlantPath(const PathString &path) const;
275
276 void FixTransitionPoint(const shash::Md5 &md5path,
277 DirectoryEntry *dirent) const;
278
279 bool LookupXattrsMd5Path(const shash::Md5 &md5path, XattrList *xattrs) const;
280 bool ListMd5PathChunks(const shash::Md5 &md5path,
281 const shash::Algorithms interpret_hashes_as,
282 FileChunkList *chunks) const;
283 bool ListingMd5Path(const shash::Md5 &md5path,
284 DirectoryEntryList *listing,
285 const bool expand_symlink = true) const;
286 bool ListingMd5PathStat(const shash::Md5 &md5path,
287 StatEntryList *listing) const;
288 bool LookupEntry(const shash::Md5 &md5path, const bool expand_symlink,
289 DirectoryEntry *dirent) const;
290
291 CatalogDatabase *database_;
292
293 const shash::Any catalog_hash_;
294 PathString root_prefix_;
295 /**
296 * Normally, catalogs are mounted at their root_prefix_. But for the structure
297 * under /.cvmfs/snapshots/..., that's not the case.
298 */
299 PathString mountpoint_;
300 /**
301 * True, iff root_prefix_ == mountpoint_
302 */
303 bool is_regular_mountpoint_;
304 bool volatile_flag_;
305 /**
306 * For catalogs in a catalog manager: doesn't have a parent catalog
307 */
308 const bool is_root_;
309 bool managed_database_;
310
311 Catalog *parent_;
312 NestedCatalogMap children_;
313 mutable NestedCatalogList nested_catalog_cache_;
314 mutable bool nested_catalog_cache_dirty_;
315
316 mutable VomsAuthzStatus voms_authz_status_;
317 mutable std::string voms_authz_;
318
319 bool initialized_;
320 InodeRange inode_range_;
321 uint64_t max_row_id_;
322 InodeAnnotation *inode_annotation_;
323 Counters counters_;
324 // Point to the maps in the catalog manager
325 const OwnerMap *uid_map_;
326 const OwnerMap *gid_map_;
327
328 SqlListing *sql_listing_;
329 SqlLookupPathHash *sql_lookup_md5path_;
330 SqlNestedCatalogLookup *sql_lookup_nested_;
331 SqlNestedCatalogListing *sql_list_nested_;
332 SqlOwnNestedCatalogListing *sql_own_list_nested_;
333 SqlAllChunks *sql_all_chunks_;
334 SqlChunksListing *sql_chunks_listing_;
335 SqlLookupXattrs *sql_lookup_xattrs_;
336
337 mutable HashVector referenced_hashes_;
338 }; // class Catalog
339
340 } // namespace catalog
341
342 #endif // CVMFS_CATALOG_H_
343