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