1 // Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
2 // Use of this source code is governed by a apache 2.0 license that can be
3 // found in the LICENSE file.
5 #include "common/step/backup/step_copy_backup.h"
8 #include <tzplatform_config.h>
10 #include <boost/filesystem/operations.hpp>
11 #include <boost/system/error_code.hpp>
17 #include "common/utils/paths.h"
18 #include "common/shared_dirs.h"
19 #include "common/utils/file_util.h"
20 #include "common/utils/user_util.h"
22 namespace bf = boost::filesystem;
23 namespace bs = boost::system;
24 namespace ci = common_installer;
28 const char kExternalMemoryMountPoint[] = ".mmc";
29 const char kSharedResPath[] = "shared/res";
31 bool CheckFreeSpace(const bf::path& backup_path, const bf::path& shared_path) {
32 int64_t shared_size = ci::GetDirectorySize(shared_path);
33 if (!ci::CheckFreeSpaceAtPath(shared_size, backup_path))
39 bool CreateSharedRes(const bf::path& src, const bf::path& dst) {
41 bf::create_directories(dst / kSharedResPath, error);
43 LOG(ERROR) << "Cannot create package directory";
47 if (!ci::CopyOwnershipAndPermissions(src / "shared", dst / "shared") ||
48 !ci::CopyOwnershipAndPermissions(src / kSharedResPath,
49 dst / kSharedResPath))
57 namespace common_installer {
60 Step::Status StepCopyBackup::precheck() {
61 if (context_->pkgid.get().empty()) {
62 LOG(ERROR) << "pkgid attribute is empty";
63 return Step::Status::PACKAGE_NOT_FOUND;
65 if (context_->root_application_path.get().empty()) {
66 LOG(ERROR) << "root_application_path attribute is empty";
67 return Step::Status::INVALID_VALUE;
70 install_path_ = context_->GetPkgPath();
71 backup_path_ = GetBackupPathForPackagePath(context_->GetPkgPath());
73 if (!CheckFreeSpace(backup_path_, install_path_ / "shared")) {
74 LOG(ERROR) << "not enough space for backup";
75 return Step::Status::OUT_OF_SPACE;
81 Step::Status StepCopyBackup::process() {
82 // if backup file exists
83 if (!CleanBackupDirectory())
84 return Status::APP_DIR_ERROR;
86 return Status::APP_DIR_ERROR;
89 return Status::APP_DIR_ERROR;
95 Step::Status StepCopyBackup::clean() {
96 LOG(DEBUG) << "Remove Applications files backup directory";
97 CleanBackupDirectory();
99 if (context_->external_storage)
100 context_->external_storage->Commit();
105 Step::Status StepCopyBackup::undo() {
106 if (context_->external_storage)
107 context_->external_storage->Abort();
109 // if backup was created then restore files
110 if (bf::exists(backup_path_)) {
111 if (!RollbackApplicationDirectory()) {
112 LOG(ERROR) << "Failed to revert package directory";
113 return Status::APP_DIR_ERROR;
115 LOG(DEBUG) << "Application files reverted from backup";
120 bool StepCopyBackup::Backup() {
121 // create backup directory
122 bs::error_code error;
124 if (!bf::exists(backup_path_)) {
125 bf::create_directories(backup_path_, error);
127 LOG(ERROR) << "Failed to create backup directory: " << backup_path_;
131 // create copy of old package content skipping the external memory mount point
132 for (bf::directory_iterator iter(context_->GetPkgPath());
133 iter != bf::directory_iterator(); ++iter) {
134 if (iter->path().filename() == kExternalMemoryMountPoint)
137 // external storage directories are mounted
138 // therefore move only content
139 if (context_->external_storage) {
140 auto& ext_dirs = context_->external_storage->external_dirs();
141 auto found = std::find(ext_dirs.begin(), ext_dirs.end(),
142 iter->path().filename());
143 if (found != ext_dirs.end()) {
144 bool done = MoveMountPointContent(iter->path(),
145 backup_path_ / iter->path().filename());
147 LOG(ERROR) << "Failed to move: " << iter->path();
154 if (bf::is_directory(iter->path())) {
155 if (!MoveDir(iter->path(), backup_path_ / iter->path().filename())) {
156 LOG(ERROR) << "Fail to backup package directory of: " << iter->path();
160 if (!MoveFile(iter->path(), backup_path_ / iter->path().filename())) {
161 LOG(ERROR) << "Fail to backup package file: " << iter->path();
167 if (bf::exists(backup_path_ / kSharedResPath) &&
168 bf::exists(context_->unpacked_dir_path.get() / kSharedResPath))
169 if (!CreateSharedRes(backup_path_, context_->GetPkgPath()))
172 recovery::RecoveryFile* recovery_file =
173 context_->recovery_info.get().recovery_file.get();
174 recovery_file->set_backup_done(true);
175 recovery_file->WriteAndCommitFileContent();
176 LOG(INFO) << "Old package context saved to: " << backup_path_;
181 bool StepCopyBackup::MoveMountPointContent(const boost::filesystem::path& from,
182 const boost::filesystem::path& to) {
183 bs::error_code error;
184 bf::create_directories(to, error);
186 for (bf::directory_iterator iter(from);
187 iter != bf::directory_iterator(); ++iter) {
188 if (bf::is_directory(iter->path())) {
189 if (!MoveDir(iter->path(), to / iter->path().filename())) {
190 LOG(ERROR) << "Fail to backup package directory of: " << iter->path();
193 } else if (bf::is_symlink(symlink_status(iter->path()))) {
194 bf::copy_symlink(iter->path(), to / iter->path().filename(), error);
196 LOG(ERROR) << "Failed to backup package symlink: " << iter->path();
200 if (!MoveFile(iter->path(), to / iter->path().filename())) {
201 LOG(ERROR) << "Fail to backup package file: " << iter->path();
209 void StepCopyBackup::RemoveContent() {
210 if (context_->request_type.get() == RequestType::Update &&
211 !context_->external_storage && bf::exists(install_path_ / ".mmc")) {
212 LOG(WARNING) << "Remove unnecessary files for external storage";
213 bs::error_code error;
214 bf::remove((install_path_ / ".mmc"), error);
216 LOG(WARNING) << "error while remove files";
220 bool StepCopyBackup::NewContent() {
221 ci::RemoveRWDirectories(context_->unpacked_dir_path.get());
223 bs::error_code error;
224 bf::create_directories(install_path_.parent_path(), error);
226 LOG(ERROR) << "Cannot create package directory";
229 for (bf::directory_iterator iter(context_->unpacked_dir_path.get());
230 iter != bf::directory_iterator(); ++iter) {
231 if (bf::is_directory(iter->path())) {
232 if (!MoveDir(iter->path(), install_path_ / iter->path().filename(),
234 LOG(ERROR) << "Fail to copy tmp dir: " << iter->path()
235 << " to dst dir: " << install_path_;
239 if (!MoveFile(iter->path(), install_path_ / iter->path().filename())) {
240 LOG(ERROR) << "Fail to copy tmp dir: " << iter->path()
241 << " to dst dir: " << install_path_;
247 // If other application tries to access shared/res of package being installed,
248 // it will be failed due to permission deny. Set its permission before
249 // StepChangeOwnershipAndPermission to prevent it.
250 uid_t uid = context_->uid.get();
251 boost::optional<gid_t> gid = common_installer::GetGidByUid(uid);
253 LOG(ERROR) << "Failed to get gid";
256 if (bf::exists(install_path_ / "shared/res") &&
257 !common_installer::SetOwnershipAll(
258 install_path_ / "shared/res", uid, *gid)) {
259 LOG(ERROR) << "Failed to set ownership";
262 LOG(INFO) << "Successfully move: " << context_->unpacked_dir_path.get()
263 << " to: " << install_path_ << " directory";
265 ci::RemoveAll(context_->unpacked_dir_path.get());
269 bool StepCopyBackup::CleanBackupDirectory() {
270 return ci::RemoveAll(backup_path_);
273 bool StepCopyBackup::RollbackApplicationDirectory() {
274 bs::error_code error;
275 if (bf::exists(context_->GetPkgPath())) {
276 bf::remove_all(context_->GetPkgPath(), error);
282 if (!MoveDir(backup_path_, context_->GetPkgPath())) {
286 uid_t uid = context_->uid.get();
287 // restore ownership changed during installation
288 if (!SetPackageDirectoryOwnerAndPermissions(context_->GetPkgPath(), uid))
294 } // namespace backup
295 } // namespace common_installer