Implement extended storage feature
[platform/core/appfw/app-installers.git] / src / common / step / filesystem / step_move_installed_storage.cc
1 // Copyright (c) 2016 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/step/filesystem/step_move_installed_storage.h"
6
7 #include <boost/filesystem/path.hpp>
8 #include <boost/system/error_code.hpp>
9 #include <tzplatform_config.h>
10
11 #include <string>
12 #include <cstring>
13
14 #include "common/external_storage.h"
15 #include "common/shared_dirs.h"
16 #include "common/utils/file_util.h"
17 #include "common/paths.h"
18 #include "common/pkgmgr_registration.h"
19 #include "common/pkgmgr_query.h"
20
21 namespace bf = boost::filesystem;
22 namespace bs = boost::system;
23
24 namespace {
25
26 const char kInternalOnly[] = "internal-only";
27
28 }  // namespace
29
30 namespace common_installer {
31 namespace filesystem {
32
33 Step::Status StepMoveInstalledStorage::process() {
34   std::string installed_storage = QueryStorageForPkgId(context_->pkgid.get(),
35       context_->uid.get());
36
37   if ((move_type_ == MoveType::TO_INTERNAL &&
38           installed_storage == "installed_external") ||
39       (move_type_ == MoveType::TO_EXTERNAL &&
40           installed_storage == "installed_internal")) {
41     if (!MoveExternal())
42       return Status::APP_DIR_ERROR;
43   } else if (
44       (move_type_ == MoveType::TO_INTERNAL &&
45           installed_storage == "installed_extended") ||
46       (move_type_ == MoveType::TO_EXTENDED &&
47           installed_storage == "installed_internal")) {
48     if (!MoveExtended())
49       return Status::APP_DIR_ERROR;
50   }
51   return Status::OK;
52 }
53
54 Step::Status StepMoveInstalledStorage::undo() {
55   if (context_->external_storage) {
56     if (new_tep_location_ != old_tep_location_)
57       if (!MoveBackTep())
58         return Status::APP_DIR_ERROR;
59     MoveBackExternal();
60   } else {
61     if (!MoveBackExtended())
62       return Status::APP_DIR_ERROR;
63   }
64   return Status::OK;
65 }
66
67 Step::Status StepMoveInstalledStorage::clean() {
68   if (context_->external_storage)
69     context_->external_storage->Commit();
70   return Status::OK;
71 }
72
73 Step::Status StepMoveInstalledStorage::precheck() {
74   move_type_ = context_->move_type.get();
75   if (context_->manifest_data.get()->installlocation == nullptr) {
76     LOG(ERROR) << "Cannot get installlocation value";
77     return Status::INVALID_VALUE;
78   }
79   if (!strcmp(context_->manifest_data.get()->installlocation, kInternalOnly)) {
80     LOG(ERROR) << "This package is interanl-only";
81     return Status::OPERATION_NOT_ALLOWED;
82   }
83   return Status::OK;
84 }
85
86 void StepMoveInstalledStorage::SetTepPaths() {
87   old_tep_location_ = context_->manifest_data.get()->tep_name;
88   if (context_->is_move_to_external.get()) {
89     new_tep_location_ = GetExternalTepPath(context_->request_mode.get(),
90                                        context_->uid.get());
91     new_tep_location_ /= old_tep_location_.filename();
92   } else {
93     new_tep_location_ =
94         GetInternalTepPath(context_->pkg_path.get()) / old_tep_location_.filename();
95   }
96 }
97
98 bool StepMoveInstalledStorage::MoveTep() {
99   if (!bf::exists(new_tep_location_.parent_path())) {
100     bs::error_code error;
101     bf::create_directory(new_tep_location_.parent_path(), error);
102     if (error) {
103       LOG(ERROR) << "Failed to destination path for new tep location";
104       return false;
105     }
106   }
107
108   if (!MoveFile(old_tep_location_, new_tep_location_)) {
109     LOG(ERROR) << "Cannot move tep file from: " << old_tep_location_
110                << " to " << new_tep_location_;
111     return false;
112   }
113
114   if (!UpdateTepInfoInPkgmgr(new_tep_location_, context_->pkgid.get(),
115       context_->uid.get(), context_->request_mode.get())) {
116     LOG(ERROR) << "Failed to update tep package location in pkgmgr";
117     return false;
118   }
119   return true;
120 }
121
122 bool StepMoveInstalledStorage::MoveBackTep() {
123   if (bf::exists(new_tep_location_)) {
124     if (!MoveFile(new_tep_location_, old_tep_location_)) {
125       LOG(ERROR) << "Cannot move tep file from: " << new_tep_location_
126                  << " to " << old_tep_location_;
127       return false;
128     }
129
130     if (!UpdateTepInfoInPkgmgr(old_tep_location_, context_->pkgid.get(),
131         context_->uid.get(), context_->request_mode.get())) {
132       LOG(ERROR) << "Failed to update tep package location in pkgmgr";
133       return false;
134     }
135   }
136   return true;
137 }
138
139 bool StepMoveInstalledStorage::MoveExternal() {
140   context_->external_storage =
141       ExternalStorage::MoveInstalledStorage(context_->request_type.get(),
142           context_->root_application_path.get(),
143           context_->pkgid.get(),
144           context_->pkg_type.get(),
145           context_->uid.get(),
146           context_->is_move_to_external.get());
147   if (!context_->external_storage) {
148     LOG(ERROR) << "Cannot initialize external storage for move";
149     return false;
150   }
151
152   // move tep
153   if (context_->manifest_data.get()->tep_name) {
154     SetTepPaths();
155
156     if (new_tep_location_ != old_tep_location_)
157       if (!MoveTep())
158         return false;
159   }
160   return true;
161 }
162
163 bool StepMoveInstalledStorage::MoveBackExternal() {
164   context_->external_storage->Abort();
165   return true;
166 }
167
168 bool StepMoveInstalledStorage::MoveExtended() {
169   if (move_type_ == MoveType::TO_EXTENDED) {
170     old_pkg_location_ = context_->pkg_path.get();
171     new_pkg_location_ = bf::path(GetExtendedRootAppPath(context_->uid.get())) /
172         context_->pkgid.get();
173     context_->storage.set(Storage::EXTENDED);
174   } else {
175     old_pkg_location_ = bf::path(GetExtendedRootAppPath(context_->uid.get())) /
176         context_->pkgid.get();
177     new_pkg_location_ = bf::path(GetRootAppPath(
178         context_->is_readonly_package.get(), context_->uid.get())) /
179         context_->pkgid.get();
180     context_->storage.set(Storage::INTERNAL);
181   }
182
183   if (move_type_ == MoveType::TO_INTERNAL) {
184     // remove existing symlink
185     if (!Remove(new_pkg_location_))
186       return false;
187   }
188
189   if (!MoveDir(old_pkg_location_, new_pkg_location_))
190     return false;
191
192   // create symlink for extended path
193   if (move_type_ == MoveType::TO_EXTENDED) {
194     bs::error_code error;
195     bf::create_symlink(new_pkg_location_, old_pkg_location_, error);
196     if (error) {
197       LOG(ERROR) << "Failed to create symlink for extended path: "
198                  << error.message();
199     }
200   }
201
202   if (!SetPackageDirectoryOwnerAndPermissions(new_pkg_location_,
203       context_->uid.get())) {
204     LOG(ERROR) << "Failed to set directory ownership";
205     return false;
206   }
207
208   if (!UpdateInstalledStorageInPkgmgr(context_->storage.get(),
209       new_pkg_location_, context_->pkgid.get(), context_->uid.get()))
210     return false;
211   return true;
212 }
213
214 bool StepMoveInstalledStorage::MoveBackExtended() {
215   if (move_type_ == MoveType::TO_EXTENDED) {
216     // Remove symlink if exist
217     if (bf::exists(old_pkg_location_) &&
218         bf::is_symlink(symlink_status(old_pkg_location_))) {
219       if (!Remove(old_pkg_location_)) {
220         LOG(ERROR) << "Failed to remove symlink for extended path";
221         return false;
222       }
223     }
224   }
225   MoveDir(new_pkg_location_, old_pkg_location_);
226   if (move_type_ == MoveType::TO_INTERNAL) {
227     bs::error_code error;
228     bf::create_symlink(old_pkg_location_, new_pkg_location_, error);
229     if (error) {
230       LOG(ERROR) << "Failed to create symlink for extended path: "
231                  << error.message();
232       return false;
233     }
234   }
235
236   if (!SetPackageDirectoryOwnerAndPermissions(old_pkg_location_,
237       context_->uid.get())) {
238     LOG(ERROR) << "Failed to set directory ownership";
239     return false;
240   }
241
242   return true;
243 }
244
245 }  // namespace filesystem
246 }  // namespace common_installer
247