GCC Code Coverage Report


Directory: cvmfs/
File: cvmfs/swissknife_reflog.cc
Date: 2024-04-28 02:33:07
Exec Total Coverage
Lines: 0 136 0.0%
Branches: 0 56 0.0%

Line Branch Exec Source
1 /**
2 * This file is part of the CernVM File System.
3 */
4
5 #include "swissknife_reflog.h"
6
7 #include <cassert>
8
9 #include <string>
10 #include <vector>
11
12 #include "manifest.h"
13 #include "object_fetcher.h"
14 #include "upload_facility.h"
15 #include "util/exception.h"
16
17 namespace swissknife {
18
19 typedef HttpObjectFetcher<> ObjectFetcher;
20
21 class RootChainWalker {
22 public:
23 typedef ObjectFetcher::CatalogTN CatalogTN;
24 typedef ObjectFetcher::HistoryTN HistoryTN;
25
26 public:
27 RootChainWalker(const manifest::Manifest *manifest,
28 ObjectFetcher *object_fetcher,
29 manifest::Reflog *reflog)
30 : object_fetcher_(object_fetcher)
31 , reflog_(reflog)
32 , manifest_(manifest) {}
33
34 void FindObjectsAndPopulateReflog();
35
36 protected:
37 typedef std::vector<shash::Any> CatalogList;
38
39 protected:
40 CatalogTN* FetchCatalog(const shash::Any catalog_hash);
41 HistoryTN* FetchHistory(const shash::Any history_hash);
42
43 void WalkRootCatalogs(const shash::Any &root_catalog_hash);
44 void WalkHistories(const shash::Any &history_hash);
45
46 bool WalkCatalogsInHistory(const HistoryTN *history);
47 void WalkListedCatalogs(const CatalogList &catalog_list);
48
49 template <class DatabaseT>
50 DatabaseT* ReturnOrAbort(const ObjectFetcherFailures::Failures failure,
51 const shash::Any &content_hash,
52 DatabaseT *database);
53
54 private:
55 ObjectFetcher *object_fetcher_;
56 manifest::Reflog *reflog_;
57 const manifest::Manifest *manifest_;
58 };
59
60
61 ParameterList CommandReconstructReflog::GetParams() const {
62 ParameterList r;
63 r.push_back(Parameter::Mandatory('r', "repository url"));
64 r.push_back(Parameter::Mandatory('u', "spooler definition string"));
65 r.push_back(Parameter::Mandatory('n', "fully qualified repository name"));
66 r.push_back(Parameter::Mandatory('t', "temporary directory"));
67 r.push_back(Parameter::Mandatory('k', "repository keychain"));
68 r.push_back(Parameter::Mandatory('R', "path to reflog.chksum file"));
69 r.push_back(Parameter::Optional('@', "proxy url"));
70 return r;
71 }
72
73
74 int CommandReconstructReflog::Main(const ArgumentList &args) {
75 const std::string &repo_url = *args.find('r')->second;
76 const std::string &spooler = *args.find('u')->second;
77 const std::string &repo_name = *args.find('n')->second;
78 const std::string &tmp_dir = *args.find('t')->second;
79 const std::string &repo_keys = *args.find('k')->second;
80 const std::string &reflog_chksum_path = *args.find('R')->second;
81
82 const bool follow_redirects = false;
83 const std::string proxy = ((args.count('@') > 0) ?
84 *args.find('@')->second : "");
85 if (!this->InitDownloadManager(follow_redirects, proxy) ||
86 !this->InitVerifyingSignatureManager(repo_keys)) {
87 LogCvmfs(kLogCvmfs, kLogStderr, "failed to init repo connection");
88 return 1;
89 }
90
91 ObjectFetcher object_fetcher(repo_name,
92 repo_url,
93 tmp_dir,
94 download_manager(),
95 signature_manager());
96
97 UniquePtr<manifest::Manifest> manifest;
98 ObjectFetcher::Failures retval = object_fetcher.FetchManifest(&manifest);
99 if (retval != ObjectFetcher::kFailOk) {
100 LogCvmfs(kLogCvmfs, kLogStderr, "failed to load repository manifest "
101 "(%d - %s)",
102 retval, Code2Ascii(retval));
103 return 1;
104 }
105
106 const upload::SpoolerDefinition spooler_definition(spooler, shash::kAny);
107 UniquePtr<upload::AbstractUploader> uploader(
108 upload::AbstractUploader::Construct(spooler_definition));
109
110 if (!uploader.IsValid()) {
111 LogCvmfs(kLogCvmfs, kLogStderr, "failed to initialize spooler for '%s'",
112 spooler.c_str());
113 return 1;
114 }
115
116 UniquePtr<manifest::Reflog> reflog(CreateEmptyReflog(tmp_dir, repo_name));
117 reflog->TakeDatabaseFileOwnership();
118
119 reflog->BeginTransaction();
120 AddStaticManifestObjects(reflog.weak_ref(), manifest.weak_ref());
121 RootChainWalker walker(manifest.weak_ref(),
122 &object_fetcher,
123 reflog.weak_ref());
124 walker.FindObjectsAndPopulateReflog();
125 reflog->CommitTransaction();
126
127 LogCvmfs(kLogCvmfs, kLogStdout, "found %lu entries", reflog->CountEntries());
128
129 reflog->DropDatabaseFileOwnership();
130 const std::string reflog_db = reflog->database_file();
131 reflog.Destroy();
132 uploader->UploadFile(reflog_db, ".cvmfsreflog");
133 shash::Any reflog_hash(manifest->GetHashAlgorithm());
134 manifest::Reflog::HashDatabase(reflog_db, &reflog_hash);
135 uploader->WaitForUpload();
136 unlink(reflog_db.c_str());
137
138 const int errors = uploader->GetNumberOfErrors();
139 if (errors > 0) {
140 LogCvmfs(kLogCvmfs, kLogStderr, "failed to upload generated Reflog");
141 }
142
143 uploader->TearDown();
144
145 manifest::Reflog::WriteChecksum(reflog_chksum_path, reflog_hash);
146
147 return (errors == 0) ? 0 : 1;
148 }
149
150
151 void CommandReconstructReflog::AddStaticManifestObjects(
152 manifest::Reflog *reflog,
153 manifest::Manifest *manifest) const {
154 const shash::Any certificate = manifest->certificate();
155 const shash::Any meta_info = manifest->meta_info();
156 assert(!certificate.IsNull());
157
158 bool success = reflog->AddCertificate(certificate);
159 assert(success);
160 LogCvmfs(kLogCvmfs, kLogStdout, "Certificate: %s",
161 certificate.ToString().c_str());
162
163 if (!meta_info.IsNull()) {
164 success = reflog->AddMetainfo(meta_info);
165 assert(success);
166 LogCvmfs(kLogCvmfs, kLogStdout, "Metainfo: %s",
167 meta_info.ToString().c_str());
168 }
169 }
170
171
172 void RootChainWalker::FindObjectsAndPopulateReflog() {
173 const shash::Any root_catalog = manifest_->catalog_hash();
174 const shash::Any history = manifest_->history();
175
176 assert(!root_catalog.IsNull());
177 WalkRootCatalogs(root_catalog);
178
179 if (!history.IsNull()) {
180 WalkHistories(history);
181 }
182 }
183
184
185 void RootChainWalker::WalkRootCatalogs(const shash::Any &root_catalog_hash) {
186 shash::Any current_hash = root_catalog_hash;
187 UniquePtr<CatalogTN> current_catalog;
188
189 while (!current_hash.IsNull() &&
190 !reflog_->ContainsCatalog(current_hash) &&
191 (current_catalog = FetchCatalog(current_hash)).IsValid()) {
192 LogCvmfs(kLogCvmfs, kLogStdout, "Catalog: %s Revision: %" PRIu64,
193 current_hash.ToString().c_str(), current_catalog->GetRevision());
194
195 const bool success = reflog_->AddCatalog(current_hash);
196 assert(success);
197
198 current_hash = current_catalog->GetPreviousRevision();
199 }
200 }
201
202
203 void RootChainWalker::WalkHistories(const shash::Any &history_hash) {
204 shash::Any current_hash = history_hash;
205 UniquePtr<HistoryTN> current_history;
206
207 while (!current_hash.IsNull() &&
208 !reflog_->ContainsHistory(current_hash) &&
209 (current_history = FetchHistory(current_hash)).IsValid()) {
210 LogCvmfs(kLogCvmfs, kLogStdout, "History: %s",
211 current_hash.ToString().c_str());
212
213 bool cancel = WalkCatalogsInHistory(current_history.weak_ref());
214 const bool success = reflog_->AddHistory(current_hash);
215 assert(success);
216
217 if (cancel) {
218 current_hash = shash::Any(current_hash.algorithm);
219 } else {
220 current_hash = current_history->previous_revision();
221 }
222 }
223 }
224
225
226 /**
227 * If false is returned, it indicates that the history database comes from
228 * an early pre-release of the history functionality. The WalkHistory()
229 * iteration will subsequently stop. This is necessary, for instance, to
230 * handle the cernvm-prod.cern.ch repository.
231 */
232 bool RootChainWalker::WalkCatalogsInHistory(const HistoryTN *history) {
233 CatalogList tag_hashes;
234 const bool list_success = history->GetHashes(&tag_hashes);
235 assert(list_success);
236
237 CatalogList bin_hashes;
238 const bool bin_success = history->ListRecycleBin(&bin_hashes);
239 if (!bin_success) {
240 LogCvmfs(kLogCvmfs, kLogStderr, " Warning: 'recycle bin' table missing");
241 }
242
243 WalkListedCatalogs(tag_hashes);
244 WalkListedCatalogs(bin_hashes);
245
246 return !bin_success;
247 }
248
249
250 void RootChainWalker::WalkListedCatalogs(
251 const RootChainWalker::CatalogList &catalog_list) {
252 CatalogList::const_iterator i = catalog_list.begin();
253 CatalogList::const_iterator iend = catalog_list.end();
254 for (; i != iend; ++i) {
255 WalkRootCatalogs(*i);
256 }
257 }
258
259
260 RootChainWalker::CatalogTN* RootChainWalker::FetchCatalog(
261 const shash::Any catalog_hash) {
262 CatalogTN *catalog = NULL;
263 const char *root_path = "";
264 ObjectFetcherFailures::Failures failure =
265 object_fetcher_->FetchCatalog(catalog_hash, root_path, &catalog);
266
267 return ReturnOrAbort(failure, catalog_hash, catalog);
268 }
269
270
271 RootChainWalker::HistoryTN* RootChainWalker::FetchHistory(
272 const shash::Any history_hash) {
273 HistoryTN *history = NULL;
274 ObjectFetcherFailures::Failures failure =
275 object_fetcher_->FetchHistory(&history, history_hash);
276
277 return ReturnOrAbort(failure, history_hash, history);
278 }
279
280
281 template <class DatabaseT>
282 DatabaseT* RootChainWalker::ReturnOrAbort(
283 const ObjectFetcherFailures::Failures failure,
284 const shash::Any &content_hash,
285 DatabaseT *database) {
286 switch (failure) {
287 case ObjectFetcherFailures::kFailOk:
288 return database;
289 case ObjectFetcherFailures::kFailNotFound:
290 return NULL;
291 default:
292 PANIC(kLogStderr, "Failed to load object '%s' (%d - %s)",
293 content_hash.ToStringWithSuffix().c_str(), failure,
294 Code2Ascii(failure));
295 }
296 }
297
298 } // namespace swissknife
299