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);
34 if (!ci::CheckFreeSpaceAtPath(shared_size, backup_path))
40 bool CreateSharedRes(const bf::path& src, const bf::path& dst) {
43 bf::create_directories(dst / kSharedResPath, error);
45 LOG(ERROR) << "Cannot create package directory";
49 if (!ci::CopyOwnershipAndPermissions(src / "shared", dst / "shared") ||
50 !ci::CopyOwnershipAndPermissions(src / kSharedResPath,
51 dst / kSharedResPath))
57 bool Move(const boost::filesystem::path& from,
58 const boost::filesystem::path& to,
59 common_installer::FSFlag flag = common_installer::FSFlag::FS_NONE) {
60 if (bf::is_directory(from)) {
61 if (!common_installer::MoveDir(from, to / from.filename(), flag)) {
62 LOG(ERROR) << "Failed to move directory: " << from;
66 if (!common_installer::MoveFile(from, to / from.filename())) {
67 LOG(ERROR) << "Fail to move file: " << from;
77 namespace common_installer {
80 Step::Status StepCopyBackup::precheck() {
81 if (context_->pkgid.get().empty()) {
82 LOG(ERROR) << "pkgid attribute is empty";
83 return Step::Status::PACKAGE_NOT_FOUND;
86 if (context_->root_application_path.get().empty()) {
87 LOG(ERROR) << "root_application_path attribute is empty";
88 return Step::Status::INVALID_VALUE;
91 install_path_ = context_->GetPkgPath();
92 backup_path_ = GetBackupPathForPackagePath(context_->GetPkgPath());
94 // We only "copy" shared dir for backup.
95 // So if there is no shared dir, we don't need to check free space.
96 bf::path shared_dir = install_path_ / "shared";
97 if (!bf::exists(shared_dir))
100 if (!CheckFreeSpace(backup_path_, shared_dir)) {
101 LOG(ERROR) << "not enough space for backup";
102 return Step::Status::OUT_OF_SPACE;
108 Step::Status StepCopyBackup::process() {
109 if (!CleanBackupDirectory())
110 return Status::APP_DIR_ERROR;
113 return Status::APP_DIR_ERROR;
116 return Status::APP_DIR_ERROR;
123 Step::Status StepCopyBackup::clean() {
124 LOG(DEBUG) << "Remove Applications files backup directory";
125 CleanBackupDirectory();
127 if (context_->external_storage)
128 context_->external_storage->Commit();
133 Step::Status StepCopyBackup::undo() {
134 if (context_->external_storage)
135 context_->external_storage->Abort();
137 if (!bf::exists(backup_path_))
140 if (!RollbackApplicationDirectory()) {
141 LOG(ERROR) << "Failed to revert package directory";
142 return Status::APP_DIR_ERROR;
145 LOG(DEBUG) << "Application files reverted from backup";
150 bool StepCopyBackup::Backup() {
151 bs::error_code error;
153 if (!bf::exists(backup_path_)) {
154 bf::create_directories(backup_path_, error);
156 LOG(ERROR) << "Failed to create backup directory: " << backup_path_;
160 // create copy of old package content skipping the external memory mount point
161 for (bf::directory_iterator iter(context_->GetPkgPath());
162 iter != bf::directory_iterator(); ++iter) {
163 if (iter->path().filename() == kExternalMemoryMountPoint)
166 // external storage directories are mounted
167 // therefore move only content
168 if (context_->external_storage) {
169 auto& ext_dirs = context_->external_storage->external_dirs();
170 auto found = std::find(ext_dirs.begin(), ext_dirs.end(),
171 iter->path().filename());
172 if (found != ext_dirs.end()) {
173 bool done = MoveMountPointContent(iter->path(),
174 backup_path_ / iter->path().filename());
176 LOG(ERROR) << "Failed to move: " << iter->path();
183 if (!Move(iter->path(), backup_path_))
187 if (ShouldBackupSharedRes()) {
188 if (!CreateSharedRes(backup_path_, context_->GetPkgPath()))
194 LOG(INFO) << "Old package context saved to: " << backup_path_;
199 bool StepCopyBackup::MoveMountPointContent(const boost::filesystem::path& from,
200 const boost::filesystem::path& to) {
201 bs::error_code error;
202 bf::create_directories(to, error);
204 for (bf::directory_iterator iter(from);
205 iter != bf::directory_iterator(); ++iter) {
206 if (bf::is_symlink(symlink_status(iter->path()))) {
207 bf::copy_symlink(iter->path(), to / iter->path().filename(), error);
209 LOG(ERROR) << "Failed to backup package symlink: " << iter->path();
213 if (!Move(iter->path(), to)) {
214 LOG(ERROR) << "Fail to backup package file: " << iter->path();
223 void StepCopyBackup::RemoveContent() {
224 if (context_->request_type.get() == RequestType::Update &&
225 !context_->external_storage && bf::exists(install_path_ / ".mmc")) {
226 LOG(WARNING) << "Remove unnecessary files for external storage";
228 bs::error_code error;
229 bf::remove((install_path_ / ".mmc"), error);
231 LOG(WARNING) << "error while remove files";
235 bool StepCopyBackup::NewContent() {
236 ci::RemoveRWDirectories(context_->unpacked_dir_path.get());
238 bs::error_code error;
239 bf::create_directories(install_path_.parent_path(), error);
241 LOG(ERROR) << "Cannot create package directory";
245 for (bf::directory_iterator iter(context_->unpacked_dir_path.get());
246 iter != bf::directory_iterator(); ++iter) {
247 if (!Move(iter->path(), install_path_, FS_MERGE_SKIP))
251 // If other application tries to access shared/res of package being installed,
252 // it will be failed due to permission deny. Set its permission before
253 // StepChangeOwnershipAndPermission to prevent it.
254 uid_t uid = context_->uid.get();
255 boost::optional<gid_t> gid = common_installer::GetGidByUid(uid);
257 LOG(ERROR) << "Failed to get gid";
260 if (bf::exists(install_path_ / "shared/res") &&
261 !common_installer::SetOwnershipAll(
262 install_path_ / "shared/res", uid, *gid)) {
263 LOG(ERROR) << "Failed to set ownership";
266 LOG(INFO) << "Successfully move: " << context_->unpacked_dir_path.get()
267 << " to: " << install_path_ << " directory";
269 ci::RemoveAll(context_->unpacked_dir_path.get());
273 bool StepCopyBackup::CleanBackupDirectory() {
274 return ci::RemoveAll(backup_path_);
277 bool StepCopyBackup::RollbackApplicationDirectory() {
278 bs::error_code error;
279 bf::path root_path = context_->GetPkgPath();
280 if (bf::exists(root_path)) {
281 for (bf::directory_iterator iter(root_path);
282 iter != bf::directory_iterator(); ++iter) {
283 bf::remove_all(iter->path(), error);
289 for (bf::directory_iterator iter(backup_path_);
290 iter != bf::directory_iterator(); ++iter) {
291 if (!Move(iter->path(), root_path)) {
292 LOG(ERROR) << "Failed to recovery backup file(" << iter->path() << ")";
296 RemoveAll(backup_path_);
298 uid_t uid = context_->uid.get();
299 // restore ownership changed during installation
300 if (!SetPackageDirectoryOwnerAndPermissions(context_->GetPkgPath(), uid))
306 void StepCopyBackup::AddRecoveryInfo() {
307 recovery::RecoveryFile* recovery_file =
308 context_->recovery_info.get().recovery_file.get();
309 recovery_file->set_backup_done(true);
310 recovery_file->WriteAndCommitFileContent();
313 bool StepCopyBackup::ShouldBackupSharedRes() {
314 if (bf::exists(backup_path_ / kSharedResPath) &&
315 bf::exists(context_->unpacked_dir_path.get() / kSharedResPath))
321 } // namespace backup
322 } // namespace common_installer