From e6a55f4dbc4c90077f8050495ee5a774f05e692f Mon Sep 17 00:00:00 2001 From: Wojciech Kosowicz Date: Fri, 12 Jun 2015 17:24:29 +0200 Subject: [PATCH] [XWALK-214] RDS support Implemented: * parsing rds_delta file * actions(add/delete/modify) on changed files * backup of files before modification * restoring files in case of failure * registering smack labels Change-Id: Ia0fd00567d50c70588dc6f4af69c5c3f581cc006 --- src/common/step/step_configure.cc | 5 + src/wgt/CMakeLists.txt | 3 + src/wgt/rds_parser.cc | 61 +++++++++++ src/wgt/rds_parser.h | 32 ++++++ src/wgt/step/step_rds_modify.cc | 224 ++++++++++++++++++++++++++++++++++++++ src/wgt/step/step_rds_modify.h | 53 +++++++++ src/wgt/step/step_rds_parse.cc | 49 +++++++++ src/wgt/step/step_rds_parse.h | 31 ++++++ src/wgt/wgt_backend.cc | 12 ++ src/wgt/wgt_backend_data.h | 7 ++ 10 files changed, 477 insertions(+) create mode 100644 src/wgt/rds_parser.cc create mode 100644 src/wgt/rds_parser.h create mode 100644 src/wgt/step/step_rds_modify.cc create mode 100644 src/wgt/step/step_rds_modify.h create mode 100644 src/wgt/step/step_rds_parse.cc create mode 100644 src/wgt/step/step_rds_parse.h diff --git a/src/common/step/step_configure.cc b/src/common/step/step_configure.cc index f93e002..e17981f 100644 --- a/src/common/step/step_configure.cc +++ b/src/common/step/step_configure.cc @@ -34,6 +34,11 @@ Step::Status StepConfigure::process() { context_->pkgid.set(pkgmgr->GetRequestInfo()); context_->file_path.set(kStrEmpty); break; + case PkgMgrInterface::Type::Reinstall: + context_->unpacked_dir_path.set(pkgmgr->GetRequestInfo()); + context_->pkgid.set(kStrEmpty); + context_->file_path.set(kStrEmpty); + break; default: // TODO(p.sikorski): should return unsupported, and display error LOG(ERROR) << diff --git a/src/wgt/CMakeLists.txt b/src/wgt/CMakeLists.txt index 2d721fd..c9fc768 100644 --- a/src/wgt/CMakeLists.txt +++ b/src/wgt/CMakeLists.txt @@ -1,8 +1,11 @@ # Target - sources SET(SRCS + rds_parser.cc step/step_check_settings_level.cc step/step_create_symbolic_link.cc step/step_parse.cc + step/step_rds_parse.cc + step/step_rds_modify.cc wgt_app_query_interface.cc wgt_backend.cc wgt_backend_data.cc diff --git a/src/wgt/rds_parser.cc b/src/wgt/rds_parser.cc new file mode 100644 index 0000000..9f2fbb7 --- /dev/null +++ b/src/wgt/rds_parser.cc @@ -0,0 +1,61 @@ +// Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved +// Use of this source code is governed by a apache 2.0 license that can be +// found in the LICENSE file. + +#include "wgt/rds_parser.h" + +#include + +namespace { +const char kAdd[] = "#add"; +const char kModify[] = "#modify"; +const char kDelete[] = "#delete"; +} + +namespace wgt { +namespace rds_parser { + +RDSParser::RDSParser(const std::string& path_to_delta) + : path_to_delta_(path_to_delta) {} + +bool RDSParser::Parse() { + std::vector* current_container = nullptr; + std::string line; + + std::ifstream file_to_parse(path_to_delta_); + if (!file_to_parse.is_open()) + return false; + while (getline(file_to_parse, line)) { + if (line.compare(kDelete) == 0) { + current_container = &files_to_delete_; + continue; + } + if (line.compare(kAdd) == 0) { + current_container = &files_to_add_; + continue; + } + if (line.compare(kModify) == 0) { + current_container = &files_to_modify_; + continue; + } + if (current_container) + current_container->push_back(line); + } + file_to_parse.close(); + return true; +} + +const std::vector& RDSParser::files_to_modify() const { + return files_to_modify_; +} + +const std::vector& RDSParser::files_to_add() const { + return files_to_add_; +} + +const std::vector& RDSParser::files_to_delete() const { + return files_to_delete_; +} + +} // namespace rds_parser +} // namespace wgt diff --git a/src/wgt/rds_parser.h b/src/wgt/rds_parser.h new file mode 100644 index 0000000..26d1b2d --- /dev/null +++ b/src/wgt/rds_parser.h @@ -0,0 +1,32 @@ +// Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved +// Use of this source code is governed by a apache 2.0 license that can be +// found in the LICENSE file. + +#ifndef WGT_RDS_PARSER_H_ +#define WGT_RDS_PARSER_H_ + +#include +#include +namespace wgt { +namespace rds_parser { + +class RDSParser { + public: + explicit RDSParser(const std::string& path_to_delta); + + bool Parse(); + + const std::vector& files_to_modify() const; + const std::vector& files_to_add() const; + const std::vector& files_to_delete() const; + private: + std::string path_to_delta_; + std::vector files_to_modify_; + std::vector files_to_add_; + std::vector files_to_delete_; +}; + +} // namespace rds_parser +} // namespace wgt + +#endif // WGT_RDS_PARSER_H_ diff --git a/src/wgt/step/step_rds_modify.cc b/src/wgt/step/step_rds_modify.cc new file mode 100644 index 0000000..673f0be --- /dev/null +++ b/src/wgt/step/step_rds_modify.cc @@ -0,0 +1,224 @@ +// Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved +// Use of this source code is governed by a apache 2.0 license that can be +// found in the LICENSE file. + +#include "wgt/step/step_rds_modify.h" + +#include + +#include "common/utils/file_util.h" +#include "common/utils/logging.h" + +namespace wgt { +namespace rds_modify { + +namespace bf = boost::filesystem; +namespace bs = boost::system; +namespace cu = common_installer; + +StepRDSModify::StepRDSModify(common_installer::ContextInstaller* context) + : Step(context), + backend_data_(nullptr) {} + +common_installer::Step::Status StepRDSModify::precheck() { + if (context_->unpacked_dir_path.get().empty()) { + LOG(ERROR) << "unpacked dir path is not set"; + return common_installer::Step::Status::ERROR; + } + if (!bf::exists(context_->unpacked_dir_path.get())) { + LOG(ERROR) << "unpacked_dir_path (" + << context_->unpacked_dir_path.get() + << ") path does not exist"; + return common_installer::Step::Status::ERROR; + } + if (context_->pkgid.get().empty()) { + LOG(ERROR) << "pkgid is not set"; + return common_installer::Step::Status::ERROR; + } + if(!context_->manifest_data.get()) { + LOG(ERROR) << "no manifest info available"; + return common_installer::Step::Status::ERROR; + } + // TODO(w.kosowicz): check if config of installed app was encrypted + backend_data_ = static_cast(context_->backend_data.get()); + if (!backend_data_) { + LOG(ERROR) << "no backend data"; + return common_installer::Step::Status::ERROR; + } + return common_installer::Step::Status::OK; +} + +common_installer::Step::Status StepRDSModify::process() { + LOG(INFO) << "entered process of step modify"; + if (!SetUpTempBackupDir()) { + LOG(ERROR) << "unable to setup temp directory"; + return common_installer::Step::Status::ERROR; + } + context_->pkg_path.set( + context_->root_application_path.get() /context_->pkgid.get()); + bf::path install_path = context_->pkg_path.get() / + context_->manifest_data.get()->mainapp_id; + bf::path unzip_path = context_->unpacked_dir_path.get(); + if (!AddFiles(unzip_path, install_path) || + !ModifyFiles(unzip_path, install_path) || + !DeleteFiles(install_path)) { + LOG(ERROR) << "error during file operation"; + return common_installer::Step::Status::ERROR; + } + return common_installer::Step::Status::OK; +} + +common_installer::Step::Status StepRDSModify::undo() { + RestoreFiles(); + return common_installer::Step::Status::OK; +} + +common_installer::Step::Status StepRDSModify::clean() { + if (bf::exists(backup_temp_dir_)) + bf::remove_all(backup_temp_dir_); + return common_installer::Step::Status::OK; +} + +bool StepRDSModify::AddFiles(bf::path unzip_path, bf::path install_path) { + LOG(INFO) << "about to add files"; + bs::error_code error; + for (const auto& file : backend_data_->files_to_add.get()) { + if (!PerformBackup(file, Operation::ADD)) { + LOG(ERROR) << "unable to perform backup of added file"; + return false; + } + bf::path temp_install_path(install_path / file); + if (bf::is_directory(temp_install_path)) { + if (!bf::exists(temp_install_path) && (!cu::CreateDir(temp_install_path))) { + LOG(ERROR) << "unable to create dir for temp backup data"; + return false; + } + } else { + if (!bf::exists(temp_install_path.parent_path()) && + !cu::CreateDir(temp_install_path.parent_path())) { + LOG(ERROR) << "unable to create dir for temp backup data"; + return false; + } + bf::path temp_unzip_path(unzip_path / file); + bf::copy_file(temp_unzip_path, temp_install_path, error); + if (error) { + LOG(ERROR) << "unable to add file " << error.message(); + return false; + } + } + } + return true; +} + +bool StepRDSModify::ModifyFiles(bf::path unzip_path, bf::path install_path) { + LOG(INFO) << "about to modify files"; + bs::error_code error; + for (const auto& file : backend_data_->files_to_modify.get()) { + bf::path temp_install_path(install_path / file); + bf::path temp_unzip_path(unzip_path / file); + if (!PerformBackup(file, Operation::MODIFY)) { + LOG(ERROR) << "unable to perform backup of to be modified file"; + return false; + } + bf::copy_file(temp_unzip_path, temp_install_path, + bf::copy_option::overwrite_if_exists, error); + if (error) { + LOG(ERROR) << "unable to modify file " << error.message(); + return false; + } + } + return true; +} + +bool StepRDSModify::DeleteFiles(bf::path install_path) { + LOG(INFO) << "about to delete files"; + bs::error_code error; + for (const auto& file : backend_data_->files_to_delete.get()) { + if (!PerformBackup(file, Operation::DELETE)) { + LOG(ERROR) << "unable to perform backup of to be deleted file"; + return false; + } + bf::remove(install_path / file, error); + if (error) { + LOG(ERROR) <<"unable to delete files " << error.message(); + return false; + } + } + return true; +} + +bool StepRDSModify::SetUpTempBackupDir() { + LOG(INFO) << "about to setup tmp backup dir"; + bs::error_code error; + backup_temp_dir_ = "/tmp/" / + bf::unique_path("%%%%-%%%%-%%%%-%%%%", error); + if (error || !cu::CreateDir(backup_temp_dir_)) { + LOG(ERROR) << "unable to create backup data temp dir"; + return false; + } + return true; +} + +bool StepRDSModify::PerformBackup(std::string relative_path, + Operation operation) { + if (backup_temp_dir_.empty()) + return false; + if (operation == Operation::DELETE || operation == Operation::MODIFY) { + bf::path app_path = context_->pkg_path.get() / + context_->manifest_data.get()->mainapp_id;; + bf::path source_path = app_path / relative_path; + if (bf::is_directory(source_path)) { + if (!cu::CreateDir(backup_temp_dir_ / relative_path)) { + LOG(ERROR) << "unable to create dir for temp backup data"; + return false; + } + } else { + bs::error_code error; + bf::path tmp_dest_path = backup_temp_dir_ / relative_path; + if (!bf::exists((tmp_dest_path).parent_path()) && + (!cu::CreateDir((tmp_dest_path).parent_path()))) { + LOG(ERROR) << "unable to create dir for temp backup data"; + return false; + } + bf::copy_file(source_path, tmp_dest_path, error); + if (error) { + LOG(ERROR) << "unable to backup file " << error.message(); + return false; + } + } + } + success_modifications_.push_back(std::make_pair(relative_path, operation)); + return true; +} + +void StepRDSModify::RestoreFiles() { + LOG(ERROR) << "error occured about to restore files"; + bf::path app_path(context_->pkg_path.get()); + for (std::pair& modification : + success_modifications_) { + bf::path source_path(backup_temp_dir_ / modification.first); + bf::path destination_path(app_path / modification.first); + if (modification.second == Operation::ADD) { + if (bf::is_directory(source_path)) { + bf::remove_all(destination_path); + } else { + bf::remove(destination_path); + } + } else if (modification.second == Operation::MODIFY) { + bf::copy_file(source_path, destination_path, + bf::copy_option::overwrite_if_exists); + } else { + if (bf::is_directory(source_path)) { + cu::CreateDir(destination_path); + } else { + bf::copy_file(source_path, destination_path, + bf::copy_option::overwrite_if_exists); + } + } + } + // after files are restore delete temporary location + bf::remove_all(backup_temp_dir_); +} + +} // namespace rds_modify +} // namespace wgt diff --git a/src/wgt/step/step_rds_modify.h b/src/wgt/step/step_rds_modify.h new file mode 100644 index 0000000..1ee0025 --- /dev/null +++ b/src/wgt/step/step_rds_modify.h @@ -0,0 +1,53 @@ +// Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved +// Use of this source code is governed by a apache 2.0 license that can be +// found in the LICENSE file. + +#ifndef WGT_STEP_STEP_RDS_MODIFY_H_ +#define WGT_STEP_STEP_RDS_MODIFY_H_ + +#include +#include +#include +#include + +#include "common/step/step.h" +#include "wgt/wgt_backend_data.h" + +namespace wgt { +namespace rds_modify { + +class StepRDSModify : public common_installer::Step { + public: + explicit StepRDSModify(common_installer::ContextInstaller* context); + Status process() override; + Status clean() override; + Status undo() override; + Status precheck() override; + + private: + enum class Operation { + ADD, + MODIFY, + DELETE + }; + + bool AddFiles(boost::filesystem::path unzip_path, + boost::filesystem::path install_path); + bool ModifyFiles(boost::filesystem::path unzip_path, + boost::filesystem::path install_path); + bool DeleteFiles(boost::filesystem::path install_path); + bool SetUpTempBackupDir(); + void DeleteTempBackupDir(); + bool PerformBackup(std::string relative_path, Operation operation); + void RestoreFiles(); + + WgtBackendData* backend_data_; + std::vector> success_modifications_; + boost::filesystem::path backup_temp_dir_; + std::vector files_to_modify_; + std::vector files_to_add_; + std::vector files_to_delete_; +}; +} // namespace rds_modify +} // namespace wgt +#endif // WGT_STEP_STEP_RDS_MODIFY_H_ diff --git a/src/wgt/step/step_rds_parse.cc b/src/wgt/step/step_rds_parse.cc new file mode 100644 index 0000000..9910b67 --- /dev/null +++ b/src/wgt/step/step_rds_parse.cc @@ -0,0 +1,49 @@ +// Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved +// Use of this source code is governed by a apache 2.0 license that can be +// found in the LICENSE file. + +#include "wgt/step/step_rds_parse.h" + +#include + +#include "common/utils/logging.h" +#include "wgt/rds_parser.h" +#include "wgt/wgt_backend_data.h" + + +namespace wgt { +namespace rds_parse { + +namespace bf = boost::filesystem; + +common_installer::Step::Status StepRDSParse::precheck() { + bf::path rdsPath(context_->unpacked_dir_path.get() / ".rds_delta"); + if (!bf::exists(rdsPath)) { + LOG(ERROR) << "no rds_delta file"; + return common_installer::Step::Status::ERROR; + } + rds_file_path_ = rdsPath; + return common_installer::Step::Status::OK; +} + +common_installer::Step::Status StepRDSParse::process() { + wgt::rds_parser::RDSParser parser(rds_file_path_.native()); + if (!parser.Parse()) { + LOG(ERROR) << "parsing of rds delta failed"; + return common_installer::Step::Status::ERROR; + } + + WgtBackendData* backend_data = + static_cast(context_->backend_data.get()); + if (!backend_data) { + LOG(ERROR) << "no wgt backend data available"; + return common_installer::Step::Status::ERROR; + } + backend_data->files_to_modify.set(parser.files_to_modify()); + backend_data->files_to_add.set(parser.files_to_add()); + backend_data->files_to_delete.set(parser.files_to_delete()); + return common_installer::Step::Status::OK; +} + +} // namespace rds_parse +} // namespace wgt diff --git a/src/wgt/step/step_rds_parse.h b/src/wgt/step/step_rds_parse.h new file mode 100644 index 0000000..6020363 --- /dev/null +++ b/src/wgt/step/step_rds_parse.h @@ -0,0 +1,31 @@ +// Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved +// Use of this source code is governed by a apache 2.0 license that can be +// found in the LICENSE file. + +#ifndef WGT_STEP_STEP_RDS_PARSE_H_ +#define WGT_STEP_STEP_RDS_PARSE_H_ + +#include "common/step/step.h" + +#include +#include +#include + +namespace wgt { +namespace rds_parse { + +class StepRDSParse : public common_installer::Step { + public: + using Step::Step; + + Status process() override; + Status clean() override { return Status::OK; } + Status undo() override { return Status::OK; } + Status precheck() override; + + private: + boost::filesystem::path rds_file_path_; +}; +} // namespace rds_parse +} // namespace wgt +#endif // WGT_STEP_STEP_RDS_PARSE_H_ diff --git a/src/wgt/wgt_backend.cc b/src/wgt/wgt_backend.cc index 7d302fa..ea62696 100644 --- a/src/wgt/wgt_backend.cc +++ b/src/wgt/wgt_backend.cc @@ -30,6 +30,8 @@ #include "wgt/step/step_create_symbolic_link.h" #include "wgt/step/step_check_settings_level.h" #include "wgt/step/step_parse.h" +#include "wgt/step/step_rds_parse.h" +#include "wgt/step/step_rds_modify.h" #include "wgt/wgt_app_query_interface.h" namespace ci = common_installer; @@ -85,6 +87,16 @@ int main(int argc, char** argv) { installer.AddStep(); break; } + case ci::PkgMgrInterface::Type::Reinstall: { + installer.AddStep(); + installer.AddStep(); + installer.AddStep(); + installer.AddStep(); + installer.AddStep(); + installer.AddStep(); + + break; + } default: { // unsupported operation return EINVAL; diff --git a/src/wgt/wgt_backend_data.h b/src/wgt/wgt_backend_data.h index 51d5c70..5df0839 100644 --- a/src/wgt/wgt_backend_data.h +++ b/src/wgt/wgt_backend_data.h @@ -7,6 +7,9 @@ #include +#include +#include + #include "common/context_installer.h" #include "common/utils/property.h" @@ -16,6 +19,10 @@ class WgtBackendData : public common_installer::BackendData { public: WgtBackendData(); + Property> files_to_add; + Property> files_to_modify; + Property> files_to_delete; + Property settings; }; -- 2.7.4