GCC Code Coverage Report


Directory: cvmfs/
File: cvmfs/magic_xattr.cc
Date: 2025-11-30 02:35:17
Exec Total Coverage
Lines: 183 511 35.8%
Branches: 297 1039 28.6%

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