0ce658e3bad656b47dc4d6405133c57a5efe029f
[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     if (!bf::exists(zip_path)) {
104       LOG(WARNING) << "zip path(" << zip_path << ") doesn't exist!";
105       return false;
106     }
107
108     const char* mount_path_str = mount_path_.string().c_str();
109     const char* zip_path_str = zip_path_.string().c_str();
110     const char* tzip_smack_rule = kTzipSmackRule;
111
112     GVariant* r = dbus_proxy_->ProxyCallSync(kTzipMountMethod,
113         g_variant_new("(sss)", mount_path_str, zip_path_str, tzip_smack_rule));
114     if (!r) {
115       LOG(ERROR) << "Could not send DBUS message when mounting zip file";
116       return false;
117     }
118     g_variant_unref(r);
119
120     return WaitForCondition([=]()->bool {
121       return IsMounted();
122     });
123   }
124
125   bool UnmountZip() {
126     const char* mount_path_str = mount_path_.string().c_str();
127
128     GVariant* r = dbus_proxy_->ProxyCallSync(kTzipUnmountMethod,
129         g_variant_new("(s)", mount_path_str));
130     if (!r) {
131       LOG(ERROR) << "Could not send DBUS message when unmounting zip file";
132       return false;
133     }
134     g_variant_unref(r);
135
136     return WaitForCondition([=]()->bool {
137       return IsUnmounted();
138     });
139   }
140
141  private:
142   bool IsMounted() {
143     const char* mount_path_str = mount_path_.string().c_str();
144     GVariant* r = dbus_proxy_->ProxyCallSync(kTzipIsMountedMethod,
145         g_variant_new("(s)", mount_path_str));
146     if (!r)
147       return false;
148
149     gint ret;
150     g_variant_get(r, "(i)", &ret);
151     g_variant_unref(r);
152     return ret != 0;
153   }
154
155   bool IsUnmounted() {
156     return !IsMounted();
157   }
158
159   bool WaitForCondition(std::function<bool()> condition) {
160     if (!mount_path_.empty()) {
161       bool rv = false;
162       int cnt = 0;
163       while (cnt < kTzipMountMaximumRetryCount) {
164         rv = condition();
165         if (rv)
166           break;
167         sleep(1);
168         cnt++;
169       }
170
171       if (!rv) {
172         return false;
173       }
174     }
175     return true;
176   }
177
178   boost::filesystem::path mount_path_;
179   boost::filesystem::path zip_path_;
180   std::unique_ptr<DBusProxy> dbus_proxy_;
181 };
182
183 TzipInterface::TzipInterface(const boost::filesystem::path& mount_path)
184   : impl_(new Pimpl(mount_path)) {}
185
186 TzipInterface::~TzipInterface() { }
187
188 bool TzipInterface::MountZip(const boost::filesystem::path& zip_path) {
189   return impl_->MountZip(zip_path);
190 }
191
192 bool TzipInterface::UnmountZip() {
193   return impl_->UnmountZip();
194 }
195
196 }  // namespace common_installer