Merge branch 'tizen' of https://github.sec.samsung.net/j-h-choi/dotnet-launcher into...
authorj-h.choi <j-h.choi@samsung.com>
Tue, 11 Jun 2019 09:14:14 +0000 (18:14 +0900)
committerj-h.choi <j-h.choi@samsung.com>
Tue, 11 Jun 2019 09:14:14 +0000 (18:14 +0900)
18 files changed:
NativeLauncher/CMakeLists.txt
NativeLauncher/dotnet-launcher.info [new file with mode: 0644]
NativeLauncher/inc/db_manager.h [new file with mode: 0644]
NativeLauncher/inc/ni_common.h [moved from NativeLauncher/installer-plugin/ni_common.h with 100% similarity]
NativeLauncher/inc/pkgmgr_parser_plugin_interface.h [moved from NativeLauncher/installer-plugin/pkgmgr_parser_plugin_interface.h with 87% similarity]
NativeLauncher/inc/utils.h
NativeLauncher/installer-plugin/prefer_dotnet_aot_plugin.cc
NativeLauncher/installer-plugin/prefer_nuget_cache_plugin.cc [new file with mode: 0644]
NativeLauncher/launcher/dotnet/dotnet_launcher.cc
NativeLauncher/launcher/launcher.cc
NativeLauncher/tool/ni_common.cc [moved from NativeLauncher/installer-plugin/ni_common.cc with 94% similarity]
NativeLauncher/tool/nitool.cc [moved from NativeLauncher/installer-plugin/nitool.cc with 97% similarity]
NativeLauncher/tool/tactool.cc [new file with mode: 0644]
NativeLauncher/tool/tpatool.cc [moved from NativeLauncher/installer-plugin/tpatool.cc with 99% similarity]
NativeLauncher/util/db_manager.cc [new file with mode: 0644]
NativeLauncher/util/utils.cc
dotnet-launcher.manifest
packaging/dotnet-launcher.spec

index ec16431..90bedcf 100644 (file)
@@ -4,7 +4,7 @@ PROJECT("dotnet-tools")
 MESSAGE("CMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}")
 
 INCLUDE(FindPkgConfig)
-PKG_CHECK_MODULES(${PROJECT_NAME} REQUIRED aul pkgmgr-info pkgmgr-installer dlog ecore bundle dlog liblaunchpad glib-2.0 libsmack capi-appfw-app-common storage)
+PKG_CHECK_MODULES(${PROJECT_NAME} REQUIRED aul pkgmgr-info pkgmgr-installer dlog ecore bundle dlog liblaunchpad glib-2.0 libsmack capi-appfw-app-common storage jsoncpp openssl sqlite3)
 
 FOREACH(flag ${${PROJECT_NAME}_CFLAGS})
     SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} ${flag}")
@@ -34,6 +34,10 @@ IF(DEFINED NATIVE_LIB_DIR)
     SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} -DNATIVE_LIB_DIR=${NATIVE_LIB_DIR}")
 ENDIF(DEFINED NATIVE_LIB_DIR)
 
+IF(DEFINED TAC_DIR)
+    SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} -DTAC_DIR=${TAC_DIR}")
+ENDIF(DEFINED TAC_DIR)
+
 OPTION(NOT_USE_FUNCTION "Remove build warning" OFF)
 IF(NOT_USE_FUNCTION)
     ADD_DEFINITIONS("-DNOT_USE_FUNCTION")
@@ -70,10 +74,11 @@ SET(${DOTNET_LAUNCHER_UTIL}_SOURCE_FILES
     util/plugin_manager.cc
     util/path_manager.cc
     util/log_manager.cc
+    util/db_manager.cc
 )
 ADD_LIBRARY(${DOTNET_LAUNCHER_UTIL} SHARED ${${DOTNET_LAUNCHER_UTIL}_SOURCE_FILES})
 SET_TARGET_PROPERTIES(${DOTNET_LAUNCHER_UTIL} PROPERTIES COMPILE_FLAGS "-fPIC")
-TARGET_LINK_LIBRARIES(${DOTNET_LAUNCHER_UTIL} ${${PROJECT_NAME}_LDFLAGS} "-ldl")
+TARGET_LINK_LIBRARIES(${DOTNET_LAUNCHER_UTIL} ${${PROJECT_NAME}_LDFLAGS} "-ldl" boost_filesystem boost_system)
 
 SET(DOTNET_LAUNCHER "dotnet-launcher")
 SET(${DOTNET_LAUNCHER}_SOURCE_FILES
@@ -92,7 +97,7 @@ SET_TARGET_PROPERTIES(${DOTNET_LAUNCHER}
 
 SET(NI_COMMON "ni_common")
 SET(${NI_COMMON}_SOURCE_FILES
-    installer-plugin/ni_common.cc
+    tool/ni_common.cc
 )
 ADD_LIBRARY(${NI_COMMON} SHARED ${${NI_COMMON}_SOURCE_FILES})
 SET_TARGET_PROPERTIES(${NI_COMMON} PROPERTIES COMPILE_FLAGS "-fPIC")
@@ -100,7 +105,7 @@ TARGET_LINK_LIBRARIES(${NI_COMMON} ${${PROJECT_NAME}_LDFLAGS} ${DOTNET_LAUNCHER_
 
 SET(NITOOL "nitool")
 SET(${NITOOL}_SOURCE_FILES
-    installer-plugin/nitool.cc
+    tool/nitool.cc
 )
 ADD_EXECUTABLE(${NITOOL} ${${NITOOL}_SOURCE_FILES})
 SET_TARGET_PROPERTIES(${NITOOL} PROPERTIES COMPILE_FLAGS "-fPIE")
@@ -108,12 +113,20 @@ TARGET_LINK_LIBRARIES(${NITOOL} ${${PROJECT_NAME}_LDFLAGS} "-pie" ${DOTNET_LAUNC
 
 SET(TPATOOL "tpatool")
 SET(${TPATOOL}_SOURCE_FILES
-    installer-plugin/tpatool.cc
+    tool/tpatool.cc
 )
 ADD_EXECUTABLE(${TPATOOL} ${${TPATOOL}_SOURCE_FILES})
 SET_TARGET_PROPERTIES(${TPATOOL} PROPERTIES COMPILE_FLAGS "-fPIE")
 TARGET_LINK_LIBRARIES(${TPATOOL} ${${PROJECT_NAME}_LDFLAGS} "-pie" ${DOTNET_LAUNCHER_UTIL})
 
+SET(TACTOOL "tactool")
+SET(${TACTOOL}_SOURCE_FILES
+    tool/tactool.cc
+)
+ADD_EXECUTABLE(${TACTOOL} ${${TACTOOL}_SOURCE_FILES})
+SET_TARGET_PROPERTIES(${TACTOOL} PROPERTIES COMPILE_FLAGS "-fPIE")
+TARGET_LINK_LIBRARIES(${TACTOOL} ${${PROJECT_NAME}_LDFLAGS} "-pie" ${DOTNET_LAUNCHER_UTIL} ${NI_COMMON})
+
 #SET(INSTALLER_PLUGIN "ui-application")
 #SET(${INSTALLER_PLUGIN}_SOURCE_FILES
 #    util/utils.cc
@@ -124,7 +137,6 @@ TARGET_LINK_LIBRARIES(${TPATOOL} ${${PROJECT_NAME}_LDFLAGS} "-pie" ${DOTNET_LAUN
 #SET_TARGET_PROPERTIES(${INSTALLER_PLUGIN} PROPERTIES COMPILE_FLAGS "-fPIC")
 #TARGET_LINK_LIBRARIES(${INSTALLER_PLUGIN} ${${PROJECT_NAME}_LDFLAGS})
 
-
 SET(PREFER_DOTNET_AOT_PLUGIN "prefer_dotnet_aot_plugin")
 SET(${PREFER_DOTNET_AOT_PLUGIN}_SOURCE_FILES
     installer-plugin/prefer_dotnet_aot_plugin.cc
@@ -133,6 +145,14 @@ ADD_LIBRARY(${PREFER_DOTNET_AOT_PLUGIN} SHARED ${${PREFER_DOTNET_AOT_PLUGIN}_SOU
 SET_TARGET_PROPERTIES(${PREFER_DOTNET_AOT_PLUGIN} PROPERTIES COMPILE_FLAGS "-fPIC")
 TARGET_LINK_LIBRARIES(${PREFER_DOTNET_AOT_PLUGIN} ${${PROJECT_NAME}_LDFLAGS} ${DOTNET_LAUNCHER_UTIL} ${NI_COMMON})
 
+SET(PREFER_NUGET_CACHE_PLUGIN "prefer_nuget_cache_plugin")
+SET(${PREFER_NUGET_CACHE_PLUGIN}_SOURCE_FILES
+    installer-plugin/prefer_nuget_cache_plugin.cc
+)
+ADD_LIBRARY(${PREFER_NUGET_CACHE_PLUGIN} SHARED ${${PREFER_NUGET_CACHE_PLUGIN}_SOURCE_FILES})
+SET_TARGET_PROPERTIES(${PREFER_NUGET_CACHE_PLUGIN} PROPERTIES COMPILE_FLAGS "-fPIC")
+TARGET_LINK_LIBRARIES(${PREFER_NUGET_CACHE_PLUGIN} ${${PROJECT_NAME}_LDFLAGS} ${DOTNET_LAUNCHER_UTIL} ${NI_COMMON})
+
 CONFIGURE_FILE(dotnet-launcher.pc.in dotnet-launcher.pc @ONLY)
 
 INSTALL(TARGETS ${DOTNET_LAUNCHER_UTIL} DESTINATION ${LIBDIR})
@@ -140,12 +160,15 @@ INSTALL(TARGETS ${DOTNET_LAUNCHER} DESTINATION ${BINDIR})
 INSTALL(TARGETS ${NI_COMMON} DESTINATION ${LIBDIR})
 INSTALL(TARGETS ${NITOOL} DESTINATION ${BINDIR})
 INSTALL(TARGETS ${TPATOOL} DESTINATION ${BINDIR})
+INSTALL(TARGETS ${TACTOOL} DESTINATION ${BINDIR})
 #INSTALL(TARGETS ${INSTALLER_PLUGIN} DESTINATION ${INSTALL_PLUGIN_DIR})
 INSTALL(TARGETS ${PREFER_DOTNET_AOT_PLUGIN} DESTINATION ${INSTALL_MDPLUGIN_DIR})
+INSTALL(TARGETS ${PREFER_NUGET_CACHE_PLUGIN} DESTINATION ${INSTALL_MDPLUGIN_DIR})
 INSTALL(FILES dotnet.loader DESTINATION ${LOADERDIR})
 INSTALL(FILES dotnet.launcher DESTINATION ${LOADERDIR})
 INSTALL(FILES dotnet.debugger DESTINATION ${LOADERDIR})
 INSTALL(FILES inc/coreclr_host.h DESTINATION ${INCLUDEDIR})
 INSTALL(FILES inc/dotnet_launcher_plugin.h DESTINATION ${INCLUDEDIR})
-INSTALL(FILES installer-plugin/ni_common.h DESTINATION ${INCLUDEDIR})
+INSTALL(FILES inc/ni_common.h DESTINATION ${INCLUDEDIR})
 INSTALL(FILES ../dotnet-launcher.pc DESTINATION ${LIBDIR}/pkgconfig)
+INSTALL(FILES dotnet-launcher.info DESTINATION /usr/share/parser-plugins)
diff --git a/NativeLauncher/dotnet-launcher.info b/NativeLauncher/dotnet-launcher.info
new file mode 100644 (file)
index 0000000..9ebf3c1
--- /dev/null
@@ -0,0 +1,2 @@
+type="metadata";name="http://tizen.org/metadata/prefer_nuget_cache";path="/etc/package-manager/parserlib/metadata/libprefer_nuget_cache_plugin.so"\r
+type="metadata";name="http://tizen.org/metadata/prefer_dotnet_aot";path="/etc/package-manager/parserlib/metadata/libprefer_dotnet_aot_plugin.so"\r
diff --git a/NativeLauncher/inc/db_manager.h b/NativeLauncher/inc/db_manager.h
new file mode 100644 (file)
index 0000000..59c23d5
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __DB_MANAGER_H__
+#define __DB_MANAGER_H__
+
+#include <string>
+#include <sqlite3.h>
+#include <vector>
+
+#define CREATE_TAC_DB_TABLE "CREATE TABLE IF NOT EXISTS TAC(\
+                       ID INTEGER PRIMARY KEY AUTOINCREMENT,\
+                       PKGID           TEXT,\
+                       NUGET           TEXT,\
+                       NAME            TEXT,\
+                       VERSION         TEXT);"
+#define QUERY_MAX_LEN  4096
+
+sqlite3* dbCreate(std::string path);
+bool dbOpen(sqlite3 *tac_db, std::string path);
+void dbClose(sqlite3 *tac_db);
+void dbRollback(sqlite3 *tac_db);
+bool dbUpdate(sqlite3 *tac_db, std::string path, std::string query);
+bool dbInsert(sqlite3 *tac_db, std::string path, std::string query);
+std::vector<std::string> dbSelect(sqlite3 *tac_db, std::string path, std::string query);
+bool dbDelete(sqlite3 *tac_db, std::string path, std::string query);
+
+#endif /* __DB_MANAGER_H__ */
@@ -28,6 +28,9 @@ extern "C"
        int PKGMGR_PARSER_PLUGIN_INSTALL(xmlDocPtr doc, const char* pkgId);
        int PKGMGR_PARSER_PLUGIN_UPGRADE(xmlDocPtr doc, const char* pkgId);
        int PKGMGR_PARSER_PLUGIN_UNINSTALL(xmlDocPtr doc, const char* pkgId);
+       int PKGMGR_PARSER_PLUGIN_REMOVED(xmlDocPtr doc, const char* pkgId);
+       int PKGMGR_PARSER_PLUGIN_CLEAN(xmlDocPtr doc, const char* pkgId);
+       int PKGMGR_PARSER_PLUGIN_UNDO(xmlDocPtr doc, const char* pkgId);
 
        int PKGMGR_PARSER_PLUGIN_POST_INSTALL(const char *pkgId);
        int PKGMGR_PARSER_PLUGIN_POST_UPGRADE(const char *pkgId);
index 79e8489..bb72e00 100644 (file)
@@ -20,6 +20,7 @@
 #include <string>
 #include <vector>
 #include <functional>
+#include <boost/filesystem.hpp>
 
 #include <launcher_env.h>
 
 #define PATH_SEPARATOR '/'
 #endif
 
+namespace bf = boost::filesystem;
+namespace bs = boost::system;
+
+enum FSFlag : int {
+  FS_NONE              = 0,
+  FS_MERGE_SKIP        = (1 << 0),
+  FS_MERGE_OVERWRITE   = (1 << 1),
+  FS_COMMIT_COPY_FILE  = (1 << 2),
+  FS_PRESERVE_OWNERSHIP_AND_PERMISSIONS = (1 << 3)
+};
+
+bool cmdOptionExists(char** begin, char** end, const std::string& option);
+
 /**
  * @brief get current executable path
  * return std::string path
@@ -56,6 +70,13 @@ std::string absolutePath(const std::string& path);
 std::string baseName(const std::string& path);
 
 /**
+ * @brief get root path
+ * @param[in] package id
+ * @param[out] root path
+ */
+int getRootPath(std::string pkgId, std::string& rootPath);
+
+/**
  * @brief split path with ":" delimiter and put that in the vector
  * @param[in] source path
  * @param[out] string vector
@@ -104,4 +125,50 @@ typedef std::function<void (const std::string&, const char*)> FileReader;
  */
 void scanFilesInDir(const std::string& directory, FileReader reader, unsigned int depth);
 
+/**
+ * @brief create the new directory.
+ * @param[in] source path
+ * @return return true when the directory was created.
+ */
+bool createDir(const bf::path& path);
+
+/**
+ * @brief copy the directory.
+ * @param[in] path to the source directory
+ * @param[in] path to the target directory
+ * @param[in] filesystem flag
+ * @return return true when the directory was copied.
+ */
+bool copyDir(const bf::path& path1, const bf::path& path2, FSFlag flags = FS_NONE);
+
+/**
+ * @brief copy the file.
+ * @param[in] path to the source file
+ * @param[in] path to the target file
+ * @return return true when the file was copied.
+ */
+bool copyFile(const bf::path& path1, const bf::path& path2);
+
+/**
+ * @brief moves of renames the file or directory.
+ * @param[in] path to the source file
+ * @param[in] path to the target file
+ * @return return true when the file was moved.
+ */
+bool moveFile(const bf::path& path1, const bf::path& path2);
+
+/**
+ * @brief removes the file or empty directory.
+ * @param[in] source path
+ * @return return true when the file was deleted.
+ */
+bool removeFile(const bf::path& path);
+
+/**
+ * @brief removes the file or directory and all its contents.
+ * @param[in] source path
+ * @return return true when the file or directory was deleted.
+ */
+bool removeAll(const bf::path& path);
+
 #endif /* __UTILS_H__ */
index 3d8c571..ffed938 100644 (file)
@@ -69,3 +69,23 @@ extern "C" int PKGMGR_MDPARSER_PLUGIN_UPGRADE(const char *pkgId, const char *app
 {
        return PKGMGR_MDPARSER_PLUGIN_INSTALL(pkgId, appId, list);
 }
+
+extern "C" int PKGMGR_MDPARSER_PLUGIN_UNINSTALL(const char *pkgId, const char *appId, GList *list)
+{
+       return 0;
+}
+
+extern "C" int PKGMGR_MDPARSER_PLUGIN_REMOVED(const char *pkgId, const char *appId, GList *list)
+{
+       return PKGMGR_MDPARSER_PLUGIN_UPGRADE(pkgId, appId, list);
+}
+
+extern "C" int PKGMGR_MDPARSER_PLUGIN_CLEAN(const char *pkgId, const char *appId, GList *list)
+{
+       return 0;
+}
+
+extern "C" int PKGMGR_MDPARSER_PLUGIN_UNDO(const char *pkgId, const char *appId, GList *list)
+{
+       return 0;
+}
diff --git a/NativeLauncher/installer-plugin/prefer_nuget_cache_plugin.cc b/NativeLauncher/installer-plugin/prefer_nuget_cache_plugin.cc
new file mode 100644 (file)
index 0000000..64afc73
--- /dev/null
@@ -0,0 +1,887 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "log.h"
+#include "ni_common.h"
+#include "utils.h"
+#include "db_manager.h"
+
+#ifdef  LOG_TAG
+#undef  LOG_TAG
+#endif
+#define LOG_TAG "DOTNET_INSTALLER_PLUGIN"
+
+#include <cstring>
+#include <fstream>
+#include <sstream>
+#include <vector>
+#include <boost/filesystem.hpp>
+#include <glib.h>
+#include <json/json.h>
+#include <pkgmgr-info.h>
+#include <pkgmgr_installer_info.h>
+#include <openssl/sha.h>
+
+typedef struct Metadata {
+       const char *key;
+       const char *value;
+} Metadata;
+
+const std::string mOptUsrDotnet = "/opt/usr/dotnet";
+const std::string mTizenNET = "Tizen.NET";
+const std::string mTizenNETSdk = "Tizen.NET.Sdk";
+const std::string mNETStandardLibrary = "NETStandard.Library";
+const std::string mTacRelease = ".TAC.Release";
+const std::string mDepsJson = ".deps.json";
+const std::string mBackup = ".bck";
+const std::string mdValue = "true";
+const std::string mdKey = "http://tizen.org/metadata/prefer_nuget_cache";
+const std::string tacAppListDB = mOptUsrDotnet + "/.TAC.App.list.db";
+
+std::vector<std::string> nugetPackagesAssembliesShaR2R;
+std::vector<std::string> tacDB;
+std::vector<std::string> createDirectories;
+std::vector<std::string> updateTac;
+std::string status = "";
+std::string rootPath;
+std::string execName;
+bf::path binPath;
+bool isCreateDirectory = false;
+static sqlite3 *tac_db = NULL;
+
+int metadataCheck(GList *list)
+{
+       GList *tag = NULL;
+       Metadata *mdInfo = NULL;
+       tag = g_list_first(list);
+       mdInfo = (Metadata*)tag->data;
+       if (mdInfo->key == mdKey && mdInfo->value == mdValue) {
+               _DBG("Prefer nuget cache set TRUE");
+               return 0;
+       } else {
+               return 1;
+       }
+}
+
+int appTypeCheck(std::string pkgId)
+{
+       uid_t uid = 0;
+       if (pkgmgr_installer_info_get_target_uid(&uid) < 0) {
+               _ERR("Failed to get UID");
+               return 0;
+       }
+
+       pkgmgrinfo_pkginfo_h handle;
+       int ret = pkgmgrinfo_pkginfo_get_usr_pkginfo(pkgId.c_str(), uid, &handle);
+       if (ret != PMINFO_R_OK) {
+               _ERR("Failed to get pkg info");
+               return 0;
+       }
+
+       bool isDotnetAppType = false;
+       auto dotnetAppCounter = [] (pkgmgrinfo_appinfo_h handle, void *userData) -> int {
+               char* type = nullptr;
+               bool* dotnet = static_cast<bool*>(userData);
+               if (pkgmgrinfo_appinfo_get_apptype(handle, &type) != PMINFO_R_OK) {
+                       _ERR("Failed to get app type : %s", type);
+                       return 0;
+               }
+               if (strcmp(type, "dotnet") == 0) {
+                       *dotnet = true;
+               }
+               return 0;
+       };
+
+       if (pkgmgrinfo_appinfo_get_usr_list(handle, PMINFO_ALL_APP, dotnetAppCounter, &isDotnetAppType, uid) != PMINFO_R_OK) {
+               _ERR("Failed to get list of app in pkg : %s", pkgId.c_str());
+               return -1;
+       }
+
+       pkgmgrinfo_pkginfo_destroy_pkginfo(handle);
+       return isDotnetAppType;
+}
+
+int getExecName(std::string pkgId)
+{
+       uid_t uid = 0;
+       if (pkgmgr_installer_info_get_target_uid(&uid) < 0) {
+               _ERR("Failed to get UID");
+               return 0;
+       }
+
+       pkgmgrinfo_pkginfo_h handle;
+       int ret = pkgmgrinfo_pkginfo_get_usr_pkginfo(pkgId.c_str(), uid, &handle);
+       if (ret != PMINFO_R_OK) {
+               _ERR("Failed to get pkg info");
+               return 0;
+       }
+
+       auto dotnetAppCounter = [] (pkgmgrinfo_appinfo_h handle, void *userData) -> int {
+               char* exec = nullptr;
+               if (pkgmgrinfo_appinfo_get_exec(handle, &exec) != PMINFO_R_OK) {
+                       _ERR("Failed to get exec : %s", exec);
+                       return 0;
+               }
+               execName = std::string(exec).substr(std::string(exec).rfind('/') + 1);
+               return 0;
+       };
+
+       if (pkgmgrinfo_appinfo_get_usr_list(handle, PMINFO_ALL_APP, dotnetAppCounter, NULL, uid) != PMINFO_R_OK) {
+               _ERR("Failed to get list of app in pkg : %s", pkgId.c_str());
+               return -1;
+       }
+
+       pkgmgrinfo_pkginfo_destroy_pkginfo(handle);
+       return 0;
+}
+
+int SHA256(std::string path, char outputBuffer[65])
+{
+       FILE *file = fopen(path.c_str(), "rb");
+       if (!file) {
+               return -1;
+       }
+
+       unsigned char hash[SHA256_DIGEST_LENGTH];
+       SHA256_CTX sha256;
+       SHA256_Init(&sha256);
+       int bytesRead = 0;
+       const int bufSize = 32768;
+       char *buffer = (char*)malloc(bufSize);
+       if (!buffer) {
+               fclose(file);
+               return -1;
+       }
+
+       while ((bytesRead = fread(buffer, 1, bufSize, file))) {
+               SHA256_Update(&sha256, buffer, bytesRead);
+       }
+       SHA256_Final(hash, &sha256);
+       for (int i = 0; i < SHA256_DIGEST_LENGTH; i++) {
+               sprintf(outputBuffer + (i * 2), "%02x", hash[i]);
+       }
+       outputBuffer[64] = 0;
+
+       fclose(file);
+       free(buffer);
+       return 0;
+}
+
+int depsJsonParser()
+{
+       std::string deps_json_name = execName.substr(0, execName.rfind(".dll")) + mDepsJson;
+       if (bf::exists(rootPath + "/" + deps_json_name)) {
+               std::string deps_json_path = rootPath + "/" + deps_json_name;
+               std::ifstream ifs(deps_json_path);
+               Json::CharReaderBuilder reader;
+               Json::Value root;
+               std::string error;
+               if (ifs.is_open()) {
+                       if (!Json::parseFromStream(reader, ifs, &root, &error)) {
+                               _INFO("Failed to parse of deps.json");
+                               ifs.close();
+                               return -1;
+                       }
+                       const Json::Value runtimeTargetName = root["runtimeTarget"]["name"];
+                       std::string runtimeTarget_name = runtimeTargetName.asString();
+                       const Json::Value nugetPackages = root["targets"][runtimeTarget_name.c_str()];
+                       for (auto& nuget : nugetPackages.getMemberNames()) {
+                               if (strstr(nuget.c_str(), mTizenNET.c_str()) != NULL ||
+                                       strstr(nuget.c_str(), mTizenNETSdk.c_str()) != NULL ||
+                                       strstr(nuget.c_str(), (execName.substr(0, execName.find(".Tizen."))).c_str()) != NULL ||
+                                       strstr(nuget.c_str(), (execName.substr(0, execName.find(".dll"))).c_str()) != NULL) {
+                                       continue;
+                               } else {
+                                       const Json::Value assemblies = nugetPackages[nuget.c_str()]["runtime"];
+                                       if (assemblies != Json::nullValue) {
+                                               const Json::Value dependencies = nugetPackages[nuget.c_str()]["dependencies"];
+                                               std::string r2r = "";
+                                               for (auto& dependency : dependencies.getMemberNames()) {
+                                                       if (strstr(dependency.c_str(), mTizenNET.c_str()) != NULL ||
+                                                               strstr(dependency.c_str(), mNETStandardLibrary.c_str()) != NULL) {
+                                                               continue;
+                                                       } else {
+                                                               r2r = "--r2r";
+                                                       }
+                                               }
+                                               if (strcmp(r2r.c_str(), "--r2r")) {
+                                                       tacDB.push_back(nuget);
+                                                       _INFO("Nuget package : %s", nuget.c_str());
+                                                       for (auto& assembly : assemblies.getMemberNames()) {
+                                                               std::string assembly_name = assembly.substr(assembly.rfind('/') + 1);
+                                                               char buffer[65];
+                                                               SHA256((binPath / assembly_name).string(), buffer);
+                                                               nugetPackagesAssembliesShaR2R.push_back(nuget + "/" + assembly_name + "/" + buffer + "/" + r2r);
+                                                               _INFO("Assembly / SHA256 : %s / %s", assembly_name.c_str(), buffer);
+                                                       }
+                                               }
+                                       }
+                               }
+                       }
+                       ifs.close();
+               }
+       }
+       return 0;
+}
+
+int createSymlink(bf::path tac_version_dir, std::string np)
+{
+       bs::error_code error;
+       uid_t uid = 0;
+       for (auto& npAssemblyShaR2R : nugetPackagesAssembliesShaR2R) {
+               std::string nuget_package_assembly_sha = npAssemblyShaR2R.substr(0, npAssemblyShaR2R.rfind('/'));
+               std::string sha = nuget_package_assembly_sha.substr(nuget_package_assembly_sha.rfind('/') + 1);
+               std::string nuget_package_assembly = nuget_package_assembly_sha.substr(0, nuget_package_assembly_sha.rfind('/'));
+               std::string nuget_package = nuget_package_assembly.substr(0, nuget_package_assembly.rfind('/'));
+               std::string assembly = nuget_package_assembly.substr(nuget_package_assembly.rfind('/') + 1);
+               std::string r2r = npAssemblyShaR2R.substr(npAssemblyShaR2R.rfind('/') + 1);
+               std::string ni_assembly = assembly.substr(0, assembly.rfind(".dll")) + ".ni.dll";
+               if (!strcmp(nuget_package.c_str(), np.c_str())) {
+                       if (bf::exists(binPath / assembly)) {
+                               if (isCreateDirectory) {
+                                       std::string command = "nitool --dll " + binPath.string() + "/" + assembly + " " + r2r;
+                                       if (system(command.c_str()) != 0) {
+                                               _ERR("Failed to create ni dll [%s]", command.c_str());
+                                               return -1;
+                                       }
+                                       if (!copyFile(binPath / ni_assembly, tac_version_dir / ni_assembly)) {
+                                               _ERR("Failed to move of %s", ni_assembly.c_str());
+                                               return -1;
+                                       }
+                                       if (!copyFile(binPath / assembly, tac_version_dir / assembly)) {
+                                               _ERR("Failed to move of %s", assembly.c_str());
+                                               return -1;
+                                       }
+                               }
+                               if (pkgmgr_installer_info_get_target_uid(&uid) < 0) {
+                                       _ERR("Failed to get UID");
+                                       return -1;
+                               }
+                               bf::create_symlink(tac_version_dir / ni_assembly, binPath / mTacRelease / ni_assembly, error);
+                               if (error) {
+                                       _ERR("Failed to create symlink");
+                                       return -1;
+                               }
+                               bf::create_symlink(tac_version_dir / assembly, binPath / mTacRelease / assembly, error);
+                               if (error) {
+                                       _ERR("Failed to create symlink");
+                                       return -1;
+                               }
+                               if (lchown((binPath / mTacRelease / ni_assembly).c_str(), uid, 0)) {
+                                       _ERR("Failed to change owner of: %s", (binPath / mTacRelease / ni_assembly).c_str());
+                                       return -1;
+                               }
+                               if (lchown((binPath / mTacRelease / assembly).c_str(), uid, 0)) {
+                                       _ERR("Failed to change owner of: %s", (binPath / mTacRelease / assembly).c_str());
+                                       return -1;
+                               }
+                       }
+               }
+       }
+       return 0;
+}
+
+int removeOriginalAssembly() {
+       for (auto& npAssemblyShaR2R : nugetPackagesAssembliesShaR2R) {
+               std::string nuget_package_assembly_sha = npAssemblyShaR2R.substr(0, npAssemblyShaR2R.rfind('/'));
+               std::string sha = nuget_package_assembly_sha.substr(nuget_package_assembly_sha.rfind('/') + 1);
+               std::string nuget_package_assembly = nuget_package_assembly_sha.substr(0, nuget_package_assembly_sha.rfind('/'));
+               std::string nuget_package = nuget_package_assembly.substr(0, nuget_package_assembly.rfind('/'));
+               std::string assembly = nuget_package_assembly.substr(nuget_package_assembly.rfind('/') + 1);
+               std::string r2r = npAssemblyShaR2R.substr(npAssemblyShaR2R.rfind('/') + 1);
+               std::string ni_assembly = assembly.substr(0, assembly.rfind(".dll")) + ".ni.dll";
+               if (bf::exists(binPath / assembly)) {
+                       if (!removeFile(binPath / assembly)) {
+                               _ERR("Failed to remove of %s", assembly.c_str());
+                               return -1;
+                       }
+               }
+               if (bf::exists(binPath / ni_assembly)) {
+                       if (!removeFile(binPath / ni_assembly)) {
+                               _ERR("Failed to remove of %s", ni_assembly.c_str());
+                               return -1;
+                       }
+               }
+       }
+       return 0;
+}
+
+extern "C" int PKGMGR_MDPARSER_PLUGIN_INSTALL(const char *pkgId, const char *appId, GList *list)
+{
+       _DBG("[===== PKGMGR_MDPARSER_PLUGIN_INSTALL =====]");
+       _INFO("PackageID : %s", pkgId);
+
+       if (!appTypeCheck(std::string(pkgId))) {
+               _INFO("App type is not dotnet");
+               return 0;
+       }
+       if (getExecName(std::string(pkgId)) < 0) {
+               return 0;
+       }
+       if (getRootPath(std::string(pkgId), rootPath) < 0) {
+               return 0;
+       } else {
+               binPath = rootPath / bf::path("bin");
+       }
+       if (!metadataCheck(list)) {
+               if (depsJsonParser()) {
+                       return 0;
+               }
+       }
+
+       status = "install";
+       tac_db = dbCreate(tacAppListDB);
+       if (tac_db) {
+               if (!dbOpen(tac_db, tacAppListDB)) {
+                       return 0;
+               }
+       } else {
+               _ERR("Sqlite create error");
+               return 0;
+       }
+
+       if (tacDB.empty()) {
+               _ERR("Not exist .deps.json file");
+               return 0;
+       }
+       if (!bf::exists(binPath / mTacRelease)) {
+               if (!createDir(binPath / mTacRelease)) {
+                       _INFO("Cannot create directory: %s", (binPath / mTacRelease).c_str());
+                       return 0;
+               }
+       }
+
+       for (auto& np : tacDB) {
+               std::string tac_name = np.substr(0, np.find('/'));
+               std::string tac_version = np.substr(np.rfind('/') + 1);
+               _INFO("TAC name : %s", tac_name.c_str());
+               _INFO("TAC version : %s", tac_version.c_str());
+
+               bf::path tac_version_dir = bf::path(mOptUsrDotnet) / np;
+               isCreateDirectory = false;
+               if (!bf::exists(tac_version_dir)) {
+                       _INFO("Create tac_version_dir [%s]", tac_version_dir.c_str());
+                       if (!createDir(tac_version_dir)) {
+                               _ERR("Cannot create directory: %s", tac_version_dir.c_str());
+                               return 0;
+                       }
+                       isCreateDirectory = true;
+                       createDirectories.push_back(tac_version_dir.string());
+                       std::string sha256_info = (tac_version_dir / bf::path("SHA256.info")).string();
+                       std::ofstream ofs(sha256_info, std::ios::app);
+                       int assembly_count = 0;
+                       for (auto& npAssemblyShaR2R : nugetPackagesAssembliesShaR2R) {
+                               std::string nuget_package_assembly_sha = npAssemblyShaR2R.substr(0, npAssemblyShaR2R.rfind('/'));
+                               std::string sha = nuget_package_assembly_sha.substr(nuget_package_assembly_sha.rfind('/') + 1);
+                               std::string nuget_package_assembly = nuget_package_assembly_sha.substr(0, nuget_package_assembly_sha.rfind('/'));
+                               std::string nuget_package = nuget_package_assembly.substr(0, nuget_package_assembly.rfind('/'));
+                               std::string assembly = nuget_package_assembly.substr(nuget_package_assembly.rfind('/') + 1);
+                               std::string r2r = npAssemblyShaR2R.substr(npAssemblyShaR2R.rfind('/') + 1);
+                               if (!strcmp(nuget_package.c_str(), np.c_str())) {
+                                       ofs << assembly << ";" << sha << std::endl;
+                                       assembly_count++;
+                               }
+                       }
+                       ofs << assembly_count << std::endl;
+                       ofs.close();
+
+                       if (createSymlink(tac_version_dir, np)) {
+                               _ERR("Failed to create symlink");
+                               return 0;
+                       }
+                       std::string sql = "INSERT INTO TAC (PKGID, NUGET, NAME, VERSION) " \
+                                       "VALUES ('" + std::string(pkgId) + "', '" + np + "', '" + tac_name + "', '" + tac_version + "');";
+                       dbInsert(tac_db, tacAppListDB, sql);
+               } else {
+                       _INFO("Exists tac_version_dir [%s]", tac_version_dir.c_str());
+                       int compare_count = 0;
+                       int assembly_count = 0;
+                       std::string sha256_count = "0";
+                       for (auto& npAssemblyShaR2R : nugetPackagesAssembliesShaR2R) {
+                               std::string nuget_package_assembly_sha = npAssemblyShaR2R.substr(0, npAssemblyShaR2R.rfind('/'));
+                               std::string sha = nuget_package_assembly_sha.substr(nuget_package_assembly_sha.rfind('/') + 1);
+                               std::string nuget_package_assembly = nuget_package_assembly_sha.substr(0, nuget_package_assembly_sha.rfind('/'));
+                               std::string nuget_package = nuget_package_assembly.substr(0, nuget_package_assembly.rfind('/'));
+                               std::string assembly = nuget_package_assembly.substr(nuget_package_assembly.rfind('/') + 1);
+                               std::string r2r = npAssemblyShaR2R.substr(npAssemblyShaR2R.rfind('/') + 1);
+                               if (!strcmp(nuget_package.c_str(), np.c_str())) {
+                                       assembly_count++;
+                                       std::string sha256_info = (tac_version_dir / bf::path("SHA256.info")).string();
+                                       std::ifstream ifs(sha256_info);
+                                       std::string get_str;
+                                       if (ifs.is_open()) {
+                                               while (getline(ifs, get_str)) {
+                                                       if (!strcmp(get_str.c_str(), (assembly + ";" + sha).c_str())) {
+                                                               compare_count++;
+                                                       }
+                                                       sha256_count = get_str;
+                                               }
+                                               ifs.close();
+                                       }
+                               }
+                       }
+                       if (!strcmp(std::to_string(assembly_count).c_str(), std::to_string(compare_count).c_str()) &&
+                               !strcmp(std::to_string(assembly_count).c_str(), sha256_count.c_str())) {
+                               _INFO("Same : %s", tac_name.c_str());
+                               if (createSymlink(tac_version_dir, np)) {
+                                       return 0;
+                               }
+                               std::string sql = "INSERT INTO TAC (PKGID, NUGET, NAME, VERSION) " \
+                                               "VALUES ('" + std::string(pkgId) + "', '" + np + "', '" + tac_name + "', '" + tac_version + "');";
+                               dbInsert(tac_db, tacAppListDB, sql);
+                       } else {
+                               _INFO("Different : %s", tac_name.c_str());
+                       }
+               }
+       }
+       if (removeOriginalAssembly()) {
+               return 0;
+       }
+       return 0;
+}
+
+static int sqliteCb(void *count, int argc, char **argv, char **azColName) {
+       int *c = (int*)count;
+       *c = atoi(argv[0]);
+       return 0;
+}
+
+int updateTacDB(const char *pkgId)
+{
+       for (auto& unp : updateTac) {
+               char *error = 0;
+               int ret;
+               int count = 0;
+               if (tac_db) {
+                       if (!dbOpen(tac_db, tacAppListDB)) {
+                               return 0;
+                       }
+               } else {
+                       _ERR("Sqlite create error");
+                       return 0;
+               }
+               std::string sql = "SELECT COUNT(NUGET) FROM TAC WHERE NUGET = '" + unp + "';";
+               ret = sqlite3_exec(tac_db, sql.c_str(), sqliteCb, &count, &error);
+               if (ret != SQLITE_OK) {
+                       _ERR("SQL error: %s", error);
+                       sqlite3_free(error);
+               }
+               if (count < 1) {
+                       bf::path tac_version_dir_prev = bf::path(mOptUsrDotnet) / unp;
+                       bf::path tac_version_dir_backup = bf::path(mOptUsrDotnet) / (unp + mBackup);
+                       if (!copyDir(tac_version_dir_prev, tac_version_dir_backup)) {
+                               _ERR("Failed to copy of %s to %s", tac_version_dir_prev.c_str(), tac_version_dir_backup.c_str());
+                               return -1;
+                       }
+                       if (!removeAll(tac_version_dir_prev)) {
+                               _ERR("Failed to remove of %s", tac_version_dir_prev.c_str());
+                               return -1;
+                       }
+               }
+       }
+       return 0;
+}
+
+extern "C" int PKGMGR_MDPARSER_PLUGIN_UPGRADE(const char *pkgId, const char *appId, GList *list)
+{
+       _DBG("[===== PKGMGR_MDPARSER_PLUGIN_UPGRADE =====]");
+       _INFO("PackageID : %s", pkgId);
+
+       if (!appTypeCheck(std::string(pkgId))) {
+               _INFO("App type is not dotnet");
+               return 0;
+       }
+       if (getExecName(std::string(pkgId)) < 0) {
+               return 0;
+       }
+       if (getRootPath(std::string(pkgId), rootPath) < 0) {
+               return 0;
+       } else {
+               binPath = rootPath / bf::path("bin");
+       }
+       if (!strcmp("removed", status.c_str())) {
+               _INFO("Skipped to parse of deps.json");
+       } else {
+               if (!metadataCheck(list)) {
+                       if (depsJsonParser()) {
+                               return 0;
+                       }
+               }
+       }
+
+       status = "update";
+       tac_db = dbCreate(tacAppListDB);
+       if (tac_db) {
+               if (!dbOpen(tac_db, tacAppListDB)) {
+                       return 0;
+               }
+       } else {
+               _ERR("Sqlite create error");
+               return 0;
+       }
+
+       std::string sql = "SELECT * FROM TAC WHERE PKGID = '" + std::string(pkgId) + "';";
+       updateTac = dbSelect(tac_db, tacAppListDB, sql);
+
+       if (tacDB.empty()) {
+               sql = "DELETE FROM TAC WHERE PKGID = '" + std::string(pkgId) + "';";
+               dbDelete(tac_db, tacAppListDB, sql);
+               if (updateTacDB(pkgId)) {
+                       return 0;
+               }
+       } else {
+               if (!bf::exists(binPath / mTacRelease)) {
+                       if (!createDir(binPath / mTacRelease)) {
+                               _INFO("Cannot create directory: %s", (binPath / mTacRelease).c_str());
+                               return 0;
+                       }
+               }
+
+               for (auto& np : tacDB) {
+                       std::string tac_name = np.substr(0, np.find('/'));
+                       std::string tac_version = np.substr(np.rfind('/') + 1);
+                       _INFO("TAC name : %s", tac_name.c_str());
+                       _INFO("TAC version : %s", tac_version.c_str());
+
+                       bf::path tac_version_dir = bf::path(mOptUsrDotnet) / np;
+                       isCreateDirectory = false;
+                       if (!bf::exists(tac_version_dir)) {
+                               _INFO("Create tac_version_dir [%s]", tac_version_dir.c_str());
+                               if (!createDir(tac_version_dir)) {
+                                       _ERR("Cannot create directory: %s", tac_version_dir.c_str());
+                                       return 0;
+                               }
+                               isCreateDirectory = true;
+                               createDirectories.push_back(tac_version_dir.string());
+                               std::string sha256_info = (tac_version_dir / bf::path("SHA256.info")).string();
+                               std::ofstream ofs2(sha256_info, std::ios::app);
+                               int assembly_count = 0;
+                               for (auto& npAssemblyShaR2R : nugetPackagesAssembliesShaR2R) {
+                                       std::string nuget_package_assembly_sha = npAssemblyShaR2R.substr(0, npAssemblyShaR2R.rfind('/'));
+                                       std::string sha = nuget_package_assembly_sha.substr(nuget_package_assembly_sha.rfind('/') + 1);
+                                       std::string nuget_package_assembly = nuget_package_assembly_sha.substr(0, nuget_package_assembly_sha.rfind('/'));
+                                       std::string nuget_package = nuget_package_assembly.substr(0, nuget_package_assembly.rfind('/'));
+                                       std::string assembly = nuget_package_assembly.substr(nuget_package_assembly.rfind('/') + 1);
+                                       std::string r2r = npAssemblyShaR2R.substr(npAssemblyShaR2R.rfind('/') + 1);
+                                       if (!strcmp(nuget_package.c_str(), np.c_str())) {
+                                               ofs2 << assembly << ";" << sha << std::endl;
+                                               assembly_count++;
+                                       }
+                               }
+                               ofs2 << assembly_count << std::endl;
+                               ofs2.close();
+                               if (createSymlink(tac_version_dir, np)) {
+                                       return 0;
+                               }
+
+                               char *error = 0;
+                               int count = 0;
+                               sql = "SELECT COUNT(NUGET) FROM TAC WHERE PKGID = '" + std::string(pkgId) + "' AND NAME = '" + tac_name + "';";
+                               int ret = sqlite3_exec(tac_db, sql.c_str(), sqliteCb, &count, &error);
+                               if (ret != SQLITE_OK) {
+                                       _ERR("SQL error: %s", error);
+                                       sqlite3_free(error);
+                               }
+
+                               if (count == 1) {
+                                       sql = "UPDATE TAC SET NAME = '" + tac_name + "', VERSION = '" + tac_version + "', NUGET = '" + np + "' WHERE PKGID = '" + std::string(pkgId) + "' AND NAME = '" + tac_name + "';";
+                                       dbUpdate(tac_db, tacAppListDB, sql);
+                               } else {
+                                       sql = "INSERT INTO TAC (PKGID, NUGET, NAME, VERSION) " \
+                                               "VALUES ('" + std::string(pkgId) + "', '" + np + "', '" + tac_name + "', '" + tac_version + "');";
+                                       dbInsert(tac_db, tacAppListDB, sql);
+                               }
+                       } else {
+                               _INFO("Exists tac_version_dir [%s]", tac_version_dir.c_str());
+                               int compare_count = 0;
+                               int assembly_count = 0;
+                               std::string sha256_count = "0";
+                               for (auto& npAssemblyShaR2R : nugetPackagesAssembliesShaR2R) {
+                                       std::string nuget_package_assembly_sha = npAssemblyShaR2R.substr(0, npAssemblyShaR2R.rfind('/'));
+                                       std::string sha = nuget_package_assembly_sha.substr(nuget_package_assembly_sha.rfind('/') + 1);
+                                       std::string nuget_package_assembly = nuget_package_assembly_sha.substr(0, nuget_package_assembly_sha.rfind('/'));
+                                       std::string nuget_package = nuget_package_assembly.substr(0, nuget_package_assembly.rfind('/'));
+                                       std::string assembly = nuget_package_assembly.substr(nuget_package_assembly.rfind('/') + 1);
+                                       std::string r2r = npAssemblyShaR2R.substr(npAssemblyShaR2R.rfind('/') + 1);
+                                       if (!strcmp(nuget_package.c_str(), np.c_str())) {
+                                               assembly_count++;
+                                               std::string sha256_info = (tac_version_dir / bf::path("SHA256.info")).string();
+                                               std::ifstream ifs2(sha256_info);
+                                               std::string get_str;
+                                               if (ifs2.is_open()) {
+                                                       while (getline(ifs2, get_str)) {
+                                                               if (!strcmp(get_str.c_str(), (assembly + ";" + sha).c_str())) {
+                                                                       compare_count++;
+                                                               }
+                                                               sha256_count = get_str;
+                                                       }
+                                                       ifs2.close();
+                                               }
+                                       }
+                               }
+
+                               if (!strcmp(std::to_string(assembly_count).c_str(), std::to_string(compare_count).c_str()) &&
+                                       !strcmp(std::to_string(assembly_count).c_str(), sha256_count.c_str())) {
+                                       _INFO("Same : %s", tac_name.c_str());
+                                       if (createSymlink(tac_version_dir, np)) {
+                                               return 0;
+                                       }
+
+                                       char *error = 0;
+                                       int count = 0;
+                                       std::string sql = "SELECT COUNT(NUGET) FROM TAC WHERE PKGID = '" + std::string(pkgId) + "' AND NAME = '" + tac_name + "';";
+                                       int ret = sqlite3_exec(tac_db, sql.c_str(), sqliteCb, &count, &error);
+                                       if (ret != SQLITE_OK) {
+                                               _ERR("SQL error: %s", error);
+                                               sqlite3_free(error);
+                                       }
+
+                                       if (count == 1) {
+                                               sql = "UPDATE TAC SET NAME = '" + tac_name + "', VERSION = '" + tac_version + "', NUGET = '" + np + "' WHERE PKGID = '" + std::string(pkgId) + "' AND NAME = '" + tac_name + "';";
+                                               dbUpdate(tac_db, tacAppListDB, sql);
+                                       } else {
+                                               sql = "INSERT INTO TAC (PKGID, NUGET, NAME, VERSION) " \
+                                                       "VALUES ('" + std::string(pkgId) + "', '" + np + "', '" + tac_name + "', '" + tac_version + "');";
+                                               dbInsert(tac_db, tacAppListDB, sql);
+                                       }
+                               } else {
+                                       _INFO("Different : %s", tac_name.c_str());
+                               }
+                       }
+               }
+               for (auto& unp : updateTac) {
+                       bool isExits = false;
+                       for (auto& np : tacDB) {
+                               if (!strcmp(unp.c_str(), np.c_str())) {
+                                       isExits = true;
+                                       break;
+                               }
+                       }
+
+                       if (!isExits) {
+                               std::string sql = "DELETE FROM TAC WHERE PKGID = '" + std::string(pkgId) + "' AND NUGET = '" + unp + "';";
+                               dbDelete(tac_db, tacAppListDB, sql);
+                       }
+               }
+
+               if (removeOriginalAssembly()) {
+                       return 0;
+               }
+               if (updateTacDB(pkgId)) {
+                       return 0;
+               }
+       }
+       return 0;
+}
+
+extern "C" int PKGMGR_MDPARSER_PLUGIN_UNINSTALL(const char *pkgId, const char *appId, GList *list)
+{
+       _DBG("[===== PKGMGR_MDPARSER_PLUGIN_UNINSTALL =====]");
+       _INFO("PackageID : %s", pkgId);
+
+       status = "uninstall";
+       tac_db = dbCreate(tacAppListDB);
+       if (tac_db) {
+               if (!dbOpen(tac_db, tacAppListDB)) {
+                       return 0;
+               }
+       } else {
+               _ERR("Sqlite create error");
+               return 0;
+       }
+
+       std::string sql = "SELECT * FROM TAC WHERE PKGID = '" + std::string(pkgId) + "';";
+       updateTac = dbSelect(tac_db, tacAppListDB, sql);
+
+       sql = "DELETE FROM TAC WHERE PKGID = '" + std::string(pkgId) + "';";
+       dbDelete(tac_db, tacAppListDB, sql);
+
+       if (updateTacDB(pkgId)) {
+               return 0;
+       }
+       return 0;
+}
+
+extern "C" int PKGMGR_MDPARSER_PLUGIN_REMOVED(const char *pkgId, const char *appId, GList *list)
+{
+       _DBG("[===== PKGMGR_MDPARSER_PLUGIN_REMOVED =====]");
+       status = "removed";
+
+       PKGMGR_MDPARSER_PLUGIN_UPGRADE(pkgId, appId, list);
+       return 0;
+}
+
+int install_Clean()
+{
+       return 0;
+}
+
+int unInstall_Clean()
+{
+       for (auto& unp : updateTac) {
+               bf::path current_tac = bf::path(mOptUsrDotnet) / unp.substr(0, unp.find('/'));
+               std::vector<std::string> exist_directory_name;
+               for (auto& bck : bf::recursive_directory_iterator(current_tac)) {
+                       if (bf::exists(bck.path()) && bf::is_directory(bck.path()) && strstr(bck.path().c_str(), mBackup.c_str()) != NULL) {
+                               if (!removeAll(bck.path().string())) {
+                                       _ERR("Failed to remove of %s", bck.path().c_str());
+                                       return 0;
+                               }
+                               break;
+                       }
+               }
+               for (auto& bck : bf::recursive_directory_iterator(current_tac)) {
+                       if (bf::exists(bck.path()) && bf::is_directory(bck.path()) && strstr(bck.path().c_str(), mBackup.c_str()) == NULL) {
+                               exist_directory_name.push_back(bck.path().string());
+                               break;
+                       }
+               }
+               if (exist_directory_name.empty()) {
+                       if (!removeAll(current_tac)) {
+                               _ERR("Failed to remove of %s", current_tac.c_str());
+                               return 0;
+                       }
+               } else {
+                       exist_directory_name.clear();
+               }
+       }
+       return 0;
+}
+
+int update_Clean()
+{
+       if (!tacDB.empty()) {
+               for (auto& np : tacDB) {
+                       bf::path current_tac = bf::path(mOptUsrDotnet) / np.substr(0, np.find('/'));
+                       std::vector<std::string> exist_directory_name;
+                       for (auto& bck : bf::recursive_directory_iterator(current_tac)) {
+                               if (bf::exists(bck.path()) && bf::is_directory(bck.path()) && strstr(bck.path().c_str(), mBackup.c_str()) != NULL) {
+                                       if (!removeAll(bck.path().string())) {
+                                               _ERR("Failed to remove of %s", bck.path().c_str());
+                                               return 0;
+                                       }
+                                       break;
+                               }
+                       }
+                       for (auto& bck : bf::recursive_directory_iterator(current_tac)) {
+                               if (bf::exists(bck.path()) && bf::is_directory(bck.path()) && strstr(bck.path().c_str(), mBackup.c_str()) == NULL) {
+                                       exist_directory_name.push_back(bck.path().string());
+                                       break;
+                               }
+                       }
+                       if (exist_directory_name.empty()) {
+                               if (!removeAll(current_tac)) {
+                                       _ERR("Failed to remove of %s", current_tac.c_str());
+                                       return 0;
+                               }
+                       } else {
+                               exist_directory_name.clear();
+                       }
+               }
+       }
+       unInstall_Clean();
+       return 0;
+}
+
+extern "C" int PKGMGR_MDPARSER_PLUGIN_CLEAN(const char *pkgId, const char *appId, GList *list)
+{
+       _DBG("[===== PKGMGR_MDPARSER_PLUGIN_CLEAN =====]");
+
+       if (tac_db) {
+               dbClose(tac_db);
+               tac_db = NULL;
+       }
+       if (!strcmp("install", status.c_str())) {
+               install_Clean();
+       } else if (!strcmp("update", status.c_str())) {
+               update_Clean();
+       } else if (!strcmp("uninstall", status.c_str())) {
+               unInstall_Clean();
+       }
+       return 0;
+}
+
+int install_Undo()
+{
+       for (auto& cd : createDirectories) {
+               if (!removeAll(cd)) {
+                       _ERR("Failed to remove of %s", cd.c_str());
+                       return 0;
+               }
+       }
+       return 0;
+}
+
+int unInstall_Undo()
+{
+       for (auto& unp : updateTac) {
+               for (auto& bck : bf::recursive_directory_iterator(bf::path(mOptUsrDotnet) / unp.substr(0, unp.find('/')))) {
+                       if (bf::exists(bck.path()) && bf::is_directory(bck.path()) && strstr(bck.path().c_str(), mBackup.c_str()) != NULL) {
+                               if (!moveFile(bck.path(), bck.path().string().substr(0, bck.path().string().rfind(mBackup.c_str())))) {
+                                       _ERR("Failed to move %s to %s",
+                                               bck.path().c_str(), bck.path().string().substr(0, bck.path().string().rfind(mBackup.c_str())).c_str());
+                                       return 0;
+                               }
+                               break;
+                       }
+               }
+       }
+       return 0;
+}
+
+int update_Undo()
+{
+       for (auto& cd : createDirectories) {
+               if (!removeAll(cd)) {
+                       _ERR("Failed to remove of %s", cd.c_str());
+                       return 0;
+               }
+       }
+       if (!tacDB.empty()) {
+               for (auto& np : tacDB) {
+                       for (auto& bck : bf::recursive_directory_iterator(bf::path(mOptUsrDotnet) / np.substr(0, np.find('/')))) {
+                               if (bf::exists(bck.path()) && bf::is_directory(bck.path()) && strstr(bck.path().c_str(), mBackup.c_str()) != NULL) {
+                                       if (!moveFile(bck.path(), bck.path().string().substr(0, bck.path().string().rfind(mBackup.c_str())))) {
+                                               _ERR("Failed to move %s to %s",
+                                                       bck.path().c_str(), bck.path().string().substr(0, bck.path().string().rfind(mBackup.c_str())).c_str());
+                                               return 0;
+                                       }
+                                       break;
+                               }
+                       }
+               }
+       }
+       unInstall_Undo();
+       return 0;
+}
+
+extern "C" int PKGMGR_MDPARSER_PLUGIN_UNDO(const char *pkgId, const char *appId, GList *list)
+{
+       _DBG("[===== PKGMGR_MDPARSER_PLUGIN_UNDO =====]");
+
+       if (tac_db) {
+               dbRollback(tac_db);
+               tac_db = NULL;
+       }
+       if (!strcmp("install", status.c_str())) {
+               install_Undo();
+       } else if (!strcmp("update", status.c_str())) {
+               update_Undo();
+       } else if (!strcmp("uninstall", status.c_str())) {
+               unInstall_Undo();
+       }
+       return 0;
+}
index feae81d..838a5e6 100644 (file)
@@ -389,8 +389,8 @@ int CoreRuntime::initialize(bool standalone)
        std::string appRoot = std::string("/proc/self/fd/") + std::to_string(fd);
        std::string appBin = concatPath(appRoot, "bin");
        std::string appLib = concatPath(appRoot, "lib");
-       std::string probePath = appBin + ":" + appLib;
-       std::string NIprobePath = appBin + APP_NI_SUB_DIR + ":" + appLib + APP_NI_SUB_DIR;
+       std::string appTAC = concatPath(appBin, ".TAC.Release");
+       std::string NIprobePath = appBin + APP_NI_SUB_DIR + ":" + appLib + APP_NI_SUB_DIR + ":" + appTAC;
        std::string tpa = getTPA();
        std::string nativeLibPath = getExtraNativeLibDirs(appRoot) + ":" + appBin + ":" + appLib + ":" + __nativeLibDirectory;
        std::string appName = std::string("dotnet-launcher-") + std::to_string(getpid());
index 0bec483..e5a1f14 100644 (file)
@@ -130,7 +130,7 @@ static void preCreateWindow(bundle *extra, int type, void *userData)
 {
        struct stat sb;
        if (stat(ELEMENTARY_PATH, &sb) != 0) {
-               _ERR("[candidate] libelememantary is not exist. skip precreation");
+               _ERR("[candidate] libelementary is not exist. skip precreation");
                return;
        }
 
similarity index 94%
rename from NativeLauncher/installer-plugin/ni_common.cc
rename to NativeLauncher/tool/ni_common.cc
index 29f0b82..d2b7ec3 100644 (file)
@@ -400,28 +400,29 @@ void createNiUnderDirs(const std::string rootPaths[], int count, bool enableR2R,
        }
 }
 
-ni_error_e createNiUnderPkgRoot(const std::string& pkgName, bool enableR2R)
+ni_error_e createNiUnderPkgRoot(const std::string& pkgId, bool enableR2R)
 {
        std::string pkgRoot;
-       if (getRootPath(pkgName, pkgRoot) != NI_ERROR_NONE) {
-               fprintf(stderr, "Failed to get root path from [%s]\n", pkgName.c_str());
+       if (getRootPath(pkgId, pkgRoot) != NI_ERROR_NONE) {
+               fprintf(stderr, "Failed to get root path from [%s]\n", pkgId.c_str());
                return NI_ERROR_INVALID_PACKAGE;
        }
 
        std::string binDir = concatPath(pkgRoot, "bin");
        std::string libDir = concatPath(pkgRoot, "lib");
-       std::string paths[] = {binDir, libDir};
+       std::string appTAC = concatPath(binDir, ".TAC.Release");
+       std::string paths[] = {binDir, libDir, appTAC};
 
-       createNiUnderDirs(paths, 2, enableR2R, true);
+       createNiUnderDirs(paths, 3, enableR2R, true);
 
        return NI_ERROR_NONE;
 }
 
-ni_error_e createNiDllUnderPkgRoot(const std::string& pkgName, const std::string& dllPath, bool enableR2R)
+ni_error_e createNiDllUnderPkgRoot(const std::string& pkgId, const std::string& dllPath, bool enableR2R)
 {
        std::string pkgRoot;
-       if (getRootPath(pkgName, pkgRoot) < 0) {
-               fprintf(stderr, "Failed to get root path from [%s]\n", pkgName.c_str());
+       if (getRootPath(pkgId, pkgRoot) < 0) {
+               fprintf(stderr, "Failed to get root path from [%s]\n", pkgId.c_str());
                return NI_ERROR_INVALID_PACKAGE;
        }
 
@@ -457,7 +458,6 @@ void removeNiPlatform()
 void removeNiUnderDirs(const std::string rootPaths[], int count)
 {
        auto convert = [](const std::string& path, std::string name) {
-               std::string ni;
                if (isNativeImage(path)) {
                        if (remove(path.c_str())) {
                                fprintf(stderr, "Failed to remove %s\n", path.c_str());
@@ -469,11 +469,11 @@ void removeNiUnderDirs(const std::string rootPaths[], int count)
                scanFilesInDir(rootPaths[i], convert, -1);
 }
 
-ni_error_e removeNiUnderPkgRoot(const std::string& pkgName)
+ni_error_e removeNiUnderPkgRoot(const std::string& pkgId)
 {
        std::string pkgRoot;
-       if (getRootPath(pkgName, pkgRoot) < 0) {
-               fprintf(stderr, "Failed to get root path from [%s]\n", pkgName.c_str());
+       if (getRootPath(pkgId, pkgRoot) < 0) {
+               fprintf(stderr, "Failed to get root path from [%s]\n", pkgId.c_str());
                return NI_ERROR_INVALID_PACKAGE;
        }
 
@@ -527,4 +527,3 @@ ni_error_e regenerateAppNI(bool enableR2R)
        pkgmgrinfo_appinfo_metadata_filter_destroy(handle);
        return NI_ERROR_NONE;
 }
-
similarity index 97%
rename from NativeLauncher/installer-plugin/nitool.cc
rename to NativeLauncher/tool/nitool.cc
index 4ff2679..9647369 100644 (file)
@@ -14,6 +14,7 @@
  * limitations under the License.
  */
 
+#include "utils.h"
 #include "ni_common.h"
 
 #include <cstdio>
@@ -32,11 +33,6 @@ std::vector<std::string> getCmdArgs(char** begin, char** end)
        return list;
 }
 
-bool cmdOptionExists(char** begin, char** end, const std::string& option)
-{
-       return std::find(begin, end, option) != end;
-}
-
 static void help(const char *argv0)
 {
        const char* helpDesc =
diff --git a/NativeLauncher/tool/tactool.cc b/NativeLauncher/tool/tactool.cc
new file mode 100644 (file)
index 0000000..98be18c
--- /dev/null
@@ -0,0 +1,268 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "log.h"
+#include "utils.h"
+#include "db_manager.h"
+
+#include <algorithm>
+#include <cstdio>
+#include <cstring>
+#include <fstream>
+#include <vector>
+
+#include <json/json.h>
+#include <pkgmgr-info.h>
+#include <pkgmgr_installer_info.h>
+
+#ifdef  LOG_TAG
+#undef  LOG_TAG
+#endif
+#define LOG_TAG "DOTNET_INSTALLER_PLUGIN"
+
+const std::string mOptUsrDotnet = "/opt/usr/dotnet";
+const std::string mTizenNET = "Tizen.NET";
+const std::string mTizenNETSdk = "Tizen.NET.Sdk";
+const std::string mNETStandardLibrary = "NETStandard.Library";
+const std::string mDepsJson = ".deps.json";
+const std::string tacAppListDB = mOptUsrDotnet + "/.TAC.App.list.db";
+const std::string tacAppListDBJournal = mOptUsrDotnet + "/.TAC.App.list.db-journal";
+const std::string tacAppListRestoreDB = mOptUsrDotnet + "/.TAC.App.list.restore.db";
+const std::string tacAppListRestoreDBJournal = mOptUsrDotnet + "/.TAC.App.list.restore.db-journal";
+const std::string mdKey = "http://tizen.org/metadata/prefer_nuget_cache";
+const std::string mdValue = "true";
+
+static sqlite3 *tac_db = NULL;
+std::vector<std::string> restoreNuget;
+
+static void help(const char *argv0)
+{
+       const char* helpDesc =
+               "Usage: %s [args] <root paths or pkg name>\n"
+               "          --help                       - Display this screen\n"
+               "          --restore-db         - Restore TAC Database\n"
+               "\n";
+       printf(helpDesc, argv0, argv0, argv0, argv0, argv0);
+}
+
+void cleanupDirectory()
+{
+       std::vector<std::string> removeNuget;
+       for (auto& nuget : bf::recursive_directory_iterator(bf::path(mOptUsrDotnet))) {
+               bool isExist = false;
+               for (auto& restore : restoreNuget) {
+                       if (!bf::is_directory(nuget.path())) {
+                               isExist = true;
+                       }
+                       if (strstr(nuget.path().c_str(), restore.c_str()) != NULL) {
+                               isExist = true;
+                               break;
+                       }
+               }
+               if (!isExist) {
+                       removeNuget.push_back(nuget.path().string());
+               }
+       }
+
+       for (auto& rm : removeNuget) {
+               if (bf::exists(rm)) {
+                       if (!removeAll(rm)) {
+                               _ERR("Failed to remove of %s", rm.c_str());
+                       }
+               }
+       }
+       removeNuget.clear();
+}
+
+void restoreTACDB(std::string pkgId, std::string depsJsonPath, std::string execName)
+{
+       std::ifstream ifs(depsJsonPath);
+       Json::CharReaderBuilder reader;
+       Json::Value root;
+       std::string error;
+       if (ifs.is_open()) {
+               if (!Json::parseFromStream(reader, ifs, &root, &error)) {
+                       _INFO("Failed to parse of deps.json");
+                       ifs.close();
+                       return;
+               }
+               const Json::Value runtimeTargetName = root["runtimeTarget"]["name"];
+               std::string runtimeTarget_name = runtimeTargetName.asString();
+               const Json::Value nugetPackages = root["targets"][runtimeTarget_name.c_str()];
+               for (auto& nuget : nugetPackages.getMemberNames()) {
+                       if (strstr(nuget.c_str(), mTizenNET.c_str()) != NULL ||
+                               strstr(nuget.c_str(), mTizenNETSdk.c_str()) != NULL ||
+                               strstr(nuget.c_str(), (execName.substr(0, execName.find(".Tizen."))).c_str()) != NULL ||
+                               strstr(nuget.c_str(), (execName.substr(0, execName.find(".dll"))).c_str()) != NULL) {
+                               continue;
+                       } else {
+                               const Json::Value assemblies = nugetPackages[nuget.c_str()]["runtime"];
+                               if (assemblies != Json::nullValue) {
+                                       const Json::Value dependencies = nugetPackages[nuget.c_str()]["dependencies"];
+                                       bool isDependency = false;
+                                       for (auto& dependency : dependencies.getMemberNames()) {
+                                               if (strstr(dependency.c_str(), mTizenNET.c_str()) != NULL ||
+                                                       strstr(dependency.c_str(), mNETStandardLibrary.c_str()) != NULL) {
+                                                       continue;
+                                               } else {
+                                                       isDependency = true;
+                                               }
+                                       }
+                                       if (!isDependency) {
+                                               _INFO("PackageId : [%s] / Nuget package : [%s]", pkgId.c_str(), nuget.c_str());
+                                               std::string name = nuget.substr(0, nuget.find('/'));
+                                               std::string version = nuget.substr(nuget.rfind('/') + 1);
+                                               std::string sql = "INSERT INTO TAC (PKGID, NUGET, NAME, VERSION) " \
+                                                               "VALUES ('" + pkgId + "', '" + nuget + "', '" + name + "', '" + version + "');";
+                                               dbInsert(tac_db, tacAppListRestoreDB, sql);
+                                               restoreNuget.push_back(mOptUsrDotnet + "/" + name);
+                                       }
+                               }
+                       }
+               }
+               ifs.close();
+       }
+}
+
+static int restoreDBCb(pkgmgrinfo_appinfo_h handle, void *userData)
+{
+       int ret = 0;
+       char *pkgId = NULL;
+       char *root = NULL;
+       char *exec = NULL;
+       std::string rootPath;
+       std::string execName;
+
+       ret = pkgmgrinfo_appinfo_get_pkgid(handle, &pkgId);
+       if (ret != PMINFO_R_OK) {
+               fprintf(stderr, "Failed to get pkgid\n");
+               return -1;
+       }
+
+       ret = pkgmgrinfo_appinfo_get_root_path(handle, &root);
+       if (ret != PMINFO_R_OK) {
+               fprintf(stderr, "Failed to get root path\n");
+               return -1;
+       }
+       rootPath = root;
+
+       ret = pkgmgrinfo_appinfo_get_exec(handle, &exec);
+       if (ret != PMINFO_R_OK) {
+               fprintf(stderr, "Failed to get exec name\n");
+               return -1;
+       }
+       execName = std::string(exec).substr(std::string(exec).rfind('/') + 1);
+
+       std::string depsJsonName = execName.substr(0, execName.rfind(".dll")) + mDepsJson;
+       std::string depsJsonPath = rootPath + "/" + depsJsonName;
+       if (bf::exists(depsJsonPath)) {
+               restoreTACDB(pkgId, depsJsonPath, execName);
+       }
+       return 0;
+}
+
+int restoreDB()
+{
+       if (bf::exists(tacAppListRestoreDB)) {
+               if (!removeFile(tacAppListRestoreDB)) {
+                       _ERR("Failed to remove of %s", tacAppListRestoreDB.c_str());
+                       return -1;
+               }
+       }
+       if (bf::exists(tacAppListRestoreDBJournal)) {
+               if (!removeFile(tacAppListRestoreDBJournal)) {
+                       _ERR("Failed to remove of %s", tacAppListRestoreDBJournal.c_str());
+                       return -1;
+               }
+       }
+
+       tac_db = dbCreate(tacAppListRestoreDB);
+       if (tac_db) {
+               if (!dbOpen(tac_db, tacAppListRestoreDB)) {
+                       return 0;
+               }
+       } else {
+               return 0;
+       }
+
+       int ret = 0;
+       pkgmgrinfo_appinfo_metadata_filter_h handle;
+
+       ret = pkgmgrinfo_appinfo_metadata_filter_create(&handle);
+       if (ret != PMINFO_R_OK) {
+               return -1;
+       }
+
+       ret = pkgmgrinfo_appinfo_metadata_filter_add(handle, mdKey.c_str(), mdValue.c_str());
+       if (ret != PMINFO_R_OK) {
+               pkgmgrinfo_appinfo_metadata_filter_destroy(handle);
+               return -1;
+       }
+
+       ret = pkgmgrinfo_appinfo_metadata_filter_foreach(handle, restoreDBCb, NULL);
+       if (ret != PMINFO_R_OK) {
+               fprintf(stderr, "Failed pkgmgrinfo_appinfo_metadata_filter_foreach\n");
+               pkgmgrinfo_appinfo_metadata_filter_destroy(handle);
+               return -1;
+       }
+       pkgmgrinfo_appinfo_metadata_filter_destroy(handle);
+
+       if (tac_db) {
+               dbClose(tac_db);
+               tac_db = NULL;
+       }
+
+       if (bf::exists(tacAppListRestoreDB)) {
+               if (!copyFile(tacAppListRestoreDB, tacAppListDB)) {
+                       _ERR("Failed to move of %s", tacAppListDB.c_str());
+                       return -1;
+               }
+               if (!removeFile(tacAppListRestoreDB)) {
+                       _ERR("Failed to remove of %s", tacAppListRestoreDB.c_str());
+                       return -1;
+               }
+       }
+
+       if (bf::exists(tacAppListRestoreDBJournal)) {
+               if (!copyFile(tacAppListRestoreDBJournal, tacAppListDBJournal)) {
+                       _ERR("Failed to move of %s", tacAppListDBJournal.c_str());
+                       return -1;
+               }
+               if (!removeFile(tacAppListRestoreDBJournal)) {
+                       _ERR("Failed to remove of %s", tacAppListRestoreDBJournal.c_str());
+                       return -1;
+               }
+       }
+
+    cleanupDirectory();
+       return 0;
+}
+
+// step 1. Remove original DB
+// step 2. Parsing the .deps.json for all apps
+// step 3. Create new DB
+// step 4. Cleanup unnecessary TAC directory
+int main(int argc, char* argv[])
+{
+       if (cmdOptionExists(argv, argv + argc, "--help")) {
+               help(argv[0]);
+       } else if (cmdOptionExists(argv, argv + argc, "--restore-db")) {
+               restoreDB();
+       } else {
+               help(argv[0]);
+       }
+       return 0;
+}
similarity index 99%
rename from NativeLauncher/installer-plugin/tpatool.cc
rename to NativeLauncher/tool/tpatool.cc
index 834eb14..fd0e2bb 100644 (file)
@@ -39,7 +39,7 @@ int main(int argc, char* argv[])
     std::ofstream out(__PLATFORM_TPA_CACHE);
     out << tpaList;
     out.close();
-    
+
     return 0;
 }
 
diff --git a/NativeLauncher/util/db_manager.cc b/NativeLauncher/util/db_manager.cc
new file mode 100644 (file)
index 0000000..f18eb5a
--- /dev/null
@@ -0,0 +1,177 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "db_manager.h"
+#include "log.h"
+
+#ifdef  LOG_TAG
+#undef  LOG_TAG
+#endif
+#define LOG_TAG "DOTNET_INSTALLER_PLUGIN"
+
+sqlite3* dbCreate(std::string path)
+{
+       sqlite3 *sqlite = NULL;
+       int ret = sqlite3_open(path.c_str(), &sqlite);
+       if (ret != SQLITE_OK) {
+               _ERR("Sqlite error : [%d] : path [%s]", ret, path.c_str());
+               return NULL;
+       }
+       ret = sqlite3_exec(sqlite, "PRAGMA journal_mode = PERSIST", NULL, NULL, NULL);
+       if (ret != SQLITE_OK) {
+               _ERR("Sqlite error : [%d]", ret);
+               return NULL;
+       }
+       ret = sqlite3_exec(sqlite, CREATE_TAC_DB_TABLE, NULL, NULL, NULL);
+       if (ret != SQLITE_OK) {
+               _ERR("Sqlite error : [%d] : path [%s]", ret, path.c_str());
+               return NULL;
+       }
+       return sqlite;
+}
+
+bool dbOpen(sqlite3 *tac_db, std::string path)
+{
+       if (!tac_db) {
+               int ret = sqlite3_open(path.c_str(), &tac_db);
+               if (ret != SQLITE_OK) {
+                       _ERR("Sqlite error : [%d] : path [%s]", ret, path.c_str());
+                       return false;
+               }
+       }
+       return true;
+}
+
+void dbFinalize(sqlite3_stmt *stmt)
+{
+       if (stmt) {
+               sqlite3_finalize(stmt);
+               stmt = NULL;
+       }
+}
+
+void dbClose(sqlite3 *tac_db)
+{
+       if (tac_db) {
+               sqlite3_exec(tac_db, "COMMIT;", NULL, NULL, NULL);
+               sqlite3_close(tac_db);
+               tac_db = NULL;
+       }
+}
+
+void dbRollback(sqlite3 *tac_db)
+{
+       if (tac_db) {
+               sqlite3_exec(tac_db, "ROLLBACK;", NULL, NULL, NULL);
+               sqlite3_close(tac_db);
+               tac_db = NULL;
+       }
+}
+
+bool dbUpdate(sqlite3 *tac_db, std::string path, std::string query)
+{
+       sqlite3_stmt *stmt = NULL;
+       if (!dbOpen(tac_db, path)) {
+               return false;
+       }
+       int ret = sqlite3_exec(tac_db, "BEGIN;", NULL, NULL, NULL);
+       ret = sqlite3_prepare(tac_db, query.c_str(), QUERY_MAX_LEN , &stmt, NULL);
+       if (ret != SQLITE_OK) {
+               _ERR("Sqlite error : [%s, %s]", query.c_str(), sqlite3_errmsg(tac_db));
+               dbClose(tac_db);
+               return false;
+       }
+       ret = sqlite3_step(stmt);
+       if (ret != SQLITE_DONE && ret != SQLITE_ROW && ret != SQLITE_OK) {
+               _ERR("Sqlite error [%d]", ret);
+               dbFinalize(stmt);
+               dbClose(tac_db);
+               return false;
+       }
+       dbFinalize(stmt);
+       return true;
+}
+
+bool dbInsert(sqlite3 *tac_db, std::string path, std::string query)
+{
+       sqlite3_stmt *stmt = NULL;
+       if (!dbOpen(tac_db, path)) {
+               return false;
+       }
+       int ret = sqlite3_exec(tac_db, "BEGIN;", NULL, NULL, NULL);
+       ret = sqlite3_prepare(tac_db, query.c_str(), QUERY_MAX_LEN , &stmt, NULL);
+       if (ret != SQLITE_OK) {
+               _ERR("Sqlite error : [%s,%s]", query.c_str(), sqlite3_errmsg(tac_db));
+               dbClose(tac_db);
+               return false;
+       }
+       ret = sqlite3_step(stmt);
+       if (ret != SQLITE_DONE && ret != SQLITE_ROW && ret != SQLITE_OK) {
+               _ERR("Sqlite error [%d]", ret);
+               dbFinalize(stmt);
+               dbClose(tac_db);
+               return false;
+       }
+       dbFinalize(stmt);
+       return true;
+}
+
+std::vector<std::string> dbSelect(sqlite3 *tac_db, std::string path, std::string query)
+{
+       std::vector<std::string> updateDB;
+       sqlite3_stmt* stmt = NULL;
+       const char* str = NULL;
+       if (!dbOpen(tac_db, path)) {
+               return updateDB;
+       }
+       int ret = sqlite3_prepare_v2(tac_db, query.c_str(), strlen(query.c_str()), &stmt, NULL);
+       if (ret != SQLITE_OK) {
+               _ERR("Sqlite error : [%s,%s]", query.c_str(), sqlite3_errmsg(tac_db));
+               dbClose(tac_db);
+               return updateDB;
+       }
+       while (sqlite3_step(stmt) == SQLITE_ROW) {
+               str = (const char *) sqlite3_column_text(stmt, 2);
+               _DBG("Nuget : %s", (!str || !strlen(str)) ? NULL : strdup(str));
+               updateDB.push_back((!str || !strlen(str)) ? NULL : strdup(str));
+       }
+       dbFinalize(stmt);
+       return updateDB;
+}
+
+bool dbDelete(sqlite3 *tac_db, std::string path, std::string query)
+{
+       sqlite3_stmt *stmt = NULL;
+       if (!dbOpen(tac_db, path)) {
+               return false;
+       }
+       int ret = sqlite3_exec(tac_db, "BEGIN;", NULL, NULL, NULL);
+       ret = sqlite3_prepare(tac_db, query.c_str(), QUERY_MAX_LEN , &stmt, NULL);
+       if (ret != SQLITE_OK) {
+               _ERR("Sqlite error : [%s,%s]", query.c_str(), sqlite3_errmsg(tac_db));
+               dbClose(tac_db);
+               return false;
+       }
+       ret = sqlite3_step(stmt);
+       if (ret != SQLITE_DONE && ret != SQLITE_ROW && ret != SQLITE_OK) {
+               _ERR("Sqlite error [%d]", ret);
+               dbFinalize(stmt);
+               dbClose(tac_db);
+               return false;
+       }
+       dbFinalize(stmt);
+       return true;
+}
index fff4cfb..45a61f6 100644 (file)
  */
 
 #include <dirent.h>
+#include <fcntl.h>
 #include <sys/stat.h>
 #include <unistd.h>
 #include <limits.h>
 #include <strings.h>
+#include <pkgmgr-info.h>
+#include <pkgmgr_installer_info.h>
 
 #include <cstdlib>
 #include <cstring>
@@ -29,6 +32,7 @@
 #include <sstream>
 #include <map>
 
+#include "log.h"
 #include "utils.h"
 #include "path_manager.h"
 
@@ -53,6 +57,11 @@ bool isNativeImage(const std::string& fileName)
        return iCompare(fileName, fileName.size()-7, ".ni", 0, 3);
 }
 
+bool cmdOptionExists(char** begin, char** end, const std::string& option)
+{
+       return std::find(begin, end, option) != end;
+}
+
 std::string readSelfPath()
 {
        char buff[PATH_MAX];
@@ -98,6 +107,40 @@ std::string absolutePath(const std::string& path)
        return absPath;
 }
 
+int getRootPath(std::string pkgId, std::string& rootPath)
+{
+       int ret = 0;
+       char *path = 0;
+       uid_t uid = 0;
+
+       if (pkgmgr_installer_info_get_target_uid(&uid) < 0) {
+               _ERR("Failed to get UID");
+               return -1;
+       }
+
+       pkgmgrinfo_pkginfo_h handle;
+       if (uid == 0) {
+               ret = pkgmgrinfo_pkginfo_get_pkginfo(pkgId.c_str(), &handle);
+               if (ret != PMINFO_R_OK) {
+                       return -1;
+               }
+       } else {
+               ret = pkgmgrinfo_pkginfo_get_usr_pkginfo(pkgId.c_str(), uid, &handle);
+               if (ret != PMINFO_R_OK) {
+                       return -1;
+               }
+       }
+
+       ret = pkgmgrinfo_pkginfo_get_root_path(handle, &path);
+       if (ret != PMINFO_R_OK) {
+               pkgmgrinfo_pkginfo_destroy_pkginfo(handle);
+               return -1;
+       }
+       rootPath = path;
+       pkgmgrinfo_pkginfo_destroy_pkginfo(handle);
+       return 0;
+}
+
 std::string baseName(const std::string& path)
 {
        auto pos = path.find_last_of(PATH_SEPARATOR);
@@ -167,6 +210,9 @@ void scanFilesInDir(const std::string& directory, FileReader reader, unsigned in
        struct dirent* entry;
        bool isDir;
 
+       if (strstr(directory.c_str(), ".TAC.Release") != NULL)
+               return; // skip nitool --regen-all-app (--r2r)
+
        dir = opendir(directory.c_str());
 
        if (dir == nullptr)
@@ -201,8 +247,213 @@ void scanFilesInDir(const std::string& directory, FileReader reader, unsigned in
 
        if (depth != 0)
                for (auto& d : innerDirectories)
-                       scanFilesInDir(d.c_str(), reader, depth-1);
+                       scanFilesInDir(d.c_str(), reader, depth - 1);
 
        closedir(dir);
 }
 
+static bool setOwnership(const bf::path& path, uid_t uid, gid_t gid) {
+       int fd = open(path.c_str(), O_RDONLY);
+       if (fd < 0) {
+               _ERR("Can't open directory: %s", path.c_str());
+               return false;
+       }
+       int ret = fchown(fd, uid, gid);
+       close(fd);
+       if (ret != 0) {
+               _ERR("Failed to change owner of: %s", path.c_str());
+               return false;
+       }
+       return true;
+}
+
+static bool setDirPermissions(const bf::path& path, bf::perms permissions) {
+       bs::error_code error;
+       bf::permissions(path, permissions, error);
+       if (error) {
+               _ERR("Failed to set permissions for directory: %s, %s", path.c_str(), error.message().c_str());
+               return false;
+       }
+       return true;
+}
+
+static bool setDirOwnershipAndPermissions(const bf::path& path, bf::perms permissions, uid_t uid, gid_t gid) {
+       if (!setOwnership(path, uid, gid)) {
+               _ERR("Failed to change owner: %s, (uid: %d, gid: %d)", path.c_str(), uid, gid);
+               return false;
+       }
+       if (!setDirPermissions(path, permissions)) {
+               _ERR("Failed to change permission: %s, (%d)", path.c_str(), permissions);
+               return false;
+       }
+       return true;
+}
+
+static bool copyOwnershipAndPermissions(const bf::path& path, const bf::path& path2) {
+       if (!bf::exists(path)) {
+               _ERR("Failed to copy ownership and permissions from %s to %s", path.c_str(), path2.c_str());
+               return false;
+       }
+       bf::perms permissions = bf::status(path).permissions();
+       struct stat stats;
+       if (stat(path.c_str(), &stats) != 0) {
+               return false;
+       }
+       if (!setDirOwnershipAndPermissions(path2, permissions, stats.st_uid, stats.st_gid)) {
+               _ERR("Failed to copy ownership and permissions from %s to %s", path.c_str(), path2.c_str());
+               return false;
+       }
+       return true;
+}
+
+bool createDir(const bf::path& path) {
+       if (bf::exists(path)) {
+               return true;
+       }
+       bs::error_code error;
+       bf::create_directories(path, error);
+       if (error) {
+               _ERR("Failed to create directory: %s", error.message().c_str());
+               return false;
+       }
+       return true;
+}
+
+bool copyDir(const bf::path& path1, const bf::path& path2, FSFlag flags) {
+       try {
+               // Check whether the function call is valid
+               if (!bf::exists(path1) || !bf::is_directory(path1)) {
+                       _ERR("Source directory %s does not exist or is not a directory", path1.c_str());
+                       return false;
+               }
+               if (!bf::exists(path2)) {
+                       // Create the destination directory
+                       if (!createDir(path2)) {
+                               _ERR("Unable to create destination directory %s", path2.c_str());
+                               return false;
+                       }
+                       if (flags & FS_PRESERVE_OWNERSHIP_AND_PERMISSIONS) {
+                               copyOwnershipAndPermissions(path1, path2);
+                       }
+               } else {
+                       if (!(flags & (FS_MERGE_SKIP | FS_MERGE_OVERWRITE))) {
+                               _ERR("Destination directory %s already exists", path2.c_str());
+                               return false;
+                       }
+                       if (flags & (FS_MERGE_OVERWRITE | FS_PRESERVE_OWNERSHIP_AND_PERMISSIONS)) {
+                               copyOwnershipAndPermissions(path1, path2);
+                       }
+               }
+       } catch (const bf::filesystem_error& error) {
+               _ERR("Failed to copy directory: %s", error.what());
+               return false;
+       }
+
+       // Iterate through the source directory
+       for (bf::directory_iterator file(path1); file != bf::directory_iterator(); ++file) {
+               try {
+                       bf::path current(file->path());
+                       bf::path target = path2 / current.filename();
+                       if (bf::is_symlink(symlink_status(current))) {
+                               if ((flags & (FS_MERGE_SKIP | FS_MERGE_OVERWRITE)) && bf::exists(target)) {
+                                       continue;
+                               }
+                               bs::error_code error;
+                               bf::copy_symlink(current, target, error);
+                               if (error) {
+                                       _ERR("Failed to copy symlink: %s, %s", current.c_str(), error.message().c_str());
+                                       return false;
+                               }
+                       } else if (bf::is_directory(current)) {
+                               // Found directory: Recursion
+                               if (!copyDir(current, target, flags)) {
+                                       return false;
+                               }
+                       } else {
+                               if ((flags & FS_MERGE_SKIP) && bf::exists(target)) {
+                                       continue;
+                               }
+                               bf::path destination = target;
+                               if (flags & FS_COMMIT_COPY_FILE) {
+                                       destination = bf::unique_path(target.parent_path() / "%%%%-%%%%-%%%%-%%%%");
+                               }
+                               if (flags & FS_MERGE_OVERWRITE) {
+                                       bf::copy_file(current, destination, bf::copy_option::overwrite_if_exists);
+                               } else {
+                                       bf::copy_file(current, destination);
+                               }
+                               if (flags & FS_PRESERVE_OWNERSHIP_AND_PERMISSIONS) {
+                                       copyOwnershipAndPermissions(current, destination);
+                               }
+                               if (flags & FS_COMMIT_COPY_FILE) {
+                                       if (flags & FS_MERGE_OVERWRITE) {
+                                               bf::remove(target);
+                                       }
+                                       bf::rename(destination, target);
+                               }
+                       }
+               } catch (const bf::filesystem_error& error) {
+                       _ERR("Failed to copy directory: %s", error.what());
+                       return false;
+               }
+       }
+       return true;
+}
+
+bool copyFile(const bf::path& path1, const bf::path& path2) {
+       bs::error_code error;
+       bf::copy_file(path1, path2, bf::copy_option::overwrite_if_exists, error);
+       if (error) {
+               _ERR("copy file %s due to error [%s]", path1.c_str(), error.message().c_str());
+               return false;
+       }
+       return true;
+}
+
+bool moveFile(const bf::path& path1, const bf::path& path2) {
+       if (bf::exists(path2)) {
+               return false;
+       }
+       bs::error_code error;
+       bf::rename(path1, path2, error);
+       if (error) {
+               _ERR("Cannot move file: %s. Will copy/remove... with error [%s]", path1.c_str(), error.message().c_str());
+               bf::copy_file(path1, path2, bf::copy_option::overwrite_if_exists, error);
+               if (error) {
+                       _ERR("Cannot copy file %s due to error [%s]", path1.c_str(), error.message().c_str());
+                       return false;
+               }
+               bf::remove_all(path1, error);
+               if (error) {
+                       _ERR("Cannot remove old file when coping: %s with error [%s]", path1.c_str(), error.message().c_str());
+                       return false;
+               }
+       }
+       return true;
+}
+
+bool removeFile(const bf::path& path) {
+       if (!bf::exists(path)) {
+               return true;
+       }
+       bs::error_code error;
+       bf::remove(path, error);
+       if (error) {
+               _ERR("Cannot remove: %s, %s", path.c_str(), error.message().c_str());
+               return false;
+       }
+       return true;
+}
+
+bool removeAll(const bf::path& path) {
+       if (!exists(path)) {
+               return true;
+       }
+       bs::error_code error;
+       bf::remove_all(path, error);
+       if (error) {
+               _ERR("Cannot remove: %s, %s", path.c_str(), error.message().c_str());
+               return false;
+       }
+       return true;
+}
\ No newline at end of file
index 75b0fa5..0f2e9fc 100644 (file)
@@ -2,4 +2,7 @@
     <request>
         <domain name="_"/>
     </request>
+    <assign>
+        <filesystem path="/opt/usr/dotnet" label="System::Shared" type="transmutable" />
+    </assign>
 </manifest>
index e551023..1c4cb6f 100644 (file)
@@ -1,6 +1,6 @@
 Name:       dotnet-launcher
 Summary:    Launchpad plugin for dotnet apps
-Version:    2.1.0
+Version:    3.0.0
 Release:    1
 Group:      Application Framework/Application State Management
 License:    Apache-2.0
@@ -20,6 +20,10 @@ BuildRequires: pkgconfig(glib-2.0)
 BuildRequires: pkgconfig(libsmack)
 BuildRequires: pkgconfig(capi-appfw-app-common)
 BuildRequires: pkgconfig(storage)
+BuildRequires: pkgconfig(jsoncpp)
+BuildRequires: pkgconfig(openssl)
+BuildRequires: sqlite-devel
+BuildRequires: boost-devel
 BuildRequires: aul-devel
 BuildRequires: dotnet-build-tools
 
@@ -48,6 +52,7 @@ Requires(preun): /usr/bin/systemctl
 %define _framework_dir /usr/share/dotnet.tizen/framework
 %define _install_mdplugin_dir /etc/package-manager/parserlib/metadata
 %define _native_lib_dir /usr/share/dotnet.tizen/lib
+%define _tac_dir /opt/usr/dotnet
 
 ExcludeArch: aarch64
 
@@ -98,6 +103,7 @@ cmake \
        -DRUNTIME_DIR=%{_runtime_dir} \
        -DCROSSGEN_PATH=%{_runtime_dir}/crossgen \
        -DINSTALL_MDPLUGIN_DIR=%{_install_mdplugin_dir} \
+       -DTAC_DIR=%{_tac_dir} \
        -DVERSION=%{version} \
        -DNATIVE_LIB_DIR=%{_native_lib_dir} \
        NativeLauncher
@@ -111,6 +117,7 @@ mkdir -p %{buildroot}%{_framework_dir}
 mv Init/bin/Release/Tizen.Init.dll %{buildroot}%{_framework_dir}
 
 
+mkdir -p %{buildroot}%{_tac_dir}
 mkdir -p %{buildroot}%{_native_lib_dir}
 ln -sf %{_libdir}/libsqlite3.so.0 %{buildroot}%{_native_lib_dir}/libsqlite3.so
 
@@ -130,11 +137,14 @@ chsmack -t -a User::App::Shared /opt/etc/skel/.dotnet
 %{_native_lib_dir}/libsqlite3.so
 %{_bindir}/nitool
 %{_bindir}/tpatool
+%{_bindir}/tactool
+%{_install_mdplugin_dir}/libprefer_nuget_cache_plugin.so
 %{_install_mdplugin_dir}/libprefer_dotnet_aot_plugin.so
 %{_bindir}/dotnet-launcher
 %{_libdir}/libdotnet_launcher_util.so
 %{_libdir}/libni_common.so
 /etc/tmpfiles.d/%{name}.conf
+/usr/share/parser-plugins/dotnet-launcher.info
 %{_framework_dir}/Tizen.Init.dll
 
 %files devel