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