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