GCC Code Coverage Report


Directory: cvmfs/
File: cvmfs/magic_xattr.h
Date: 2026-04-26 02:35:59
Exec Total Coverage
Lines: 36 37 97.3%
Branches: 4 8 50.0%

Line Branch Exec Source
1 /**
2 * This file is part of the CernVM File System.
3 */
4
5 #ifndef CVMFS_MAGIC_XATTR_H_
6 #define CVMFS_MAGIC_XATTR_H_
7
8 #include <map>
9 #include <set>
10 #include <string>
11 #include <utility>
12 #include <vector>
13
14 #include "backoff.h"
15 #include "catalog_counters.h"
16 #include "directory_entry.h"
17 #include "shortstring.h"
18
19 class MountPoint;
20
21 enum MagicXattrFlavor {
22 kXattrBase = 0,
23 kXattrWithHash,
24 kXattrRegular,
25 kXattrExternal,
26 kXattrSymlink,
27 kXattrAuthz
28 };
29
30 enum MagicXattrMode {
31 kXattrMachineMode = 0,
32 kXattrHumanMode
33 };
34
35 class MagicXattrManager; // needed for BaseMagicXattr
36 /**
37 * This is a base class for magic extended attribute. Every extended
38 * attributes must inherit from this class. It should be generally used only
39 * in cooperation with MagicXattrManager.
40 * It contains an access mutex. Users should use Lock() and Release()
41 * before and after usage (Lock() is called implicitly in MagicXattrManager).
42 *
43 * To read out the attribute value, do:
44 * 0. Get an instance through MagicXattrManager::Get()
45 * 1. Call PrepareValueFenced() inside FuseRemounter::fence()
46 * 2. Call GetValue(int32_t requested_page, const MagicXattrMode mode);
47 * It returns a <bool, string> pair where the bool is set to true if the
48 * request was successful and the string contains the actual value.
49 * GetValue() can be called outside the fence.
50 * This will internally call FinalizeValue() to finalize the value
51 * preparation outside the fuse fence.
52 *
53 * Implementation notes:
54 * - Each MagicXattr must implement it's own FinalizeValue() function which
55 * has to write its value into result_pages_.
56 * - result_pages_ is a vector of strings. Each string is <= kMaxCharsPerPage
57 * - BaseMagicXattr::GetValue() takes care of clearing result_pages_ before each
58 * new call of FinalizeValue(), and takes care of adding a header for the
59 * human readable version
60 * - In case an invalid request happens, GetValue() <bool> is set to false.
61 * "ENOENT" will be returned, while in human-readable mode a more verbose
62 * error message will be returned
63 */
64 class BaseMagicXattr {
65 friend class MagicXattrManager;
66 FRIEND_TEST(T_MagicXattr, ProtectedXattr);
67 FRIEND_TEST(T_MagicXattr, TestFqrn);
68 FRIEND_TEST(T_MagicXattr, TestLogBuffer);
69
70 public:
71 30516 BaseMagicXattr() : is_protected_(false) {
72 30516 const int retval = pthread_mutex_init(&access_mutex_, NULL);
73
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 30516 times.
30516 assert(retval == 0);
74 30516 }
75
76 /**
77 * Mark a Xattr protected so that only certain users with the correct gid
78 * can access it.
79 */
80 3 void MarkProtected() { is_protected_ = true; }
81
82
83 // TODO(hereThereBeDragons) from C++11 should be marked final
84 /**
85 * Access right check before normal fence
86 */
87 bool PrepareValueFencedProtected(gid_t gid);
88
89 /**
90 * This function needs to be called after PrepareValueFenced(),
91 * which prepares the necessary data and header for kXattrHumanMode.
92 * It does the computationaly intensive part, which should not
93 * be done inside the FuseRemounter::fence(), and returns the
94 * value.
95 *
96 * Internally it calls FinalizeValue() which each MagicXAttr has to implement
97 * to set the value of result_pages_
98 *
99 * @params
100 * - requested_page:
101 * >= 0: requested paged of the attribute
102 * -1: get info about xattr: e.g. the number of pages available
103 * - mode: either machine-readable or human-readable
104 *
105 * @returns
106 * std::pair<bool, std::string>
107 * bool = false if in machine-readable mode an invalid request is performed
108 * (human-readable mode always succeeds and gives a verbose message)
109 * otherwise true
110 * std::string = the actual value of the attribute or info element
111 * ( or error message in human-readable mode)
112 *
113 */
114 std::pair<bool, std::string> GetValue(int32_t requested_page,
115 const MagicXattrMode mode);
116
117 96 virtual MagicXattrFlavor GetXattrFlavor() { return kXattrBase; }
118
119 12 void Lock(PathString path, catalog::DirectoryEntry *dirent) {
120 12 const int retval = pthread_mutex_lock(&access_mutex_);
121
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
12 assert(retval == 0);
122 12 path_ = path;
123 12 dirent_ = dirent;
124 12 }
125 12 void Release() {
126 12 const int retval = pthread_mutex_unlock(&access_mutex_);
127
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
12 assert(retval == 0);
128 12 }
129
130 12 virtual ~BaseMagicXattr() { }
131
132 // how many chars per page (with some leeway). system maximum would be 64k
133 static const uint32_t kMaxCharsPerPage = 40000;
134
135 protected:
136 /**
137 * This function is used to obtain the necessary information while
138 * inside FuseRemounter::fence(), which should prevent data races.
139 */
140 12 virtual bool PrepareValueFenced() { return true; }
141 virtual void FinalizeValue() { }
142
143 std::string HeaderMultipageHuman(uint32_t requested_page);
144
145 MagicXattrManager *xattr_mgr_;
146 PathString path_;
147 catalog::DirectoryEntry *dirent_;
148
149 pthread_mutex_t access_mutex_;
150 bool is_protected_;
151 std::vector<std::string> result_pages_;
152 };
153
154 /**
155 * This wrapper ensures that the attribute instance "ptr_" is
156 * released after the user finishes using it (on wrapper destruction).
157 */
158 class MagicXattrRAIIWrapper : public SingleCopy {
159 public:
160 inline MagicXattrRAIIWrapper() : ptr_(NULL) { }
161
162 inline explicit MagicXattrRAIIWrapper(BaseMagicXattr *ptr,
163 PathString path,
164 catalog::DirectoryEntry *d)
165 : ptr_(ptr) {
166 if (ptr_ != NULL)
167 ptr_->Lock(path, d);
168 }
169 /// Wraps around a BaseMagicXattr* that is already locked (or NULL)
170 12 inline explicit MagicXattrRAIIWrapper(BaseMagicXattr *ptr) : ptr_(ptr) { }
171
172 12 inline ~MagicXattrRAIIWrapper() {
173
1/2
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
12 if (ptr_ != NULL)
174 12 ptr_->Release();
175 12 }
176
177 27 inline BaseMagicXattr *operator->() const { return ptr_; }
178 12 inline bool IsNull() const { return ptr_ == NULL; }
179 inline BaseMagicXattr *Move() {
180 BaseMagicXattr *ret = ptr_;
181 ptr_ = NULL;
182 return ret;
183 }
184
185 protected:
186 BaseMagicXattr *ptr_;
187 };
188
189 class WithHashMagicXattr : public BaseMagicXattr {
190 6 virtual MagicXattrFlavor GetXattrFlavor() { return kXattrWithHash; }
191 };
192
193 class RegularMagicXattr : public BaseMagicXattr {
194 15 virtual MagicXattrFlavor GetXattrFlavor() { return kXattrRegular; }
195 };
196
197 class ExternalMagicXattr : public BaseMagicXattr {
198 9 virtual MagicXattrFlavor GetXattrFlavor() { return kXattrExternal; }
199 };
200
201 class SymlinkMagicXattr : public BaseMagicXattr {
202 6 virtual MagicXattrFlavor GetXattrFlavor() { return kXattrSymlink; }
203 };
204
205 /**
206 * This class is acting as a user entry point for magic extended attributes.
207 * It instantiates all defined attributes in the constructor.
208 * Users can:
209 * 1. Register additional attributes
210 * 2. Get a string containing zero-byte delimited list of attribute names
211 * (used in "cvmfs.cc")
212 * 3. Get an attribute by name. Specifically, get a RAII wrapper around
213 * a singleton attribute instance. This means that the attribute instance
214 * registered with the manager does not get cloned or copied inside Get().
215 * Instead, member variables are set and the original instance is returned.
216 * A mutex prevents from race conditions in case of concurrent access.
217 */
218 class MagicXattrManager : public SingleCopy {
219 public:
220 enum EVisibility {
221 kVisibilityAlways,
222 kVisibilityNever,
223 kVisibilityRootOnly
224 };
225
226 MagicXattrManager(MountPoint *mountpoint, EVisibility visibility,
227 const std::set<std::string> &protected_xattrs,
228 const std::set<gid_t> &privileged_xattr_gids);
229 /// The returned BaseMagicXattr* is supposed to be wrapped by a
230 /// MagicXattrRAIIWrapper
231 BaseMagicXattr *GetLocked(const std::string &name, PathString path,
232 catalog::DirectoryEntry *d);
233 std::string GetListString(catalog::DirectoryEntry *dirent);
234 /**
235 * Registers a new extended attribute.
236 * Will fail if called after Freeze().
237 */
238 void Register(const std::string &name, BaseMagicXattr *magic_xattr);
239
240 /**
241 * Freezes the current setup of MagicXattrManager.
242 * No new extended attributes can be added.
243 * Only after freezing MagicXattrManager can registered attributes be
244 * accessed.
245 */
246 3 void Freeze() {
247 3 is_frozen_ = true;
248 3 SanityCheckProtectedXattrs();
249 3 }
250 bool IsPrivilegedGid(gid_t gid);
251
252
253 18 EVisibility visibility() { return visibility_; }
254 std::set<gid_t> privileged_xattr_gids() { return privileged_xattr_gids_; }
255 6 MountPoint *mount_point() { return mount_point_; }
256 6 bool is_frozen() const { return is_frozen_; }
257
258 protected:
259 std::map<std::string, BaseMagicXattr *> xattr_list_;
260 MountPoint *mount_point_;
261 EVisibility visibility_;
262
263 // privileged_xattr_gids_ contains the (fuse) gids that
264 // can access xattrs that are part of protected_xattrs_
265 const std::set<std::string> protected_xattrs_;
266 const std::set<gid_t> privileged_xattr_gids_;
267
268 private:
269 bool is_frozen_;
270
271 void SanityCheckProtectedXattrs();
272 };
273
274 class AuthzMagicXattr : public BaseMagicXattr {
275 virtual bool PrepareValueFenced();
276 virtual void FinalizeValue();
277
278 virtual MagicXattrFlavor GetXattrFlavor();
279 };
280
281 class CatalogCountersMagicXattr : public BaseMagicXattr {
282 std::string subcatalog_path_;
283 shash::Any hash_;
284 catalog::Counters counters_;
285
286 virtual bool PrepareValueFenced();
287 virtual void FinalizeValue();
288 };
289
290 class ChunkListMagicXattr : public RegularMagicXattr {
291 virtual bool PrepareValueFenced();
292 virtual void FinalizeValue();
293
294 private:
295 std::vector<std::string> chunk_list_;
296 };
297
298 class ChunksMagicXattr : public RegularMagicXattr {
299 uint64_t n_chunks_;
300
301 virtual bool PrepareValueFenced();
302 virtual void FinalizeValue();
303 };
304
305 class CompressionMagicXattr : public RegularMagicXattr {
306 virtual bool PrepareValueFenced();
307 virtual void FinalizeValue();
308 };
309
310 class DirectIoMagicXattr : public RegularMagicXattr {
311 virtual bool PrepareValueFenced();
312 virtual void FinalizeValue();
313 };
314
315 class ExternalFileMagicXattr : public RegularMagicXattr {
316 virtual bool PrepareValueFenced();
317 virtual void FinalizeValue();
318 };
319
320 class ExternalHostMagicXattr : public BaseMagicXattr {
321 virtual void FinalizeValue();
322 };
323
324 class ExternalTimeoutMagicXattr : public BaseMagicXattr {
325 virtual void FinalizeValue();
326 };
327
328 class FqrnMagicXattr : public BaseMagicXattr {
329 virtual void FinalizeValue();
330 };
331
332 class HashMagicXattr : public WithHashMagicXattr {
333 virtual bool PrepareValueFenced();
334 virtual void FinalizeValue();
335 };
336
337 class HostMagicXattr : public BaseMagicXattr {
338 virtual void FinalizeValue();
339 };
340
341 class HostListMagicXattr : public BaseMagicXattr {
342 virtual void FinalizeValue();
343 };
344
345 class LHashMagicXattr : public WithHashMagicXattr {
346 virtual bool PrepareValueFenced();
347 virtual void FinalizeValue();
348 };
349
350 class LogBufferXattr : public BaseMagicXattr {
351 public:
352 LogBufferXattr();
353
354 private:
355 const unsigned int kMaxLogLine = 4096; // longer log lines are trimmed
356 // Generating the log buffer report involves 64 string copies. To mitigate
357 // memory fragmentation and performance loss, throttle the use of this
358 // attribute a little.
359 BackoffThrottle throttle_;
360
361 virtual void FinalizeValue();
362 };
363
364 class NCleanup24MagicXattr : public BaseMagicXattr {
365 virtual void FinalizeValue();
366 };
367
368 class NClgMagicXattr : public BaseMagicXattr {
369 int n_catalogs_;
370
371 virtual bool PrepareValueFenced();
372 virtual void FinalizeValue();
373 };
374
375 class NDirOpenMagicXattr : public BaseMagicXattr {
376 virtual void FinalizeValue();
377 };
378
379 class NDownloadMagicXattr : public BaseMagicXattr {
380 virtual void FinalizeValue();
381 };
382
383 class NIOErrMagicXattr : public BaseMagicXattr {
384 virtual void FinalizeValue();
385 };
386
387 class NOpenMagicXattr : public BaseMagicXattr {
388 virtual void FinalizeValue();
389 };
390
391 class HitrateMagicXattr : public BaseMagicXattr {
392 virtual void FinalizeValue();
393 };
394
395 class ProxyMagicXattr : public BaseMagicXattr {
396 virtual void FinalizeValue();
397 };
398
399 class ProxyListMagicXattr : public BaseMagicXattr {
400 virtual void FinalizeValue();
401 };
402
403 class ProxyListExternalMagicXattr : public BaseMagicXattr {
404 virtual void FinalizeValue();
405 };
406
407 class PubkeysMagicXattr : public BaseMagicXattr {
408 FRIEND_TEST(T_MagicXattr, MultiPageMachineModeXattr);
409 FRIEND_TEST(T_MagicXattr, MultiPageHumanModeXattr);
410
411 std::vector<std::string> pubkeys_;
412
413 virtual bool PrepareValueFenced();
414 virtual void FinalizeValue();
415 };
416
417 class RawlinkMagicXattr : public SymlinkMagicXattr {
418 virtual bool PrepareValueFenced();
419 virtual void FinalizeValue();
420 };
421
422 class RepoCountersMagicXattr : public BaseMagicXattr {
423 catalog::Counters counters_;
424
425 virtual bool PrepareValueFenced();
426 virtual void FinalizeValue();
427 };
428
429 class RepoMetainfoMagicXattr : public BaseMagicXattr {
430 static uint64_t kMaxMetainfoLength;
431
432 shash::Any metainfo_hash_;
433 std::string error_reason_;
434
435 virtual bool PrepareValueFenced();
436 virtual void FinalizeValue();
437 };
438
439 class RevisionMagicXattr : public BaseMagicXattr {
440 uint64_t revision_;
441
442 virtual bool PrepareValueFenced();
443 virtual void FinalizeValue();
444 };
445
446 class RevisionTimestampMagicXattr : public BaseMagicXattr {
447 uint64_t timestamp_;
448
449 virtual bool PrepareValueFenced();
450 virtual void FinalizeValue();
451 };
452
453 class RootHashMagicXattr : public BaseMagicXattr {
454 shash::Any root_hash_;
455
456 virtual bool PrepareValueFenced();
457 virtual void FinalizeValue();
458 };
459
460 class RxMagicXattr : public BaseMagicXattr {
461 virtual void FinalizeValue();
462 };
463
464 class SpeedMagicXattr : public BaseMagicXattr {
465 virtual void FinalizeValue();
466 };
467
468 class TagMagicXattr : public BaseMagicXattr {
469 std::string tag_;
470
471 virtual bool PrepareValueFenced();
472 virtual void FinalizeValue();
473 };
474
475 class TimeoutMagicXattr : public BaseMagicXattr {
476 virtual void FinalizeValue();
477 };
478
479 class TimeoutDirectMagicXattr : public BaseMagicXattr {
480 virtual void FinalizeValue();
481 };
482
483 class TimestampLastIOErrMagicXattr : public BaseMagicXattr {
484 virtual void FinalizeValue();
485 };
486
487 class UsedFdMagicXattr : public BaseMagicXattr {
488 virtual void FinalizeValue();
489 };
490
491 class UsedDirPMagicXattr : public BaseMagicXattr {
492 virtual void FinalizeValue();
493 };
494
495 class VersionMagicXattr : public BaseMagicXattr {
496 virtual void FinalizeValue();
497 };
498
499 class ExternalURLMagicXattr : public ExternalMagicXattr {
500 virtual bool PrepareValueFenced();
501 virtual void FinalizeValue();
502 };
503
504 class CleanupUnusedFirstMagicXattr : public ExternalMagicXattr {
505 virtual void FinalizeValue();
506 };
507
508 class ListOpenHashesMagicXattr : public ExternalMagicXattr {
509 virtual void FinalizeValue();
510 };
511 #endif // CVMFS_MAGIC_XATTR_H_
512
513