GCC Code Coverage Report


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