GCC Code Coverage Report


Directory: cvmfs/
File: cvmfs/magic_xattr.cc
Date: 2026-06-28 02:36:10
Exec Total Coverage
Lines: 185 522 35.4%
Branches: 305 1063 28.7%

Line Branch Exec Source
1 /**
2 * This file is part of the CernVM File System.
3 */
4
5 #include "magic_xattr.h"
6
7 #include <cassert>
8 #include <string>
9 #include <vector>
10
11 #include "cache_posix.h"
12 #include "catalog_mgr_client.h"
13 #include "crypto/hash.h"
14 #include "crypto/signature.h"
15 #include "fetch.h"
16 #include "mountpoint.h"
17 #include "quota.h"
18 #include "util/logging.h"
19 #include "util/string.h"
20
21 419 MagicXattrManager::MagicXattrManager(
22 MountPoint *mountpoint,
23 EVisibility visibility,
24 const std::set<std::string> &protected_xattrs,
25 419 const std::set<gid_t> &priviledged_xattr_gids)
26 419 : mount_point_(mountpoint)
27 419 , visibility_(visibility)
28
1/2
✓ Branch 1 taken 419 times.
✗ Branch 2 not taken.
419 , protected_xattrs_(protected_xattrs)
29
1/2
✓ Branch 1 taken 419 times.
✗ Branch 2 not taken.
419 , privileged_xattr_gids_(priviledged_xattr_gids)
30 419 , is_frozen_(false) {
31
4/8
✓ Branch 1 taken 419 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 419 times.
✗ Branch 5 not taken.
✓ Branch 8 taken 419 times.
✗ Branch 9 not taken.
✓ Branch 11 taken 419 times.
✗ Branch 12 not taken.
419 Register("user.catalog_counters", new CatalogCountersMagicXattr());
32
4/8
✓ Branch 1 taken 419 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 419 times.
✗ Branch 5 not taken.
✓ Branch 8 taken 419 times.
✗ Branch 9 not taken.
✓ Branch 11 taken 419 times.
✗ Branch 12 not taken.
419 Register("user.external_host", new ExternalHostMagicXattr());
33
4/8
✓ Branch 1 taken 419 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 419 times.
✗ Branch 5 not taken.
✓ Branch 8 taken 419 times.
✗ Branch 9 not taken.
✓ Branch 11 taken 419 times.
✗ Branch 12 not taken.
419 Register("user.external_timeout", new ExternalTimeoutMagicXattr());
34
4/8
✓ Branch 1 taken 419 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 419 times.
✗ Branch 5 not taken.
✓ Branch 8 taken 419 times.
✗ Branch 9 not taken.
✓ Branch 11 taken 419 times.
✗ Branch 12 not taken.
419 Register("user.fqrn", new FqrnMagicXattr());
35
4/8
✓ Branch 1 taken 419 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 419 times.
✗ Branch 5 not taken.
✓ Branch 8 taken 419 times.
✗ Branch 9 not taken.
✓ Branch 11 taken 419 times.
✗ Branch 12 not taken.
419 Register("user.host", new HostMagicXattr());
36
4/8
✓ Branch 1 taken 419 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 419 times.
✗ Branch 5 not taken.
✓ Branch 8 taken 419 times.
✗ Branch 9 not taken.
✓ Branch 11 taken 419 times.
✗ Branch 12 not taken.
419 Register("user.host_list", new HostListMagicXattr());
37
4/8
✓ Branch 1 taken 419 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 419 times.
✗ Branch 5 not taken.
✓ Branch 8 taken 419 times.
✗ Branch 9 not taken.
✓ Branch 11 taken 419 times.
✗ Branch 12 not taken.
419 Register("user.ncleanup24", new NCleanup24MagicXattr());
38
4/8
✓ Branch 1 taken 419 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 419 times.
✗ Branch 5 not taken.
✓ Branch 8 taken 419 times.
✗ Branch 9 not taken.
✓ Branch 11 taken 419 times.
✗ Branch 12 not taken.
419 Register("user.nclg", new NClgMagicXattr());
39
4/8
✓ Branch 1 taken 419 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 419 times.
✗ Branch 5 not taken.
✓ Branch 8 taken 419 times.
✗ Branch 9 not taken.
✓ Branch 11 taken 419 times.
✗ Branch 12 not taken.
419 Register("user.ndiropen", new NDirOpenMagicXattr());
40
4/8
✓ Branch 1 taken 419 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 419 times.
✗ Branch 5 not taken.
✓ Branch 8 taken 419 times.
✗ Branch 9 not taken.
✓ Branch 11 taken 419 times.
✗ Branch 12 not taken.
419 Register("user.ndownload", new NDownloadMagicXattr());
41
4/8
✓ Branch 1 taken 419 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 419 times.
✗ Branch 5 not taken.
✓ Branch 8 taken 419 times.
✗ Branch 9 not taken.
✓ Branch 11 taken 419 times.
✗ Branch 12 not taken.
419 Register("user.nioerr", new NIOErrMagicXattr());
42
4/8
✓ Branch 1 taken 419 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 419 times.
✗ Branch 5 not taken.
✓ Branch 8 taken 419 times.
✗ Branch 9 not taken.
✓ Branch 11 taken 419 times.
✗ Branch 12 not taken.
419 Register("user.nopen", new NOpenMagicXattr());
43
4/8
✓ Branch 1 taken 419 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 419 times.
✗ Branch 5 not taken.
✓ Branch 8 taken 419 times.
✗ Branch 9 not taken.
✓ Branch 11 taken 419 times.
✗ Branch 12 not taken.
419 Register("user.hitrate", new HitrateMagicXattr());
44
4/8
✓ Branch 1 taken 419 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 419 times.
✗ Branch 5 not taken.
✓ Branch 8 taken 419 times.
✗ Branch 9 not taken.
✓ Branch 11 taken 419 times.
✗ Branch 12 not taken.
419 Register("user.logbuffer", new LogBufferXattr());
45
4/8
✓ Branch 1 taken 419 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 419 times.
✗ Branch 5 not taken.
✓ Branch 8 taken 419 times.
✗ Branch 9 not taken.
✓ Branch 11 taken 419 times.
✗ Branch 12 not taken.
419 Register("user.proxy", new ProxyMagicXattr());
46
4/8
✓ Branch 1 taken 419 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 419 times.
✗ Branch 5 not taken.
✓ Branch 8 taken 419 times.
✗ Branch 9 not taken.
✓ Branch 11 taken 419 times.
✗ Branch 12 not taken.
419 Register("user.proxy_list", new ProxyListMagicXattr());
47
4/8
✓ Branch 1 taken 419 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 419 times.
✗ Branch 5 not taken.
✓ Branch 8 taken 419 times.
✗ Branch 9 not taken.
✓ Branch 11 taken 419 times.
✗ Branch 12 not taken.
419 Register("user.proxy_list_external", new ProxyListExternalMagicXattr());
48
4/8
✓ Branch 1 taken 419 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 419 times.
✗ Branch 5 not taken.
✓ Branch 8 taken 419 times.
✗ Branch 9 not taken.
✓ Branch 11 taken 419 times.
✗ Branch 12 not taken.
419 Register("user.pubkeys", new PubkeysMagicXattr());
49
4/8
✓ Branch 1 taken 419 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 419 times.
✗ Branch 5 not taken.
✓ Branch 8 taken 419 times.
✗ Branch 9 not taken.
✓ Branch 11 taken 419 times.
✗ Branch 12 not taken.
419 Register("user.repo_counters", new RepoCountersMagicXattr());
50
4/8
✓ Branch 1 taken 419 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 419 times.
✗ Branch 5 not taken.
✓ Branch 8 taken 419 times.
✗ Branch 9 not taken.
✓ Branch 11 taken 419 times.
✗ Branch 12 not taken.
419 Register("user.repo_metainfo", new RepoMetainfoMagicXattr());
51
4/8
✓ Branch 1 taken 419 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 419 times.
✗ Branch 5 not taken.
✓ Branch 8 taken 419 times.
✗ Branch 9 not taken.
✓ Branch 11 taken 419 times.
✗ Branch 12 not taken.
419 Register("user.revision", new RevisionMagicXattr());
52
4/8
✓ Branch 1 taken 419 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 419 times.
✗ Branch 5 not taken.
✓ Branch 8 taken 419 times.
✗ Branch 9 not taken.
✓ Branch 11 taken 419 times.
✗ Branch 12 not taken.
419 Register("user.revision_timestamp", new RevisionTimestampMagicXattr());
53
4/8
✓ Branch 1 taken 419 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 419 times.
✗ Branch 5 not taken.
✓ Branch 8 taken 419 times.
✗ Branch 9 not taken.
✓ Branch 11 taken 419 times.
✗ Branch 12 not taken.
419 Register("user.root_hash", new RootHashMagicXattr());
54
4/8
✓ Branch 1 taken 419 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 419 times.
✗ Branch 5 not taken.
✓ Branch 8 taken 419 times.
✗ Branch 9 not taken.
✓ Branch 11 taken 419 times.
✗ Branch 12 not taken.
419 Register("user.rx", new RxMagicXattr());
55
4/8
✓ Branch 1 taken 419 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 419 times.
✗ Branch 5 not taken.
✓ Branch 8 taken 419 times.
✗ Branch 9 not taken.
✓ Branch 11 taken 419 times.
✗ Branch 12 not taken.
419 Register("user.speed", new SpeedMagicXattr());
56
4/8
✓ Branch 1 taken 419 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 419 times.
✗ Branch 5 not taken.
✓ Branch 8 taken 419 times.
✗ Branch 9 not taken.
✓ Branch 11 taken 419 times.
✗ Branch 12 not taken.
419 Register("user.tag", new TagMagicXattr());
57
4/8
✓ Branch 1 taken 419 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 419 times.
✗ Branch 5 not taken.
✓ Branch 8 taken 419 times.
✗ Branch 9 not taken.
✓ Branch 11 taken 419 times.
✗ Branch 12 not taken.
419 Register("user.timeout", new TimeoutMagicXattr());
58
4/8
✓ Branch 1 taken 419 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 419 times.
✗ Branch 5 not taken.
✓ Branch 8 taken 419 times.
✗ Branch 9 not taken.
✓ Branch 11 taken 419 times.
✗ Branch 12 not taken.
419 Register("user.timeout_direct", new TimeoutDirectMagicXattr());
59
4/8
✓ Branch 1 taken 419 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 419 times.
✗ Branch 5 not taken.
✓ Branch 8 taken 419 times.
✗ Branch 9 not taken.
✓ Branch 11 taken 419 times.
✗ Branch 12 not taken.
419 Register("user.timestamp_last_ioerr", new TimestampLastIOErrMagicXattr());
60
4/8
✓ Branch 1 taken 419 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 419 times.
✗ Branch 5 not taken.
✓ Branch 8 taken 419 times.
✗ Branch 9 not taken.
✓ Branch 11 taken 419 times.
✗ Branch 12 not taken.
419 Register("user.usedfd", new UsedFdMagicXattr());
61
4/8
✓ Branch 1 taken 419 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 419 times.
✗ Branch 5 not taken.
✓ Branch 8 taken 419 times.
✗ Branch 9 not taken.
✓ Branch 11 taken 419 times.
✗ Branch 12 not taken.
419 Register("user.useddirp", new UsedDirPMagicXattr());
62
4/8
✓ Branch 1 taken 419 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 419 times.
✗ Branch 5 not taken.
✓ Branch 8 taken 419 times.
✗ Branch 9 not taken.
✓ Branch 11 taken 419 times.
✗ Branch 12 not taken.
419 Register("user.version", new VersionMagicXattr());
63
64
4/8
✓ Branch 1 taken 419 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 419 times.
✗ Branch 5 not taken.
✓ Branch 8 taken 419 times.
✗ Branch 9 not taken.
✓ Branch 11 taken 419 times.
✗ Branch 12 not taken.
419 Register("user.hash", new HashMagicXattr());
65
4/8
✓ Branch 1 taken 419 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 419 times.
✗ Branch 5 not taken.
✓ Branch 8 taken 419 times.
✗ Branch 9 not taken.
✓ Branch 11 taken 419 times.
✗ Branch 12 not taken.
419 Register("user.lhash", new LHashMagicXattr());
66
67
4/8
✓ Branch 1 taken 419 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 419 times.
✗ Branch 5 not taken.
✓ Branch 8 taken 419 times.
✗ Branch 9 not taken.
✓ Branch 11 taken 419 times.
✗ Branch 12 not taken.
419 Register("user.chunk_list", new ChunkListMagicXattr());
68
4/8
✓ Branch 1 taken 419 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 419 times.
✗ Branch 5 not taken.
✓ Branch 8 taken 419 times.
✗ Branch 9 not taken.
✓ Branch 11 taken 419 times.
✗ Branch 12 not taken.
419 Register("user.chunks", new ChunksMagicXattr());
69
4/8
✓ Branch 1 taken 419 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 419 times.
✗ Branch 5 not taken.
✓ Branch 8 taken 419 times.
✗ Branch 9 not taken.
✓ Branch 11 taken 419 times.
✗ Branch 12 not taken.
419 Register("user.compression", new CompressionMagicXattr());
70
4/8
✓ Branch 1 taken 419 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 419 times.
✗ Branch 5 not taken.
✓ Branch 8 taken 419 times.
✗ Branch 9 not taken.
✓ Branch 11 taken 419 times.
✗ Branch 12 not taken.
419 Register("user.direct_io", new DirectIoMagicXattr());
71
4/8
✓ Branch 1 taken 419 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 419 times.
✗ Branch 5 not taken.
✓ Branch 8 taken 419 times.
✗ Branch 9 not taken.
✓ Branch 11 taken 419 times.
✗ Branch 12 not taken.
419 Register("user.bundle_trigger", new BundleTriggerMagicXattr());
72
4/8
✓ Branch 1 taken 419 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 419 times.
✗ Branch 5 not taken.
✓ Branch 8 taken 419 times.
✗ Branch 9 not taken.
✓ Branch 11 taken 419 times.
✗ Branch 12 not taken.
419 Register("user.external_file", new ExternalFileMagicXattr());
73
74
4/8
✓ Branch 1 taken 419 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 419 times.
✗ Branch 5 not taken.
✓ Branch 8 taken 419 times.
✗ Branch 9 not taken.
✓ Branch 11 taken 419 times.
✗ Branch 12 not taken.
419 Register("user.rawlink", new RawlinkMagicXattr());
75
4/8
✓ Branch 1 taken 419 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 419 times.
✗ Branch 5 not taken.
✓ Branch 8 taken 419 times.
✗ Branch 9 not taken.
✓ Branch 11 taken 419 times.
✗ Branch 12 not taken.
419 Register("xfsroot.rawlink", new RawlinkMagicXattr());
76
77
4/8
✓ Branch 1 taken 419 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 419 times.
✗ Branch 5 not taken.
✓ Branch 8 taken 419 times.
✗ Branch 9 not taken.
✓ Branch 11 taken 419 times.
✗ Branch 12 not taken.
419 Register("user.authz", new AuthzMagicXattr());
78
4/8
✓ Branch 1 taken 419 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 419 times.
✗ Branch 5 not taken.
✓ Branch 8 taken 419 times.
✗ Branch 9 not taken.
✓ Branch 11 taken 419 times.
✗ Branch 12 not taken.
419 Register("user.external_url", new ExternalURLMagicXattr());
79
80
4/8
✓ Branch 1 taken 419 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 419 times.
✗ Branch 5 not taken.
✓ Branch 8 taken 419 times.
✗ Branch 9 not taken.
✓ Branch 11 taken 419 times.
✗ Branch 12 not taken.
419 Register("user.cleanup_unused_first", new CleanupUnusedFirstMagicXattr());
81
4/8
✓ Branch 1 taken 419 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 419 times.
✗ Branch 5 not taken.
✓ Branch 8 taken 419 times.
✗ Branch 9 not taken.
✓ Branch 11 taken 419 times.
✗ Branch 12 not taken.
419 Register("user.list_open_hashes", new ListOpenHashesMagicXattr());
82 419 }
83
84 4 std::string MagicXattrManager::GetListString(catalog::DirectoryEntry *dirent) {
85
2/2
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 2 times.
4 if (visibility() == kVisibilityNever) {
86
1/2
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
2 return "";
87 }
88 // Only the root entry has an empty name
89
7/12
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 1 times.
✓ Branch 8 taken 1 times.
✓ Branch 9 taken 2 times.
✗ Branch 10 not taken.
✓ Branch 12 taken 1 times.
✓ Branch 13 taken 1 times.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
2 if (visibility() == kVisibilityRootOnly && !dirent->name().IsEmpty()) {
90
1/2
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
1 return "";
91 }
92
93 1 std::string result;
94 1 std::map<std::string, BaseMagicXattr *>::iterator it = xattr_list_.begin();
95
2/2
✓ Branch 3 taken 46 times.
✓ Branch 4 taken 1 times.
47 for (; it != xattr_list_.end(); ++it) {
96
1/2
✓ Branch 2 taken 46 times.
✗ Branch 3 not taken.
46 const MagicXattrFlavor flavor = (*it).second->GetXattrFlavor();
97 // Skip those which should not be displayed
98
6/7
✓ Branch 0 taken 32 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 6 times.
✓ Branch 3 taken 3 times.
✓ Branch 4 taken 2 times.
✓ Branch 5 taken 1 times.
✗ Branch 6 not taken.
46 switch (flavor) {
99 32 case kXattrBase:
100 32 break;
101 2 case kXattrWithHash:
102
1/2
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
2 if (dirent->checksum().IsNull())
103 2 continue;
104 break;
105 6 case kXattrRegular:
106
1/2
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
6 if (!dirent->IsRegular())
107 6 continue;
108 break;
109 3 case kXattrExternal:
110
2/6
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 3 times.
✗ Branch 7 not taken.
3 if (!(dirent->IsRegular() && dirent->IsExternalFile()))
111 3 continue;
112 break;
113 2 case kXattrSymlink:
114
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 if (!dirent->IsLink())
115 2 continue;
116 break;
117 1 case kXattrAuthz:
118
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 if (!mount_point_->has_membership_req())
119 1 continue;
120 break;
121 default:
122 PANIC("unknown magic xattr flavor");
123 }
124
1/2
✓ Branch 2 taken 32 times.
✗ Branch 3 not taken.
32 result += (*it).first;
125
1/2
✓ Branch 1 taken 32 times.
✗ Branch 2 not taken.
32 result.push_back('\0');
126 }
127
128 1 return result;
129 1 }
130
131 4 BaseMagicXattr *MagicXattrManager::GetLocked(const std::string &name,
132 PathString path,
133 catalog::DirectoryEntry *d) {
134 BaseMagicXattr *result;
135
1/2
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
4 if (xattr_list_.count(name) > 0) {
136 4 result = xattr_list_[name];
137 } else {
138 return NULL;
139 }
140
141
1/2
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
4 result->Lock(path, d);
142
143 4 return result;
144 }
145
146 19274 void MagicXattrManager::Register(const std::string &name,
147 BaseMagicXattr *magic_xattr) {
148
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 19274 times.
19274 assert(!is_frozen_);
149
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 19274 times.
19274 if (xattr_list_.count(name) > 0) {
150 PANIC(kLogSyslogErr,
151 "Magic extended attribute with name %s already registered",
152 name.c_str());
153 }
154 19274 magic_xattr->xattr_mgr_ = this;
155 19274 xattr_list_[name] = magic_xattr;
156
157 // Mark Xattr protected so that only certain fuse_gids' can access it.
158 // If Xattr with registered "name" is part of *protected_xattrs
159
2/2
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 19273 times.
19274 if (protected_xattrs_.count(name) > 0) {
160 1 magic_xattr->MarkProtected();
161 }
162 19274 }
163
164 2 bool MagicXattrManager::IsPrivilegedGid(gid_t gid) {
165 2 return privileged_xattr_gids_.count(gid) > 0;
166 }
167
168 2 bool BaseMagicXattr::PrepareValueFencedProtected(gid_t gid) {
169
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
2 assert(xattr_mgr_->is_frozen());
170
5/6
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 1 times.
✓ Branch 4 taken 1 times.
✓ Branch 5 taken 1 times.
✓ Branch 6 taken 1 times.
2 if (is_protected_ && !xattr_mgr_->IsPrivilegedGid(gid)) {
171 1 return false;
172 }
173
174 1 return PrepareValueFenced();
175 }
176
177 1 void MagicXattrManager::SanityCheckProtectedXattrs() {
178 1 std::set<std::string>::const_iterator iter;
179 1 std::vector<string> tmp;
180
2/2
✓ Branch 3 taken 1 times.
✓ Branch 4 taken 1 times.
2 for (iter = protected_xattrs_.begin(); iter != protected_xattrs_.end();
181 1 iter++) {
182
2/4
✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 1 times.
1 if (xattr_list_.find(*iter) == xattr_list_.end()) {
183 tmp.push_back(*iter);
184 }
185 }
186
187
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
1 if (tmp.size() > 0) {
188 const std::string msg = JoinStrings(tmp, ",");
189 LogCvmfs(kLogCvmfs, kLogDebug | kLogSyslogWarn,
190 "Following CVMFS_XATTR_PROTECTED_XATTRS are "
191 "set but not recognized: %s",
192 msg.c_str());
193 }
194
195 1 tmp.clear();
196 1 std::set<gid_t>::const_iterator iter_gid;
197 1 for (iter_gid = privileged_xattr_gids_.begin();
198
2/2
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 1 times.
2 iter_gid != privileged_xattr_gids_.end();
199 1 iter_gid++) {
200
2/4
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 1 times.
✗ Branch 6 not taken.
1 tmp.push_back(StringifyUint(*iter_gid));
201 }
202
203
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 if (tmp.size() > 0) {
204
2/4
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 1 times.
✗ Branch 6 not taken.
2 const std::string msg = JoinStrings(tmp, ",");
205
1/2
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
1 LogCvmfs(kLogCvmfs, kLogDebug | kLogSyslog,
206 "Following CVMFS_XATTR_PRIVILEGED_GIDS are set: %s", msg.c_str());
207 1 }
208 1 }
209
210 4 std::string BaseMagicXattr::HeaderMultipageHuman(uint32_t requested_page) {
211
3/6
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 4 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 4 times.
✗ Branch 8 not taken.
8 return "# Access page at idx: " + StringifyUint(requested_page) + ". "
212
2/4
✓ Branch 3 taken 4 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 4 times.
✗ Branch 7 not taken.
16 + "Total num pages: " + StringifyUint(result_pages_.size())
213
1/2
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
8 + " (access other pages: xattr~<page_num>, starting "
214
1/2
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
8 + " with 0; number of pages available: xattr~?)\n";
215 }
216
217 20 std::pair<bool, std::string> BaseMagicXattr::GetValue(
218 int32_t requested_page, const MagicXattrMode mode) {
219
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 20 times.
20 assert(requested_page >= -1);
220 20 result_pages_.clear();
221
1/2
✓ Branch 1 taken 20 times.
✗ Branch 2 not taken.
20 FinalizeValue();
222
223
1/2
✓ Branch 2 taken 20 times.
✗ Branch 3 not taken.
20 std::string res = "";
224
2/2
✓ Branch 0 taken 14 times.
✓ Branch 1 taken 6 times.
20 if (mode == kXattrMachineMode) {
225
2/2
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 12 times.
14 if (requested_page >= static_cast<int32_t>(result_pages_.size())) {
226
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 return std::pair<bool, std::string>(false, "");
227 }
228
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
12 if (requested_page == -1) {
229 return std::pair<bool, std::string>(
230 true, "num_pages, " + StringifyUint(result_pages_.size()));
231 }
232
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 } else if (mode == kXattrHumanMode) {
233
2/2
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 4 times.
6 if (requested_page >= static_cast<int32_t>(result_pages_.size())) {
234 return std::pair<bool, std::string>(
235 true,
236 "Page requested does not exists. There are "
237
3/6
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 2 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 2 times.
✗ Branch 9 not taken.
4 + StringifyUint(result_pages_.size()) + " pages available.\n"
238
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
4 + "Access them with xattr~<page_num> (machine-readable mode) "
239
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
4 + "or xattr@<page_num> (human-readable mode).\n"
240
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 + "Use xattr@? or xattr~? to get extra info about the attribute");
241
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 } else if (requested_page == -1) {
242 return std::pair<bool, std::string>(
243 true,
244 "Access xattr with xattr~<page_num> (machine-readable mode) or "
245 + std::string(" xattr@<page_num> (human-readable mode).\n")
246 + "Pages available: " + StringifyUint(result_pages_.size()));
247 } else {
248
1/2
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
4 res = HeaderMultipageHuman(requested_page);
249 }
250 } else {
251 PANIC(kLogStderr | kLogSyslogErr,
252 "Unknown mode of magic xattr requested: %d", mode);
253 }
254
255
1/2
✓ Branch 2 taken 16 times.
✗ Branch 3 not taken.
16 res += result_pages_[requested_page];
256
257
1/2
✓ Branch 1 taken 16 times.
✗ Branch 2 not taken.
16 return std::pair<bool, std::string>(true, res);
258 20 }
259
260 bool AuthzMagicXattr::PrepareValueFenced() {
261 return xattr_mgr_->mount_point()->has_membership_req();
262 }
263
264 void AuthzMagicXattr::FinalizeValue() {
265 result_pages_.push_back(xattr_mgr_->mount_point()->membership_req());
266 }
267
268 1 MagicXattrFlavor AuthzMagicXattr::GetXattrFlavor() { return kXattrAuthz; }
269
270 bool CatalogCountersMagicXattr::PrepareValueFenced() {
271 counters_ = xattr_mgr_->mount_point()->catalog_mgr()->LookupCounters(
272 path_, &subcatalog_path_, &hash_);
273 return true;
274 }
275
276 void CatalogCountersMagicXattr::FinalizeValue() {
277 std::string res;
278 res = "catalog_hash: " + hash_.ToString() + "\n";
279 res += "catalog_mountpoint: " + subcatalog_path_ + "\n";
280 res += counters_.GetCsvMap();
281
282 result_pages_.push_back(res);
283 }
284
285 bool ChunkListMagicXattr::PrepareValueFenced() {
286 chunk_list_.clear();
287
288 const std::string header = "hash,offset,size\n";
289 std::string chunk_list_page_(header);
290 if (!dirent_->IsRegular()) {
291 chunk_list_.push_back(chunk_list_page_);
292 return false;
293 }
294 if (dirent_->IsChunkedFile()) {
295 FileChunkList chunks;
296 if (!xattr_mgr_->mount_point()->catalog_mgr()->ListFileChunks(
297 path_, dirent_->hash_algorithm(), &chunks)
298 || chunks.IsEmpty()) {
299 LogCvmfs(kLogCvmfs, kLogDebug | kLogSyslogErr,
300 "file %s is marked as "
301 "'chunked', but no chunks found.",
302 path_.c_str());
303 return false;
304 } else {
305 for (size_t i = 0; i < chunks.size(); ++i) {
306 chunk_list_page_ += chunks.At(i).content_hash().ToString() + ",";
307 chunk_list_page_ += StringifyInt(chunks.At(i).offset()) + ",";
308 chunk_list_page_ += StringifyUint(chunks.At(i).size()) + "\n";
309
310 if (chunk_list_page_.size() > kMaxCharsPerPage) {
311 chunk_list_.push_back(chunk_list_page_);
312 chunk_list_page_ = header;
313 }
314 }
315 }
316 } else {
317 chunk_list_page_ += dirent_->checksum().ToString() + ",";
318 chunk_list_page_ += "0,";
319 chunk_list_page_ += StringifyUint(dirent_->size()) + "\n";
320 }
321
322 // add the last page
323 if (chunk_list_page_.size() > header.size()) {
324 chunk_list_.push_back(chunk_list_page_);
325 }
326
327 return true;
328 }
329
330 void ChunkListMagicXattr::FinalizeValue() { result_pages_ = chunk_list_; }
331
332 bool ChunksMagicXattr::PrepareValueFenced() {
333 if (!dirent_->IsRegular()) {
334 return false;
335 }
336 if (dirent_->IsChunkedFile()) {
337 FileChunkList chunks;
338 if (!xattr_mgr_->mount_point()->catalog_mgr()->ListFileChunks(
339 path_, dirent_->hash_algorithm(), &chunks)
340 || chunks.IsEmpty()) {
341 LogCvmfs(kLogCvmfs, kLogDebug | kLogSyslogErr,
342 "file %s is marked as "
343 "'chunked', but no chunks found.",
344 path_.c_str());
345 return false;
346 } else {
347 n_chunks_ = chunks.size();
348 }
349 } else {
350 n_chunks_ = 1;
351 }
352
353 return true;
354 }
355
356 void ChunksMagicXattr::FinalizeValue() {
357 result_pages_.push_back(StringifyUint(n_chunks_));
358 }
359
360 bool CompressionMagicXattr::PrepareValueFenced() {
361 return dirent_->IsRegular();
362 }
363
364 void CompressionMagicXattr::FinalizeValue() {
365 result_pages_.push_back(
366 zlib::AlgorithmName(dirent_->compression_algorithm()));
367 }
368
369 bool DirectIoMagicXattr::PrepareValueFenced() { return dirent_->IsRegular(); }
370
371 void DirectIoMagicXattr::FinalizeValue() {
372 result_pages_.push_back(dirent_->IsDirectIo() ? "1" : "0");
373 }
374
375 bool BundleTriggerMagicXattr::PrepareValueFenced() {
376 return dirent_->IsRegular();
377 }
378
379 void BundleTriggerMagicXattr::FinalizeValue() {
380 result_pages_.push_back(dirent_->IsBundleTrigger() ? "1" : "0");
381 }
382
383 bool ExternalFileMagicXattr::PrepareValueFenced() {
384 return dirent_->IsRegular();
385 }
386
387 void ExternalFileMagicXattr::FinalizeValue() {
388 result_pages_.push_back(dirent_->IsExternalFile() ? "1" : "0");
389 }
390
391 void ExternalHostMagicXattr::FinalizeValue() {
392 std::vector<string> host_chain;
393 std::vector<int> rtt;
394 unsigned current_host;
395 xattr_mgr_->mount_point()->external_download_mgr()->GetHostInfo(
396 &host_chain, &rtt, &current_host);
397 if (host_chain.size()) {
398 result_pages_.push_back(std::string(host_chain[current_host]));
399 } else {
400 result_pages_.push_back("internal error: no hosts defined");
401 }
402 }
403
404 void ExternalTimeoutMagicXattr::FinalizeValue() {
405 unsigned seconds, seconds_direct;
406 xattr_mgr_->mount_point()->external_download_mgr()->GetTimeout(
407 &seconds, &seconds_direct);
408 result_pages_.push_back(StringifyUint(seconds_direct));
409 }
410
411 2 void FqrnMagicXattr::FinalizeValue() {
412
1/2
✓ Branch 3 taken 2 times.
✗ Branch 4 not taken.
2 result_pages_.push_back(xattr_mgr_->mount_point()->fqrn());
413 2 }
414
415 bool HashMagicXattr::PrepareValueFenced() {
416 return !dirent_->checksum().IsNull();
417 }
418
419 void HashMagicXattr::FinalizeValue() {
420 result_pages_.push_back(dirent_->checksum().ToString());
421 }
422
423 void HostMagicXattr::FinalizeValue() {
424 std::vector<std::string> host_chain;
425 std::vector<int> rtt;
426 unsigned current_host;
427 xattr_mgr_->mount_point()->download_mgr()->GetHostInfo(&host_chain, &rtt,
428 &current_host);
429 if (host_chain.size()) {
430 result_pages_.push_back(std::string(host_chain[current_host]));
431 } else {
432 result_pages_.push_back("internal error: no hosts defined");
433 }
434 }
435
436 void HostListMagicXattr::FinalizeValue() {
437 std::string result;
438 std::vector<std::string> host_chain;
439 std::vector<int> rtt;
440 unsigned current_host;
441 xattr_mgr_->mount_point()->download_mgr()->GetHostInfo(&host_chain, &rtt,
442 &current_host);
443 if (host_chain.size()) {
444 result = host_chain[current_host];
445 for (unsigned i = 1; i < host_chain.size(); ++i) {
446 result += ";" + host_chain[(i + current_host) % host_chain.size()];
447 }
448 } else {
449 result = "internal error: no hosts defined";
450 }
451 result_pages_.push_back(result);
452 }
453
454 bool LHashMagicXattr::PrepareValueFenced() {
455 return !dirent_->checksum().IsNull();
456 }
457
458 void LHashMagicXattr::FinalizeValue() {
459 string result;
460 CacheManager::Label label;
461 label.path = path_.ToString();
462 if (xattr_mgr_->mount_point()->catalog_mgr()->volatile_flag())
463 label.flags = CacheManager::kLabelVolatile;
464 const int fd = xattr_mgr_->mount_point()->file_system()->cache_mgr()->Open(
465 CacheManager::LabeledObject(dirent_->checksum(), label));
466 if (fd < 0) {
467 result = "Not in cache";
468 } else {
469 shash::Any hash(dirent_->checksum().algorithm);
470 const int retval_i = xattr_mgr_->mount_point()
471 ->file_system()
472 ->cache_mgr()
473 ->ChecksumFd(fd, &hash);
474 if (retval_i != 0)
475 result = "I/O error (" + StringifyInt(retval_i) + ")";
476 else
477 result = hash.ToString();
478 xattr_mgr_->mount_point()->file_system()->cache_mgr()->Close(fd);
479 }
480 result_pages_.push_back(result);
481 }
482
483
1/2
✓ Branch 2 taken 419 times.
✗ Branch 3 not taken.
419 LogBufferXattr::LogBufferXattr() : BaseMagicXattr(), throttle_(1, 500, 2000) { }
484
485 2 void LogBufferXattr::FinalizeValue() {
486
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 throttle_.Throttle();
487
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 std::vector<LogBufferEntry> buffer = GetLogBuffer();
488 2 std::string result;
489 2 for (std::vector<LogBufferEntry>::reverse_iterator itr = buffer.rbegin();
490
3/4
✓ Branch 2 taken 22 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 20 times.
✓ Branch 5 taken 2 times.
22 itr != buffer.rend();
491 20 ++itr) {
492
3/4
✓ Branch 1 taken 20 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✓ Branch 5 taken 19 times.
20 if (itr->message.size() > kMaxLogLine) {
493
2/4
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
1 itr->message.resize(kMaxLogLine);
494
2/4
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
1 itr->message += " <snip>";
495 }
496
6/12
✓ Branch 1 taken 20 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 20 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 20 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 20 times.
✗ Branch 11 not taken.
✓ Branch 13 taken 20 times.
✗ Branch 14 not taken.
✓ Branch 16 taken 20 times.
✗ Branch 17 not taken.
40 result += "[" + StringifyLocalTime(itr->timestamp) + "] " + itr->message
497
2/4
✓ Branch 1 taken 20 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 20 times.
✗ Branch 5 not taken.
20 + "\n";
498 }
499
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 result_pages_.push_back(result);
500 2 }
501
502 void NCleanup24MagicXattr::FinalizeValue() {
503 QuotaManager *quota_mgr = xattr_mgr_->mount_point()
504 ->file_system()
505 ->cache_mgr()
506 ->quota_mgr();
507 if (!quota_mgr->HasCapability(QuotaManager::kCapIntrospectCleanupRate)) {
508 result_pages_.push_back(StringifyInt(-1));
509 } else {
510 const uint64_t period_s = 24 * 60 * 60;
511 const uint64_t rate = quota_mgr->GetCleanupRate(period_s);
512 result_pages_.push_back(StringifyUint(rate));
513 }
514 }
515
516 bool NClgMagicXattr::PrepareValueFenced() {
517 n_catalogs_ = xattr_mgr_->mount_point()->catalog_mgr()->GetNumCatalogs();
518 return true;
519 }
520
521 void NClgMagicXattr::FinalizeValue() {
522 result_pages_.push_back(StringifyInt(n_catalogs_));
523 }
524
525 void NDirOpenMagicXattr::FinalizeValue() {
526 result_pages_.push_back(
527 xattr_mgr_->mount_point()->file_system()->n_fs_dir_open()->ToString());
528 }
529
530 void NDownloadMagicXattr::FinalizeValue() {
531 result_pages_.push_back(xattr_mgr_->mount_point()
532 ->statistics()
533 ->Lookup("fetch.n_downloads")
534 ->Print());
535 }
536
537 void NIOErrMagicXattr::FinalizeValue() {
538 result_pages_.push_back(StringifyInt(
539 xattr_mgr_->mount_point()->file_system()->io_error_info()->count()));
540 }
541
542 void NOpenMagicXattr::FinalizeValue() {
543 result_pages_.push_back(
544 xattr_mgr_->mount_point()->file_system()->n_fs_open()->ToString());
545 }
546
547 void HitrateMagicXattr::FinalizeValue() {
548 const int64_t n_invocations = xattr_mgr_->mount_point()
549 ->statistics()
550 ->Lookup("fetch.n_invocations")
551 ->Get();
552 if (n_invocations == 0) {
553 result_pages_.push_back("n/a");
554 return;
555 }
556
557 const int64_t n_downloads = xattr_mgr_->mount_point()
558 ->statistics()
559 ->Lookup("fetch.n_downloads")
560 ->Get();
561 const float hitrate = 100.
562 * (1.
563 - (static_cast<float>(n_downloads)
564 / static_cast<float>(n_invocations)));
565 result_pages_.push_back(StringifyDouble(hitrate));
566 }
567
568 void ProxyMagicXattr::FinalizeValue() {
569 vector<vector<download::DownloadManager::ProxyInfo> > proxy_chain;
570 unsigned current_group;
571 xattr_mgr_->mount_point()->download_mgr()->GetProxyInfo(&proxy_chain,
572 &current_group, NULL);
573 if (proxy_chain.size()) {
574 result_pages_.push_back(proxy_chain[current_group][0].url);
575 } else {
576 result_pages_.push_back("DIRECT");
577 }
578 }
579
580 static void ListProxy(download::DownloadManager *dm,
581 std::vector<std::string> *result_pages) {
582 vector<vector<download::DownloadManager::ProxyInfo> > proxy_chain;
583 unsigned current_group;
584 dm->GetProxyInfo(&proxy_chain, &current_group, NULL);
585 std::string buf = "";
586 for (unsigned int i = 0; i < proxy_chain.size(); i++) {
587 for (unsigned int j = 0; j < proxy_chain[i].size(); j++) {
588 buf += proxy_chain[i][j].url;
589 buf += "\n";
590 }
591
592 if (buf.size() > BaseMagicXattr::kMaxCharsPerPage) {
593 result_pages->push_back(buf);
594 buf = "";
595 }
596 }
597
598 if (buf.size() > 0 || result_pages->size() == 0) {
599 result_pages->push_back(buf);
600 }
601 }
602
603 void ProxyListMagicXattr::FinalizeValue() {
604 ListProxy(xattr_mgr_->mount_point()->download_mgr(), &result_pages_);
605 }
606
607 void ProxyListExternalMagicXattr::FinalizeValue() {
608 ListProxy(xattr_mgr_->mount_point()->external_download_mgr(), &result_pages_);
609 }
610
611 bool PubkeysMagicXattr::PrepareValueFenced() {
612 pubkeys_ = xattr_mgr_->mount_point()
613 ->signature_mgr()
614 ->GetActivePubkeysAsVector();
615 return true;
616 }
617
618 16 void PubkeysMagicXattr::FinalizeValue() {
619 16 size_t full_size = 0;
620
621
2/2
✓ Branch 1 taken 79 times.
✓ Branch 2 taken 16 times.
95 for (size_t i = 0; i < pubkeys_.size(); i++) {
622 79 full_size += pubkeys_[i].size();
623 }
624
625
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 14 times.
16 if (full_size == 0) {
626 2 return;
627 }
628
629 14 size_t size_within_page = 0;
630
1/2
✓ Branch 2 taken 14 times.
✗ Branch 3 not taken.
14 std::string res = "";
631
632
2/2
✓ Branch 1 taken 79 times.
✓ Branch 2 taken 14 times.
93 for (size_t i = 0; i < pubkeys_.size(); i++) {
633
2/2
✓ Branch 2 taken 13 times.
✓ Branch 3 taken 66 times.
79 if (size_within_page + pubkeys_[i].size() >= kMaxCharsPerPage) {
634
1/2
✓ Branch 1 taken 13 times.
✗ Branch 2 not taken.
13 result_pages_.push_back(res);
635
1/2
✓ Branch 1 taken 13 times.
✗ Branch 2 not taken.
13 res = "";
636 13 size_within_page = 0;
637 }
638
639
1/2
✓ Branch 2 taken 79 times.
✗ Branch 3 not taken.
79 res += pubkeys_[i];
640 79 size_within_page += pubkeys_[i].size();
641 }
642
1/2
✓ Branch 1 taken 14 times.
✗ Branch 2 not taken.
14 if (res.size() > 0) {
643
1/2
✓ Branch 1 taken 14 times.
✗ Branch 2 not taken.
14 result_pages_.push_back(res);
644 }
645 14 }
646
647 bool RawlinkMagicXattr::PrepareValueFenced() { return dirent_->IsLink(); }
648
649 void RawlinkMagicXattr::FinalizeValue() {
650 result_pages_.push_back(dirent_->symlink().ToString());
651 }
652
653 bool RepoCountersMagicXattr::PrepareValueFenced() {
654 counters_ = xattr_mgr_->mount_point()
655 ->catalog_mgr()
656 ->GetRootCatalog()
657 ->GetCounters();
658 return true;
659 }
660
661 void RepoCountersMagicXattr::FinalizeValue() {
662 result_pages_.push_back(counters_.GetCsvMap());
663 }
664
665 const uint64_t RepoMetainfoMagicXattr::kMaxMetainfoLength = 65536;
666
667 bool RepoMetainfoMagicXattr::PrepareValueFenced() {
668 if (!xattr_mgr_->mount_point()->catalog_mgr()->manifest()) {
669 error_reason_ = "manifest not available";
670 return true;
671 }
672
673 metainfo_hash_ = xattr_mgr_->mount_point()
674 ->catalog_mgr()
675 ->manifest()
676 ->meta_info();
677 if (metainfo_hash_.IsNull()) {
678 error_reason_ = "metainfo not available";
679 return true;
680 }
681 return true;
682 }
683
684 void RepoMetainfoMagicXattr::FinalizeValue() {
685 if (metainfo_hash_.IsNull()) {
686 result_pages_.push_back(error_reason_);
687 return;
688 }
689
690 CacheManager::Label label;
691 label.path = xattr_mgr_->mount_point()->fqrn() + "("
692 + metainfo_hash_.ToString() + ")";
693 label.flags = CacheManager::kLabelMetainfo;
694 const int fd = xattr_mgr_->mount_point()->fetcher()->Fetch(
695 CacheManager::LabeledObject(metainfo_hash_, label));
696 if (fd < 0) {
697 result_pages_.push_back("Failed to open metadata file");
698 return;
699 }
700 const uint64_t actual_size = xattr_mgr_->mount_point()
701 ->file_system()
702 ->cache_mgr()
703 ->GetSize(fd);
704 if (actual_size > kMaxMetainfoLength) {
705 xattr_mgr_->mount_point()->file_system()->cache_mgr()->Close(fd);
706 result_pages_.push_back("Failed to open: metadata file is too big");
707 return;
708 }
709 char buffer[kMaxMetainfoLength];
710 const int64_t
711 bytes_read = xattr_mgr_->mount_point()->file_system()->cache_mgr()->Pread(
712 fd, buffer, actual_size, 0);
713 xattr_mgr_->mount_point()->file_system()->cache_mgr()->Close(fd);
714 if (bytes_read < 0) {
715 result_pages_.push_back("Failed to read metadata file");
716 return;
717 }
718 result_pages_.push_back(string(buffer, buffer + bytes_read));
719 }
720
721 bool RevisionMagicXattr::PrepareValueFenced() {
722 revision_ = xattr_mgr_->mount_point()->catalog_mgr()->GetRevision();
723 return true;
724 }
725
726 void RevisionMagicXattr::FinalizeValue() {
727 result_pages_.push_back(StringifyUint(revision_));
728 }
729
730 bool RevisionTimestampMagicXattr::PrepareValueFenced() {
731 timestamp_ = xattr_mgr_->mount_point()->catalog_mgr()->GetTimestamp();
732 return true;
733 }
734
735 void RevisionTimestampMagicXattr::FinalizeValue() {
736 result_pages_.push_back(StringifyUint(timestamp_));
737 }
738
739 bool RootHashMagicXattr::PrepareValueFenced() {
740 root_hash_ = xattr_mgr_->mount_point()->catalog_mgr()->GetRootHash();
741 return true;
742 }
743
744 void RootHashMagicXattr::FinalizeValue() {
745 result_pages_.push_back(root_hash_.ToString());
746 }
747
748 void RxMagicXattr::FinalizeValue() {
749 perf::Statistics *statistics = xattr_mgr_->mount_point()->statistics();
750 const int64_t rx = statistics->Lookup("download.sz_transferred_bytes")->Get();
751 result_pages_.push_back(StringifyInt(rx / 1024));
752 }
753
754 void SpeedMagicXattr::FinalizeValue() {
755 perf::Statistics *statistics = xattr_mgr_->mount_point()->statistics();
756 const int64_t rx = statistics->Lookup("download.sz_transferred_bytes")->Get();
757 const int64_t time = statistics->Lookup("download.sz_transfer_time")->Get();
758 if (time == 0) {
759 result_pages_.push_back("n/a");
760 } else {
761 result_pages_.push_back(StringifyInt((1000 * (rx / 1024)) / time));
762 }
763 }
764
765 bool TagMagicXattr::PrepareValueFenced() {
766 tag_ = xattr_mgr_->mount_point()->repository_tag();
767 return true;
768 }
769
770 void TagMagicXattr::FinalizeValue() { result_pages_.push_back(tag_); }
771
772 void TimeoutMagicXattr::FinalizeValue() {
773 unsigned seconds, seconds_direct;
774 xattr_mgr_->mount_point()->download_mgr()->GetTimeout(&seconds,
775 &seconds_direct);
776 result_pages_.push_back(StringifyUint(seconds));
777 }
778
779 void TimeoutDirectMagicXattr::FinalizeValue() {
780 unsigned seconds, seconds_direct;
781 xattr_mgr_->mount_point()->download_mgr()->GetTimeout(&seconds,
782 &seconds_direct);
783 result_pages_.push_back(StringifyUint(seconds_direct));
784 }
785
786 void TimestampLastIOErrMagicXattr::FinalizeValue() {
787 result_pages_.push_back(StringifyInt(xattr_mgr_->mount_point()
788 ->file_system()
789 ->io_error_info()
790 ->timestamp_last()));
791 }
792
793 void UsedFdMagicXattr::FinalizeValue() {
794 result_pages_.push_back(
795 xattr_mgr_->mount_point()->file_system()->no_open_files()->ToString());
796 }
797
798 void UsedDirPMagicXattr::FinalizeValue() {
799 result_pages_.push_back(
800 xattr_mgr_->mount_point()->file_system()->no_open_dirs()->ToString());
801 }
802
803 void VersionMagicXattr::FinalizeValue() {
804 result_pages_.push_back(std::string(CVMFS_VERSION) + "."
805 + std::string(CVMFS_PATCH_LEVEL));
806 }
807
808 void ExternalURLMagicXattr::FinalizeValue() {
809 std::vector<std::string> host_chain;
810 std::vector<int> rtt;
811 unsigned current_host;
812 if (xattr_mgr_->mount_point()->external_download_mgr() != NULL) {
813 xattr_mgr_->mount_point()->external_download_mgr()->GetHostInfo(
814 &host_chain, &rtt, &current_host);
815 if (host_chain.size()) {
816 result_pages_.push_back(std::string(host_chain[current_host])
817 + std::string(path_.c_str()));
818 return;
819 }
820 }
821 result_pages_.push_back("");
822 }
823
824 bool ExternalURLMagicXattr::PrepareValueFenced() {
825 return dirent_->IsRegular() && dirent_->IsExternalFile();
826 }
827
828 void CleanupUnusedFirstMagicXattr::FinalizeValue() {
829 auto cm = xattr_mgr_->mount_point()->file_system()->cache_mgr();
830 PosixCacheManager *pcm = dynamic_cast<PosixCacheManager *>(cm);
831 if (pcm != nullptr) {
832 if (pcm->cleanup_unused_first()) {
833 result_pages_.push_back("yes");
834 } else {
835 result_pages_.push_back("no");
836 }
837 } else {
838 result_pages_.push_back("no");
839 }
840 }
841
842 void ListOpenHashesMagicXattr::FinalizeValue() {
843 auto cm = xattr_mgr_->mount_point()->file_system()->cache_mgr();
844 PosixCacheManager *pcm = dynamic_cast<PosixCacheManager *>(cm);
845 std::string result;
846 if (pcm != nullptr) {
847 if (pcm->cleanup_unused_first()) {
848 if (pcm->fd_mgr_.IsValid()) {
849 const auto &hash_map = pcm->fd_mgr_->map_fd_;
850 auto empty = hash_map.empty_key();
851 auto *keys = hash_map.keys();
852 for (size_t i = 0; i < hash_map.capacity(); ++i) {
853 const shash::Any &hash = keys[i];
854 if (hash != empty) {
855 shash::Short short_hash(hash);
856 result += short_hash.ToString() + "\n";
857 }
858 }
859 }
860 }
861 }
862 result_pages_.push_back(result);
863 }
864
865