GCC Code Coverage Report


Directory: cvmfs/
File: cvmfs/manifest.cc
Date: 2024-04-28 02:33:07
Exec Total Coverage
Lines: 140 160 87.5%
Branches: 154 340 45.3%

Line Branch Exec Source
1 /**
2 * This file is part of the CernVM File System.
3 */
4
5 #include "manifest.h"
6
7 #include <cstdio>
8 #include <map>
9 #include <vector>
10
11 #include "catalog.h"
12 #include "util/posix.h"
13 #include "util/string.h"
14
15 using namespace std; // NOLINT
16
17 namespace manifest {
18
19 21 Breadcrumb::Breadcrumb(const std::string &from_string) {
20 21 timestamp = 0;
21 21 revision = 0; // for backward compatibility: no revision --> revision = 0
22
23
2/2
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 20 times.
21 if (from_string.empty()) {
24 1 return;
25 }
26
27 // Separate hash from timestamp
28
1/2
✓ Branch 1 taken 20 times.
✗ Branch 2 not taken.
20 std::vector<std::string> vec_split_timestamp = SplitString(from_string, 'T');
29
30
1/2
✓ Branch 3 taken 20 times.
✗ Branch 4 not taken.
20 catalog_hash = shash::MkFromHexPtr(shash::HexPtr(vec_split_timestamp[0]),
31 shash::kSuffixCatalog);
32
33
2/2
✓ Branch 1 taken 18 times.
✓ Branch 2 taken 2 times.
20 if (vec_split_timestamp.size() > 1) {
34 // check if revision number is included
35 std::vector<std::string> vec_split_revision =
36
1/2
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
18 SplitString(vec_split_timestamp[1], 'R');
37
38 // Get local last modified time
39
1/2
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
18 timestamp = String2Uint64(vec_split_revision[0]);
40
41 // Get local revision
42
2/2
✓ Branch 1 taken 9 times.
✓ Branch 2 taken 9 times.
18 if (vec_split_revision.size() > 1) {
43
1/2
✓ Branch 2 taken 9 times.
✗ Branch 3 not taken.
9 revision = String2Uint64(vec_split_revision[1]);
44 }
45 18 }
46 20 }
47
48 11 bool Breadcrumb::Export(const string &fqrn, const string &directory,
49 const int mode) const {
50
2/4
✓ Branch 1 taken 11 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 11 times.
✗ Branch 5 not taken.
22 string breadcrumb_path = MakeCanonicalPath(directory) +
51
1/2
✓ Branch 1 taken 11 times.
✗ Branch 2 not taken.
11 "/cvmfschecksum." + fqrn;
52 11 string tmp_path;
53
1/2
✓ Branch 1 taken 11 times.
✗ Branch 2 not taken.
11 FILE *fbreadcrumb = CreateTempFile(breadcrumb_path, mode, "w", &tmp_path);
54
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 11 times.
11 if (fbreadcrumb == NULL)
55 return false;
56
1/2
✓ Branch 1 taken 11 times.
✗ Branch 2 not taken.
11 string str_breadcrumb = ToString();
57
2/4
✓ Branch 2 taken 11 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 11 times.
✗ Branch 6 not taken.
11 int written = fwrite(&(str_breadcrumb[0]), 1, str_breadcrumb.length(),
58 11 fbreadcrumb);
59
1/2
✓ Branch 1 taken 11 times.
✗ Branch 2 not taken.
11 fclose(fbreadcrumb);
60
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 11 times.
11 if (static_cast<unsigned>(written) != str_breadcrumb.length()) {
61 unlink(tmp_path.c_str());
62 return false;
63 }
64 11 int retval = rename(tmp_path.c_str(), breadcrumb_path.c_str());
65
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 11 times.
11 if (retval != 0) {
66 unlink(tmp_path.c_str());
67 return false;
68 }
69 11 return true;
70 11 }
71
72 24 std::string Breadcrumb::ToString() const {
73
1/2
✓ Branch 1 taken 24 times.
✗ Branch 2 not taken.
24 return catalog_hash.ToString()
74
3/6
✓ Branch 1 taken 24 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 24 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 24 times.
✗ Branch 8 not taken.
72 + "T" + StringifyInt(static_cast<int64_t>(timestamp))
75
2/4
✓ Branch 2 taken 24 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 24 times.
✗ Branch 6 not taken.
96 + "R" + StringifyUint(revision);
76 }
77
78
79 //------------------------------------------------------------------------------
80
81
82 28 Manifest *Manifest::LoadMem(const unsigned char *buffer,
83 const unsigned length)
84 {
85 28 map<char, string> content;
86
1/2
✓ Branch 1 taken 28 times.
✗ Branch 2 not taken.
28 ParseKeyvalMem(buffer, length, &content);
87
88
1/2
✓ Branch 1 taken 28 times.
✗ Branch 2 not taken.
56 return Load(content);
89 28 }
90
91
92 9 Manifest *Manifest::LoadFile(const std::string &from_path) {
93 9 map<char, string> content;
94
2/4
✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 9 times.
9 if (!ParseKeyvalPath(from_path, &content))
95 return NULL;
96
97
1/2
✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
9 return Load(content);
98 9 }
99
100
101 37 Manifest *Manifest::Load(const map<char, string> &content) {
102 37 map<char, string>::const_iterator iter;
103
104 // Required keys
105
1/2
✓ Branch 1 taken 37 times.
✗ Branch 2 not taken.
37 shash::Any catalog_hash;
106
1/2
✓ Branch 1 taken 37 times.
✗ Branch 2 not taken.
37 shash::Md5 root_path;
107 uint32_t ttl;
108 uint64_t revision;
109
110
1/2
✓ Branch 1 taken 37 times.
✗ Branch 2 not taken.
37 iter = content.find('C');
111
2/5
✓ Branch 2 taken 37 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 37 times.
37 if ((iter = content.find('C')) == content.end())
112 return NULL;
113
1/2
✓ Branch 3 taken 37 times.
✗ Branch 4 not taken.
37 catalog_hash = MkFromHexPtr(shash::HexPtr(iter->second),
114 shash::kSuffixCatalog);
115
2/5
✓ Branch 2 taken 37 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 37 times.
37 if ((iter = content.find('R')) == content.end())
116 return NULL;
117
1/2
✓ Branch 3 taken 37 times.
✗ Branch 4 not taken.
37 root_path = shash::Md5(shash::HexPtr(iter->second));
118
2/5
✓ Branch 2 taken 37 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 37 times.
37 if ((iter = content.find('D')) == content.end())
119 return NULL;
120
1/2
✓ Branch 2 taken 37 times.
✗ Branch 3 not taken.
37 ttl = String2Uint64(iter->second);
121
2/5
✓ Branch 2 taken 37 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 37 times.
37 if ((iter = content.find('S')) == content.end())
122 return NULL;
123
1/2
✓ Branch 2 taken 37 times.
✗ Branch 3 not taken.
37 revision = String2Uint64(iter->second);
124
125
126 // Optional keys
127 37 uint64_t catalog_size = 0;
128
1/2
✓ Branch 1 taken 37 times.
✗ Branch 2 not taken.
37 shash::Any micro_catalog_hash;
129 37 string repository_name;
130
1/2
✓ Branch 1 taken 37 times.
✗ Branch 2 not taken.
37 shash::Any certificate;
131
1/2
✓ Branch 1 taken 37 times.
✗ Branch 2 not taken.
37 shash::Any history;
132 37 uint64_t publish_timestamp = 0;
133 37 bool garbage_collectable = false;
134 37 bool has_alt_catalog_path = false;
135
1/2
✓ Branch 1 taken 37 times.
✗ Branch 2 not taken.
37 shash::Any meta_info;
136
1/2
✓ Branch 1 taken 37 times.
✗ Branch 2 not taken.
37 shash::Any reflog_hash;
137
138
2/5
✓ Branch 2 taken 37 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 37 times.
✗ Branch 6 not taken.
37 if ((iter = content.find('B')) != content.end())
139
1/2
✓ Branch 2 taken 37 times.
✗ Branch 3 not taken.
37 catalog_size = String2Uint64(iter->second);
140
2/5
✓ Branch 2 taken 37 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 37 times.
37 if ((iter = content.find('L')) != content.end())
141 micro_catalog_hash = MkFromHexPtr(shash::HexPtr(iter->second),
142 shash::kSuffixMicroCatalog);
143
2/5
✓ Branch 2 taken 37 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 37 times.
✗ Branch 6 not taken.
37 if ((iter = content.find('N')) != content.end())
144
1/2
✓ Branch 2 taken 37 times.
✗ Branch 3 not taken.
37 repository_name = iter->second;
145
2/5
✓ Branch 2 taken 37 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 37 times.
✗ Branch 6 not taken.
37 if ((iter = content.find('X')) != content.end())
146
1/2
✓ Branch 3 taken 37 times.
✗ Branch 4 not taken.
37 certificate = MkFromHexPtr(shash::HexPtr(iter->second),
147 shash::kSuffixCertificate);
148
2/5
✓ Branch 2 taken 37 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 37 times.
✗ Branch 6 not taken.
37 if ((iter = content.find('H')) != content.end())
149
1/2
✓ Branch 3 taken 37 times.
✗ Branch 4 not taken.
37 history = MkFromHexPtr(shash::HexPtr(iter->second),
150 shash::kSuffixHistory);
151
3/5
✓ Branch 2 taken 37 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 23 times.
✓ Branch 6 taken 14 times.
37 if ((iter = content.find('T')) != content.end())
152
1/2
✓ Branch 2 taken 23 times.
✗ Branch 3 not taken.
23 publish_timestamp = String2Uint64(iter->second);
153
2/5
✓ Branch 2 taken 37 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 37 times.
✗ Branch 6 not taken.
37 if ((iter = content.find('G')) != content.end())
154 37 garbage_collectable = (iter->second == "yes");
155
2/5
✓ Branch 2 taken 37 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 37 times.
✗ Branch 6 not taken.
37 if ((iter = content.find('A')) != content.end())
156 37 has_alt_catalog_path = (iter->second == "yes");
157
2/5
✓ Branch 2 taken 37 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 37 times.
37 if ((iter = content.find('M')) != content.end())
158 meta_info = MkFromHexPtr(shash::HexPtr(iter->second),
159 shash::kSuffixMetainfo);
160
2/5
✓ Branch 2 taken 37 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 37 times.
37 if ((iter = content.find('Y')) != content.end()) {
161 reflog_hash = MkFromHexPtr(shash::HexPtr(iter->second));
162 }
163
164 return new Manifest(catalog_hash, catalog_size, root_path, ttl, revision,
165 micro_catalog_hash, repository_name, certificate,
166 history, publish_timestamp, garbage_collectable,
167
2/4
✓ Branch 1 taken 37 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 37 times.
✗ Branch 5 not taken.
37 has_alt_catalog_path, meta_info, reflog_hash);
168 37 }
169
170
171 188 Manifest::Manifest(const shash::Any &catalog_hash,
172 const uint64_t catalog_size,
173 188 const string &root_path)
174 188 : catalog_hash_(catalog_hash)
175 188 , catalog_size_(catalog_size)
176
1/2
✓ Branch 2 taken 188 times.
✗ Branch 3 not taken.
188 , root_path_(shash::Md5(shash::AsciiPtr(root_path)))
177 188 , ttl_(catalog::Catalog::kDefaultTTL)
178 188 , revision_(0)
179 188 , publish_timestamp_(0)
180 188 , garbage_collectable_(false)
181
4/8
✓ Branch 3 taken 188 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 188 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 188 times.
✗ Branch 10 not taken.
✓ Branch 12 taken 188 times.
✗ Branch 13 not taken.
188 , has_alt_catalog_path_(false)
182 188 { }
183
184
185 /**
186 * Creates the manifest string
187 */
188 48 string Manifest::ExportString() const {
189 string manifest =
190
4/8
✓ Branch 1 taken 48 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 48 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 48 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 48 times.
✗ Branch 11 not taken.
96 "C" + catalog_hash_.ToString() + "\n" +
191
4/8
✓ Branch 1 taken 48 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 48 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 48 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 48 times.
✗ Branch 11 not taken.
192 "B" + StringifyInt(catalog_size_) + "\n" +
192
4/8
✓ Branch 1 taken 48 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 48 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 48 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 48 times.
✗ Branch 11 not taken.
192 "R" + root_path_.ToString() + "\n" +
193
4/8
✓ Branch 1 taken 48 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 48 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 48 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 48 times.
✗ Branch 11 not taken.
192 "D" + StringifyInt(ttl_) + "\n" +
194
4/8
✓ Branch 1 taken 48 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 48 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 48 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 48 times.
✗ Branch 11 not taken.
192 "S" + StringifyInt(revision_) + "\n" +
195
4/8
✓ Branch 1 taken 48 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 48 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 48 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 48 times.
✗ Branch 11 not taken.
192 "G" + StringifyBool(garbage_collectable_) + "\n" +
196
2/4
✓ Branch 2 taken 48 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 48 times.
✗ Branch 6 not taken.
144 "A" + StringifyBool(has_alt_catalog_path_) + "\n";
197
198
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 48 times.
48 if (!micro_catalog_hash_.IsNull())
199 manifest += "L" + micro_catalog_hash_.ToString() + "\n";
200
1/2
✓ Branch 1 taken 48 times.
✗ Branch 2 not taken.
48 if (repository_name_ != "")
201
3/6
✓ Branch 1 taken 48 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 48 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 48 times.
✗ Branch 8 not taken.
48 manifest += "N" + repository_name_ + "\n";
202
1/2
✓ Branch 1 taken 48 times.
✗ Branch 2 not taken.
48 if (!certificate_.IsNull())
203
4/8
✓ Branch 1 taken 48 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 48 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 48 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 48 times.
✗ Branch 11 not taken.
48 manifest += "X" + certificate_.ToString() + "\n";
204
1/2
✓ Branch 1 taken 48 times.
✗ Branch 2 not taken.
48 if (!history_.IsNull())
205
4/8
✓ Branch 1 taken 48 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 48 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 48 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 48 times.
✗ Branch 11 not taken.
48 manifest += "H" + history_.ToString() + "\n";
206
2/2
✓ Branch 0 taken 28 times.
✓ Branch 1 taken 20 times.
48 if (publish_timestamp_ > 0)
207
4/8
✓ Branch 1 taken 28 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 28 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 28 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 28 times.
✗ Branch 11 not taken.
28 manifest += "T" + StringifyInt(publish_timestamp_) + "\n";
208
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 48 times.
48 if (!meta_info_.IsNull())
209 manifest += "M" + meta_info_.ToString() + "\n";
210
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 48 times.
48 if (!reflog_hash_.IsNull()) {
211 manifest += "Y" + reflog_hash_.ToString() + "\n";
212 }
213 // Reserved: Z -> for identification of channel tips
214
215 48 return manifest;
216 }
217
218
219
220 /**
221 * Writes the .cvmfspublished file (unsigned).
222 */
223 2 bool Manifest::Export(const std::string &path) const {
224
1/2
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
2 FILE *fmanifest = fopen(path.c_str(), "w");
225
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (!fmanifest)
226 return false;
227
228
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 string manifest = ExportString();
229
230
2/4
✓ Branch 3 taken 2 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 2 times.
4 if (fwrite(manifest.data(), 1, manifest.length(), fmanifest) !=
231 2 manifest.length())
232 {
233 fclose(fmanifest);
234 unlink(path.c_str());
235 return false;
236 }
237
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 fclose(fmanifest);
238
239 2 return true;
240 2 }
241
242
243 /**
244 * Writes the cvmfschecksum.$repository file. Atomic store.
245 */
246 11 bool Manifest::ExportBreadcrumb(const string &directory, const int mode) const {
247 22 return Breadcrumb(catalog_hash_, publish_timestamp_, revision_).
248
1/2
✓ Branch 1 taken 11 times.
✗ Branch 2 not taken.
22 Export(repository_name_, directory, mode);
249 }
250
251
252 /**
253 * Read the hash and the last-modified time stamp from the
254 * cvmfschecksum.$repository file in the given directory.
255 */
256 29 Breadcrumb Manifest::ReadBreadcrumb(
257 const std::string &repo_name,
258 const std::string &directory)
259 {
260
1/2
✓ Branch 1 taken 29 times.
✗ Branch 2 not taken.
29 Breadcrumb breadcrumb;
261
2/4
✓ Branch 1 taken 29 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 29 times.
✗ Branch 5 not taken.
29 const string breadcrumb_path = directory + "/cvmfschecksum." + repo_name;
262
1/2
✓ Branch 2 taken 29 times.
✗ Branch 3 not taken.
29 FILE *fbreadcrumb = fopen(breadcrumb_path.c_str(), "r");
263
2/2
✓ Branch 0 taken 17 times.
✓ Branch 1 taken 12 times.
29 if (!fbreadcrumb) {
264 // Return invalid breadcrumb if not found
265 17 return breadcrumb;
266 }
267 char tmp[164];
268
1/2
✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
12 const size_t read_bytes = fread(tmp, 1, 164, fbreadcrumb);
269
2/2
✓ Branch 0 taken 11 times.
✓ Branch 1 taken 1 times.
12 if (read_bytes > 0) {
270
2/4
✓ Branch 2 taken 11 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 11 times.
✗ Branch 6 not taken.
11 breadcrumb = Breadcrumb(std::string(tmp, read_bytes));
271 }
272
1/2
✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
12 fclose(fbreadcrumb);
273
274 12 return breadcrumb;
275 29 }
276
277 } // namespace manifest
278