a70c101e609c31b359faadd40e67da3cf424ae72
[platform/core/appfw/app-installers.git] / src / common / external_storage.cc
1 // Copyright (c) 2015 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/external_storage.h"
6
7 #include <glib.h>
8
9 #include <manifest_parser/utils/logging.h>
10
11 #include "common/utils/byte_size_literals.h"
12 #include "common/utils/file_util.h"
13 #include "common/utils/request.h"
14
15 namespace bf = boost::filesystem;
16
17 namespace {
18
19 const char kWgtType[] = "wgt";
20 const char kExternalDirForWgt[] = "res";
21
22 const std::vector<std::string> kExternalDirsForTpk = {
23   "bin",
24   "lib",
25   "res"
26 };
27
28 int64_t SizeInMB(int64_t size) {
29   return (size + 1_MB - 1) / 1_MB;
30 }
31
32 void ClearApp2ExtDirDetail(gpointer data) {
33   app2ext_dir_details* dir_detail =
34       reinterpret_cast<app2ext_dir_details*>(data);
35   if (dir_detail->name)
36     free(dir_detail->name);
37   free(dir_detail);
38 }
39
40 }  // namespace
41
42 namespace common_installer {
43
44 ExternalStorage::ExternalStorage(RequestType type,
45     const std::string& pkgid, const std::string& package_type,
46     const boost::filesystem::path& application_root, uid_t uid)
47     : type_(type),
48       pkgid_(pkgid),
49       package_type_(package_type),
50       application_root_(application_root),
51       uid_(uid),
52       move_type_(-1),
53       handle_(nullptr) {
54   if (package_type_ == kWgtType)
55     external_dirs_.push_back(kExternalDirForWgt);
56   else
57     external_dirs_ = kExternalDirsForTpk;
58 }
59
60 ExternalStorage::ExternalStorage(RequestType type,
61     const std::string& pkgid, const std::string& package_type,
62     const boost::filesystem::path& application_root, uid_t uid,
63     bool is_external_move)
64     : type_(type),
65       pkgid_(pkgid),
66       package_type_(package_type),
67       application_root_(application_root),
68       uid_(uid),
69       handle_(nullptr) {
70   if (package_type_ == kWgtType)
71     external_dirs_.push_back(kExternalDirForWgt);
72   else
73     external_dirs_ = kExternalDirsForTpk;
74
75   if (is_external_move)
76     move_type_ = APP2EXT_MOVE_TO_EXT;
77   else
78     move_type_ = APP2EXT_MOVE_TO_PHONE;
79 }
80
81 ExternalStorage::ExternalStorage(RequestType type,
82     const std::string& pkgid, uid_t uid)
83     : type_(type),
84       pkgid_(pkgid),
85       uid_(uid),
86       move_type_(-1),
87       handle_(nullptr) {
88 }
89
90 ExternalStorage::~ExternalStorage() {
91 }
92
93 bool ExternalStorage::Finalize(bool success) {
94   int ret = APP2EXT_STATUS_SUCCESS;
95   switch (type_) {
96   case RequestType::Install:
97     ret = handle_->interface.client_usr_post_install(pkgid_.c_str(),
98         success ? APP2EXT_STATUS_SUCCESS : APP2EXT_STATUS_FAILED, uid_);
99     break;
100   case RequestType::Update:
101   case RequestType::Delta:
102     ret = handle_->interface.client_usr_post_upgrade(pkgid_.c_str(),
103         success ? APP2EXT_STATUS_SUCCESS : APP2EXT_STATUS_FAILED, uid_);
104     break;
105   case RequestType::Uninstall:
106     ret = handle_->interface.client_usr_post_uninstall(pkgid_.c_str(), uid_);
107     break;
108   case RequestType::Move:
109     ret = handle_->interface.client_usr_post_move(pkgid_.c_str(),
110                                static_cast<app2ext_move_type_t>(move_type_),
111                                uid_);
112     break;
113   case RequestType::MigrateExtImg:
114     ret = handle_->interface.client_usr_post_migrate_legacy(pkgid_.c_str(),
115                                                             uid_);
116     break;
117   default:
118     LOG(ERROR) << "Not supported installation mode ("
119                << GetRequestTypeString(type_) << ")";
120   }
121   return ret == APP2EXT_STATUS_SUCCESS;
122 }
123
124 bool ExternalStorage::Commit() {
125   return Finalize(true);
126 }
127
128 bool ExternalStorage::Abort() {
129   return Finalize(false);
130 }
131
132 const std::vector<std::string>& ExternalStorage::external_dirs() const {
133   return external_dirs_;
134 }
135
136 bool ExternalStorage::Initialize(
137     const boost::filesystem::path& space_requirement) {
138   // external size in MB, set any-non zero size as default
139   int external_size = 1;
140
141   if (!space_requirement.empty()) {
142     if (package_type_ != kWgtType) {
143       for (auto& dir : kExternalDirsForTpk) {
144         bf::path requirement = space_requirement / dir;
145         if (!bf::exists(requirement))
146           continue;
147         external_size +=
148             SizeInMB(GetDirectorySize(requirement));
149       }
150     } else {
151       // for wgt whole content of package goes to res/
152       external_size +=
153           SizeInMB(GetDirectorySize(space_requirement));
154     }
155   }
156
157   handle_ = service.getInterfaceHandle();
158   if (!handle_) {
159     LOG(ERROR) << "app2ext_init() failed";
160     return false;
161   }
162
163   GList* glist = nullptr;
164   for (auto& dir : external_dirs_) {
165     app2ext_dir_details* dir_detail = reinterpret_cast<app2ext_dir_details*>(
166         calloc(1, sizeof(app2ext_dir_details)));
167     if (!dir_detail) {
168       LOG(ERROR) << "Out of memory";
169       g_list_free_full(glist, &ClearApp2ExtDirDetail);
170       return false;
171     }
172     dir_detail->name = strdup(dir.c_str());
173     if (!dir_detail->name) {
174       LOG(ERROR) << "Out of memory";
175       free(dir_detail);
176       g_list_free_full(glist, &ClearApp2ExtDirDetail);
177       return false;
178     }
179     dir_detail->type = APP2EXT_DIR_RO;
180     glist = g_list_append(glist, dir_detail);
181   }
182
183   int ret = 0;
184   switch (type_) {
185   case RequestType::Install:
186     ret = handle_->interface.client_usr_force_clean(pkgid_.c_str(), uid_);
187     if (ret) {
188       LOG(ERROR) << "force_clean failed";
189       break;
190     }
191     ret = handle_->interface.client_usr_pre_install(pkgid_.c_str(), glist,
192                                                     external_size, uid_);
193     break;
194   case RequestType::Update:
195   case RequestType::Delta:
196     ret = handle_->interface.client_usr_pre_upgrade(pkgid_.c_str(), glist,
197                                                     external_size, uid_);
198     break;
199   case RequestType::Move:
200     if (move_type_ == -1) {
201       LOG(ERROR) << "Invalid request [" << move_type_ << "]";
202       ret = -1;
203       break;
204     }
205
206     // try umount before move
207     ret = handle_->interface.client_usr_disable(pkgid_.c_str(), uid_);
208
209     ret = handle_->interface.client_usr_pre_move(pkgid_.c_str(), glist,
210                                static_cast<app2ext_move_type_t>(move_type_),
211                                uid_);
212     break;
213   case RequestType::Uninstall:
214     ret = handle_->interface.client_usr_pre_uninstall(pkgid_.c_str(), uid_);
215     break;
216   case RequestType::MigrateExtImg:
217     ret = handle_->interface.client_usr_pre_migrate_legacy(pkgid_.c_str(),
218                                                            uid_);
219     break;
220   default:
221     LOG(ERROR) << "Installation type (" << GetRequestTypeString(type_) << ")"
222                << " is not supported by external installation";
223     ret = -1;
224     break;
225   }
226
227   g_list_free_full(glist, &ClearApp2ExtDirDetail);
228   return ret == 0;
229 }
230
231 std::unique_ptr<ExternalStorage> ExternalStorage::MoveInstalledStorage(
232     RequestType type, const boost::filesystem::path& application_root,
233     const std::string& pkgid, const std::string& package_type,
234     uid_t uid, bool is_external_move) {
235
236   std::unique_ptr<ExternalStorage> external_storage(
237     new ExternalStorage(type, pkgid, package_type, application_root, uid,
238                        is_external_move));
239   if (!external_storage->Initialize(application_root)) {
240     LOG(WARNING) << "Cannot initialize external storage for move";
241     return nullptr;
242   }
243
244   return external_storage;
245 }
246
247 std::unique_ptr<ExternalStorage> ExternalStorage::AcquireExternalStorage(
248     RequestType type, const boost::filesystem::path& application_root,
249     const std::string& pkgid, const std::string& package_type,
250     const boost::filesystem::path& space_requirement,
251     uid_t uid) {
252   std::unique_ptr<ExternalStorage> external_storage(
253       new ExternalStorage(type, pkgid, package_type, application_root, uid));
254   if (!external_storage->Initialize(space_requirement)) {
255     LOG(WARNING) << "Cannot initialize external storage for request";
256     return nullptr;
257   }
258   return external_storage;
259 }
260
261 std::unique_ptr<ExternalStorage> ExternalStorage::MigrateExternalStorage(
262     RequestType type, const std::string& pkgid, uid_t uid) {
263   std::unique_ptr<ExternalStorage> external_storage(
264       new ExternalStorage(type, pkgid, uid));
265   bf::path empty_path("");
266   if (!external_storage->Initialize(empty_path)) {
267     LOG(WARNING) << "Cannot initialize external storage for request";
268     return nullptr;
269   }
270   return external_storage;
271 }
272
273 }  // namespace common_installer