Implement pkg move
[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() {
74   if (handle_)
75     app2ext_deinit(handle_);
76 }
77
78 bool ExternalStorage::Finalize(bool success) {
79   int ret = APP2EXT_STATUS_SUCCESS;
80   switch (type_) {
81   case RequestType::Install: {
82     ret = handle_->interface.client_usr_post_install(pkgid_.c_str(),
83         success ? APP2EXT_STATUS_SUCCESS : APP2EXT_STATUS_FAILED, uid_);
84     break;
85   }
86   case RequestType::Update: {
87     ret = handle_->interface.client_usr_post_upgrade(pkgid_.c_str(),
88         success ? APP2EXT_STATUS_SUCCESS : APP2EXT_STATUS_FAILED, uid_);
89     break;
90   }
91   case RequestType::Uninstall: {
92     ret = handle_->interface.client_usr_post_uninstall(pkgid_.c_str(), uid_);
93     break;
94   }
95   case RequestType::Move: {
96     break;
97   }
98   default:
99     assert(false && "Not supported installation mode");
100   }
101   return ret == APP2EXT_STATUS_SUCCESS;
102 }
103
104 bool ExternalStorage::Commit() {
105   return Finalize(true);
106 }
107
108 bool ExternalStorage::Abort() {
109   return Finalize(false);
110 }
111
112 const std::vector<std::string>& ExternalStorage::external_dirs() const {
113   return external_dirs_;
114 }
115
116 bool ExternalStorage::Initialize(
117     const boost::filesystem::path& space_requirement) {
118   // external size in MB, set any-non zero size as default
119   int external_size = 1;
120
121   if (!space_requirement.empty()) {
122     if (package_type_ == kWgtType) {
123       for (auto& dir : kExternalDirsForTpk) {
124         bf::path requirement = space_requirement / dir;
125         if (!bf::exists(requirement))
126           continue;
127         external_size +=
128             SizeInMB(GetDirectorySize(requirement));
129       }
130     } else {
131       // for wgt whole content of package goes to res/
132       external_size =
133           SizeInMB(GetDirectorySize(space_requirement));
134     }
135   }
136
137   if (external_size == 0)
138     external_size = 1;
139
140   handle_ = app2ext_init(APP2EXT_SD_CARD);
141   if (!handle_) {
142     LOG(ERROR) << "app2ext_init() failed";
143     return false;
144   }
145
146   GList* glist = nullptr;
147   for (auto& dir : external_dirs_) {
148     app2ext_dir_details* dir_detail = reinterpret_cast<app2ext_dir_details*>(
149         calloc(1, sizeof(app2ext_dir_details)));
150     dir_detail->name = strdup(dir.c_str());
151     dir_detail->type = APP2EXT_DIR_RO;
152     glist = g_list_append(glist, dir_detail);
153   }
154
155   int ret = 0;
156   switch (type_) {
157   case RequestType::Install:
158     ret = handle_->interface.client_usr_pre_install(pkgid_.c_str(), glist,
159                                                     external_size, uid_);
160     break;
161   case RequestType::Update:
162   case RequestType::Delta:
163     ret = handle_->interface.client_usr_pre_upgrade(pkgid_.c_str(), glist,
164                                                     external_size, uid_);
165     break;
166   case RequestType::Move:
167     if (move_type_ == -1) {
168       LOG(ERROR) << "Invalid request [" << move_type_ << "]";
169       ret = -1;
170       break;
171     }
172
173     ret = app2ext_usr_get_app_location(pkgid_.c_str(), uid_);
174     if (ret == APP2EXT_ERROR_INVALID_ARGUMENTS) {
175       LOG(ERROR) << "Failed to get installed location [" << pkgid_ << "]";
176       ret = -1;
177       break;
178     }
179
180     if ((ret == APP2EXT_SD_CARD && move_type_ == APP2EXT_MOVE_TO_EXT) ||
181         (ret == APP2EXT_INTERNAL_MEM && move_type_ == APP2EXT_MOVE_TO_PHONE)) {
182       LOG(ERROR) << "Invalid move request [" << move_type_ << "]";
183       ret = -1;
184       break;
185     }
186
187     ret = handle_->interface.client_usr_move(pkgid_.c_str(), glist,
188                                      (app2ext_move_type_t)move_type_,
189                                      uid_);
190     break;
191   case RequestType::Uninstall:
192     ret = handle_->interface.client_usr_pre_uninstall(pkgid_.c_str(), uid_);
193     break;
194   case RequestType::Clear:
195   case RequestType::Reinstall:
196   case RequestType::Recovery:
197   case RequestType::ManifestDirectInstall:
198   case RequestType::ManifestDirectUpdate:
199   case RequestType::MountInstall:
200   case RequestType::MountUpdate:
201     LOG(ERROR) << "Installation type is not supported by external installation";
202     ret = -1;
203     break;
204   default:
205     assert(false && "Invalid installation mode");
206   }
207
208   g_list_free_full(glist, [](gpointer data) {
209       app2ext_dir_details* dir_detail =
210           reinterpret_cast<app2ext_dir_details*>(data);
211       free(dir_detail->name);
212       free(dir_detail);
213     });
214   return ret == 0;
215 }
216
217 std::unique_ptr<ExternalStorage> ExternalStorage::MoveInstalledStorage(
218     RequestType type, const boost::filesystem::path& application_root,
219     const std::string& pkgid, const std::string& package_type,
220     uid_t uid, bool is_external_move) {
221
222   std::unique_ptr<ExternalStorage> external_storage(
223     new ExternalStorage(type, pkgid, package_type, application_root, uid,
224                        is_external_move));
225   if (!external_storage->Initialize(application_root)) {
226     LOG(WARNING) << "Cannot initialize external storage for move";
227     return nullptr;
228   }
229
230   return external_storage;
231 }
232
233 std::unique_ptr<ExternalStorage> ExternalStorage::AcquireExternalStorage(
234     RequestType type, const boost::filesystem::path& application_root,
235     const std::string& pkgid, const std::string& package_type,
236     const boost::filesystem::path& space_requirement,
237     uid_t uid) {
238   std::unique_ptr<ExternalStorage> external_storage(
239       new ExternalStorage(type, pkgid, package_type, application_root, uid));
240   if (!external_storage->Initialize(space_requirement)) {
241     LOG(WARNING) << "Cannot initialize external storage for request";
242     return nullptr;
243   }
244   return external_storage;
245 }
246
247 }  // namespace common_installer