This patch implements installation of package in external sd card storage.
Tpk and wgt applications may declare preference of being installed on external
storage. If so and space requirement is satisified then their resource directory
is installed in sd card with use of app2sd API.
Following patchsets should be submitted together:
- https://review.tizen.org/gerrit/61678
- https://review.tizen.org/gerrit/61679
- https://review.tizen.org/gerrit/61680
Verify by:
- running smoke tests,
- running installation, update, deinstallation for package that prefers external
installation (SD card must be inserted).
Requires:
- https://review.tizen.org/gerrit/#/c/64796/
Change-Id: I3c49eaa3c65ce318b2e1ce6ccf049d285a83e58b
Signed-off-by: jongmyeongko <jongmyeong.ko@samsung.com>
PKG_CHECK_MODULES(DBUS_DEPS REQUIRED dbus-1)
PKG_CHECK_MODULES(GDBUS_DEPS REQUIRED glib-2.0 gio-2.0)
PKG_CHECK_MODULES(GUM_DEPS REQUIRED libgum)
+PKG_CHECK_MODULES(APP2SD_DEPS REQUIRED app2sd)
FIND_PACKAGE(Boost REQUIRED COMPONENTS system filesystem regex program_options)
FIND_PACKAGE(GTest REQUIRED)
BuildRequires: pkgconfig(dbus-1)
BuildRequires: pkgconfig(aul)
BuildRequires: pkgconfig(libgum)
+BuildRequires: pkgconfig(app2sd)
Requires: ca-certificates-tizen
Requires: libtzplatform-config
app_installer.cc
backup_paths.cc
certificate_validation.cc
+ external_storage.cc
installer_context.cc
- shared_dirs.cc
plugins/plugin_factory.cc
plugins/plugin_manager.cc
plugins/plugin_list_parser.cc
recovery_file.cc
request.cc
security_registration.cc
+ shared_dirs.cc
step/backup/step_backup_icons.cc
step/backup/step_backup_manifest.cc
step/backup/step_copy_backup.cc
step/configuration/step_configure.cc
step/configuration/step_fail.cc
step/configuration/step_parse_manifest.cc
+ step/filesystem/step_acquire_external_storage.cc
step/filesystem/step_clear_data.cc
step/filesystem/step_copy.cc
step/filesystem/step_copy_storage_directories.cc
step/filesystem/step_recover_files.cc
step/filesystem/step_recover_icons.cc
step/filesystem/step_recover_manifest.cc
+ step/filesystem/step_recover_external_storage.cc
step/filesystem/step_recover_storage_directories.cc
step/filesystem/step_remove_files.cc
step/filesystem/step_remove_icons.cc
TPK_MANIFEST_HANDLERS_DEPS
GDBUS_DEPS
GUM_DEPS
+ APP2SD_DEPS
Boost
)
Name: app-installers
Description: Common library for pkgmgr backends
Version: @VERSION@
-Requires: pkgmgr pkgmgr-installer minizip zlib libtzplatform-config security-manager manifest-parser-utils delta-manifest-handlers cert-svc-vcore pkgmgr-parser pkgmgr-info libxml-2.0 security-privilege-manager
+Requires: pkgmgr pkgmgr-installer minizip zlib libtzplatform-config security-manager manifest-parser-utils delta-manifest-handlers cert-svc-vcore pkgmgr-parser pkgmgr-info libxml-2.0 security-privilege-manager app2sd
Libs: -L${libdir} -lapp-installers
Cflags: -I${includedir}/app-installers/
--- /dev/null
+// 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/external_storage.h"
+
+#include <glib.h>
+
+#include <manifest_parser/utils/logging.h>
+
+#include "common/utils/byte_size_literals.h"
+#include "common/utils/file_util.h"
+
+namespace bf = boost::filesystem;
+
+namespace {
+
+const char kWgtType[] = "wgt";
+const char kExternalDirForWgt[] = "res";
+
+const std::vector<std::string> kExternalDirsForTpk = {
+ "bin",
+ "lib",
+ "res"
+};
+
+int64_t SizeInMB(int64_t size) {
+ return (size + 1_MB - 1) / 1_MB;
+}
+
+} // namespace
+
+namespace common_installer {
+
+ExternalStorage::ExternalStorage(RequestType type,
+ const std::string& pkgid, const std::string& package_type,
+ const boost::filesystem::path& application_root, uid_t uid)
+ : type_(type),
+ pkgid_(pkgid),
+ package_type_(package_type),
+ application_root_(application_root),
+ uid_(uid),
+ handle_(nullptr) {
+ if (package_type_ == kWgtType) {
+ external_dirs_.push_back(kExternalDirForWgt);
+ } else {
+ external_dirs_ = kExternalDirsForTpk;
+ }
+}
+
+ExternalStorage::~ExternalStorage() {
+ if (handle_)
+ app2ext_deinit(handle_);
+}
+
+bool ExternalStorage::Finalize(bool success) {
+ int ret = APP2EXT_STATUS_SUCCESS;
+ switch (type_) {
+ case RequestType::Install: {
+ ret = handle_->interface.client_usr_post_install(pkgid_.c_str(),
+ success ? APP2EXT_STATUS_SUCCESS : APP2EXT_STATUS_FAILED, uid_);
+ break;
+ }
+ case RequestType::Update: {
+ ret = handle_->interface.client_usr_post_upgrade(pkgid_.c_str(),
+ success ? APP2EXT_STATUS_SUCCESS : APP2EXT_STATUS_FAILED, uid_);
+ break;
+ }
+ case RequestType::Uninstall: {
+ ret = handle_->interface.client_usr_post_uninstall(pkgid_.c_str(), uid_);
+ break;
+ }
+ default:
+ assert(false && "Not supported installation mode");
+ }
+ return ret == APP2EXT_STATUS_SUCCESS;
+}
+
+bool ExternalStorage::Commit() {
+ return Finalize(true);
+}
+
+bool ExternalStorage::Abort() {
+ return Finalize(false);
+}
+
+const std::vector<std::string>& ExternalStorage::external_dirs() const {
+ return external_dirs_;
+}
+
+bool ExternalStorage::Initialize(
+ const boost::filesystem::path& space_requirement) {
+ // external size in MB, set any-non zero size as default
+ int external_size = 1;
+
+ if (!space_requirement.empty()) {
+ if (package_type_ == kWgtType) {
+ for (auto& dir : kExternalDirsForTpk) {
+ bf::path requirement = space_requirement / dir;
+ if (!bf::exists(requirement))
+ continue;
+ external_size +=
+ SizeInMB(GetDirectorySize(requirement));
+ }
+ } else {
+ // for wgt whole content of package goes to res/
+ external_size =
+ SizeInMB(GetDirectorySize(space_requirement));
+ }
+ }
+
+ if (external_size == 0)
+ external_size = 1;
+
+ handle_ = app2ext_init(APP2EXT_SD_CARD);
+ if (!handle_) {
+ LOG(ERROR) << "app2ext_init() failed";
+ return false;
+ }
+
+ GList* glist = nullptr;
+ for (auto& dir : external_dirs_) {
+ app2ext_dir_details* dir_detail = reinterpret_cast<app2ext_dir_details*>(
+ calloc(1, sizeof(app2ext_dir_details)));
+ dir_detail->name = strdup(dir.c_str());
+ dir_detail->type = APP2EXT_DIR_RO;
+ glist = g_list_append(glist, dir_detail);
+ }
+
+ int ret = 0;
+ switch (type_) {
+ case RequestType::Install:
+ ret = handle_->interface.client_usr_pre_install(pkgid_.c_str(), glist,
+ external_size, uid_);
+ break;
+ case RequestType::Update:
+ case RequestType::Delta:
+ ret = handle_->interface.client_usr_pre_upgrade(pkgid_.c_str(), glist,
+ external_size, uid_);
+ break;
+ case RequestType::Uninstall:
+ ret = handle_->interface.client_usr_pre_uninstall(pkgid_.c_str(), uid_);
+ break;
+ case RequestType::Clear:
+ case RequestType::Reinstall:
+ case RequestType::Recovery:
+ case RequestType::ManifestDirectInstall:
+ case RequestType::ManifestDirectUpdate:
+ case RequestType::MountInstall:
+ case RequestType::MountUpdate:
+ LOG(ERROR) << "Installation type is not supported by external installation";
+ ret = -1;
+ break;
+ default:
+ assert(false && "Invalid installation mode");
+ }
+
+ g_list_free_full(glist, [](gpointer data) {
+ app2ext_dir_details* dir_detail =
+ reinterpret_cast<app2ext_dir_details*>(data);
+ free(dir_detail->name);
+ free(dir_detail);
+ });
+ return ret == 0;
+}
+
+std::unique_ptr<ExternalStorage> ExternalStorage::AcquireExternalStorage(
+ RequestType type, const boost::filesystem::path& application_root,
+ const std::string& pkgid, const std::string& package_type,
+ const boost::filesystem::path& space_requirement,
+ uid_t uid) {
+ std::unique_ptr<ExternalStorage> external_storage(
+ new ExternalStorage(type, pkgid, package_type, application_root, uid));
+ if (!external_storage->Initialize(space_requirement)) {
+ LOG(WARNING) << "Cannot initialize external storage for request";
+ return nullptr;
+ }
+ return external_storage;
+}
+
+} // namespace common_installer
--- /dev/null
+// 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_EXTERNAL_STORAGE_H_
+#define COMMON_EXTERNAL_STORAGE_H_
+
+#include <boost/filesystem/path.hpp>
+
+#include <app2ext_interface.h>
+#include <sys/types.h>
+
+#include <string>
+#include <vector>
+
+#include "common/request.h"
+
+namespace common_installer {
+
+class ExternalStorage final {
+ public:
+ static std::unique_ptr<ExternalStorage> AcquireExternalStorage(
+ RequestType type, const boost::filesystem::path& application_root,
+ const std::string& pkgid, const std::string& package_type,
+ const boost::filesystem::path& space_requirement, uid_t uid);
+
+ ExternalStorage(RequestType type, const std::string& pkgid,
+ const std::string& package_type,
+ const boost::filesystem::path& application_root, uid_t uid);
+ ~ExternalStorage();
+
+ bool Commit();
+ bool Abort();
+
+ const std::vector<std::string>& external_dirs() const;
+
+ private:
+ bool Initialize(const boost::filesystem::path& space_requirement);
+ bool Finalize(bool success);
+
+ RequestType type_;
+ std::string pkgid_;
+ std::string package_type_;
+ boost::filesystem::path application_root_;
+ uid_t uid_;
+ app2ext_handle* handle_;
+ std::vector<std::string> external_dirs_;
+};
+
+} // namespace common_installer
+
+#endif // COMMON_EXTERNAL_STORAGE_H_
#include <utility>
#include <vector>
+#include "common/external_storage.h"
#include "common/pkgmgr_interface.h"
#include "common/recovery_file.h"
#include "common/request.h"
* \brief Property of vector of files to delete
*/
Property<std::vector<std::string>> files_to_delete;
+
+ /**
+ * @brief External Storage object if installing in external
+ */
+ std::unique_ptr<ExternalStorage> external_storage;
};
} // namespace common_installer
// "removable" : this package can be removed.
// "readonly" : this package exists in readonly location.
bool AssignPackageTags(manifest_x* manifest,
- common_installer::RequestMode,
bool is_update) {
if (!strcmp(manifest->preload, "true")) {
manifest->removable = strdup("false");
manifest->system = strdup("false");
manifest->update = strdup("false");
}
- // external installation should alter this flag
- manifest->installed_storage = strdup("installed_internal");
return true;
}
if (!tep_path.empty())
manifest->tep_name = strdup(tep_path.c_str());
- if (!AssignPackageTags(manifest, request_mode, false))
+ if (!AssignPackageTags(manifest, false))
return false;
int ret = request_mode != RequestMode::GLOBAL ?
const CertificateInfo& cert_info,
uid_t uid,
RequestMode request_mode) {
- if (!AssignPackageTags(manifest, request_mode, true))
+ if (!AssignPackageTags(manifest, true))
return false;
int ret = request_mode != RequestMode::GLOBAL ?
return ret;
}
+std::string QueryStorageForPkgId(const std::string& pkg_id, uid_t uid) {
+ pkgmgrinfo_pkginfo_h package_info;
+ if (pkgmgrinfo_pkginfo_get_usr_pkginfo(pkg_id.c_str(), uid, &package_info)
+ != PMINFO_R_OK) {
+ return false;
+ }
+
+ pkgmgrinfo_installed_storage storage;
+ bool ok = pkgmgrinfo_pkginfo_get_installed_storage(package_info,
+ &storage) == PMINFO_R_OK;
+ pkgmgrinfo_pkginfo_destroy_pkginfo(package_info);
+
+ if (!ok)
+ return "";
+
+ // TODO(t.iwanek): enum is used in pkgmgr API, whereas here we assign internal
+ // values known to pkgmgr
+ if (storage == PMINFO_INTERNAL_STORAGE) {
+ return "installed_internal";
+ } else if (storage == PMINFO_EXTERNAL_STORAGE) {
+ return "installed_external";
+ } else {
+ return "";
+ }
+}
+
bool IsPackageInstalled(const std::string& pkg_id, RequestMode request_mode) {
pkgmgrinfo_pkginfo_h handle;
int ret = pkgmgrinfo_pkginfo_get_usr_pkginfo(pkg_id.c_str(), getuid(),
std::vector<std::string>* result);
/**
+ * \brief Adapter interface for external PkgMgr module used for getting
+ * storage for given package
+ *
+ * \param pkg_id id of package
+ * \param uid user id
+ *
+ * \return storage name of empty if not installed
+ */
+std::string QueryStorageForPkgId(const std::string& pkg_id, uid_t uid);
+
+/**
* \brief Adapter interface for external PkgMgr module used for checking
* if given package is installed/registered
*
#include "common/backup_paths.h"
#include "common/utils/file_util.h"
+namespace {
+
+const char kExternalMemoryMountPoint[] = ".mmc";
+
+}
+
namespace common_installer {
namespace backup {
}
LOG(DEBUG) << "Applications files backup directory removed";
+ if (context_->external_storage)
+ context_->external_storage->Commit();
+
return Status::OK;
}
LOG(DEBUG) << "Remove tmp dir: " << context_->unpacked_dir_path.get();
bf::remove_all(context_->unpacked_dir_path.get(), error); // ignore error
+ if (context_->external_storage)
+ context_->external_storage->Abort();
+
// if backup was created then restore files
if (bf::exists(backup_path_)) {
if (!RollbackApplicationDirectory()) {
}
bool StepCopyBackup::Backup() {
- if (!MoveDir(context_->pkg_path.get(), backup_path_)) {
- LOG(ERROR) << "Fail to backup package directory";
- return false;
+ // create backup directory
+ bs::error_code error;
+ bf::create_directories(backup_path_, error);
+
+ // create copy of old package content skipping the external memory mount point
+ for (bf::directory_iterator iter(context_->pkg_path.get());
+ iter != bf::directory_iterator(); ++iter) {
+ if (iter->path().filename() == kExternalMemoryMountPoint)
+ continue;
+
+ // external storage directories are mounted
+ // therefore move only content
+ if (context_->external_storage) {
+ auto& ext_dirs = context_->external_storage->external_dirs();
+ auto found = std::find(ext_dirs.begin(), ext_dirs.end(),
+ iter->path().filename());
+ if (found != ext_dirs.end()) {
+ bool done = MoveMountPointContent(iter->path(),
+ backup_path_ / iter->path().filename());
+ if (!done) {
+ LOG(ERROR) << "Failed to move: " << iter->path();
+ return false;
+ }
+ 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 of: " << iter->path();
+ return false;
+ }
+ }
}
LOG(INFO) << "Old package context saved to: " << backup_path_;
return true;
}
+
+bool StepCopyBackup::MoveMountPointContent(const boost::filesystem::path& from,
+ const boost::filesystem::path& to) {
+ bs::error_code error;
+ bf::create_directories(to, error);
+
+ 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 (!MoveFile(iter->path(), to / iter->path().filename())) {
+ LOG(ERROR) << "Fail to backup package file of: " << iter->path();
+ return false;
+ }
+ }
+ }
+ return true;
+}
+
bool StepCopyBackup::NewContent() {
bs::error_code error;
bf::create_directories(install_path_.parent_path(), error);
LOG(ERROR) << "Cannot create package directory";
return false;
}
- if (!MoveDir(context_->unpacked_dir_path.get(), install_path_)) {
+ if (!MoveDir(context_->unpacked_dir_path.get(), install_path_,
+ FSFlag::FS_MERGE_DIRECTORIES)) {
LOG(ERROR) << "Fail to copy tmp dir: " << context_->unpacked_dir_path.get()
<< " to dst dir: " << install_path_;
return false;
bool NewContent();
bool CleanBackupDirectory();
bool RollbackApplicationDirectory();
+ bool MoveMountPointContent(const boost::filesystem::path& from,
+ const boost::filesystem::path& to);
boost::filesystem::path install_path_;
boost::filesystem::path backup_path_;
bf::path backup_path = common_installer::GetBackupPathForPackagePath(
context_->pkg_path.get()) / kManifestFileName;
bf::path in_package_path = context_->pkg_path.get() / kManifestFileName;
+ bf::path install_path =
+ bf::path(getUserManifestPath(context_->uid.get(), false))
+ / bf::path(context_->pkgid.get());
+ install_path += ".xml";
if (bf::exists(backup_path))
manifest = backup_path;
else if (bf::exists(in_package_path))
manifest = in_package_path;
+ else if (bf::exists(install_path))
+ manifest = install_path;
break;
}
case ManifestLocation::INSTALLED: {
}
}
+ // set installed_storage if package is installed
+ // this is internal field in package manager but after reading configuration
+ // we must know it
+ if (manifest_location_ == ManifestLocation::INSTALLED ||
+ manifest_location_ == ManifestLocation::RECOVERY) {
+ std::string storage = QueryStorageForPkgId(manifest->package,
+ context_->uid.get());
+ if (!storage.empty())
+ manifest->installed_storage = strdup(storage.c_str());
+ }
+
if (ui_application_list) {
manifest->mainapp_id =
strdup(ui_application_list->items[0].app_info.appid().c_str());
--- /dev/null
+// 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/filesystem/step_acquire_external_storage.h"
+
+#include "common/external_storage.h"
+
+namespace {
+
+const char kInstalledExternally[] = "installed_external";
+const char kPreferExternal[] = "prefer-external";
+
+enum class Storage {
+ NONE,
+ INTERNAL,
+ EXTERNAL
+};
+
+} // namespace
+
+namespace common_installer {
+namespace filesystem {
+
+Step::Status StepAcquireExternalStorage::precheck() {
+ if (!context_->manifest_data.get()) {
+ LOG(ERROR) << "Manifest data is empty";
+ return Status::ERROR;
+ }
+ return Status::OK;
+}
+
+Step::Status StepAcquireExternalStorage::process() {
+ manifest_x* manifest = context_->manifest_data.get();
+ manifest_x* old_manifest = context_->old_manifest_data.get();
+
+ Storage storage = Storage::NONE;
+ if (old_manifest) {
+ storage = Storage::INTERNAL;
+ if (old_manifest->installed_storage)
+ if (!strcmp(old_manifest->installed_storage, kInstalledExternally))
+ storage = Storage::EXTERNAL;
+ }
+
+ if (storage == Storage::EXTERNAL ||
+ (!strcmp(manifest->installlocation, kPreferExternal) &&
+ storage == Storage::NONE)) {
+ context_->external_storage =
+ ExternalStorage::AcquireExternalStorage(context_->request_type.get(),
+ context_->root_application_path.get(),
+ context_->pkgid.get(),
+ context_->pkg_type.get(),
+ context_->unpacked_dir_path.get(),
+ context_->uid.get());
+ }
+
+ if (storage == Storage::EXTERNAL && !context_->external_storage) {
+ LOG(ERROR) << "Cannot initialize external storage for installed package";
+ return Status::APP_DIR_ERROR;
+ }
+
+ if (context_->external_storage) {
+ // This may be allocated by step parse unfortunatelly to indicate storage
+ // in case of recovery and update.
+ free(const_cast<char*>(manifest->installed_storage));
+ manifest->installed_storage = strdup(kInstalledExternally);
+ LOG(INFO) << "Package storage: external";
+ } else {
+ LOG(INFO) << "Package storage: internal";
+ }
+ return Status::OK;
+}
+
+} // namespace filesystem
+} // namespace common_installer
+
--- /dev/null
+// 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_FILESYSTEM_STEP_ACQUIRE_EXTERNAL_STORAGE_H_
+#define COMMON_STEP_FILESYSTEM_STEP_ACQUIRE_EXTERNAL_STORAGE_H_
+
+#include "common/installer_context.h"
+#include "common/step/step.h"
+
+namespace common_installer {
+namespace filesystem {
+
+/**
+ * \brief Creates package storage according to:
+ * 1) package installation
+ * 2) manifest file
+ */
+class StepAcquireExternalStorage : public Step {
+ public:
+ using Step::Step;
+
+ Status process() override;
+
+ Status clean() override { return Status::OK; }
+ Status undo() override { return Status::OK; }
+ Status precheck() override;
+
+ SCOPE_LOG_TAG(AcquireExternalStorage)
+};
+
+} // namespace filesystem
+} // namespace common_installer
+
+#endif // COMMON_STEP_FILESYSTEM_STEP_ACQUIRE_EXTERNAL_STORAGE_H_
return Status::OK;
}
+Step::Status StepCopy::clean() {
+ if (context_->external_storage)
+ context_->external_storage->Commit();
+ return Status::OK;
+}
+
Step::Status StepCopy::undo() {
+ if (context_->external_storage)
+ context_->external_storage->Abort();
+
if (bf::exists(context_->pkg_path.get()))
bf::remove_all(context_->pkg_path.get());
return Status::OK;
*/
Status process() override;
- Status clean() override { return Status::OK; }
+ Status clean() override;
/**
* \brief removes files from final package destination
--- /dev/null
+// 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/filesystem/step_recover_external_storage.h"
+
+namespace common_installer {
+namespace filesystem {
+
+Step::Status StepRecoverExternalStorage::process() {
+ (void) StepAcquireExternalStorage::process();
+ return Status::OK;
+}
+
+} // namespace filesystem
+} // namespace common_installer
+
--- /dev/null
+// 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_FILESYSTEM_STEP_RECOVER_EXTERNAL_STORAGE_H_
+#define COMMON_STEP_FILESYSTEM_STEP_RECOVER_EXTERNAL_STORAGE_H_
+
+#include "common/installer_context.h"
+#include "common/step/filesystem/step_acquire_external_storage.h"
+
+namespace common_installer {
+namespace filesystem {
+
+/**
+ * \brief Creates external storage according to:
+ * 1) package installation
+ * 2) manifest file
+ */
+class StepRecoverExternalStorage : public StepAcquireExternalStorage {
+ public:
+ using StepAcquireExternalStorage::StepAcquireExternalStorage;
+
+ Status process() override;
+
+ SCOPE_LOG_TAG(RecoverExternalStorage)
+};
+
+} // namespace filesystem
+} // namespace common_installer
+
+#endif // COMMON_STEP_FILESYSTEM_STEP_RECOVER_EXTERNAL_STORAGE_H_
bs::error_code error;
bf::path pkg_path(context_->pkg_path.get());
+ // We need to unmount external storage before removing package directory
+ // because mount point is inside
+ if (context_->external_storage)
+ context_->external_storage->Commit();
+
if (IsPackageInstalled(context_->pkgid.get(), GLOBAL_USER)) {
for (bf::directory_iterator itr(pkg_path); itr != bf::directory_iterator();
++itr) {
return size;
}
+int64_t GetDirectorySize(const boost::filesystem::path& path) {
+ int64_t block_size = GetBlockSizeForPath(path);
+
+ // if failed to stat path
+ if (block_size == -1)
+ return -1;
+
+ int64_t size = 0;
+ for (bf::recursive_directory_iterator iter(path);
+ iter != bf::recursive_directory_iterator(); ++iter) {
+ struct stat buf;
+ if (lstat(iter->path().c_str(), &buf) == -1) {
+ LOG(ERROR) << "lstat() failed for: " << iter->path();
+ return -1;
+ }
+ size += RoundUpToBlockSizeOf(buf.st_size, block_size);
+ }
+
+ // FIXME: block size for external device may differ...
+ return size;
+}
+
boost::filesystem::path GenerateTmpDir(const bf::path &app_path) {
boost::filesystem::path install_tmp_dir;
boost::filesystem::path tmp_dir(app_path);
int64_t GetUnpackedPackageSize(const boost::filesystem::path& path);
+int64_t GetDirectorySize(const boost::filesystem::path& path);
+
boost::filesystem::path GenerateTmpDir(const boost::filesystem::path& app_path);
boost::filesystem::path GenerateTemporaryPath(