External installation
[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 }
50
51 ExternalStorage::~ExternalStorage() {
52   if (handle_)
53     app2ext_deinit(handle_);
54 }
55
56 bool ExternalStorage::Finalize(bool success) {
57   int ret = APP2EXT_STATUS_SUCCESS;
58   switch (type_) {
59   case RequestType::Install: {
60     ret = handle_->interface.client_usr_post_install(pkgid_.c_str(),
61         success ? APP2EXT_STATUS_SUCCESS : APP2EXT_STATUS_FAILED, uid_);
62     break;
63   }
64   case RequestType::Update: {
65     ret = handle_->interface.client_usr_post_upgrade(pkgid_.c_str(),
66         success ? APP2EXT_STATUS_SUCCESS : APP2EXT_STATUS_FAILED, uid_);
67     break;
68   }
69   case RequestType::Uninstall: {
70     ret = handle_->interface.client_usr_post_uninstall(pkgid_.c_str(), uid_);
71     break;
72   }
73   default:
74     assert(false && "Not supported installation mode");
75   }
76   return ret == APP2EXT_STATUS_SUCCESS;
77 }
78
79 bool ExternalStorage::Commit() {
80   return Finalize(true);
81 }
82
83 bool ExternalStorage::Abort() {
84   return Finalize(false);
85 }
86
87 const std::vector<std::string>& ExternalStorage::external_dirs() const {
88   return external_dirs_;
89 }
90
91 bool ExternalStorage::Initialize(
92     const boost::filesystem::path& space_requirement) {
93   // external size in MB, set any-non zero size as default
94   int external_size = 1;
95
96   if (!space_requirement.empty()) {
97     if (package_type_ == kWgtType) {
98       for (auto& dir : kExternalDirsForTpk) {
99         bf::path requirement = space_requirement / dir;
100         if (!bf::exists(requirement))
101           continue;
102         external_size +=
103             SizeInMB(GetDirectorySize(requirement));
104       }
105     } else {
106       // for wgt whole content of package goes to res/
107       external_size =
108           SizeInMB(GetDirectorySize(space_requirement));
109     }
110   }
111
112   if (external_size == 0)
113     external_size = 1;
114
115   handle_ = app2ext_init(APP2EXT_SD_CARD);
116   if (!handle_) {
117     LOG(ERROR) << "app2ext_init() failed";
118     return false;
119   }
120
121   GList* glist = nullptr;
122   for (auto& dir : external_dirs_) {
123     app2ext_dir_details* dir_detail = reinterpret_cast<app2ext_dir_details*>(
124         calloc(1, sizeof(app2ext_dir_details)));
125     dir_detail->name = strdup(dir.c_str());
126     dir_detail->type = APP2EXT_DIR_RO;
127     glist = g_list_append(glist, dir_detail);
128   }
129
130   int ret = 0;
131   switch (type_) {
132   case RequestType::Install:
133     ret = handle_->interface.client_usr_pre_install(pkgid_.c_str(), glist,
134                                                     external_size, uid_);
135     break;
136   case RequestType::Update:
137   case RequestType::Delta:
138     ret = handle_->interface.client_usr_pre_upgrade(pkgid_.c_str(), glist,
139                                                     external_size, uid_);
140     break;
141   case RequestType::Uninstall:
142     ret = handle_->interface.client_usr_pre_uninstall(pkgid_.c_str(), uid_);
143     break;
144   case RequestType::Clear:
145   case RequestType::Reinstall:
146   case RequestType::Recovery:
147   case RequestType::ManifestDirectInstall:
148   case RequestType::ManifestDirectUpdate:
149   case RequestType::MountInstall:
150   case RequestType::MountUpdate:
151     LOG(ERROR) << "Installation type is not supported by external installation";
152     ret = -1;
153     break;
154   default:
155     assert(false && "Invalid installation mode");
156   }
157
158   g_list_free_full(glist, [](gpointer data) {
159       app2ext_dir_details* dir_detail =
160           reinterpret_cast<app2ext_dir_details*>(data);
161       free(dir_detail->name);
162       free(dir_detail);
163     });
164   return ret == 0;
165 }
166
167 std::unique_ptr<ExternalStorage> ExternalStorage::AcquireExternalStorage(
168     RequestType type, const boost::filesystem::path& application_root,
169     const std::string& pkgid, const std::string& package_type,
170     const boost::filesystem::path& space_requirement,
171     uid_t uid) {
172   std::unique_ptr<ExternalStorage> external_storage(
173       new ExternalStorage(type, pkgid, package_type, application_root, uid));
174   if (!external_storage->Initialize(space_requirement)) {
175     LOG(WARNING) << "Cannot initialize external storage for request";
176     return nullptr;
177   }
178   return external_storage;
179 }
180
181 }  // namespace common_installer