Add RequestType::Delta and implement delta mode for tpk 21/50521/10
authorTomasz Iwanek <t.iwanek@samsung.com>
Tue, 27 Oct 2015 10:50:59 +0000 (11:50 +0100)
committerPawel Sikorski <p.sikorski@samsung.com>
Thu, 5 Nov 2015 13:50:34 +0000 (05:50 -0800)
Requires:
 - submission of https://review.tizen.org/gerrit/#/c/50418/
 - release of xdelta3 for tizen 3.0

Change-Id: I3066c9457368e9ab229d1500b0cd4a7549edce15

15 files changed:
CMakeLists.txt
packaging/app-installers.spec
src/common/CMakeLists.txt
src/common/pkgmgr_interface.cc
src/common/pkgmgr_signal.cc
src/common/recovery_file.cc
src/common/request.h
src/common/step/step_configure.cc
src/common/step/step_delta_patch.cc [new file with mode: 0644]
src/common/step/step_delta_patch.h [new file with mode: 0644]
src/common/utils/file_util.cc
src/common/utils/file_util.h
src/tpk/tpk_installer.cc
src/tpk/tpk_installer.h
src/wgt/wgt_installer.cc

index 8e6bbbb..706feaa 100644 (file)
@@ -47,6 +47,7 @@ PKG_CHECK_MODULES(TZPLATFORM_CONFIG_DEPS REQUIRED libtzplatform-config)
 PKG_CHECK_MODULES(SECURITY_MANAGER_DEPS REQUIRED security-manager)
 PKG_CHECK_MODULES(MANIFEST_PARSER_DEPS REQUIRED manifest-parser)
 PKG_CHECK_MODULES(MANIFEST_HANDLERS_DEPS REQUIRED manifest-handlers)
+PKG_CHECK_MODULES(DELTA_MANIFEST_HANDLERS_DEPS REQUIRED delta-manifest-handlers)
 PKG_CHECK_MODULES(TPK_MANIFEST_HANDLERS_DEPS REQUIRED tpk-manifest-handlers)
 PKG_CHECK_MODULES(CERT_SVC_DEPS_VCORE REQUIRED cert-svc-vcore)
 PKG_CHECK_MODULES(PKGMGR_PARSER_DEPS REQUIRED pkgmgr-parser)
index ff6deda..62f22e1 100644 (file)
@@ -32,12 +32,14 @@ BuildRequires:  pkgconfig(libtzplatform-config)
 BuildRequires:  pkgconfig(cert-svc-vcore)
 BuildRequires:  pkgconfig(manifest-parser)
 BuildRequires:  pkgconfig(manifest-handlers)
+BuildRequires:  pkgconfig(delta-manifest-handlers)
 BuildRequires:  pkgconfig(capi-security-privilege-manager)
 BuildRequires:  pkgconfig(libwebappenc)
 BuildRequires:  pkgconfig(capi-appfw-app-manager)
 
 Requires: ca-certificates-tizen
 Requires: libtzplatform-config
+Requires: xdelta3
 
 %description
 This is a meta package that installs the common application
index d0d3617..c5e0449 100644 (file)
@@ -20,6 +20,7 @@ SET(SRCS
   step/step_copy_backup.cc
   step/step_copy_storage_directories.cc
   step/step_create_storage_directories.cc
+  step/step_delta_patch.cc
   step/step_fail.cc
   step/step_kill_apps.cc
   step/step_generate_xml.cc
@@ -66,6 +67,7 @@ APPLY_PKG_CONFIG(${TARGET_LIBNAME_COMMON} PUBLIC
   ZLIB_DEPS
   PRIVILEGE_CHECKER_DEPS
   APPMANAGER_DEPS
+  DELTA_MANIFEST_HANDLERS_DEPS
   Boost
 )
 
index 7191276..d599351 100644 (file)
@@ -4,10 +4,21 @@
 
 #include "common/pkgmgr_interface.h"
 
+#include <boost/filesystem/path.hpp>
+
 #include <memory>
+#include <string>
 
 #include "common/app_query_interface.h"
 
+namespace bf = boost::filesystem;
+
+namespace {
+
+const char kDeltaFileExtension[] = ".delta";
+
+}
+
 namespace common_installer {
 
 PkgMgrPtr PkgMgrInterface::Create(int argc, char** argv,
@@ -48,12 +59,26 @@ PkgMgrInterface::~PkgMgrInterface() {
 
 RequestType PkgMgrInterface::GetRequestType() const {
   switch (pkgmgr_installer_get_request_type(pi_)) {
-    case PKGMGR_REQ_INSTALL:
+    case PKGMGR_REQ_INSTALL : {
+      auto request_info = GetRequestInfo();
+      if (!request_info)
+        return RequestType::Unknown;
+      std::string extension = bf::path(request_info).extension().string();
       if (!is_app_installed_) {
-        return RequestType::Install;
+        if (extension == kDeltaFileExtension) {
+          LOG(ERROR) << "Package is not installed. "
+                        "Cannot update from delta package";
+          return RequestType::Unknown;
+        } else {
+          return RequestType::Install;
+        }
       } else {
-        return RequestType::Update;
+        if (extension == kDeltaFileExtension)
+          return RequestType::Delta;
+        else
+          return RequestType::Update;
       }
+    }
     case PKGMGR_REQ_UNINSTALL:
       return RequestType::Uninstall;
     case PKGMGR_REQ_REINSTALL:
index 004cd0a..bf40452 100644 (file)
@@ -23,8 +23,8 @@ const std::map<ci::RequestType, const char*> kEventStr = {
   {ci::RequestType::Recovery, PKGMGR_INSTALLER_INSTALL_EVENT_STR},
   {ci::RequestType::Reinstall, PKGMGR_INSTALLER_INSTALL_EVENT_STR},
   {ci::RequestType::Uninstall, PKGMGR_INSTALLER_UNINSTALL_EVENT_STR},
-  {ci::RequestType::Unknown, PKGMGR_INSTALLER_INSTALL_EVENT_STR},  // not needed
-  {ci::RequestType::Update, PKGMGR_INSTALLER_UPGRADE_EVENT_STR}
+  {ci::RequestType::Update, PKGMGR_INSTALLER_UPGRADE_EVENT_STR},
+  {ci::RequestType::Delta, PKGMGR_INSTALLER_UPGRADE_EVENT_STR}
 };
 
 }  // namespace
@@ -44,6 +44,9 @@ bool PkgmgrSignal::SendStarted(
   }
 
   auto key = kEventStr.find(request_type_);
+  if (key == kEventStr.end()) {
+    return false;
+  }
   if (!SendSignal(PKGMGR_INSTALLER_START_KEY_STR, key->second, type, pkgid)) {
     return false;
   }
index d9bd79d..c4d46f1 100644 (file)
@@ -19,6 +19,7 @@ const char kRecoveryNewInstallationString[] = "NEW";
 const char kRecoveryUpdateInstallationString[] = "UPDATE";
 const char kRecoveryUninstallationString[] = "UNINSTALLATION";
 const char kRecoveryRdsString[] = "RDS";
+const char kRecoveryDeltaString[] = "DELTA";
 const char kRecoveryUnknownString[] = "UNKNOWN";
 
 std::string TruncateNewLine(const char* data) {
@@ -146,6 +147,8 @@ bool RecoveryFile::ReadFileContent() {
     type_ = RequestType::Uninstall;
   } else if (mode == kRecoveryRdsString) {
     type_ = RequestType::Reinstall;
+  } else if (mode == kRecoveryDeltaString) {
+    type_ = RequestType::Delta;
   } else {
     type_ = RequestType::Unknown;
   }
@@ -182,6 +185,9 @@ bool RecoveryFile::WriteAndCommitFileContent() {
   case RequestType::Reinstall:
     fputs(kRecoveryRdsString, handle);
     break;
+  case RequestType::Delta:
+    fputs(kRecoveryDeltaString, handle);
+    break;
   default:
     fputs(kRecoveryUnknownString, handle);
     break;
index ed9ca9b..330c3ff 100644 (file)
@@ -14,6 +14,7 @@ enum class RequestType : int {
   Update,
   Uninstall,
   Reinstall,
+  Delta,
   Recovery
 };
 
index c128065..056ef12 100644 (file)
@@ -44,6 +44,11 @@ Step::Status StepConfigure::process() {
       context_->pkgid.set(kStrEmpty);
       context_->file_path.set(kStrEmpty);
       break;
+    case RequestType::Delta:
+      context_->unpacked_dir_path.set(kStrEmpty);
+      context_->pkgid.set(kStrEmpty);
+      context_->file_path.set(pkgmgr_->GetRequestInfo());
+      break;
     case RequestType::Recovery:
       context_->file_path.set(pkgmgr_->GetRequestInfo());
       context_->pkgid.set(kStrEmpty);
diff --git a/src/common/step/step_delta_patch.cc b/src/common/step/step_delta_patch.cc
new file mode 100644 (file)
index 0000000..3600c3d
--- /dev/null
@@ -0,0 +1,252 @@
+// Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+// Use of this source code is governed by an apache-2.0 license that can be
+// found in the LICENSE file.
+
+#include "common/step/step_delta_patch.h"
+
+#include <boost/system/error_code.hpp>
+#include <boost/filesystem/path.hpp>
+#include <delta/delta_handler.h>
+#include <delta/delta_parser.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#include <cstdlib>
+
+#include "common/utils/file_util.h"
+
+namespace bf = boost::filesystem;
+namespace bs = boost::system;
+namespace ci = common_installer;
+
+namespace {
+
+const char kBinaryDir[] = "bin";
+const char kCacheDir[] = "cache";
+const char kDataDir[] = "data";
+const char kSharedData[] = "shared/data";
+const char kSharedTrusted[] = "shared/trusted";
+
+const char kDeltaFile[] = "delta_info.xml";
+const char kXDeltaBinary[] = "/usr/bin/xdelta3";
+
+bool ValidateDeltaInfo(const delta::DeltaInfo& info) {
+  for (auto& item : info.added()) {
+    if (ci::HasDirectoryClimbing(item))
+      return false;
+  }
+  for (auto& item : info.modified()) {
+    if (ci::HasDirectoryClimbing(item))
+      return false;
+  }
+  for (auto& item : info.removed()) {
+    if (ci::HasDirectoryClimbing(item))
+      return false;
+  }
+  return true;
+}
+
+void RemoveBinarySymlinks(const bf::path& dir) {
+  for (bf::directory_iterator iter(dir / kBinaryDir);
+      iter != bf::directory_iterator(); ++iter) {
+    if (bf::is_symlink(iter->path())) {
+      // FIXME: note that this assumes that it is not possible to create
+      // explicitly symlinks in bin/ directory pointing to whatever
+      bs::error_code error;
+      bf::remove(iter->path(), error);
+    }
+  }
+}
+
+void RemoveStorageDirectories(const bf::path& dir) {
+  bs::error_code error;
+  bf::remove_all(dir / kDataDir, error);
+  bf::remove_all(dir / kCacheDir, error);
+  bf::remove_all(dir / kSharedData, error);
+  bf::remove_all(dir / kSharedTrusted, error);
+}
+
+bool ApplyDeletedFiles(const delta::DeltaInfo& info, const bf::path& app_dir) {
+  for (auto& relative : info.removed()) {
+    bs::error_code error;
+    bf::remove_all(app_dir / relative, error);
+    if (error) {
+      LOG(WARNING) << "Failed to remove";
+    }
+    LOG(DEBUG) << "Deleted: " << relative;
+  }
+  return true;
+}
+
+bool ApplyModifiedFiles(const delta::DeltaInfo& info, const bf::path& app_dir,
+                        const bf::path& patch_dir) {
+  for (auto& relative : info.modified()) {
+    bf::path temp_file = ci::GenerateTemporaryPath(
+        bf::path(ci::GetRootAppPath()) / "tmp_file");
+    bf::path patch_file = patch_dir / relative;
+    bf::path input = app_dir / relative;
+    if (!bf::is_regular_file(input)) {
+      LOG(ERROR) << "Cannot modify. Not a regular file: " << input;
+      return false;
+    }
+    const char* const argv[] = {
+      kXDeltaBinary,
+      "-d",
+      "-s",
+      input.c_str(),
+      patch_file.c_str(),
+      temp_file.c_str(),
+      nullptr,
+    };
+    pid_t pid = fork();
+    if (pid == 0) {
+    int ret = execv(argv[0], const_cast<char* const*>(argv));
+      if (ret != 0) {
+        // no other thing to -> do just quit
+        exit(-1);
+      }
+    } else if (pid == -1) {
+      LOG(ERROR) << "Failed to fork with errno: " << errno;
+      return false;
+    } else {
+      int status;
+      waitpid(pid, &status, 0);
+      if (status != 0) {
+        LOG(ERROR) << "xdelta3 failed with error code: " << status;
+        return false;
+      }
+    }
+    bs::error_code error;
+    bf::copy_file(temp_file, input, bf::copy_option::overwrite_if_exists,
+                  error);
+    if (error) {
+      LOG(ERROR) << "Failed to copy from " << temp_file << " to " << input;
+      bf::remove(temp_file, error);
+      return false;
+    }
+    bf::remove(temp_file, error);
+    LOG(DEBUG) << "Patched: " << relative;
+  }
+  return true;
+}
+
+bool ApplyAddedFiles(const delta::DeltaInfo& info, const bf::path& app_dir,
+                     const bf::path& patch_dir) {
+  for (auto& relative : info.added()) {
+    bf::path source = patch_dir / relative;
+    bf::path target = app_dir / relative;
+    bs::error_code error;
+    if (bf::is_directory(source)) {
+      bf::create_directories(target, error);
+      if (error) {
+        LOG(ERROR) << "Failed to add: " << relative;
+        return false;
+      }
+    } else {
+      if (bf::exists(target)) {
+        bf::remove(target, error);
+        if (error) {
+          LOG(ERROR) << "Cannot remove file: " << target;
+          return false;
+        }
+      }
+      bf::create_directories(target.parent_path(), error);
+      if (!ci::MoveFile(source, target)) {
+        LOG(ERROR) << "Failed to move file: " << source << " to " << target;
+        return false;
+      }
+    }
+    LOG(DEBUG) << "Added: " << relative;
+  }
+  return true;
+}
+
+bool ApplyPatch(const delta::DeltaInfo& info, const bf::path& app_dir,
+                const bf::path& patch_dir) {
+  if (!ApplyDeletedFiles(info, app_dir))
+    return false;
+  if (!ApplyModifiedFiles(info, app_dir, patch_dir))
+    return false;
+  if (!ApplyAddedFiles(info, app_dir, patch_dir))
+    return false;
+  return true;
+}
+
+}  // namespace
+
+namespace common_installer {
+namespace filesystem {
+
+Step::Status StepDeltaPatch::precheck() {
+  if (context_->unpacked_dir_path.get().empty()) {
+    LOG(ERROR) << "Unpacked dir is not set";
+    return Status::ERROR;
+  }
+  if (context_->pkgid.get().empty()) {
+    LOG(ERROR) << "Package id is not set";
+    return Status::ERROR;
+  }
+  return Status::OK;
+}
+
+Step::Status StepDeltaPatch::process() {
+  bf::path delta_file = context_->unpacked_dir_path.get() / kDeltaFile;
+  if (!bf::exists(delta_file)) {
+    LOG(ERROR) << "Delta file doesn't exist in package.";
+    return Status::ERROR;
+  }
+  delta::DeltaParser parser;
+  if (!parser.ParseManifest(delta_file)) {
+    LOG(ERROR) << parser.GetErrorMessage();
+    return Status::ERROR;
+  }
+  std::shared_ptr<const delta::DeltaInfo> delta_info =
+      std::static_pointer_cast<const delta::DeltaInfo>(
+        parser.GetManifestData(delta::kDeltaInfoKey));
+  if (!delta_info) {
+    LOG(ERROR) << "Failed to parse delta information";
+    return Status::ERROR;
+  }
+
+  // additional validation
+  if (!ValidateDeltaInfo(*delta_info)) {
+    LOG(ERROR) << "Delta info is malformed";
+    return Status::ERROR;
+  }
+
+  // create old content directory and patch directory
+  patch_dir_ = context_->unpacked_dir_path.get();
+  patch_dir_ += ".patch";
+  if (!MoveDir(context_->unpacked_dir_path.get(), patch_dir_)) {
+    LOG(ERROR) << "Failed to move content to patch directory";
+    return Status::ERROR;
+  }
+
+  if (!CopyDir(context_->root_application_path.get() / context_->pkgid.get(),
+               context_->unpacked_dir_path.get())) {
+    LOG(ERROR) << "Failed to copy package files";
+    return Status::ERROR;
+  }
+
+  RemoveBinarySymlinks(context_->unpacked_dir_path.get());
+  RemoveStorageDirectories(context_->unpacked_dir_path.get());
+
+  // apply changes mentioned in delta
+  if (!ApplyPatch(*delta_info, context_->unpacked_dir_path.get(), patch_dir_))
+    return Status::ERROR;
+
+  bs::error_code error;
+  bf::remove_all(patch_dir_, error);
+  LOG(INFO) << "Delta patch applied successfully";
+  return Status::OK;
+}
+
+Step::Status StepDeltaPatch::undo() {
+  bs::error_code error;
+  bf::remove_all(patch_dir_, error);
+  return Status::OK;
+}
+
+}  // namespace filesystem
+}  // namespace common_installer
diff --git a/src/common/step/step_delta_patch.h b/src/common/step/step_delta_patch.h
new file mode 100644 (file)
index 0000000..6722c88
--- /dev/null
@@ -0,0 +1,53 @@
+// Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+// Use of this source code is governed by an apache-2.0 license that can be
+// found in the LICENSE file.
+
+#ifndef COMMON_STEP_STEP_DELTA_PATCH_H_
+#define COMMON_STEP_STEP_DELTA_PATCH_H_
+
+#include "common/installer_context.h"
+
+#include "common/step/step.h"
+#include "common/utils/logging.h"
+
+namespace common_installer {
+namespace filesystem {
+
+/**
+ * @brief The StepDeltaPatch class
+ *        Patches the unpack directory content according to delta file so that
+ *        new package content is complete and no file is missing.
+ *
+ * Patching package files with delta is performed in unpacked_dir before all
+ * step that operates on widget's final location. That means that whole new
+ * package content is prepared before any files of package installation are
+ * touched.
+ *
+ * Flow goes as below:
+ *  1) `unpacked_dir` (where delta package is unpacked) is moved to
+ *     `unpacked_dir_patch` (PATCH DIR)
+ *  2) old package content is moved to `unpacked_dir` (it becomes APP_DIR)
+ *  3) `unpacked_dir` is being applied with patches (using xdelta3 tool)
+ *  4) `unpacked_dir_patch` is removed.
+ *  5) Normal update flow proceeds as if it it was normal update installation
+ *     (as the unpacked_dir contains full new version of package).
+ */
+class StepDeltaPatch : public Step {
+ public:
+  using Step::Step;
+
+  Status process() override;
+  Status clean() override { return Status::OK; }
+  Status undo() override;
+  Status precheck() override;
+
+ private:
+  boost::filesystem::path patch_dir_;
+
+  SCOPE_LOG_TAG(DeltaPatch)
+};
+
+}  // namespace filesystem
+}  // namespace common_installer
+
+#endif  // COMMON_STEP_STEP_DELTA_PATCH_H_
index 2567944..864cd32 100644 (file)
@@ -131,7 +131,8 @@ bool CopyDir(const bf::path& src, const bf::path& dst) {
       return false;
     }
   } catch (const bf::filesystem_error& error) {
-      LOG(ERROR) << error.what();
+    LOG(ERROR) << "Failed to copy directory: " << error.what();
+    return false;
   }
 
   // Iterate through the source directory
@@ -153,7 +154,8 @@ bool CopyDir(const bf::path& src, const bf::path& dst) {
         bf::copy_file(current, dst / current.filename());
       }
     } catch (const bf::filesystem_error& error) {
-        LOG(ERROR) << error.what();
+      LOG(ERROR) << "Failed to copy directory: " << error.what();
+      return false;
     }
   }
   return true;
@@ -310,12 +312,7 @@ bool ExtractToTmpDir(const char* zip_path, const bf::path& tmp_dir,
       bf::path filename_in_zip_path(raw_file_name_in_zip);
 
       // prevent "directory climbing" attack
-      std::vector<std::string> segments;
-      ba::split(segments, filename_in_zip_path.string(), ba::is_any_of("/\\"));
-      if (std::any_of(segments.begin(), segments.end(),
-                      [](const std::string& segment) {
-                        return segment == "..";
-                      })) {
+      if (HasDirectoryClimbing(filename_in_zip_path)) {
         LOG(ERROR) << "Relative path in widget in malformed";
         return false;
       }
@@ -368,4 +365,20 @@ bool ExtractToTmpDir(const char* zip_path, const bf::path& tmp_dir,
   return true;
 }
 
+bool HasDirectoryClimbing(const boost::filesystem::path& path) {
+  std::vector<std::string> segments;
+  ba::split(segments, path.string(), ba::is_any_of("/\\"));
+  return std::any_of(segments.begin(), segments.end(),
+                  [](const std::string& segment) {
+                    return segment == "..";
+                  });
+}
+
+boost::filesystem::path MakeRelativePath(const boost::filesystem::path& input,
+                                         const boost::filesystem::path& base) {
+  bf::path input_absolute = bf::absolute(input);
+  bf::path base_absolute = bf::absolute(base);
+  return input_absolute.string().substr(base_absolute.string().length() + 1);
+}
+
 }  // namespace common_installer
index f1ab81b..feed526 100644 (file)
@@ -34,6 +34,11 @@ bool ExtractToTmpDir(const char* zip_path,
                      const boost::filesystem::path& tmp_dir,
                      const std::string& filter_prefix);
 
+bool HasDirectoryClimbing(const boost::filesystem::path& path);
+
+boost::filesystem::path MakeRelativePath(const boost::filesystem::path& input,
+                                         const boost::filesystem::path& base);
+
 }  // namespace common_installer
 
 #endif  // COMMON_UTILS_FILE_UTIL_H_
index 2172f1b..2cd62f6 100644 (file)
@@ -9,6 +9,7 @@
 #include "common/step/step_copy.h"
 #include "common/step/step_copy_backup.h"
 #include "common/step/step_check_old_certificate.h"
+#include "common/step/step_delta_patch.h"
 #include "common/step/step_fail.h"
 #include "common/step/step_kill_apps.h"
 #include "common/step/step_generate_xml.h"
@@ -72,6 +73,9 @@ void TpkInstaller::Prepare() {
     case ci::RequestType::Reinstall:
       ReinstallSteps();
       break;
+    case ci::RequestType::Delta:
+      DeltaSteps();
+      break;
     case ci::RequestType::Recovery:
       RecoverySteps();
       break;
@@ -134,6 +138,28 @@ void TpkInstaller::ReinstallSteps() {
   AddStep<ci::configuration::StepFail>();
 }
 
+void TpkInstaller::DeltaSteps() {
+  AddStep<ci::configuration::StepConfigure>(pkgmgr_);
+  AddStep<ci::filesystem::StepUnzip>();
+  AddStep<tpk::parse::StepParse>();
+  AddStep<ci::filesystem::StepDeltaPatch>();
+  AddStep<ci::security::StepCheckSignature>();
+  AddStep<ci::security::StepPrivilegeCompatibility>();
+  AddStep<ci::security::StepCheckOldCertificate>();
+  AddStep<ci::backup::StepOldManifest>();
+  AddStep<ci::pkgmgr::StepKillApps>();
+  AddStep<ci::backup::StepBackupManifest>();
+  AddStep<ci::backup::StepBackupIcons>();
+  AddStep<ci::backup::StepCopyBackup>();
+  AddStep<ci::filesystem::StepCreateStorageDirectories>();
+  // TODO(t.iwanek): handle coping storage directories
+  AddStep<tpk::filesystem::StepCreateSymbolicLink>();
+  AddStep<ci::filesystem::StepCreateIcons>();
+  AddStep<ci::security::StepUpdateSecurity>();
+  AddStep<ci::pkgmgr::StepGenerateXml>();
+  AddStep<ci::pkgmgr::StepUpdateApplication>();
+}
+
 void TpkInstaller::RecoverySteps() {
   AddStep<ci::configuration::StepConfigure>(pkgmgr_);
   AddStep<ci::recovery::StepOpenRecoveryFile>();
index 83291bd..ddaa14a 100644 (file)
@@ -28,6 +28,7 @@ class TpkInstaller : public common_installer::AppInstaller {
   void UpdateSteps();
   void UninstallSteps();
   void ReinstallSteps();
+  void DeltaSteps();
   void RecoverySteps();
 
   SCOPE_LOG_TAG(TpkInstaller)
index 8a99d83..43a0f8c 100644 (file)
@@ -129,6 +129,10 @@ WgtInstaller::WgtInstaller(ci::PkgMgrPtr pkgrmgr)
       AddStep<ci::security::StepUpdateSecurity>();
       break;
     }
+    case ci::RequestType::Delta: {
+      // TODO(t.iwanek): add proper steps for this mode...
+      AddStep<ci::configuration::StepFail>();
+    }
     case ci::RequestType::Recovery: {
       AddStep<ci::configuration::StepConfigure>(pkgmgr_);
       AddStep<ci::recovery::StepOpenRecoveryFile>();