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>
15 #include <system_error>
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 ci = common_installer;
23 namespace fs = std::filesystem;
27 const char kExternalMemoryMountPoint[] = ".mmc";
28 const char kSharedResPath[] = "shared/res";
30 bool CheckFreeSpace(const fs::path& backup_path, const fs::path& shared_path) {
31 int64_t shared_size = ci::GetDirectorySize(shared_path);
33 if (!ci::CheckFreeSpaceAtPath(shared_size, backup_path))
39 bool CreateSharedRes(const fs::path& src, const fs::path& dst) {
40 std::error_code error;
42 fs::create_directories(dst / kSharedResPath, error);
44 LOG(ERROR) << "Cannot create package directory";
48 if (!ci::CopyOwnershipAndPermissions(src / "shared", dst / "shared") ||
49 !ci::CopyOwnershipAndPermissions(src / kSharedResPath,
50 dst / kSharedResPath))
56 bool Move(const std::filesystem::path& from,
57 const std::filesystem::path& to,
58 common_installer::FSFlag flag = common_installer::FSFlag::FS_NONE) {
59 if (fs::is_directory(from)) {
60 if (!common_installer::MoveDir(from, to / from.filename(), flag)) {
61 LOG(ERROR) << "Failed to move directory: " << from;
65 if (!common_installer::MoveFile(from, to / from.filename())) {
66 LOG(ERROR) << "Fail to move file: " << from;
76 namespace common_installer {
79 Step::Status StepCopyBackup::precheck() {
80 if (context_->pkgid.get().empty()) {
81 LOG(ERROR) << "pkgid attribute is empty";
82 return Step::Status::PACKAGE_NOT_FOUND;
85 if (context_->root_application_path.get().empty()) {
86 LOG(ERROR) << "root_application_path attribute is empty";
87 return Step::Status::INVALID_VALUE;
90 install_path_ = context_->GetPkgPath();
91 backup_path_ = GetBackupPathForPackagePath(context_->GetPkgPath());
93 // We only "copy" shared dir for backup.
94 // So if there is no shared dir, we don't need to check free space.
95 fs::path shared_dir = install_path_ / "shared";
96 if (!fs::exists(shared_dir))
99 if (!CheckFreeSpace(backup_path_, shared_dir)) {
100 LOG(ERROR) << "not enough space for backup";
101 return Step::Status::OUT_OF_SPACE;
107 Step::Status StepCopyBackup::process() {
108 if (!CleanBackupDirectory())
109 return Status::APP_DIR_ERROR;
112 return Status::APP_DIR_ERROR;
115 return Status::APP_DIR_ERROR;
122 Step::Status StepCopyBackup::clean() {
123 LOG(DEBUG) << "Remove Applications files backup directory";
124 CleanBackupDirectory();
126 if (context_->external_storage)
127 context_->external_storage->Commit();
132 Step::Status StepCopyBackup::undo() {
133 if (context_->external_storage)
134 context_->external_storage->Abort();
136 if (!fs::exists(backup_path_))
139 if (!RollbackApplicationDirectory()) {
140 LOG(ERROR) << "Failed to revert package directory";
141 return Status::APP_DIR_ERROR;
144 LOG(DEBUG) << "Application files reverted from backup";
149 bool StepCopyBackup::Backup() {
150 std::error_code error;
152 if (!fs::exists(backup_path_)) {
153 fs::create_directories(backup_path_, error);
155 LOG(ERROR) << "Failed to create backup directory: " << backup_path_;
159 // create copy of old package content skipping the external memory mount point
160 for (fs::directory_iterator iter(context_->GetPkgPath());
161 iter != fs::directory_iterator(); ++iter) {
162 if (iter->path().filename() == kExternalMemoryMountPoint)
165 // external storage directories are mounted
166 // therefore move only content
167 if (context_->external_storage) {
168 auto& ext_dirs = context_->external_storage->external_dirs();
169 auto found = std::find(ext_dirs.begin(), ext_dirs.end(),
170 iter->path().filename().string());
171 if (found != ext_dirs.end()) {
172 bool done = MoveMountPointContent(iter->path(),
173 backup_path_ / iter->path().filename());
175 LOG(ERROR) << "Failed to move: " << iter->path();
182 if (!Move(iter->path(), backup_path_))
188 LOG(INFO) << "Old package context saved to: " << backup_path_;
193 bool StepCopyBackup::MoveMountPointContent(const std::filesystem::path& from,
194 const std::filesystem::path& to) {
195 std::error_code error;
196 fs::create_directories(to, error);
198 for (fs::directory_iterator iter(from);
199 iter != fs::directory_iterator(); ++iter) {
200 if (fs::is_symlink(symlink_status(iter->path()))) {
201 fs::copy_symlink(iter->path(), to / iter->path().filename(), error);
203 LOG(ERROR) << "Failed to backup package symlink: " << iter->path();
207 if (!Move(iter->path(), to)) {
208 LOG(ERROR) << "Fail to backup package file: " << iter->path();
217 void StepCopyBackup::RemoveContent() {
218 if (context_->request_type.get() == RequestType::Update &&
219 !context_->external_storage && fs::exists(install_path_ / ".mmc")) {
220 LOG(WARNING) << "Remove unnecessary files for external storage";
222 std::error_code error;
223 fs::remove((install_path_ / ".mmc"), error);
225 LOG(WARNING) << "error while remove files";
229 bool StepCopyBackup::NewContent() {
230 ci::RemoveRWDirectories(context_->unpacked_dir_path.get());
232 std::error_code error;
233 fs::create_directories(install_path_.parent_path(), error);
235 LOG(ERROR) << "Cannot create package directory";
239 if (ShouldBackupSharedRes()) {
240 if (!CreateSharedRes(backup_path_, context_->GetPkgPath()))
244 for (fs::directory_iterator iter(context_->unpacked_dir_path.get());
245 iter != fs::directory_iterator(); ++iter) {
246 if (!Move(iter->path(), install_path_, FS_MERGE_SKIP))
250 // If other application tries to access shared/res of package being installed,
251 // it will be failed due to permission deny. Set its permission before
252 // StepChangeOwnershipAndPermission to prevent it.
253 uid_t uid = context_->uid.get();
254 std::optional<gid_t> gid = common_installer::GetGidByUid(uid);
256 LOG(ERROR) << "Failed to get gid";
259 if (fs::exists(install_path_ / "shared/res") &&
260 !common_installer::SetOwnershipAll(
261 install_path_ / "shared/res", uid, *gid)) {
262 LOG(ERROR) << "Failed to set ownership";
265 LOG(INFO) << "Successfully move: " << context_->unpacked_dir_path.get()
266 << " to: " << install_path_ << " directory";
268 ci::RemoveAll(context_->unpacked_dir_path.get());
272 bool StepCopyBackup::CleanBackupDirectory() {
273 return ci::RemoveAll(backup_path_);
276 bool StepCopyBackup::RollbackApplicationDirectory() {
277 std::error_code error;
278 fs::path root_path = context_->GetPkgPath();
279 if (fs::exists(root_path)) {
280 for (fs::directory_iterator iter(root_path);
281 iter != fs::directory_iterator(); ++iter) {
282 fs::remove_all(iter->path(), error);
288 for (fs::directory_iterator iter(backup_path_);
289 iter != fs::directory_iterator(); ++iter) {
290 if (!Move(iter->path(), root_path)) {
291 LOG(ERROR) << "Failed to recovery backup file(" << iter->path() << ")";
295 RemoveAll(backup_path_);
297 uid_t uid = context_->uid.get();
298 // restore ownership changed during installation
299 if (!SetPackageDirectoryOwnerAndPermissions(context_->GetPkgPath(), uid))
305 void StepCopyBackup::AddRecoveryInfo() {
306 recovery::RecoveryFile* recovery_file =
307 context_->recovery_info.get().recovery_file.get();
308 recovery_file->set_backup_done(true);
309 recovery_file->WriteAndCommitFileContent();
312 bool StepCopyBackup::ShouldBackupSharedRes() {
313 if (fs::exists(backup_path_ / kSharedResPath) &&
314 fs::exists(context_->unpacked_dir_path.get() / kSharedResPath))
320 } // namespace backup
321 } // namespace common_installer