Style check
[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 <dbus/dbus.h>
12
13 #include <cstdlib>
14
15 namespace bf = boost::filesystem;
16
17 namespace {
18
19 const char kTzipBusName[] = "org.tizen.system.deviced";
20 const char kTzipObjectPath[] = "/Org/Tizen/System/DeviceD/Tzip";
21 const char kTzipInterfaceName[] = "org.tizen.system.deviced.Tzip";
22 const char kTzipMountMethod[] = "Mount";
23 const char kTzipUnmountMethod[] = "Unmount";
24 const char kTzipIsMountedMethod[] = "IsMounted";
25 const char kTzipSmackRule[] = "User::Home";
26 const int kTzipMountMaximumRetryCount = 15;
27
28 }  // namespace
29
30 void DBusMessageDeleter(DBusMessage* message) {
31   dbus_message_unref(message);
32 }
33
34 void DBusErrorDeleter(DBusError* error) {
35   dbus_error_free(error);
36   std::default_delete<DBusError>();
37 }
38
39 namespace common_installer {
40
41 class TzipInterface::Pimpl {
42  public:
43   explicit Pimpl(const boost::filesystem::path& mount_path) :
44     mount_path_(mount_path) { }
45
46   bool MountZip(const boost::filesystem::path& zip_path) {
47     zip_path_ = zip_path;
48
49     DBusConnection *conn = dbus_bus_get(DBUS_BUS_SYSTEM, nullptr);
50     if (!conn) {
51       return false;
52     }
53
54     if (bf::exists(mount_path_)) {
55       LOG(WARNING) << "Mount path(" << mount_path_ << ") already exists! "
56                    << "We will remove it...";
57       bf::remove(mount_path_);
58     }
59
60     std::unique_ptr<DBusMessage, void(*)(DBusMessage*)> msg(
61         dbus_message_new_method_call(kTzipBusName, kTzipObjectPath,
62                                      kTzipInterfaceName,
63                                      kTzipMountMethod),
64                                      DBusMessageDeleter);
65     if (!msg) {
66       LOG(ERROR) << "Could not create new dbus message";
67       return false;
68     }
69
70     const char* mount_path_str = mount_path_.string().c_str();
71     const char* zip_path_str = zip_path_.string().c_str();
72     const char* tzip_smack_rule = kTzipSmackRule;
73
74     if (!dbus_message_append_args(msg.get(),
75             DBUS_TYPE_STRING, &mount_path_str,
76             DBUS_TYPE_STRING, &zip_path_str,
77             DBUS_TYPE_STRING, &tzip_smack_rule,
78             DBUS_TYPE_INVALID)) {
79       return false;
80     }
81
82     if (dbus_connection_send(conn, msg.get(), nullptr) == FALSE) {
83       LOG(ERROR) << "Could not send DBUS message when mounting zip file";
84       return false;
85     }
86     return WaitForMounted();
87   }
88
89   bool UnmountZip() {
90     DBusConnection *conn = dbus_bus_get(DBUS_BUS_SYSTEM, nullptr);
91     if (!conn) {
92       return false;
93     }
94
95     std::unique_ptr<DBusMessage, void(*)(DBusMessage*)> msg(
96         dbus_message_new_method_call(kTzipBusName, kTzipObjectPath,
97                                      kTzipInterfaceName,
98                                      kTzipUnmountMethod),
99                                      DBusMessageDeleter);
100     if (!msg) {
101       LOG(ERROR) << "Could not create new dbus message";
102       return false;
103     }
104
105     const char* mount_path_str = mount_path_.string().c_str();
106     if (!dbus_message_append_args(msg.get(),
107             DBUS_TYPE_STRING, &mount_path_str,
108             DBUS_TYPE_INVALID)) {
109       return false;
110     }
111
112     if (dbus_connection_send(conn, msg.get(), nullptr) == FALSE) {
113       LOG(ERROR) << "Could not send DBUS message when unmounting zip file";
114       return false;
115     }
116
117     return true;
118   }
119
120  private:
121   bool IsMounted() {
122     int ret = -1;
123     int r = -1;
124     DBusMessage *reply;
125     std::unique_ptr<DBusError, void(*)(DBusError*)> err(new DBusError(),
126                                                         DBusErrorDeleter);
127
128     DBusConnection* conn = dbus_bus_get(DBUS_BUS_SYSTEM, nullptr);
129     if (!conn) {
130       return false;
131     }
132     std::unique_ptr<DBusMessage, void(*)(DBusMessage*)> msg(
133         dbus_message_new_method_call(kTzipBusName, kTzipObjectPath,
134                                      kTzipInterfaceName,
135                                      kTzipIsMountedMethod),
136                                      DBusMessageDeleter);
137     if (!msg) {
138       return false;
139     }
140
141     const char* mount_path_str = mount_path_.string().c_str();
142     if (!dbus_message_append_args(msg.get(),
143             DBUS_TYPE_STRING, &mount_path_str,
144             DBUS_TYPE_INVALID)) {
145       return false;
146     }
147
148     dbus_error_init(err.get());
149     reply = dbus_connection_send_with_reply_and_block(conn, msg.get(), 500,
150                                                       err.get());
151     if (!reply) {
152       return false;
153     }
154
155     r = dbus_message_get_args(reply, err.get(), DBUS_TYPE_INT32, &ret,
156                               DBUS_TYPE_INVALID);
157     if (!r) {
158       return false;
159     }
160
161     return ret != 0;
162   }
163
164   bool WaitForMounted() {
165     if (!mount_path_.empty()) {
166       bool rv = false;
167       int cnt = 0;
168       while (cnt < kTzipMountMaximumRetryCount) {
169         rv = IsMounted();
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   boost::filesystem::path mount_path_;
184   boost::filesystem::path zip_path_;
185 };
186
187
188 TzipInterface::TzipInterface(const boost::filesystem::path& mount_path)
189   : impl_(new Pimpl(mount_path)) {}
190
191 TzipInterface::~TzipInterface() { }
192
193 bool TzipInterface::MountZip(const boost::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