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