Aktualizr
C++ SOTA Client
All Classes Namespaces Files Functions Variables Enumerations Enumerator Pages
ostreereposync.cc
1 #include <ostree.h>
2 
3 #include <cstring>
4 
5 #include <boost/filesystem.hpp>
6 #include <boost/scope_exit.hpp>
7 
8 #include "logging/logging.h"
9 
10 namespace {
11 const OstreeRepoMode kOstreeRepoModeArchive =
12 #if !defined(OSTREE_CHECK_VERSION)
13  OSTREE_REPO_MODE_ARCHIVE_Z2;
14 #elif (OSTREE_CHECK_VERSION(2017, 12))
15  OSTREE_REPO_MODE_ARCHIVE;
16 #else
17  OSTREE_REPO_MODE_ARCHIVE_Z2;
18 #endif
19 } // namespace
20 
21 namespace fs = boost::filesystem;
22 
23 namespace ostree_repo_sync {
24 
25 bool ArchiveModeRepo(const fs::path& repo_dir) {
26  GError* error = nullptr;
27  GFile* repo_path = nullptr;
28  OstreeRepo* repo = nullptr;
29 
30  BOOST_SCOPE_EXIT(&error, &repo_path, &repo) { // NOLINT
31  if (error != nullptr) {
32  g_error_free(error);
33  }
34  if (repo_path != nullptr) {
35  g_object_unref(repo_path);
36  }
37  if (repo != nullptr) {
38  g_object_unref(repo);
39  }
40  }
41  BOOST_SCOPE_EXIT_END
42 
43  repo_path = g_file_new_for_path(repo_dir.c_str());
44  repo = ostree_repo_new(repo_path);
45 
46  gboolean open_succeed = ostree_repo_open(repo, nullptr, &error);
47 
48  return ((open_succeed != 0) && (ostree_repo_get_mode(repo) == kOstreeRepoModeArchive));
49 }
50 
51 bool LocalPullRepo(const fs::path& src_repo_dir, const fs::path& dst_repo_dir, const std::string& ref_hash) {
52  GError* error = nullptr;
53  GVariant* options = nullptr;
54  GHashTable* refs = nullptr;
55  GPtrArray* refs_to_fetch = g_ptr_array_new_with_free_func(g_free);
56  OstreeRepo* src_repo = nullptr;
57  OstreeRepo* dst_repo = nullptr;
58  GFile* src_repo_path = nullptr;
59  GFile* dst_repo_path = nullptr;
60 
61  BOOST_SCOPE_EXIT(&error, &options, &refs, &refs_to_fetch, &src_repo_path, &src_repo, &dst_repo_path, // NOLINT
62  &dst_repo) {
63  if (error != nullptr) {
64  g_error_free(error);
65  }
66  if (options != nullptr) {
67  g_variant_unref(options);
68  }
69  if (src_repo_path != nullptr) {
70  g_object_unref(src_repo_path);
71  }
72  if (src_repo != nullptr) {
73  g_object_unref(src_repo);
74  }
75  if (dst_repo_path != nullptr) {
76  g_object_unref(dst_repo_path);
77  }
78  if (dst_repo != nullptr) {
79  g_object_unref(dst_repo);
80  }
81  if (refs != nullptr) {
82  g_hash_table_unref(refs);
83  }
84  g_ptr_array_unref(refs_to_fetch);
85  }
86  BOOST_SCOPE_EXIT_END
87 
88  // check source repo
89  src_repo_path = g_file_new_for_path(src_repo_dir.c_str());
90  src_repo = ostree_repo_new(src_repo_path);
91  if (ostree_repo_open(src_repo, nullptr, &error) == 0) {
92  LOG_ERROR << "OSTree sync error: unable to open source repo, " << error->message;
93  return false;
94  }
95 
96  // check destination repo
97  dst_repo_path = g_file_new_for_path(dst_repo_dir.c_str());
98  dst_repo = ostree_repo_new(dst_repo_path);
99  if (ostree_repo_create(dst_repo, kOstreeRepoModeArchive, nullptr, &error) == 0) {
100  LOG_ERROR << "OSTree sync error: unable to open destination repo, " << error->message;
101  return false;
102  }
103 
104  // collect refs to pull
105  //
106  // Under some circumstances the following call may not be enough,
107  // see the comment before the same call in OSTree sources
108  // (src/ostree/ot-builtin-pull-local.c).
109  if (ostree_repo_list_refs(src_repo, nullptr, &refs, nullptr, &error) == 0) {
110  LOG_ERROR << "OSTree sync error: unable to get refs on source repo, " << error->message;
111  return false;
112  }
113  {
114  GHashTableIter hashiter;
115  gpointer hkey;
116  gpointer hvalue;
117 
118  g_hash_table_iter_init(&hashiter, refs);
119  while (g_hash_table_iter_next(&hashiter, &hkey, &hvalue) != 0) {
120  g_ptr_array_add(refs_to_fetch, g_strdup(static_cast<const char*>(hkey)));
121  }
122  }
123  g_ptr_array_add(refs_to_fetch, nullptr);
124 
125  // pull from source repo
126  const char* const refs_to_fetch_list[] = {ref_hash.c_str()}; // NOLINT(modernize-avoid-c-arrays)
127  GVariantBuilder builder;
128  g_variant_builder_init(&builder, G_VARIANT_TYPE("a{sv}"));
129  g_variant_builder_add(&builder, "{s@v}", "flags", g_variant_new_variant(g_variant_new_int32(0)));
130  if (strlen(refs_to_fetch_list[0]) == 0) {
131  g_variant_builder_add(
132  &builder, "{s@v}", "refs",
133  g_variant_new_variant(g_variant_new_strv(reinterpret_cast<const char* const*>(refs_to_fetch->pdata), -1)));
134  } else {
135  g_variant_builder_add(&builder, "{s@v}", "refs", g_variant_new_variant(g_variant_new_strv(refs_to_fetch_list, 1)));
136  }
137  options = g_variant_ref_sink(g_variant_builder_end(&builder));
138 
139  std::string src_repo_url("file://");
140  src_repo_url += src_repo_dir.native();
141  if (ostree_repo_pull_with_options(dst_repo, src_repo_url.c_str(), options, nullptr, nullptr, &error) == 0) {
142  LOG_ERROR << "OSTree sync error: unable to pull repository, " << error->message;
143  return false;
144  }
145  return true;
146 }
147 
148 fs::path GetOstreeRepoPath(const fs::path& ostree_sysroot_path) { return (ostree_sysroot_path / "ostree" / "repo"); }
149 
150 } // namespace ostree_repo_sync