#include <boost/system/error_code.hpp>
#include <cassert>
+#include <cstdint>
#include <string>
-#include "common/paths.h"
+#include "common/utils/paths.h"
+#include "common/shared_dirs.h"
#include "common/utils/file_util.h"
+#include "common/utils/user_util.h"
+
+namespace bf = boost::filesystem;
+namespace bs = boost::system;
+namespace ci = common_installer;
namespace {
const char kExternalMemoryMountPoint[] = ".mmc";
+const char kSharedResPath[] = "shared/res";
+
+bool CheckFreeSpace(const bf::path& backup_path, const bf::path& shared_path) {
+ int64_t shared_size = ci::GetDirectorySize(shared_path);
+
+ if (!ci::CheckFreeSpaceAtPath(shared_size, backup_path))
+ return false;
+
+ return true;
+}
+
+bool CreateSharedRes(const bf::path& src, const bf::path& dst) {
+ bs::error_code error;
+
+ bf::create_directories(dst / kSharedResPath, error);
+ if (error) {
+ LOG(ERROR) << "Cannot create package directory";
+ return false;
+ }
+
+ if (!ci::CopyOwnershipAndPermissions(src / "shared", dst / "shared") ||
+ !ci::CopyOwnershipAndPermissions(src / kSharedResPath,
+ dst / kSharedResPath))
+ return false;
+ return true;
}
+bool Move(const boost::filesystem::path& from,
+ const boost::filesystem::path& to,
+ common_installer::FSFlag flag = common_installer::FSFlag::FS_NONE) {
+ if (bf::is_directory(from)) {
+ if (!common_installer::MoveDir(from, to / from.filename(), flag)) {
+ LOG(ERROR) << "Failed to move directory: " << from;
+ return false;
+ }
+ } else {
+ if (!common_installer::MoveFile(from, to / from.filename())) {
+ LOG(ERROR) << "Fail to move file: " << from;
+ return false;
+ }
+ }
+
+ return true;
+}
+
+} // namespace
+
namespace common_installer {
namespace backup {
-namespace bf = boost::filesystem;
-namespace bs = boost::system;
-
Step::Status StepCopyBackup::precheck() {
if (context_->pkgid.get().empty()) {
LOG(ERROR) << "pkgid attribute is empty";
return Step::Status::PACKAGE_NOT_FOUND;
}
+
if (context_->root_application_path.get().empty()) {
LOG(ERROR) << "root_application_path attribute is empty";
return Step::Status::INVALID_VALUE;
}
- // set package path
- context_->pkg_path.set(
- context_->root_application_path.get() / context_->pkgid.get());
- install_path_ = context_->pkg_path.get();
- backup_path_ = GetBackupPathForPackagePath(context_->pkg_path.get());
+ install_path_ = context_->GetPkgPath();
+ backup_path_ = GetBackupPathForPackagePath(context_->GetPkgPath());
+
+ // We only "copy" shared dir for backup.
+ // So if there is no shared dir, we don't need to check free space.
+ bf::path shared_dir = install_path_ / "shared";
+ if (!bf::exists(shared_dir))
+ return Status::OK;
+
+ if (!CheckFreeSpace(backup_path_, shared_dir)) {
+ LOG(ERROR) << "not enough space for backup";
+ return Step::Status::OUT_OF_SPACE;
+ }
return Status::OK;
}
Step::Status StepCopyBackup::process() {
+ if (!CleanBackupDirectory())
+ return Status::APP_DIR_ERROR;
+
if (!Backup())
return Status::APP_DIR_ERROR;
}
Step::Status StepCopyBackup::clean() {
- if (!CleanBackupDirectory()) {
- LOG(DEBUG) << "Cannot remove backup directory";
- return Status::APP_DIR_ERROR;
- }
- LOG(DEBUG) << "Applications files backup directory removed";
+ LOG(DEBUG) << "Remove Applications files backup directory";
+ CleanBackupDirectory();
if (context_->external_storage)
context_->external_storage->Commit();
if (context_->external_storage)
context_->external_storage->Abort();
- // if backup was created then restore files
- if (bf::exists(backup_path_)) {
- if (!RollbackApplicationDirectory()) {
- LOG(ERROR) << "Failed to revert package directory";
- return Status::APP_DIR_ERROR;
- }
- LOG(DEBUG) << "Application files reverted from backup";
+ if (!bf::exists(backup_path_))
+ return Status::OK;
+
+ if (!RollbackApplicationDirectory()) {
+ LOG(ERROR) << "Failed to revert package directory";
+ return Status::APP_DIR_ERROR;
}
+
+ LOG(DEBUG) << "Application files reverted from backup";
+
return Status::OK;
}
bool StepCopyBackup::Backup() {
- // create backup directory
bs::error_code error;
- bf::create_directories(backup_path_, error);
+ if (!bf::exists(backup_path_)) {
+ bf::create_directories(backup_path_, error);
+ if (error) {
+ LOG(ERROR) << "Failed to create backup directory: " << backup_path_;
+ return false;
+ }
+ }
// create copy of old package content skipping the external memory mount point
- for (bf::directory_iterator iter(context_->pkg_path.get());
+ for (bf::directory_iterator iter(context_->GetPkgPath());
iter != bf::directory_iterator(); ++iter) {
if (iter->path().filename() == kExternalMemoryMountPoint)
continue;
}
}
- if (bf::is_directory(iter->path())) {
- if (!MoveDir(iter->path(), backup_path_ / iter->path().filename())) {
- LOG(ERROR) << "Fail to backup package directory of: " << iter->path();
- return false;
- }
- } else {
- if (!MoveFile(iter->path(), backup_path_ / iter->path().filename())) {
- LOG(ERROR) << "Fail to backup package file: " << iter->path();
- return false;
- }
- }
+ if (!Move(iter->path(), backup_path_))
+ return false;
}
+
+ AddRecoveryInfo();
+
LOG(INFO) << "Old package context saved to: " << backup_path_;
return true;
}
for (bf::directory_iterator iter(from);
iter != bf::directory_iterator(); ++iter) {
- if (bf::is_directory(iter->path())) {
- if (!MoveDir(iter->path(), to / iter->path().filename())) {
- LOG(ERROR) << "Fail to backup package directory of: " << iter->path();
- return false;
- }
- } else if (bf::is_symlink(symlink_status(iter->path()))) {
- bs::error_code error;
+ if (bf::is_symlink(symlink_status(iter->path()))) {
bf::copy_symlink(iter->path(), to / iter->path().filename(), error);
if (error) {
LOG(ERROR) << "Failed to backup package symlink: " << iter->path();
return false;
}
} else {
- if (!MoveFile(iter->path(), to / iter->path().filename())) {
+ if (!Move(iter->path(), to)) {
LOG(ERROR) << "Fail to backup package file: " << iter->path();
return false;
}
}
}
+
return true;
}
if (context_->request_type.get() == RequestType::Update &&
!context_->external_storage && bf::exists(install_path_ / ".mmc")) {
LOG(WARNING) << "Remove unnecessary files for external storage";
+
bs::error_code error;
bf::remove((install_path_ / ".mmc"), error);
if (error)
}
bool StepCopyBackup::NewContent() {
+ ci::RemoveRWDirectories(context_->unpacked_dir_path.get());
+
bs::error_code error;
bf::create_directories(install_path_.parent_path(), error);
if (error) {
LOG(ERROR) << "Cannot create package directory";
return false;
}
- if (!MoveDir(context_->unpacked_dir_path.get(), install_path_,
- FSFlag::FS_MERGE_SKIP)) {
- LOG(ERROR) << "Fail to copy tmp dir: " << context_->unpacked_dir_path.get()
- << " to dst dir: " << install_path_;
- return false;
+
+ if (ShouldBackupSharedRes()) {
+ if (!CreateSharedRes(backup_path_, context_->GetPkgPath()))
+ return false;
+ }
+
+ for (bf::directory_iterator iter(context_->unpacked_dir_path.get());
+ iter != bf::directory_iterator(); ++iter) {
+ if (!Move(iter->path(), install_path_, FS_MERGE_SKIP))
+ return false;
}
+ // If other application tries to access shared/res of package being installed,
+ // it will be failed due to permission deny. Set its permission before
+ // StepChangeOwnershipAndPermission to prevent it.
+ uid_t uid = context_->uid.get();
+ boost::optional<gid_t> gid = common_installer::GetGidByUid(uid);
+ if (!gid) {
+ LOG(ERROR) << "Failed to get gid";
+ return false;
+ }
+ if (bf::exists(install_path_ / "shared/res") &&
+ !common_installer::SetOwnershipAll(
+ install_path_ / "shared/res", uid, *gid)) {
+ LOG(ERROR) << "Failed to set ownership";
+ return false;
+ }
LOG(INFO) << "Successfully move: " << context_->unpacked_dir_path.get()
<< " to: " << install_path_ << " directory";
+ ci::RemoveAll(context_->unpacked_dir_path.get());
return true;
}
bool StepCopyBackup::CleanBackupDirectory() {
- if (bf::exists(backup_path_)) {
- bs::error_code error;
- bf::remove_all(backup_path_, error);
- if (error)
- return false;
- }
- return true;
+ return ci::RemoveAll(backup_path_);
}
bool StepCopyBackup::RollbackApplicationDirectory() {
bs::error_code error;
- if (bf::exists(context_->pkg_path.get())) {
- bf::remove_all(context_->pkg_path.get(), error);
- if (error) {
- return false;
+ bf::path root_path = context_->GetPkgPath();
+ if (bf::exists(root_path)) {
+ for (bf::directory_iterator iter(root_path);
+ iter != bf::directory_iterator(); ++iter) {
+ bf::remove_all(iter->path(), error);
+ if (error)
+ return false;
}
}
- if (!MoveDir(backup_path_, context_->pkg_path.get())) {
- return false;
+ for (bf::directory_iterator iter(backup_path_);
+ iter != bf::directory_iterator(); ++iter) {
+ if (!Move(iter->path(), root_path)) {
+ LOG(ERROR) << "Failed to recovery backup file(" << iter->path() << ")";
+ return false;
+ }
}
+ RemoveAll(backup_path_);
uid_t uid = context_->uid.get();
- tzplatform_set_user(uid);
- gid_t gid = tzplatform_getgid(TZ_USER_NAME);
- tzplatform_reset_user();
// restore ownership changed during installation
- if (!SetOwnershipAll(context_->pkg_path.get(), uid, gid))
+ if (!SetPackageDirectoryOwnerAndPermissions(context_->GetPkgPath(), uid))
return false;
return true;
}
+void StepCopyBackup::AddRecoveryInfo() {
+ recovery::RecoveryFile* recovery_file =
+ context_->recovery_info.get().recovery_file.get();
+ recovery_file->set_backup_done(true);
+ recovery_file->WriteAndCommitFileContent();
+}
+
+bool StepCopyBackup::ShouldBackupSharedRes() {
+ if (bf::exists(backup_path_ / kSharedResPath) &&
+ bf::exists(context_->unpacked_dir_path.get() / kSharedResPath))
+ return true;
+
+ return false;
+}
+
} // namespace backup
} // namespace common_installer