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