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();