[XWALK-214] RDS support 51/42051/4
authorWojciech Kosowicz <w.kosowicz@samsung.com>
Fri, 12 Jun 2015 15:24:29 +0000 (17:24 +0200)
committerPawel Sikorski <p.sikorski@samsung.com>
Mon, 29 Jun 2015 12:30:47 +0000 (05:30 -0700)
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
src/wgt/CMakeLists.txt
src/wgt/rds_parser.cc [new file with mode: 0644]
src/wgt/rds_parser.h [new file with mode: 0644]
src/wgt/step/step_rds_modify.cc [new file with mode: 0644]
src/wgt/step/step_rds_modify.h [new file with mode: 0644]
src/wgt/step/step_rds_parse.cc [new file with mode: 0644]
src/wgt/step/step_rds_parse.h [new file with mode: 0644]
src/wgt/wgt_backend.cc
src/wgt/wgt_backend_data.h

index f93e002..e17981f 100644 (file)
@@ -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) <<
index 2d721fd..c9fc768 100644 (file)
@@ -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 (file)
index 0000000..9f2fbb7
--- /dev/null
@@ -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 <fstream>
+
+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<std::string>* 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<std::string>& RDSParser::files_to_modify() const {
+  return files_to_modify_;
+}
+
+const std::vector<std::string>& RDSParser::files_to_add() const {
+  return files_to_add_;
+}
+
+const std::vector<std::string>& 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 (file)
index 0000000..26d1b2d
--- /dev/null
@@ -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 <string>
+#include <vector>
+namespace wgt {
+namespace rds_parser {
+
+class RDSParser {
+ public:
+  explicit RDSParser(const std::string& path_to_delta);
+
+  bool Parse();
+
+  const std::vector<std::string>& files_to_modify() const;
+  const std::vector<std::string>& files_to_add() const;
+  const std::vector<std::string>& files_to_delete() const;
+ private:
+  std::string path_to_delta_;
+  std::vector<std::string> files_to_modify_;
+  std::vector<std::string> files_to_add_;
+  std::vector<std::string> 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 (file)
index 0000000..673f0be
--- /dev/null
@@ -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 <boost/system/error_code.hpp>
+
+#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<WgtBackendData*>(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<std::string, Operation>& 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 (file)
index 0000000..1ee0025
--- /dev/null
@@ -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 <boost/filesystem.hpp>
+#include <string>
+#include <utility>
+#include <vector>
+
+#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<std::pair<std::string, Operation>> success_modifications_;
+  boost::filesystem::path backup_temp_dir_;
+  std::vector<std::string> files_to_modify_;
+  std::vector<std::string> files_to_add_;
+  std::vector<std::string> 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 (file)
index 0000000..9910b67
--- /dev/null
@@ -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 <memory>
+
+#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<WgtBackendData*>(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 (file)
index 0000000..6020363
--- /dev/null
@@ -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 <boost/filesystem.hpp>
+#include <string>
+#include <vector>
+
+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_
index 7d302fa..ea62696 100644 (file)
@@ -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<ci::revoke_security::StepRevokeSecurity>();
       break;
     }
+    case ci::PkgMgrInterface::Type::Reinstall: {
+      installer.AddStep<ci::configure::StepConfigure>();
+      installer.AddStep<wgt::parse::StepParse>();
+      installer.AddStep<ci::old_manifest::StepOldManifest>();
+      installer.AddStep<wgt::rds_parse::StepRDSParse>();
+      installer.AddStep<wgt::rds_modify::StepRDSModify>();
+      installer.AddStep<ci::update_security::StepUpdateSecurity>();
+
+    break;
+  }
     default: {
       // unsupported operation
       return EINVAL;
index 51d5c70..5df0839 100644 (file)
@@ -7,6 +7,9 @@
 
 #include <manifest_handlers/setting_handler.h>
 
+#include <string>
+#include <vector>
+
 #include "common/context_installer.h"
 #include "common/utils/property.h"
 
@@ -16,6 +19,10 @@ class WgtBackendData : public common_installer::BackendData {
  public:
   WgtBackendData();
 
+  Property<std::vector<std::string>> files_to_add;
+  Property<std::vector<std::string>> files_to_modify;
+  Property<std::vector<std::string>> files_to_delete;
+
   Property<parse::SettingInfo> settings;
 };