From: Piotr Dabrowski
Date: Mon, 19 Sep 2016 13:43:16 +0000 (+0200)
Subject: Reworked sharing of widget's shared/res directory.
X-Git-Tag: accepted/tizen/common/20170322.154043~7^2~1
X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=refs%2Fchanges%2F55%2F88255%2F10;p=platform%2Fcore%2Fappfw%2Fwgt-backend.git
Reworked sharing of widget's shared/res directory.
./res/wgt/shared/res directory content was moved to ./shared/res
and then ./res/wgt/shared/res was symlinked to ./shared/res
This broke signatures check for delta update.
Now all items (files and directories) under ./res/wgt/shared/res
are symlinked into ./shared/res, and vice versa.
During delta update these symlinks are removed, so that the
signatures check can complete successfully, and later the symlinks
are recreated again.
Added smoke tests for symlinking shared/res contents in Tizen 3.0
To added tests pass requires:
- https://review.tizen.org/gerrit/#/c/117264/
Change-Id: I9423d78aba5cb338b14a9f8853754e0fa8980e0c
---
diff --git a/src/hybrid/hybrid_installer.cc b/src/hybrid/hybrid_installer.cc
index 4e36b4b..f1dd5c4 100644
--- a/src/hybrid/hybrid_installer.cc
+++ b/src/hybrid/hybrid_installer.cc
@@ -89,6 +89,7 @@
#include "wgt/step/filesystem/step_create_symbolic_link.h"
#include "wgt/step/filesystem/step_wgt_patch_icons.h"
#include "wgt/step/filesystem/step_wgt_patch_storage_directories.h"
+#include "wgt/step/filesystem/step_wgt_undo_patch_storage_directories.h"
#include "wgt/step/pkgmgr/step_generate_xml.h"
#include "wgt/step/security/step_check_settings_level.h"
#include "wgt/step/security/step_check_wgt_background_category.h"
@@ -238,6 +239,7 @@ HybridInstaller::HybridInstaller(common_installer::PkgMgrPtr pkgmgr)
AddStep(
ci::configuration::StepParseManifest::ManifestLocation::PACKAGE,
ci::configuration::StepParseManifest::StoreLocation::NORMAL);
+ AddStep();
AddStep();
AddStep(
ci::configuration::StepParseManifest::ManifestLocation::INSTALLED,
diff --git a/src/unit_tests/smoke_test.cc b/src/unit_tests/smoke_test.cc
index d4c0efc..8322b48 100644
--- a/src/unit_tests/smoke_test.cc
+++ b/src/unit_tests/smoke_test.cc
@@ -1422,6 +1422,77 @@ TEST_F(PreloadSmokeTest, DeinstallationMode_Preload) {
CheckPackageReadonlyNonExistance(pkgid, {appid});
}
+TEST_F(SmokeTest, SharedRes24) {
+ bf::path path = kSmokePackagesDirectory / "SharedRes24.wgt";
+ std::string pkgid = "smokeSh2xx";
+ std::string appid = "smokeSh2xx.SharedRes24";
+ ASSERT_EQ(Install(path, PackageType::WGT), ci::AppInstaller::Result::OK);
+ ValidatePackage(pkgid, {appid});
+ bf::path root_path = ci::GetRootAppPath(false, kTestUserId);
+ ASSERT_TRUE(bf::is_regular_file(root_path / pkgid / "res" / "wgt" / "shared" / "res" / "NOT-SHARED-WGT")); // NOLINT
+ ASSERT_FALSE(bf::exists(root_path / pkgid / "shared" / "res" / "NOT-SHARED-WGT")); // NOLINT
+}
+
+TEST_F(SmokeTest, SharedRes30) {
+ bf::path path = kSmokePackagesDirectory / "SharedRes30.wgt";
+ std::string pkgid = "smokeSh3xx";
+ std::string appid = "smokeSh3xx.SharedRes30";
+ ASSERT_EQ(Install(path, PackageType::WGT), ci::AppInstaller::Result::OK);
+ ValidatePackage(pkgid, {appid});
+ bf::path root_path = ci::GetRootAppPath(false, kTestUserId);
+ ASSERT_TRUE(bf::is_regular_file(root_path / pkgid / "res" / "wgt" / "shared" / "res" / "SHARED-WGT")); // NOLINT
+ ASSERT_TRUE(bf::is_symlink(root_path / pkgid / "shared" / "res" / "SHARED-WGT")); // NOLINT
+}
+
+TEST_F(SmokeTest, SharedRes30Delta) {
+ bf::path path = kSmokePackagesDirectory / "SharedRes30Delta.wgt";
+ bf::path delta_package = kSmokePackagesDirectory / "SharedRes30Delta.delta";
+ std::string pkgid = "smokeSh3De";
+ std::string appid = "smokeSh3De.SharedRes30Delta";
+ ASSERT_EQ(DeltaInstall(path, delta_package, PackageType::WGT),
+ ci::AppInstaller::Result::OK);
+ ValidatePackage(pkgid, {appid});
+ // Check delta modifications
+ bf::path root_path = ci::GetRootAppPath(false, kTestUserId);
+ ASSERT_TRUE(bf::is_regular_file(root_path / pkgid / "res" / "wgt" / "shared" / "res" / "SHARED-WGT-2")); // NOLINT
+ ASSERT_TRUE(bf::is_symlink(root_path / pkgid / "shared" / "res" / "SHARED-WGT-2")); // NOLINT
+ ASSERT_FALSE(bf::exists(root_path / pkgid / "res" / "wgt" / "shared" / "res" / "SHARED-WGT-1")); // NOLINT
+ ASSERT_FALSE(bf::exists(root_path / pkgid / "shared" / "res" / "SHARED-WGT-1")); // NOLINT
+}
+
+TEST_F(SmokeTest, SharedRes30Hybrid) {
+ bf::path path = kSmokePackagesDirectory / "SharedRes30Hybrid.wgt";
+ std::string pkgid = "smokeSh3Hy";
+ std::string appid1 = "smokeSh3Hy.SharedRes30Hybrid";
+ std::string appid2 = "sharedres30hybridserivce";
+ ASSERT_EQ(Install(path, PackageType::HYBRID), ci::AppInstaller::Result::OK);
+ ValidatePackage(pkgid, {appid1, appid2});
+ bf::path root_path = ci::GetRootAppPath(false, kTestUserId);
+ ASSERT_TRUE(bf::is_regular_file(root_path / pkgid / "res" / "wgt" / "shared" / "res" / "SHARED-WGT")); // NOLINT
+ ASSERT_TRUE(bf::is_symlink(root_path / pkgid / "shared" / "res" / "SHARED-WGT")); // NOLINT
+ ASSERT_TRUE(bf::is_regular_file(root_path / pkgid / "shared" / "res" / "SHARED-TPK")); // NOLINT
+ ASSERT_TRUE(bf::is_symlink(root_path / pkgid / "res" / "wgt" / "shared" / "res" / "SHARED-TPK")); // NOLINT
+}
+
+TEST_F(SmokeTest, SharedRes30HybridDelta) {
+ bf::path path = kSmokePackagesDirectory / "SharedRes30HybridDelta.wgt";
+ bf::path delta_package = kSmokePackagesDirectory / "SharedRes30HybridDelta.delta";
+ std::string pkgid = "smokeSh3HD";
+ std::string appid1 = "smokeSh3HD.SharedRes30HybridDelta";
+ std::string appid2 = "sharedres30hybriddeltaserivce";
+ ASSERT_EQ(DeltaInstall(path, delta_package, PackageType::HYBRID),
+ ci::AppInstaller::Result::OK);
+ ValidatePackage(pkgid, {appid1, appid2});
+ // Check delta modifications
+ bf::path root_path = ci::GetRootAppPath(false, kTestUserId);
+ ASSERT_TRUE(bf::is_regular_file(root_path / pkgid / "res" / "wgt" / "shared" / "res" / "SHARED-WGT-2")); // NOLINT
+ ASSERT_TRUE(bf::is_symlink(root_path / pkgid / "shared" / "res" / "SHARED-WGT-2")); // NOLINT
+ ASSERT_TRUE(bf::is_regular_file(root_path / pkgid / "shared" / "res" / "SHARED-TPK-2")); // NOLINT
+ ASSERT_TRUE(bf::is_symlink(root_path / pkgid / "res" / "wgt" / "shared" / "res" / "SHARED-TPK-2")); // NOLINT
+ ASSERT_FALSE(bf::exists(root_path / pkgid / "res" / "wgt" / "shared" / "res" / "SHARED-WGT-1")); // NOLINT
+ ASSERT_FALSE(bf::exists(root_path / pkgid / "shared" / "res" / "SHARED-WGT-1")); // NOLINT
+}
+
} // namespace common_installer
int main(int argc, char** argv) {
diff --git a/src/unit_tests/test_samples/smoke/SharedRes24.wgt b/src/unit_tests/test_samples/smoke/SharedRes24.wgt
new file mode 100644
index 0000000..782e7e9
Binary files /dev/null and b/src/unit_tests/test_samples/smoke/SharedRes24.wgt differ
diff --git a/src/unit_tests/test_samples/smoke/SharedRes30.wgt b/src/unit_tests/test_samples/smoke/SharedRes30.wgt
new file mode 100644
index 0000000..e235841
Binary files /dev/null and b/src/unit_tests/test_samples/smoke/SharedRes30.wgt differ
diff --git a/src/unit_tests/test_samples/smoke/SharedRes30Delta.delta b/src/unit_tests/test_samples/smoke/SharedRes30Delta.delta
new file mode 100644
index 0000000..26e28bf
Binary files /dev/null and b/src/unit_tests/test_samples/smoke/SharedRes30Delta.delta differ
diff --git a/src/unit_tests/test_samples/smoke/SharedRes30Delta.wgt b/src/unit_tests/test_samples/smoke/SharedRes30Delta.wgt
new file mode 100644
index 0000000..f73d723
Binary files /dev/null and b/src/unit_tests/test_samples/smoke/SharedRes30Delta.wgt differ
diff --git a/src/unit_tests/test_samples/smoke/SharedRes30Delta_2.wgt b/src/unit_tests/test_samples/smoke/SharedRes30Delta_2.wgt
new file mode 100644
index 0000000..6f52919
Binary files /dev/null and b/src/unit_tests/test_samples/smoke/SharedRes30Delta_2.wgt differ
diff --git a/src/unit_tests/test_samples/smoke/SharedRes30Hybrid.wgt b/src/unit_tests/test_samples/smoke/SharedRes30Hybrid.wgt
new file mode 100644
index 0000000..2aa90d3
Binary files /dev/null and b/src/unit_tests/test_samples/smoke/SharedRes30Hybrid.wgt differ
diff --git a/src/unit_tests/test_samples/smoke/SharedRes30HybridDelta.delta b/src/unit_tests/test_samples/smoke/SharedRes30HybridDelta.delta
new file mode 100644
index 0000000..93d0374
Binary files /dev/null and b/src/unit_tests/test_samples/smoke/SharedRes30HybridDelta.delta differ
diff --git a/src/unit_tests/test_samples/smoke/SharedRes30HybridDelta.wgt b/src/unit_tests/test_samples/smoke/SharedRes30HybridDelta.wgt
new file mode 100644
index 0000000..b60b43c
Binary files /dev/null and b/src/unit_tests/test_samples/smoke/SharedRes30HybridDelta.wgt differ
diff --git a/src/unit_tests/test_samples/smoke/SharedRes30HybridDelta_2.wgt b/src/unit_tests/test_samples/smoke/SharedRes30HybridDelta_2.wgt
new file mode 100644
index 0000000..6399c85
Binary files /dev/null and b/src/unit_tests/test_samples/smoke/SharedRes30HybridDelta_2.wgt differ
diff --git a/src/wgt/step/filesystem/step_wgt_patch_storage_directories.cc b/src/wgt/step/filesystem/step_wgt_patch_storage_directories.cc
index 2e897b8..cb8a221 100644
--- a/src/wgt/step/filesystem/step_wgt_patch_storage_directories.cc
+++ b/src/wgt/step/filesystem/step_wgt_patch_storage_directories.cc
@@ -29,9 +29,10 @@ common_installer::Step::Status StepWgtPatchStorageDirectories::process() {
if (!CreatePrivateTmpDir())
return Status::APP_DIR_ERROR;
- char version = context_->manifest_data.get()->api_version[0];
- if ((version-'0') >= 3) {
- LOG(DEBUG) << "Copying widget's shared/ directory";
+ int version = std::stoi(context_->manifest_data.get()->api_version);
+ if (version >= 3) {
+ LOG(DEBUG) << "Symlinking widget's shared/res directory content in "
+ << context_->pkg_path.get();
if (!ShareDirFor3x())
return Status::APP_DIR_ERROR;
}
@@ -40,6 +41,12 @@ common_installer::Step::Status StepWgtPatchStorageDirectories::process() {
}
bool StepWgtPatchStorageDirectories::ShareDirFor3x() {
+ // check if ${pkg_path}/res/wgt/shared/res exists
+ bf::path wgt_shared_res_dir =
+ context_->pkg_path.get() / kResWgtSubPath / kSharedResLocation;
+ if (!bf::exists(wgt_shared_res_dir))
+ return true;
+ // create ${pkg_path}/shared/res
bf::path shared_dir = context_->pkg_path.get() / kSharedLocation;
if (!bf::exists(shared_dir)) {
bs::error_code error;
@@ -49,35 +56,67 @@ bool StepWgtPatchStorageDirectories::ShareDirFor3x() {
return false;
}
}
- bf::path src = context_->pkg_path.get() / kResWgtSubPath / kSharedResLocation;
- if (!bf::exists(src))
- return true;
- if (!bf::is_directory(src)) {
- LOG(WARNING) << "Widget's shared/res/ is not directory";
- return true;
+ bf::path shared_res_dir = context_->pkg_path.get() / kSharedResLocation;
+ if (!bf::exists(shared_res_dir)) {
+ bs::error_code error;
+ bf::create_directory(shared_res_dir, error);
+ if (error) {
+ LOG(ERROR) << "Failed to create directory: " << shared_res_dir;
+ return false;
+ }
}
- bf::path dst = context_->pkg_path.get() / kSharedResLocation;
- if (!common_installer::MoveDir(src, dst,
- common_installer::FS_MERGE_SKIP)) {
- LOG(ERROR) << "Failed to move shared data from res/wgt to shared";
- return false;
+ // link all ${pkg_path}/res/wgt/shared/res content to ${pkg_path}/shared/res
+ bf::directory_iterator end_itr;
+ for (bf::directory_iterator itr(wgt_shared_res_dir); itr != end_itr; ++itr) {
+ bf::path link_target = itr->path();
+ if (bf::is_symlink(link_target)) {
+ continue;
+ }
+ bf::path link_file = shared_res_dir / link_target.filename();
+ if (bf::exists(link_file)) {
+ LOG(DEBUG) << "shared/res linking: skipping existing " << link_file;
+ continue;
+ }
+ LOG(DEBUG) << "shared/res linking: creating link " << link_file;
+ bs::error_code error;
+ bf::create_symlink(link_target, link_file, error);
+ if (error) {
+ LOG(ERROR) << "shared/res linking: linking failed for " << link_file
+ << ": " << boost::system::system_error(error).what();
+ return false;
+ }
}
-
- bs::error_code error_code;
- bf::create_symlink(dst, src, error_code);
- if (error_code) {
- LOG(ERROR) << "Failed to create symbolic link for shared dir"
- << boost::system::system_error(error_code).what();
- return false;
+ // link all ${pkg_path}/shared/res content to ${pkg_path}/res/wgt/shared/res
+ for (bf::directory_iterator itr(shared_res_dir); itr != end_itr; ++itr) {
+ bf::path link_target = itr->path();
+ if (bf::is_symlink(link_target)) {
+ continue;
+ }
+ bf::path link_file = wgt_shared_res_dir / link_target.filename();
+ if (bf::exists(link_file)) {
+ LOG(DEBUG) << "shared/res linking: skipping existing " << link_file;
+ continue;
+ }
+ LOG(DEBUG) << "shared/res linking: creating link " << link_file;
+ bs::error_code error;
+ bf::create_symlink(link_target, link_file, error);
+ if (error) {
+ LOG(ERROR) << "shared/res linking: linking failed for " << link_file
+ << ": " << boost::system::system_error(error).what();
+ return false;
+ }
}
return true;
}
bool StepWgtPatchStorageDirectories::CreatePrivateTmpDir() {
- bs::error_code error_code;
bf::path tmp_path = context_->pkg_path.get() / kTemporaryData;
- bf::create_directory(tmp_path, error_code);
- if (error_code) {
+ if (bf::exists(tmp_path) && bf::is_directory(tmp_path)) {
+ return true;
+ }
+ bs::error_code error;
+ bf::create_directory(tmp_path, error);
+ if (error) {
LOG(ERROR) << "Failed to create private temporary directory for package";
return false;
}
diff --git a/src/wgt/step/filesystem/step_wgt_patch_storage_directories.h b/src/wgt/step/filesystem/step_wgt_patch_storage_directories.h
index 035936b..96c5da6 100644
--- a/src/wgt/step/filesystem/step_wgt_patch_storage_directories.h
+++ b/src/wgt/step/filesystem/step_wgt_patch_storage_directories.h
@@ -13,8 +13,9 @@ namespace filesystem {
/**
* \brief Installation (WGT).
- * Responsible for copying widgets shared/ directory into package's
- * shared/ directory for tizen widget with api version >= 3.0
+ * Responsible for linking the content of widget's shared/res directory
+ * into package's shared/res directory and vice versa for Tizen widget
+ * with API version >= 3.0
*/
class StepWgtPatchStorageDirectories :
public common_installer::Step {
diff --git a/src/wgt/step/filesystem/step_wgt_undo_patch_storage_directories.cc b/src/wgt/step/filesystem/step_wgt_undo_patch_storage_directories.cc
new file mode 100644
index 0000000..241b2ca
--- /dev/null
+++ b/src/wgt/step/filesystem/step_wgt_undo_patch_storage_directories.cc
@@ -0,0 +1,94 @@
+// Copyright (c) 2016 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 "wgt/step/filesystem/step_wgt_undo_patch_storage_directories.h"
+
+#include
+#include
+#include
+
+#include
+
+namespace bf = boost::filesystem;
+namespace bs = boost::system;
+
+namespace {
+
+const char kSharedLocation[] = "shared";
+const char kSharedResLocation[] = "shared/res";
+const char kResWgtSubPath[] = "res/wgt";
+
+} // namespace
+
+namespace wgt {
+namespace filesystem {
+
+common_installer::Step::Status StepWgtUndoPatchStorageDirectories::process() {
+ int version = std::stoi(context_->manifest_data.get()->api_version);
+ if (version >= 3) {
+ LOG(DEBUG) << "Unlinking widget's shared/res directory content in "
+ << context_->pkg_path.get();
+ if (!UndoShareDirFor3x())
+ return Status::APP_DIR_ERROR;
+ }
+
+ return Status::OK;
+}
+
+bool StepWgtUndoPatchStorageDirectories::UndoShareDirFor3x() {
+ // check if ${pkg_path}/shared/res exists
+ bf::path shared_res_dir = context_->pkg_path.get() / kSharedResLocation;
+ bf::path wgt_shared_res_dir =
+ context_->pkg_path.get() / kResWgtSubPath / kSharedResLocation;
+ if (!bf::exists(shared_res_dir))
+ return true;
+ // delete symlinks in ${pkg_path}/shared/res
+ if (bf::exists(shared_res_dir)) {
+ bf::directory_iterator end_itr;
+ for (bf::directory_iterator itr(shared_res_dir); itr != end_itr; ++itr) {
+ bf::path link_file = itr->path();
+ if (!bf::is_symlink(link_file)) {
+ continue;
+ }
+ bf::path link_target = bf::read_symlink(link_file);
+ if (link_target.native().substr(0, wgt_shared_res_dir.native().length()) !=
+ wgt_shared_res_dir.native()) {
+ continue;
+ }
+ LOG(DEBUG) << "shared/res linking: removing symlink " << link_file;
+ bs::error_code error;
+ bf::remove(link_file, error);
+ if (error) {
+ LOG(ERROR) << "Failed to remove symlink " << link_file;
+ return false;
+ }
+ }
+ }
+ // delete symlinks in ${pkg_path}/res/wgt/shared/res
+ if (bf::exists(wgt_shared_res_dir)) {
+ bf::directory_iterator end_itr;
+ for (bf::directory_iterator itr(wgt_shared_res_dir); itr != end_itr; ++itr) {
+ bf::path link_file = itr->path();
+ if (!bf::is_symlink(link_file)) {
+ continue;
+ }
+ bf::path link_target = bf::read_symlink(link_file);
+ if (link_target.native().substr(0, shared_res_dir.native().length()) !=
+ shared_res_dir.native()) {
+ continue;
+ }
+ LOG(DEBUG) << "shared/res linking: removing symlink " << link_file;
+ bs::error_code error;
+ bf::remove(link_file, error);
+ if (error) {
+ LOG(ERROR) << "Failed to remove symlink " << link_file;
+ return false;
+ }
+ }
+ }
+ return true;
+}
+
+} // namespace filesystem
+} // namespace wgt
diff --git a/src/wgt/step/filesystem/step_wgt_undo_patch_storage_directories.h b/src/wgt/step/filesystem/step_wgt_undo_patch_storage_directories.h
new file mode 100644
index 0000000..382ab72
--- /dev/null
+++ b/src/wgt/step/filesystem/step_wgt_undo_patch_storage_directories.h
@@ -0,0 +1,39 @@
+// Copyright (c) 2016 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 WGT_STEP_FILESYSTEM_STEP_WGT_UNDO_PATCH_STORAGE_DIRECTORIES_H_
+#define WGT_STEP_FILESYSTEM_STEP_WGT_UNDO_PATCH_STORAGE_DIRECTORIES_H_
+
+#include
+#include
+
+namespace wgt {
+namespace filesystem {
+
+/**
+ * \brief Installation (WGT).
+ * Responsible for unlinking the content of widget's shared/res directory
+ * into package's shared/res directory and vice versa for Tizen widget
+ * with API version >= 3.0
+ */
+class StepWgtUndoPatchStorageDirectories :
+ 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 { return Status::OK; }
+
+ private:
+ bool UndoShareDirFor3x();
+
+ STEP_NAME(UndoPatchWgtStorageDirectories)
+};
+
+} // namespace filesystem
+} // namespace wgt
+
+#endif // WGT_STEP_FILESYSTEM_STEP_WGT_UNDO_PATCH_STORAGE_DIRECTORIES_H_
diff --git a/src/wgt/wgt_installer.cc b/src/wgt/wgt_installer.cc
index ffa669f..1eacc18 100755
--- a/src/wgt/wgt_installer.cc
+++ b/src/wgt/wgt_installer.cc
@@ -92,6 +92,7 @@
#include "wgt/step/filesystem/step_wgt_patch_storage_directories.h"
#include "wgt/step/filesystem/step_wgt_prepare_package_directory.h"
#include "wgt/step/filesystem/step_wgt_resource_directory.h"
+#include "wgt/step/filesystem/step_wgt_undo_patch_storage_directories.h"
#include "wgt/step/filesystem/step_wgt_update_package_directory.h"
#include "wgt/step/pkgmgr/step_generate_xml.h"
#include "wgt/step/security/step_add_default_privileges.h"
@@ -339,6 +340,7 @@ WgtInstaller::WgtInstaller(ci::PkgMgrPtr pkgrmgr)
AddStep();
AddStep();
AddStep();
+ AddStep();
AddStep("res/wgt/");
AddStep();
AddStep();