Implement clean operation for recovery 57/216457/6
authorJunghyun Yeon <jungh.yeon@samsung.com>
Fri, 25 Oct 2019 06:08:31 +0000 (15:08 +0900)
committerJunghyun Yeon <jungh.yeon@samsung.com>
Thu, 7 Nov 2019 05:01:40 +0000 (14:01 +0900)
Installer operates based on files so it could not work properly
when any package file has deleted. Sometimes abnormal termination during
updating package will fail due to loss of backup files, so when installer
pass through some threshold, its recovery operation should be "cleanup",
not revert into previous package.
This implementation sets recovery type as cleanup before removing backup files
and when recovery has invoked due to sudden power loss, cleanup will be performed.

Change-Id: I129003c514abf9b553b9687719ba28549893acb1
Signed-off-by: Junghyun Yeon <jungh.yeon@samsung.com>
src/common/recovery_file.cc
src/common/recovery_file.h
src/common/step/backup/step_copy_backup.cc
src/common/step/filesystem/step_recover_files.cc
src/common/step/filesystem/step_recover_files.h
src/common/step/filesystem/step_remove_temporary_directory.cc
src/common/step/filesystem/step_remove_temporary_directory.h
src/common/step/recovery/step_open_recovery_file.cc
src/common/step/recovery/step_recovery.cc
src/common/step/recovery/step_recovery.h

index c923b46..6481475 100644 (file)
@@ -87,7 +87,7 @@ std::unique_ptr<RecoveryFile> RecoveryFile::OpenRecoveryFile(
 }
 
 RecoveryFile::RecoveryFile(const bf::path& path, RequestType type, bool load)
-    : type_(type), path_(path), backup_done_(false) {
+    : type_(type), path_(path), backup_done_(false), cleanup_(false) {
   if (load) {
     if (!ReadFileContent()) {
       path_.clear();
@@ -130,6 +130,10 @@ void RecoveryFile::set_backup_done(bool backup_done) {
   backup_done_ = backup_done;
 }
 
+void RecoveryFile::set_cleanup(bool cleanup) {
+  cleanup_ = cleanup;
+}
+
 const boost::filesystem::path& RecoveryFile::unpacked_dir() const {
   return unpacked_dir_;
 }
@@ -146,6 +150,10 @@ bool RecoveryFile::backup_done() const {
   return backup_done_;
 }
 
+bool RecoveryFile::cleanup() const {
+  return cleanup_;
+}
+
 bool RecoveryFile::ReadFileContent() {
   FILE* handle = fopen(path_.c_str(), "r");
   if (!handle) {
@@ -186,6 +194,15 @@ bool RecoveryFile::ReadFileContent() {
     backup_done_ = true;
   else
     backup_done_ = false;
+  if (!fgets(data.data(), data.size(), handle)) {
+    fclose(handle);
+    return true;
+  }
+  std::string cleanup_flag = TruncateNewLine(data.data());
+  if (cleanup_flag == "cleanup")
+    cleanup_ = true;
+  else
+    cleanup_ = false;
   fclose(handle);
   return true;
 }
@@ -233,6 +250,8 @@ bool RecoveryFile::WriteAndCommitFileContent() {
   fputs("\n", handle);
   fputs(backup_done_ ? "true" : "false", handle);
   fputs("\n", handle);
+  fputs(cleanup_ ? "cleanup" : "rollback", handle);
+  fputs("\n", handle);
   fclose(handle);
   sync();
   return true;
index b5a2bc5..39face2 100644 (file)
@@ -81,6 +81,13 @@ class RecoveryFile {
   void set_backup_done(bool backup_done);
 
   /**
+   * setter for cleanup flag
+   *
+   * \param cleanup boolean value of cleanup
+   */
+  void set_cleanup(bool cleanup);
+
+  /**
    * getter for unpacked dir
    *
    * \return current unpacked_dir
@@ -109,6 +116,13 @@ class RecoveryFile {
   bool backup_done() const;
 
   /**
+   * getter for cleanup flag
+   *
+   * \return true if cleanup flag has set
+   */
+  bool cleanup() const;
+
+  /**
    * Transaction of current RecoveryFile content into recovery file
    *
    * \return true if success
@@ -127,6 +141,7 @@ class RecoveryFile {
 
   boost::filesystem::path path_;
   bool backup_done_;
+  bool cleanup_;
 };
 
 }  // namespace recovery
index 531ff33..10f8465 100644 (file)
@@ -93,6 +93,11 @@ Step::Status StepCopyBackup::process() {
 }
 
 Step::Status StepCopyBackup::clean() {
+  recovery::RecoveryFile* recovery_file =
+      context_->recovery_info.get().recovery_file.get();
+  recovery_file->set_cleanup(true);
+  recovery_file->WriteAndCommitFileContent();
+
   if (!CleanBackupDirectory()) {
     LOG(DEBUG) << "Cannot remove backup directory";
     return Status::APP_DIR_ERROR;
index c7ad7a1..616de93 100644 (file)
@@ -10,6 +10,7 @@
 
 #include "common/paths.h"
 #include "common/recovery_file.h"
+#include "common/request.h"
 #include "common/utils/file_util.h"
 
 namespace bf = boost::filesystem;
@@ -97,6 +98,24 @@ Step::Status StepRecoverFiles::RecoveryReadonlyUpdateInstall() {
   return Status::OK;
 }
 
+Step::Status StepRecoverFiles::Cleanup() {
+  recovery::RecoveryFile* recovery_file =
+      context_->recovery_info.get().recovery_file.get();
+  bf::path root_path(GetRootAppPath(
+      context_->is_readonly_package.get(), context_->uid.get()));
+  bf::path backup_path = GetBackupPathForPackagePath(
+      root_path / recovery_file->pkgid());
+  if (!bf::exists(backup_path))
+    return Status::OK;
+
+  if (!RemoveAll(backup_path)) {
+    LOG(ERROR) << "Failed to remove backup path";
+    return Status::RECOVERY_ERROR;
+  }
+
+  return Status::OK;
+}
+
 }  // namespace filesystem
 }  // namespace common_installer
 
index 93df5b4..c844ff3 100644 (file)
@@ -30,6 +30,7 @@ class StepRecoverFiles : public recovery::StepRecovery {
   Status RecoveryMountNew() override;
   Status RecoveryMountUpdate() override;
   Status RecoveryReadonlyUpdateInstall() override;
+  Status Cleanup() override;
 
   STEP_NAME(RecoverFiles)
 };
index 4d6878a..98b52b6 100644 (file)
@@ -22,6 +22,10 @@ Step::Status StepRemoveTemporaryDirectory::RecoveryNew() {
   return RemoveFiles();
 }
 
+Step::Status StepRemoveTemporaryDirectory::Cleanup() {
+  return RemoveFiles();
+}
+
 Step::Status StepRemoveTemporaryDirectory::RemoveFiles() {
   bf::path unpack_dir_path = context_->unpacked_dir_path.get();
   bf::path patch_dir_path = unpack_dir_path;
index d7c779d..fd5ae94 100644 (file)
@@ -26,6 +26,7 @@ class StepRemoveTemporaryDirectory : public recovery::StepRecovery {
 
   Status RecoveryNew() override;
   Status RecoveryUpdate() override;
+  Status Cleanup() override;
  private:
   /**
    * @brief RemoveFiles
index 4f36c7d..dded54a 100644 (file)
@@ -56,6 +56,8 @@ Step::Status StepOpenRecoveryFile::process() {
                  << static_cast<int>(recovery_file->type()) << ")";
       return Status::RECOVERY_ERROR;
   }
+  if (recovery_file->cleanup())
+    LOG(INFO) << "Running cleanup operation";
 
   context_->recovery_info.set(RecoveryInfo(std::move(recovery_file)));
   return Status::OK;
index 41b1400..a24d844 100644 (file)
@@ -12,6 +12,9 @@ namespace common_installer {
 namespace recovery {
 
 Step::Status StepRecovery::process() {
+  if (context_->recovery_info.get().recovery_file->cleanup())
+    return Cleanup();
+
   switch (context_->recovery_info.get().recovery_file->type()) {
   case RequestType::Install:
     return RecoveryNew();
@@ -47,5 +50,9 @@ Step::Status StepRecovery::RecoveryReadonlyUpdateInstall() {
   return RecoveryUpdate();
 }
 
+Step::Status StepRecovery::Cleanup() {
+  return Status::OK;
+}
+
 }  // namespace recovery
 }  // namespace common_installer
index f4653d3..9ad7b53 100644 (file)
@@ -38,6 +38,7 @@ class StepRecovery : public Step {
   virtual Status RecoveryMountNew();
   virtual Status RecoveryMountUpdate();
   virtual Status RecoveryReadonlyUpdateInstall();
+  virtual Status Cleanup();
 };
 
 }  // namespace recovery