Remove boost dependency
[platform/core/appfw/app-installers.git] / src / common / tzip_interface.cc
1 // Copyright (c) 2016 Samsung Electronics Co., Ltd All Rights Reserved
2 // Use of this source code is governed by an apache 2.0 license that can be
3 // found in the LICENSE file.
4
5 #include "common/tzip_interface.h"
6
7 #include <manifest_parser/utils/logging.h>
8
9 #include <gio/gio.h>
10 #include <glib.h>
11
12 #include <cstdlib>
13 #include <functional>
14 #include <filesystem>
15
16 namespace fs = std::filesystem;
17
18 namespace {
19
20 const char kTzipBusName[] = "org.tizen.system.deviced";
21 const char kTzipObjectPath[] = "/Org/Tizen/System/DeviceD/Tzip";
22 const char kTzipInterfaceName[] = "org.tizen.system.deviced.Tzip";
23 const char kTzipMountMethod[] = "Mount";
24 const char kTzipUnmountMethod[] = "Unmount";
25 const char kTzipIsMountedMethod[] = "IsMounted";
26 const char kTzipSmackRule[] = "User::Home";
27 const int kTzipMountMaximumRetryCount = 15;
28
29 }  // namespace
30
31 namespace common_installer {
32
33 class DBusProxy {
34  public:
35   DBusProxy() : conn_(nullptr), proxy_(nullptr) {
36     if (!Init())
37       LOG(ERROR) << "Failed to initialize DBus proxy";
38   }
39
40   ~DBusProxy() {
41     if (proxy_)
42       g_object_unref(proxy_);
43     if (conn_) {
44       g_dbus_connection_flush_sync(conn_, nullptr, nullptr);
45       g_object_unref(conn_);
46     }
47   }
48
49   bool Init() {
50     GError* error = nullptr;
51     conn_ = g_bus_get_sync(G_BUS_TYPE_SYSTEM, nullptr, &error);
52     if (!conn_ || error) {
53       LOG(ERROR) << "g_bus_get_sync() failed: " << error->message;
54       g_error_free(error);
55       return false;
56     }
57     proxy_ = g_dbus_proxy_new_sync(conn_, G_DBUS_PROXY_FLAGS_NONE, nullptr,
58         kTzipBusName, kTzipObjectPath, kTzipInterfaceName, nullptr, &error);
59     if (!proxy_ || error) {
60       LOG(ERROR) << "g_dbus_proxy_new_sync() failed: " << error->message;
61       g_error_free(error);
62       return false;
63     }
64     return true;
65   }
66
67   GVariant* ProxyCallSync(const char* method, GVariant* params) {
68     if (!proxy_) {
69       LOG(ERROR) << "DBus proxy is not initialized";
70       return nullptr;
71     }
72     GError* error = nullptr;
73     GVariant* ret = g_dbus_proxy_call_sync(proxy_, method,
74         params, G_DBUS_CALL_FLAGS_NONE, -1, nullptr, &error);
75     if (error) {
76       LOG(ERROR) << "g_dbus_proxy_call_sync() of " << method << " failed: "
77                  << error->message;
78       g_error_free(error);
79     }
80     return ret;
81   }
82
83  private:
84   GDBusConnection* conn_;
85   GDBusProxy* proxy_;
86 };
87
88 class TzipInterface::Pimpl {
89  public:
90   explicit Pimpl(const std::filesystem::path& mount_path) :
91     mount_path_(mount_path), dbus_proxy_(new DBusProxy()) { }
92
93   bool MountZip(const std::filesystem::path& zip_path) {
94     zip_path_ = zip_path;
95
96     if (IsMounted()) {
97       LOG(WARNING) << "Mount path(" << mount_path_
98           << ") already mounted, try to unmount";
99       UnmountZip();
100     }
101
102     if (fs::exists(mount_path_)) {
103       LOG(WARNING) << "Mount path(" << mount_path_ << ") already exists! "
104                    << "We will remove it...";
105       fs::remove(mount_path_);
106     }
107
108     if (!fs::exists(zip_path)) {
109       LOG(WARNING) << "zip path(" << zip_path << ") doesn't exist!";
110       return false;
111     }
112
113     const char* mount_path_str = mount_path_.c_str();
114     const char* zip_path_str = zip_path_.c_str();
115     const char* tzip_smack_rule = kTzipSmackRule;
116
117     GVariant* r = dbus_proxy_->ProxyCallSync(kTzipMountMethod,
118         g_variant_new("(sss)", mount_path_str, zip_path_str, tzip_smack_rule));
119     if (!r) {
120       LOG(ERROR) << "Could not send DBUS message when mounting zip file";
121       return false;
122     }
123     g_variant_unref(r);
124
125     return WaitForCondition([=]()->bool {
126       return IsMounted();
127     });
128   }
129
130   bool UnmountZip() {
131     const char* mount_path_str = mount_path_.c_str();
132
133     GVariant* r = dbus_proxy_->ProxyCallSync(kTzipUnmountMethod,
134         g_variant_new("(s)", mount_path_str));
135     if (!r) {
136       LOG(ERROR) << "Could not send DBUS message when unmounting zip file";
137       return false;
138     }
139     g_variant_unref(r);
140
141     return WaitForCondition([=]()->bool {
142       return IsUnmounted();
143     });
144   }
145
146  private:
147   bool IsMounted() {
148     const char* mount_path_str = mount_path_.c_str();
149     GVariant* r = dbus_proxy_->ProxyCallSync(kTzipIsMountedMethod,
150         g_variant_new("(s)", mount_path_str));
151     if (!r)
152       return false;
153
154     gint ret;
155     g_variant_get(r, "(i)", &ret);
156     g_variant_unref(r);
157     return ret != 0;
158   }
159
160   bool IsUnmounted() {
161     return !IsMounted();
162   }
163
164   bool WaitForCondition(std::function<bool()> condition) {
165     if (!mount_path_.empty()) {
166       bool rv = false;
167       int cnt = 0;
168       while (cnt < kTzipMountMaximumRetryCount) {
169         rv = condition();
170         if (rv)
171           break;
172         sleep(1);
173         cnt++;
174       }
175
176       if (!rv) {
177         return false;
178       }
179     }
180     return true;
181   }
182
183   std::filesystem::path mount_path_;
184   std::filesystem::path zip_path_;
185   std::unique_ptr<DBusProxy> dbus_proxy_;
186 };
187
188 TzipInterface::TzipInterface(const std::filesystem::path& mount_path)
189   : impl_(new Pimpl(mount_path)) {}
190
191 TzipInterface::~TzipInterface() { }
192
193 bool TzipInterface::MountZip(const std::filesystem::path& zip_path) {
194   return impl_->MountZip(zip_path);
195 }
196
197 bool TzipInterface::UnmountZip() {
198   return impl_->UnmountZip();
199 }
200
201 }  // namespace common_installer