CernVM-FS  2.13.0
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
object_fetcher.h
Go to the documentation of this file.
1 
5 #ifndef CVMFS_OBJECT_FETCHER_H_
6 #define CVMFS_OBJECT_FETCHER_H_
7 
8 #include <unistd.h>
9 
10 #include <string>
11 
12 #include "catalog.h"
13 #include "crypto/signature.h"
14 #include "history_sqlite.h"
15 #include "manifest.h"
16 #include "manifest_fetch.h"
17 #include "network/download.h"
18 #include "reflog.h"
19 #include "util/posix.h"
20 
31 template<class ConcreteObjectFetcherT>
33 
35  enum Failures {
45 
47  };
48 };
49 
50 inline const char *Code2Ascii(const ObjectFetcherFailures::Failures error) {
51  const char *texts[ObjectFetcherFailures::kFailNumEntries + 1];
52  texts[0] = "OK";
53  texts[1] = "object not found";
54  texts[2] = "local I/O failure";
55  texts[3] = "network failure";
56  texts[4] = "decompression failed";
57  texts[5] = "manifest name doesn't match";
58  texts[6] = "manifest signature is invalid";
59  texts[7] = "bad data received";
60  texts[8] = "no text";
61  return texts[error];
62 }
63 
80 template<class DerivedT>
82  public:
86 
88 
89  static const std::string kManifestFilename;
90  static const std::string kReflogFilename;
91 
92  public:
101  return static_cast<DerivedT *>(this)->FetchManifest(manifest);
102  }
103 
116  const shash::Any &history_hash = shash::Any()) {
117  // retrieve the current HEAD history hash (if nothing else given)
118  shash::Any effective_history_hash = (!history_hash.IsNull())
119  ? history_hash
120  : GetHistoryHash();
121  if (effective_history_hash.IsNull()) {
122  return kFailNotFound;
123  }
124  assert(history_hash.suffix == shash::kSuffixHistory
125  || history_hash.IsNull());
126 
127  // download the history hash
128  std::string path;
129  const Failures retval = Fetch(effective_history_hash, &path);
130  if (retval != kFailOk) {
131  return retval;
132  }
133 
134  // open the history file
135  *history = HistoryTN::Open(path);
136  if (NULL == *history) {
137  return kFailLocalIO;
138  }
139 
140  (*history)->TakeDatabaseFileOwnership();
141  return kFailOk;
142  }
143 
155  Failures FetchCatalog(const shash::Any &catalog_hash,
156  const std::string &catalog_path,
157  CatalogTN **catalog,
158  const bool is_nested = false,
159  CatalogTN *parent = NULL) {
160  assert(!catalog_hash.IsNull());
161  assert(catalog_hash.suffix == shash::kSuffixCatalog);
162 
163  std::string path;
164  const Failures retval = Fetch(catalog_hash, &path);
165  if (retval != kFailOk) {
166  return retval;
167  }
168 
169  *catalog = CatalogTN::AttachFreely(
170  catalog_path, path, catalog_hash, parent, is_nested);
171  if (NULL == *catalog) {
172  return kFailLocalIO;
173  }
174 
175  (*catalog)->TakeDatabaseFileOwnership();
176  return kFailOk;
177  }
178 
179  Failures FetchReflog(const shash::Any &reflog_hash, ReflogTN **reflog) {
180  assert(!reflog_hash.IsNull());
181  assert(reflog_hash.suffix == shash::kSuffixNone);
182 
183  std::string tmp_path;
184  const bool decompress = false;
185  const bool nocache = true;
186  Failures failure = Fetch(kReflogFilename, decompress, nocache, &tmp_path);
187  if (failure != kFailOk) {
188  return failure;
189  }
190 
191  // Ensure data integrity
192  shash::Any computed_hash(reflog_hash.algorithm);
193  ReflogTN::HashDatabase(tmp_path, &computed_hash);
194  if (computed_hash != reflog_hash) {
195  unlink(tmp_path.c_str());
196  return kFailBadData;
197  }
198 
199  *reflog = ReflogTN::Open(tmp_path);
200  if (NULL == *reflog) {
201  return kFailLocalIO;
202  }
203 
204  (*reflog)->TakeDatabaseFileOwnership();
205  return kFailOk;
206  }
207 
209  manifest::Manifest *raw_manifest_ptr = NULL;
210  Failures failure = FetchManifest(&raw_manifest_ptr);
211  if (failure == kFailOk)
212  *manifest = raw_manifest_ptr;
213  return failure;
214  }
215 
217  const shash::Any &history_hash = shash::Any()) {
218  HistoryTN *raw_history_ptr = NULL;
219  Failures failure = FetchHistory(&raw_history_ptr, history_hash);
220  if (failure == kFailOk)
221  *history = raw_history_ptr;
222  return failure;
223  }
224 
225  Failures FetchCatalog(const shash::Any &catalog_hash,
226  const std::string &catalog_path,
227  UniquePtr<CatalogTN> *catalog,
228  const bool is_nested = false,
229  CatalogTN *parent = NULL) {
230  CatalogTN *raw_catalog_ptr = NULL;
231  Failures failure = FetchCatalog(
232  catalog_hash, catalog_path, &raw_catalog_ptr, is_nested, parent);
233  if (failure == kFailOk)
234  *catalog = raw_catalog_ptr;
235  return failure;
236  }
237 
238  Failures FetchReflog(const shash::Any &reflog_hash,
240  ReflogTN *raw_reflog_ptr = NULL;
241  Failures failure = FetchReflog(reflog_hash, &raw_reflog_ptr);
242  if (failure == kFailOk)
243  *reflog = raw_reflog_ptr;
244  return failure;
245  }
246 
247  std::string GetUrl(const shash::Any &hash) const {
248  return static_cast<DerivedT *>(this)->GetUrl(hash);
249  }
250 
251  bool HasHistory() {
252  shash::Any history_hash = GetHistoryHash();
253  return !history_hash.IsNull();
254  }
255 
256  const std::string &temporary_directory() const {
257  return temporary_directory_;
258  }
259 
260  protected:
261  explicit AbstractObjectFetcher(const std::string &temp_dir)
262  : temporary_directory_(temp_dir) { }
263 
273  Failures Fetch(const shash::Any &object_hash, std::string *file_path) {
274  return static_cast<DerivedT *>(this)->Fetch(object_hash, file_path);
275  }
276 
277  Failures Fetch(const std::string &relative_path,
278  const bool decompress,
279  const bool nocache,
280  std::string *file_path) {
281  return static_cast<DerivedT *>(this)->Fetch(
282  relative_path, decompress, nocache, file_path);
283  }
284 
293  const Failures retval = FetchManifest(&manifest);
294 
295  if (retval != kFailOk || !manifest.IsValid()
296  || manifest->history().IsNull()) {
297  return shash::Any();
298  }
299 
300  return manifest->history();
301  }
302 
303  private:
304  const std::string temporary_directory_;
305 };
306 
307 template<class DerivedT>
308 const std::string
310 template<class DerivedT>
311 const std::string
313 
314 
320 template<class CatalogT = catalog::Catalog,
321  class HistoryT = history::SqliteHistory,
322  class ReflogT = manifest::Reflog>
324  : public AbstractObjectFetcher<
325  LocalObjectFetcher<CatalogT, HistoryT, ReflogT> > {
326  protected:
329 
330  public:
331  typedef typename BaseTN::Failures Failures;
332 
333  public:
340  LocalObjectFetcher(const std::string &base_path, const std::string &temp_dir)
341  : BaseTN(temp_dir), base_path_(base_path) { }
342 
343  using BaseTN::FetchManifest; // un-hiding convenience overload
345  const std::string path = BuildPath(BaseTN::kManifestFilename);
346  if (!FileExists(path)) {
347  return BaseTN::kFailNotFound;
348  }
349 
350  *manifest = manifest::Manifest::LoadFile(path);
351  return (*manifest != NULL) ? BaseTN::kFailOk : BaseTN::kFailUnknown;
352  }
353 
354  std::string GetUrl(const shash::Any &hash) const {
355  return "file://" + BuildPath(BuildRelativePath(hash));
356  }
357 
358  Failures Fetch(const shash::Any &object_hash, std::string *file_path) {
359  assert(file_path != NULL);
360  file_path->clear();
361 
362  const std::string relative_path = BuildRelativePath(object_hash);
363  const bool decompress = true;
364  const bool nocache = false;
365  return Fetch(relative_path, decompress, nocache, file_path);
366  }
367 
368 
369  Failures Fetch(const std::string &relative_path,
370  const bool decompress,
371  const bool /* nocache */,
372  std::string *file_path) {
373  assert(file_path != NULL);
374  file_path->clear();
375 
376  // check if the requested file object is available locally
377  const std::string source = BuildPath(relative_path);
378  if (!FileExists(source)) {
379  LogCvmfs(kLogDownload, kLogDebug, "failed to locate file '%s'",
380  relative_path.c_str());
381  return BaseTN::kFailNotFound;
382  }
383 
384  // create a temporary file to store the (decompressed) object file
385  const std::string tmp_path = BaseTN::temporary_directory() + "/"
386  + GetFileName(relative_path);
387  FILE *f = CreateTempFile(tmp_path, 0600, "w", file_path);
388  if (NULL == f) {
390  "failed to create temp file '%s' (errno: %d)", tmp_path.c_str(),
391  errno);
392  return BaseTN::kFailLocalIO;
393  }
394 
395  // decompress or copy the requested object file
396  const bool success = (decompress) ? zlib::DecompressPath2File(source, f)
397  : CopyPath2File(source, f);
398  fclose(f);
399 
400  // check the decompression success and remove the temporary file otherwise
401  if (!success) {
403  "failed to fetch file from '%s' "
404  "to '%s' (errno: %d)",
405  source.c_str(), file_path->c_str(), errno);
406  unlink(file_path->c_str());
407  file_path->clear();
409  }
410 
411  return BaseTN::kFailOk;
412  }
413 
414  protected:
415  std::string BuildPath(const std::string &relative_path) const {
416  return base_path_ + "/" + relative_path;
417  }
418 
419  std::string BuildRelativePath(const shash::Any &hash) const {
420  return "data/" + hash.MakePath();
421  }
422 
423  private:
424  const std::string base_path_;
425 };
426 
427 template<class CatalogT, class HistoryT, class ReflogT>
428 struct object_fetcher_traits<LocalObjectFetcher<CatalogT, HistoryT, ReflogT> > {
429  typedef CatalogT CatalogTN;
430  typedef HistoryT HistoryTN;
431  typedef ReflogT ReflogTN;
432 };
433 
434 
440 template<class CatalogT = catalog::Catalog,
441  class HistoryT = history::SqliteHistory,
442  class ReflogT = manifest::Reflog>
444  HttpObjectFetcher<CatalogT, HistoryT, ReflogT> > {
445  protected:
448 
449  public:
450  typedef typename BaseTN::Failures Failures;
451 
452  public:
465  HttpObjectFetcher(const std::string &repo_name,
466  const std::string &repo_url,
467  const std::string &temp_dir,
468  download::DownloadManager *download_mgr,
470  : BaseTN(temp_dir)
471  , repo_url_(repo_url)
472  , repo_name_(repo_name)
473  , download_manager_(download_mgr)
474  , signature_manager_(signature_mgr) { }
475 
476  public:
477  using BaseTN::FetchManifest; // un-hiding convenience overload
479  const std::string url = BuildUrl(BaseTN::kManifestFilename);
480 
481  // Download manifest file
482  struct manifest::ManifestEnsemble manifest_ensemble;
484  repo_name_,
485  0,
486  NULL,
489  &manifest_ensemble);
490 
491  // Check if manifest was loaded correctly
492  switch (retval) {
493  case manifest::kFailOk:
494  break;
495 
498  "repository name mismatch. No name provided?");
500 
505  "repository signature mismatch. No key(s) provided?");
507 
508  default:
509  LogCvmfs(kLogDownload, kLogDebug, "failed to load manifest (%d - %s)",
510  retval, Code2Ascii(retval));
511  return BaseTN::kFailUnknown;
512  }
513 
514  assert(retval == manifest::kFailOk);
515  *manifest = new manifest::Manifest(*manifest_ensemble.manifest);
516  return (*manifest != NULL) ? BaseTN::kFailOk : BaseTN::kFailUnknown;
517  }
518 
519  std::string GetUrl(const shash::Any &hash) const {
520  return BuildUrl(BuildRelativeUrl(hash));
521  }
522 
523  Failures Fetch(const shash::Any &object_hash, std::string *object_file) {
524  assert(object_file != NULL);
525  assert(!object_hash.IsNull());
526 
527  const bool decompress = true;
528  const bool nocache = false;
529  const std::string url = BuildRelativeUrl(object_hash);
530  return Download(url, decompress, nocache, &object_hash, object_file);
531  }
532 
533  Failures Fetch(const std::string &relative_path,
534  const bool decompress,
535  const bool nocache,
536  std::string *file_path) {
537  const shash::Any *expected_hash = NULL;
538  return Download(relative_path, decompress, nocache, expected_hash,
539  file_path);
540  }
541 
542  protected:
543  std::string BuildUrl(const std::string &relative_path) const {
544  return repo_url_ + "/" + relative_path;
545  }
546 
547  std::string BuildRelativeUrl(const shash::Any &hash) const {
548  return "data/" + hash.MakePath();
549  }
550 
551  Failures Download(const std::string &relative_path,
552  const bool decompress,
553  const bool nocache,
554  const shash::Any *expected_hash,
555  std::string *file_path) {
556  file_path->clear();
557 
558  // create temporary file to host the fetching result
559  const std::string tmp_path = BaseTN::temporary_directory() + "/"
560  + GetFileName(relative_path);
561  FILE *f = CreateTempFile(tmp_path, 0600, "w", file_path);
562  if (NULL == f) {
564  "failed to create temp file '%s' (errno: %d)", tmp_path.c_str(),
565  errno);
566  return BaseTN::kFailLocalIO;
567  }
568 
569  // fetch and decompress the requested object
570  const std::string url = BuildUrl(relative_path);
571  const bool probe_hosts = false;
572  cvmfs::FileSink filesink(f);
573  download::JobInfo download_job(&url, decompress, probe_hosts, expected_hash,
574  &filesink);
575  download_job.SetForceNocache(nocache);
576  download::Failures retval = download_manager_->Fetch(&download_job);
577  const bool success = (retval == download::kFailOk);
578  fclose(f);
579 
580  // check if download worked and remove temporary file if not
581  if (!success) {
583  "failed to download file "
584  "%s to '%s' (%d - %s)",
585  relative_path.c_str(), file_path->c_str(), retval,
586  Code2Ascii(retval));
587  unlink(file_path->c_str());
588  file_path->clear();
589 
590  // hand out the error status
591  switch (retval) {
593  return BaseTN::kFailLocalIO;
594 
600  "HTTP connection error %d: %s", retval, url.c_str());
601  return BaseTN::kFailNetwork;
602 
605  if (download_job.http_code() == 404)
606  return BaseTN::kFailNotFound;
608  "HTTP protocol error %d: %s (%d)", download_job.http_code(),
609  url.c_str(), retval);
610  return BaseTN::kFailNetwork;
611 
614  return BaseTN::kFailBadData;
615 
616  default:
618  || download::IsHostTransferError(retval)) {
620  "HTTP transfer error %d (HTTP code %d): %s", retval,
621  download_job.http_code(), url.c_str());
622  return BaseTN::kFailNetwork;
623  }
624  return BaseTN::kFailUnknown;
625  }
626  }
627 
628  assert(success);
629  return BaseTN::kFailOk;
630  }
631 
632  private:
633  const std::string repo_url_;
634  const std::string repo_name_;
637 };
638 
639 template<class CatalogT, class HistoryT, class ReflogT>
640 struct object_fetcher_traits<HttpObjectFetcher<CatalogT, HistoryT, ReflogT> > {
641  typedef CatalogT CatalogTN;
642  typedef HistoryT HistoryTN;
643  typedef ReflogT ReflogTN;
644 };
645 
646 #endif // CVMFS_OBJECT_FETCHER_H_
const char * Code2Ascii(const ObjectFetcherFailures::Failures error)
bool IsNull() const
Definition: hash.h:371
const manifest::Manifest * manifest() const
Definition: repository.h:125
NameString GetFileName(const PathString &path)
Definition: shortstring.cc:28
ObjectFetcherFailures::Failures Failures
Failures Fetch(const shash::Any &object_hash, std::string *file_path)
CVMFS_EXPORT const LogSource source
Definition: exception.h:33
FILE * CreateTempFile(const std::string &path_prefix, const int mode, const char *open_flags, std::string *final_path)
Definition: posix.cc:1013
void Open()
const history::History * history() const
Failures FetchReflog(const shash::Any &reflog_hash, ReflogTN **reflog)
std::string BuildRelativeUrl(const shash::Any &hash) const
Failures FetchHistory(HistoryTN **history, const shash::Any &history_hash=shash::Any())
const std::string temporary_directory_
Failures FetchManifest(UniquePtr< manifest::Manifest > *manifest)
Failures FetchManifest(manifest::Manifest **manifest)
assert((mem||(size==0))&&"Out Of Memory")
Failures FetchReflog(const shash::Any &reflog_hash, UniquePtr< ReflogTN > *reflog)
Algorithms algorithm
Definition: hash.h:122
shash::Any GetHistoryHash()
object_fetcher_traits< DerivedT >::ReflogTN ReflogTN
std::string BuildUrl(const std::string &relative_path) const
std::string BuildPath(const std::string &relative_path) const
bool CopyPath2File(const std::string &src, FILE *fdest)
Definition: compression.cc:46
const std::string repo_name_
int http_code() const
Definition: jobinfo.h:201
bool FileExists(const std::string &path)
Definition: posix.cc:803
AbstractObjectFetcher< ThisTN > BaseTN
BaseTN::Failures Failures
object_fetcher_traits< DerivedT >::CatalogTN CatalogTN
Failures Fetch(const std::string &relative_path, const bool decompress, const bool nocache, std::string *file_path)
std::string GetUrl(const shash::Any &hash) const
void SetForceNocache(bool force_nocache)
Definition: jobinfo.h:223
signature::SignatureManager * signature_manager_
const char kSuffixCatalog
Definition: hash.h:54
Failures FetchCatalog(const shash::Any &catalog_hash, const std::string &catalog_path, CatalogTN **catalog, const bool is_nested=false, CatalogTN *parent=NULL)
Failures Fetch(const std::string &base_url, const std::string &repository_name, const uint64_t minimum_timestamp, const shash::Any *base_catalog, signature::SignatureManager *signature_manager, download::DownloadManager *download_manager, ManifestEnsemble *ensemble)
bool DecompressPath2File(const string &src, FILE *fdest)
Definition: compression.cc:681
const signature::SignatureManager * signature_mgr() const
Definition: repository.h:121
const std::string repo_url_
bool IsProxyTransferError(const Failures error)
download::DownloadManager * download_manager_
object_fetcher_traits< DerivedT >::HistoryTN HistoryTN
HttpObjectFetcher< CatalogT, HistoryT, ReflogT > ThisTN
BaseTN::Failures Failures
HttpObjectFetcher(const std::string &repo_name, const std::string &repo_url, const std::string &temp_dir, download::DownloadManager *download_mgr, signature::SignatureManager *signature_mgr)
Failures FetchCatalog(const shash::Any &catalog_hash, const std::string &catalog_path, UniquePtr< CatalogTN > *catalog, const bool is_nested=false, CatalogTN *parent=NULL)
bool IsValid() const
Definition: pointer.h:47
const std::string base_path_
const char kSuffixHistory
Definition: hash.h:55
AbstractObjectFetcher< ThisTN > BaseTN
LocalObjectFetcher< CatalogT, HistoryT, ReflogT > ThisTN
static const std::string kReflogFilename
Failures Fetch(JobInfo *info)
Definition: download.cc:1982
LocalObjectFetcher(const std::string &base_path, const std::string &temp_dir)
Failures FetchManifest(manifest::Manifest **manifest)
Failures FetchHistory(UniquePtr< HistoryTN > *history, const shash::Any &history_hash=shash::Any())
Failures FetchManifest(manifest::Manifest **manifest)
Failures Download(const std::string &relative_path, const bool decompress, const bool nocache, const shash::Any *expected_hash, std::string *file_path)
bool IsHostTransferError(const Failures error)
Failures Fetch(const shash::Any &object_hash, std::string *object_file)
Failures Fetch(const std::string &relative_path, const bool decompress, const bool, std::string *file_path)
std::string GetUrl(const shash::Any &hash) const
static const std::string kManifestFilename
Suffix suffix
Definition: hash.h:123
std::string MakePath() const
Definition: hash.h:306
Failures Fetch(const std::string &relative_path, const bool decompress, const bool nocache, std::string *file_path)
static Manifest * LoadFile(const std::string &path)
Definition: manifest.cc:91
Failures Fetch(const shash::Any &object_hash, std::string *file_path)
const std::string & temporary_directory() const
AbstractObjectFetcher(const std::string &temp_dir)
const char kSuffixNone
Definition: hash.h:53
std::string BuildRelativePath(const shash::Any &hash) const
std::string GetUrl(const shash::Any &hash) const
CVMFS_EXPORT void LogCvmfs(const LogSource source, const int mask, const char *format,...)
Definition: logging.cc:545