Modify the problem that the original assembly is deleted (#80)
author최종헌/Common Platform Lab(SR)/Engineer/삼성전자 <j-h.choi@samsung.com>
Tue, 16 Jul 2019 05:38:38 +0000 (14:38 +0900)
committer조웅석/Common Platform Lab(SR)/Principal Engineer/삼성전자 <ws77.cho@samsung.com>
Tue, 16 Jul 2019 05:38:38 +0000 (14:38 +0900)
12 files changed:
NativeLauncher/CMakeLists.txt
NativeLauncher/inc/tac_common.h [new file with mode: 0644]
NativeLauncher/inc/utils.h
NativeLauncher/installer-plugin/prefer_dotnet_aot_plugin.cc
NativeLauncher/installer-plugin/prefer_nuget_cache_plugin.cc
NativeLauncher/tool/dotnettool.cc [new file with mode: 0644]
NativeLauncher/tool/ni_common.cc
NativeLauncher/tool/nitool.cc
NativeLauncher/tool/tac_common.cc [new file with mode: 0644]
NativeLauncher/tool/tactool.cc [deleted file]
NativeLauncher/util/utils.cc
packaging/dotnet-launcher.spec

index b5c2a38..fbf61f5 100644 (file)
@@ -114,6 +114,7 @@ SET_TARGET_PROPERTIES(${DOTNET_LAUNCHER}
 SET(NI_COMMON "ni_common")
 SET(${NI_COMMON}_SOURCE_FILES
     tool/ni_common.cc
 SET(NI_COMMON "ni_common")
 SET(${NI_COMMON}_SOURCE_FILES
     tool/ni_common.cc
+    tool/tac_common.cc
 )
 ADD_LIBRARY(${NI_COMMON} SHARED ${${NI_COMMON}_SOURCE_FILES})
 SET_TARGET_PROPERTIES(${NI_COMMON} PROPERTIES COMPILE_FLAGS "-fPIC")
 )
 ADD_LIBRARY(${NI_COMMON} SHARED ${${NI_COMMON}_SOURCE_FILES})
 SET_TARGET_PROPERTIES(${NI_COMMON} PROPERTIES COMPILE_FLAGS "-fPIC")
@@ -135,13 +136,13 @@ 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_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
+SET(DOTNETTOOL "dotnettool")
+SET(${DOTNETTOOL}_SOURCE_FILES
+    tool/dotnettool.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})
+ADD_EXECUTABLE(${DOTNETTOOL} ${${DOTNETTOOL}_SOURCE_FILES})
+SET_TARGET_PROPERTIES(${DOTNETTOOL} PROPERTIES COMPILE_FLAGS "-fPIE")
+TARGET_LINK_LIBRARIES(${DOTNETTOOL} ${${PROJECT_NAME}_LDFLAGS} "-pie" ${DOTNET_LAUNCHER_UTIL} ${NI_COMMON})
 
 #SET(INSTALLER_PLUGIN "ui-application")
 #SET(${INSTALLER_PLUGIN}_SOURCE_FILES
 
 #SET(INSTALLER_PLUGIN "ui-application")
 #SET(${INSTALLER_PLUGIN}_SOURCE_FILES
@@ -176,7 +177,7 @@ INSTALL(TARGETS ${DOTNET_LAUNCHER} DESTINATION ${BINDIR})
 INSTALL(TARGETS ${NI_COMMON} DESTINATION ${LIBDIR})
 INSTALL(TARGETS ${NITOOL} DESTINATION ${BINDIR})
 INSTALL(TARGETS ${TPATOOL} 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 ${DOTNETTOOL} 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(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})
@@ -186,5 +187,6 @@ 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 inc/ni_common.h DESTINATION ${INCLUDEDIR})
 INSTALL(FILES inc/coreclr_host.h DESTINATION ${INCLUDEDIR})
 INSTALL(FILES inc/dotnet_launcher_plugin.h DESTINATION ${INCLUDEDIR})
 INSTALL(FILES inc/ni_common.h DESTINATION ${INCLUDEDIR})
+INSTALL(FILES inc/tac_common.h DESTINATION ${INCLUDEDIR})
 INSTALL(FILES ../dotnet-launcher.pc DESTINATION ${LIBDIR}/pkgconfig)
 INSTALL(FILES dotnet-launcher.info DESTINATION /usr/share/parser-plugins)
 INSTALL(FILES ../dotnet-launcher.pc DESTINATION ${LIBDIR}/pkgconfig)
 INSTALL(FILES dotnet-launcher.info DESTINATION /usr/share/parser-plugins)
diff --git a/NativeLauncher/inc/tac_common.h b/NativeLauncher/inc/tac_common.h
new file mode 100644 (file)
index 0000000..e18f4a7
--- /dev/null
@@ -0,0 +1,72 @@
+/*
+ * 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 __TAC_COMMON_H__
+#define __TAC_COMMON_H__
+
+#include <functional>
+
+typedef enum {
+       TAC_ERROR_NONE = 0,
+       TAC_ERROR_INVALID_PARAMETER = -1,
+       TAC_ERROR_ALREADY_EXIST = -2,
+       TAC_ERROR_NO_SUCH_FILE = -3,
+       TAC_ERROR_INVALID_PACKAGE = -4,
+       TAC_ERROR_NOT_SUPPORTED = -5,
+       TAC_ERROR_UNKNOWN = -9
+} tac_error_e;
+
+/**
+ * @brief restore database of TAC
+ * @return tac_error_e
+ */
+tac_error_e restoreTACDB();
+
+/**
+ * @brief remove a symbolic link file, the native images of TAC for specific package.
+ * @param[i] pkgId package ID
+ * @return tac_error_e
+ */
+tac_error_e resetTACPackage(const std::string& pkgId);
+
+/**
+ * @brief creates a symbolic link file, the native image of TAC for specific package.
+ * @param[i] pkgId package ID
+ * @return tac_error_e
+ */
+tac_error_e createTACPackage(const std::string& pkgId);
+
+/**
+ * @brief regenerate native image of TAC for all shared assembly.
+ * @return tac_error_e
+ */
+tac_error_e regenerateTAC();
+
+/**
+ * @brief disable tac feature.
+ * @param[i] pkgId package ID
+ * @return tac_error_e
+ */
+tac_error_e disableTACPackage(const std::string& pkgId);
+
+/**
+ * @brief enable tac feature.
+ * @param[i] pkgId package ID
+ * @return tac_error_e
+ */
+tac_error_e enableTACPackage(const std::string& pkgId);
+
+#endif /* __TAC_COMMON_H__ */
index c8843b5..d0bb588 100644 (file)
@@ -39,6 +39,12 @@ enum FSFlag : int {
   FS_PRESERVE_OWNERSHIP_AND_PERMISSIONS = (1 << 3)
 };
 
   FS_PRESERVE_OWNERSHIP_AND_PERMISSIONS = (1 << 3)
 };
 
+/**
+ * @brief an iterator to the begin element in the range that compares equal to option
+ * @param[in] begin element
+ * @param[in] end elment
+ * return return true when elements match
+ */
 bool cmdOptionExists(char** begin, char** end, const std::string& option);
 
 /**
 bool cmdOptionExists(char** begin, char** end, const std::string& option);
 
 /**
@@ -77,6 +83,21 @@ std::string baseName(const std::string& path);
 int getRootPath(std::string pkgId, std::string& rootPath);
 
 /**
 int getRootPath(std::string pkgId, std::string& rootPath);
 
 /**
+ * @brief get exec name
+ * @param[in] package id
+ * @param[out] exec name
+ */
+int getExecName(std::string pkgId, std::string& execName);
+
+/**
+ * @brief get metadata value
+ * @param[in] package id
+ * @param[in] metadata key
+ * @param[out] metadata value
+ */
+int getMetadataValue(std::string pkgId, std::string metadataKey, std::string& metadataValue);
+
+/**
  * @brief split path with ":" delimiter and put that in the vector
  * @param[in] source path
  * @param[out] string vector
  * @brief split path with ":" delimiter and put that in the vector
  * @param[in] source path
  * @param[out] string vector
@@ -133,6 +154,14 @@ typedef std::function<void (const std::string&, const char*)> FileReader;
 void scanFilesInDir(const std::string& directory, FileReader reader, unsigned int depth);
 
 /**
 void scanFilesInDir(const std::string& directory, FileReader reader, unsigned int depth);
 
 /**
+ * @brief update assembly file info.
+ * @param[in] get path
+ * @param[in] set path
+ * @param[in] symbolic link
+ */
+void updateAssemblyInfo(const std::string& getPath, const std::string& setPath, bool isSymlink = false);
+
+/**
  * @brief create the new directory.
  * @param[in] source path
  * @return return true when the directory was created.
  * @brief create the new directory.
  * @param[in] source path
  * @return return true when the directory was created.
@@ -140,13 +169,6 @@ void scanFilesInDir(const std::string& directory, FileReader reader, unsigned in
 bool createDir(const bf::path& path);
 
 /**
 bool createDir(const bf::path& path);
 
 /**
- * @brief update assembly file info.
- * @param[in] get path
- * @param[in] set path
- */
-void updateAssemblyInfo(const std::string& getPath, const std::string& setPath);
-
-/**
  * @brief copy the directory.
  * @param[in] path to the source directory
  * @param[in] path to the target directory
  * @brief copy the directory.
  * @param[in] path to the source directory
  * @param[in] path to the target directory
index 1c1968f..494dddc 100644 (file)
@@ -56,7 +56,7 @@ extern "C" int PKGMGR_MDPARSER_PLUGIN_INSTALL(const char *pkgId, const char *app
                        return -1;
                }
 
                        return -1;
                }
 
-               if (createNiUnderPkgRoot(pkgId, false) != 0) {
+               if (createNiUnderPkgRoot(pkgId, false) != NI_ERROR_NONE) {
                        _ERR("Failed to get root path from [%s]", pkgId);
                        return -1;
                } else {
                        _ERR("Failed to get root path from [%s]", pkgId);
                        return -1;
                } else {
@@ -65,8 +65,8 @@ extern "C" int PKGMGR_MDPARSER_PLUGIN_INSTALL(const char *pkgId, const char *app
 
                std::string pkgRoot;
                if (getRootPath(pkgId, pkgRoot) < 0) {
 
                std::string pkgRoot;
                if (getRootPath(pkgId, pkgRoot) < 0) {
-                       fprintf(stderr, "Failed to get root path from [%s]\n", pkgId);
-                       return -1;
+                       _ERR("Failed to get root path from [%s]", pkgId);
+                       return 0;
                }
 
                std::string binDir = concatPath(pkgRoot, "bin");
                }
 
                std::string binDir = concatPath(pkgRoot, "bin");
@@ -75,23 +75,23 @@ extern "C" int PKGMGR_MDPARSER_PLUGIN_INSTALL(const char *pkgId, const char *app
                        uid_t uid = 0;
                        if (pkgmgr_installer_info_get_target_uid(&uid) < 0) {
                                _ERR("Failed to get UID");
                        uid_t uid = 0;
                        if (pkgmgr_installer_info_get_target_uid(&uid) < 0) {
                                _ERR("Failed to get UID");
-                               return -1;
+                               return 0;
                        }
                        }
-                       for (auto& symlinkAssembly : bf::recursive_directory_iterator(bf::path(tacDir))) {
+                       for (auto& symlinkAssembly : bf::recursive_directory_iterator(tacDir)) {
                                std::string symPath = symlinkAssembly.path().string();
                                if (!isNativeImage(symPath)) {
                                        std::string originPath = bf::read_symlink(symPath).string();
                                        std::string originNiPath = originPath.substr(0, originPath.rfind(".dll")) + ".ni.dll";
                                        if (!bf::exists(originNiPath)) {
                                                if(createNiDll(originPath, false, false) != NI_ERROR_NONE) {
                                std::string symPath = symlinkAssembly.path().string();
                                if (!isNativeImage(symPath)) {
                                        std::string originPath = bf::read_symlink(symPath).string();
                                        std::string originNiPath = originPath.substr(0, originPath.rfind(".dll")) + ".ni.dll";
                                        if (!bf::exists(originNiPath)) {
                                                if(createNiDll(originPath, false, false) != NI_ERROR_NONE) {
-                                                       _ERR("Failed to create NI file [%s]\n", originPath.c_str());
+                                                       _ERR("Failed to create NI file [%s]", originPath.c_str());
                                                        return -1;
                                                }
                                        }
                                        std::string setNiPath = symPath.substr(0, symPath.rfind(".dll")) + ".ni.dll";
                                        if (!bf::exists(setNiPath)) {
                                                bf::create_symlink(originNiPath, setNiPath);
                                                        return -1;
                                                }
                                        }
                                        std::string setNiPath = symPath.substr(0, symPath.rfind(".dll")) + ".ni.dll";
                                        if (!bf::exists(setNiPath)) {
                                                bf::create_symlink(originNiPath, setNiPath);
-                                               fprintf(stderr, "%s symbolic link file generated successfully.\n", setNiPath.c_str());
+                                               _ERR("%s symbolic link file generated successfully.", setNiPath.c_str());
                                                if (lchown(setNiPath.c_str(), uid, 0)) {
                                                        _ERR("Failed to change owner of: %s", setNiPath.c_str());
                                                        return -1;
                                                if (lchown(setNiPath.c_str(), uid, 0)) {
                                                        _ERR("Failed to change owner of: %s", setNiPath.c_str());
                                                        return -1;
index c5d6a2f..6e3e2c3 100644 (file)
@@ -57,7 +57,7 @@ std::string binPath;
 bool isCreateDirectory = false;
 static sqlite3 *tac_db = NULL;
 
 bool isCreateDirectory = false;
 static sqlite3 *tac_db = NULL;
 
-int metadataCheck(GList *list)
+bool metadataCheck(GList *list)
 {
        GList *tag = NULL;
        Metadata *mdInfo = NULL;
 {
        GList *tag = NULL;
        Metadata *mdInfo = NULL;
@@ -68,27 +68,26 @@ int metadataCheck(GList *list)
                NiCommonOption option = {std::string(), std::string(), std::string()};
                if (initNICommon(&option) < 0) {
                        _ERR("Fail to initialize NI Common");
                NiCommonOption option = {std::string(), std::string(), std::string()};
                if (initNICommon(&option) < 0) {
                        _ERR("Fail to initialize NI Common");
-                       return -1;
+                       return false;
                }
                }
-               return 0;
-       } else {
-               return -1;
+               return true;
        }
        }
+       return false;
 }
 
 }
 
-int appTypeCheck(std::string pkgId)
+bool appTypeCheck(std::string pkgId)
 {
        uid_t uid = 0;
        if (pkgmgr_installer_info_get_target_uid(&uid) < 0) {
                _ERR("Failed to get UID");
 {
        uid_t uid = 0;
        if (pkgmgr_installer_info_get_target_uid(&uid) < 0) {
                _ERR("Failed to get UID");
-               return 0;
+               return false;
        }
 
        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");
        }
 
        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;
+               return false;
        }
 
        bool isDotnetAppType = false;
        }
 
        bool isDotnetAppType = false;
@@ -97,7 +96,7 @@ int appTypeCheck(std::string pkgId)
                bool* dotnet = static_cast<bool*>(userData);
                if (pkgmgrinfo_appinfo_get_apptype(handle, &type) != PMINFO_R_OK) {
                        _ERR("Failed to get app type : %s", type);
                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;
+                       return -1;
                }
                if (strcmp(type, "dotnet") == 0) {
                        *dotnet = true;
                }
                if (strcmp(type, "dotnet") == 0) {
                        *dotnet = true;
@@ -107,52 +106,19 @@ int appTypeCheck(std::string pkgId)
 
        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());
 
        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 false;
        }
 
        pkgmgrinfo_pkginfo_destroy_pkginfo(handle);
        return isDotnetAppType;
 }
 
        }
 
        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])
+void SHA256(std::string path, char outputBuffer[65])
 {
        FILE *file = fopen(path.c_str(), "rb");
        if (!file) {
 {
        FILE *file = fopen(path.c_str(), "rb");
        if (!file) {
-               return -1;
+               return;
        }
 
        unsigned char hash[SHA256_DIGEST_LENGTH];
        }
 
        unsigned char hash[SHA256_DIGEST_LENGTH];
@@ -163,7 +129,7 @@ int SHA256(std::string path, char outputBuffer[65])
        char *buffer = (char*)malloc(bufSize);
        if (!buffer) {
                fclose(file);
        char *buffer = (char*)malloc(bufSize);
        if (!buffer) {
                fclose(file);
-               return -1;
+               return;
        }
 
        while ((bytesRead = fread(buffer, 1, bufSize, file))) {
        }
 
        while ((bytesRead = fread(buffer, 1, bufSize, file))) {
@@ -177,7 +143,6 @@ int SHA256(std::string path, char outputBuffer[65])
 
        fclose(file);
        free(buffer);
 
        fclose(file);
        free(buffer);
-       return 0;
 }
 
 int depsJsonParser()
 }
 
 int depsJsonParser()
@@ -191,13 +156,12 @@ int depsJsonParser()
                std::string error;
                if (ifs.is_open()) {
                        if (!Json::parseFromStream(reader, ifs, &root, &error)) {
                std::string error;
                if (ifs.is_open()) {
                        if (!Json::parseFromStream(reader, ifs, &root, &error)) {
-                               _INFO("Failed to parse of deps.json");
+                               _ERR("Failed to parse of deps.json");
                                ifs.close();
                                return -1;
                        }
                        const Json::Value runtimeTargetName = root["runtimeTarget"]["name"];
                                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()];
+                       const Json::Value nugetPackages = root["targets"][runtimeTargetName.asString().c_str()];
                        for (auto& nuget : nugetPackages.getMemberNames()) {
                                if (strstr(nuget.c_str(), TIZEN_DOTNET_NUGET) != NULL ||
                                        strstr(nuget.c_str(), TIZEN_DOTNET_SDK_NUGET) != NULL ||
                        for (auto& nuget : nugetPackages.getMemberNames()) {
                                if (strstr(nuget.c_str(), TIZEN_DOTNET_NUGET) != NULL ||
                                        strstr(nuget.c_str(), TIZEN_DOTNET_SDK_NUGET) != NULL ||
@@ -222,7 +186,7 @@ int depsJsonParser()
                                                        _INFO("Nuget package : %s", nuget.c_str());
                                                        for (auto& assembly : assemblies.getMemberNames()) {
                                                                std::string assembly_name = assembly.substr(assembly.rfind('/') + 1);
                                                        _INFO("Nuget package : %s", nuget.c_str());
                                                        for (auto& assembly : assemblies.getMemberNames()) {
                                                                std::string assembly_name = assembly.substr(assembly.rfind('/') + 1);
-                                                               char buffer[65];
+                                                               char buffer[65] = {0};
                                                                SHA256(concatPath(binPath, assembly_name), buffer);
                                                                nugetPackagesAssembliesShaR2R.push_back(nuget + "/" + assembly_name + "/" + buffer + "/" + r2r);
                                                                _INFO("Assembly / SHA256 : %s / %s", assembly_name.c_str(), buffer);
                                                                SHA256(concatPath(binPath, assembly_name), buffer);
                                                                nugetPackagesAssembliesShaR2R.push_back(nuget + "/" + assembly_name + "/" + buffer + "/" + r2r);
                                                                _INFO("Assembly / SHA256 : %s / %s", assembly_name.c_str(), buffer);
@@ -237,10 +201,15 @@ int depsJsonParser()
        return 0;
 }
 
        return 0;
 }
 
-int createSymlink(bf::path tac_version_dir, std::string np)
+int createSymlink(std::string tac_version_dir, std::string np)
 {
 {
-       bs::error_code error;
        uid_t uid = 0;
        uid_t uid = 0;
+       std::string tac_dir = concatPath(binPath, TAC_SYMLINK_SUB_DIR);
+       if (!createDir(tac_dir)) {
+               _INFO("Cannot create directory: %s", tac_dir.c_str());
+               return -1;
+       }
+
        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);
        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);
@@ -251,7 +220,7 @@ int createSymlink(bf::path tac_version_dir, std::string np)
                if (!strcmp(nuget_package.c_str(), np.c_str())) {
                        if (bf::exists(concatPath(binPath, assembly))) {
                                if (isCreateDirectory) {
                if (!strcmp(nuget_package.c_str(), np.c_str())) {
                        if (bf::exists(concatPath(binPath, assembly))) {
                                if (isCreateDirectory) {
-                                       if (!copyFile(concatPath(binPath, assembly), tac_version_dir / assembly)) {
+                                       if (!copyFile(concatPath(binPath, assembly), concatPath(tac_version_dir, assembly))) {
                                                _ERR("Failed to move of %s", assembly.c_str());
                                                return -1;
                                        }
                                                _ERR("Failed to move of %s", assembly.c_str());
                                                return -1;
                                        }
@@ -260,34 +229,15 @@ int createSymlink(bf::path tac_version_dir, std::string np)
                                        _ERR("Failed to get UID");
                                        return -1;
                                }
                                        _ERR("Failed to get UID");
                                        return -1;
                                }
-                               std::string tac_dir = concatPath(binPath, TAC_SYMLINK_SUB_DIR);
-                               bf::create_symlink(tac_version_dir / assembly, concatPath(tac_dir, assembly), error);
-                               if (error) {
-                                       _ERR("Failed to create symlink");
-                                       return -1;
-                               }
+                               bf::create_symlink(concatPath(tac_version_dir, assembly), concatPath(tac_dir, assembly));
                                if (lchown(concatPath(tac_dir, assembly).c_str(), uid, 0)) {
                                        _ERR("Failed to change owner of: %s", concatPath(tac_dir, assembly).c_str());
                                        return -1;
                                }
                                if (lchown(concatPath(tac_dir, assembly).c_str(), uid, 0)) {
                                        _ERR("Failed to change owner of: %s", concatPath(tac_dir, 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);
-               if (bf::exists(concatPath(binPath, assembly))) {
-                       if (!removeFile(concatPath(binPath, assembly))) {
-                               _ERR("Failed to remove of %s", assembly.c_str());
-                               return -1;
+                               if (!removeFile(concatPath(binPath, assembly))) {
+                                       _ERR("Failed to remove of %s", assembly.c_str());
+                                       return -1;
+                               }
                        }
                }
        }
                        }
                }
        }
@@ -303,7 +253,7 @@ extern "C" int PKGMGR_MDPARSER_PLUGIN_INSTALL(const char *pkgId, const char *app
                _INFO("App type is not dotnet");
                return 0;
        }
                _INFO("App type is not dotnet");
                return 0;
        }
-       if (getExecName(std::string(pkgId)) < 0) {
+       if (getExecName(std::string(pkgId), execName) < 0) {
                return 0;
        }
        if (getRootPath(std::string(pkgId), rootPath) < 0) {
                return 0;
        }
        if (getRootPath(std::string(pkgId), rootPath) < 0) {
@@ -311,8 +261,8 @@ extern "C" int PKGMGR_MDPARSER_PLUGIN_INSTALL(const char *pkgId, const char *app
        } else {
                binPath = concatPath(rootPath, "bin");
        }
        } else {
                binPath = concatPath(rootPath, "bin");
        }
-       if (!metadataCheck(list)) {
-               if (depsJsonParser()) {
+       if (metadataCheck(list)) {
+               if (depsJsonParser() < 0) {
                        return 0;
                }
        }
                        return 0;
                }
        }
@@ -321,6 +271,7 @@ extern "C" int PKGMGR_MDPARSER_PLUGIN_INSTALL(const char *pkgId, const char *app
        tac_db = dbCreate(TAC_APP_LIST_DB);
        if (tac_db) {
                if (!dbOpen(tac_db, TAC_APP_LIST_DB)) {
        tac_db = dbCreate(TAC_APP_LIST_DB);
        if (tac_db) {
                if (!dbOpen(tac_db, TAC_APP_LIST_DB)) {
+                       _ERR("Sqlite open error");
                        return 0;
                }
        } else {
                        return 0;
                }
        } else {
@@ -332,13 +283,6 @@ extern "C" int PKGMGR_MDPARSER_PLUGIN_INSTALL(const char *pkgId, const char *app
                _ERR("Not exist .deps.json file");
                return 0;
        }
                _ERR("Not exist .deps.json file");
                return 0;
        }
-       std::string tac_dir = concatPath(binPath, TAC_SYMLINK_SUB_DIR);
-       if (!bf::exists(tac_dir)) {
-               if (!createDir(tac_dir)) {
-                       _INFO("Cannot create directory: %s", tac_dir.c_str());
-                       return 0;
-               }
-       }
 
        for (auto& np : tacDB) {
                std::string tac_name = np.substr(0, np.find('/'));
 
        for (auto& np : tacDB) {
                std::string tac_name = np.substr(0, np.find('/'));
@@ -346,7 +290,8 @@ extern "C" int PKGMGR_MDPARSER_PLUGIN_INSTALL(const char *pkgId, const char *app
                _INFO("TAC name : %s", tac_name.c_str());
                _INFO("TAC version : %s", tac_version.c_str());
 
                _INFO("TAC name : %s", tac_name.c_str());
                _INFO("TAC version : %s", tac_version.c_str());
 
-               bf::path tac_version_dir = concatPath(__TAC_DIR, np);
+               std::string tac_version_dir = concatPath(__TAC_DIR, np);
+               std::string sha256_info = concatPath(tac_version_dir, TAC_SHA_256_INFO);
                isCreateDirectory = false;
                if (!bf::exists(tac_version_dir)) {
                        _INFO("Create tac_version_dir [%s]", tac_version_dir.c_str());
                isCreateDirectory = false;
                if (!bf::exists(tac_version_dir)) {
                        _INFO("Create tac_version_dir [%s]", tac_version_dir.c_str());
@@ -355,8 +300,7 @@ extern "C" int PKGMGR_MDPARSER_PLUGIN_INSTALL(const char *pkgId, const char *app
                                return 0;
                        }
                        isCreateDirectory = true;
                                return 0;
                        }
                        isCreateDirectory = true;
-                       createDirectories.push_back(tac_version_dir.string());
-                       std::string sha256_info = (tac_version_dir / TAC_SHA_256_INFO).string();
+                       createDirectories.push_back(tac_version_dir);
                        std::ofstream ofs(sha256_info, std::ios::app);
                        int assembly_count = 0;
                        for (auto& npAssemblyShaR2R : nugetPackagesAssembliesShaR2R) {
                        std::ofstream ofs(sha256_info, std::ios::app);
                        int assembly_count = 0;
                        for (auto& npAssemblyShaR2R : nugetPackagesAssembliesShaR2R) {
@@ -374,9 +318,9 @@ extern "C" int PKGMGR_MDPARSER_PLUGIN_INSTALL(const char *pkgId, const char *app
                        ofs << assembly_count << std::endl;
                        ofs.close();
 
                        ofs << assembly_count << std::endl;
                        ofs.close();
 
-                       if (createSymlink(tac_version_dir, np)) {
+                       if (createSymlink(tac_version_dir, np) < 0) {
                                _ERR("Failed to create symlink");
                                _ERR("Failed to create symlink");
-                               return 0;
+                               return -1;
                        }
                        std::string sql = "INSERT INTO TAC (PKGID, NUGET, NAME, VERSION) " \
                                        "VALUES ('" + std::string(pkgId) + "', '" + np + "', '" + tac_name + "', '" + tac_version + "');";
                        }
                        std::string sql = "INSERT INTO TAC (PKGID, NUGET, NAME, VERSION) " \
                                        "VALUES ('" + std::string(pkgId) + "', '" + np + "', '" + tac_name + "', '" + tac_version + "');";
@@ -395,7 +339,6 @@ extern "C" int PKGMGR_MDPARSER_PLUGIN_INSTALL(const char *pkgId, const char *app
                                std::string r2r = npAssemblyShaR2R.substr(npAssemblyShaR2R.rfind('/') + 1);
                                if (!strcmp(nuget_package.c_str(), np.c_str())) {
                                        assembly_count++;
                                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 / TAC_SHA_256_INFO).string();
                                        std::ifstream ifs(sha256_info);
                                        std::string get_str;
                                        if (ifs.is_open()) {
                                        std::ifstream ifs(sha256_info);
                                        std::string get_str;
                                        if (ifs.is_open()) {
@@ -412,8 +355,9 @@ extern "C" int PKGMGR_MDPARSER_PLUGIN_INSTALL(const char *pkgId, const char *app
                        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 (!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;
+                               if (createSymlink(tac_version_dir, np) < 0) {
+                                       _ERR("Failed to create symlink");
+                                       return -1;
                                }
                                std::string sql = "INSERT INTO TAC (PKGID, NUGET, NAME, VERSION) " \
                                                "VALUES ('" + std::string(pkgId) + "', '" + np + "', '" + tac_name + "', '" + tac_version + "');";
                                }
                                std::string sql = "INSERT INTO TAC (PKGID, NUGET, NAME, VERSION) " \
                                                "VALUES ('" + std::string(pkgId) + "', '" + np + "', '" + tac_name + "', '" + tac_version + "');";
@@ -422,9 +366,11 @@ extern "C" int PKGMGR_MDPARSER_PLUGIN_INSTALL(const char *pkgId, const char *app
                                _INFO("Different : %s", tac_name.c_str());
                        }
                }
                                _INFO("Different : %s", tac_name.c_str());
                        }
                }
-       }
-       if (removeOriginalAssembly()) {
-               return 0;
+               if (!bf::exists(sha256_info)) {
+                       if(!removeAll(tac_version_dir)) {
+                               _ERR("Failed to remove of %s", tac_version_dir.c_str());
+                       }
+               }
        }
        return 0;
 }
        }
        return 0;
 }
@@ -438,26 +384,26 @@ static int sqliteCb(void *count, int argc, char **argv, char **azColName) {
 int updateTacDB(const char *pkgId)
 {
        for (auto& unp : updateTac) {
 int updateTacDB(const char *pkgId)
 {
        for (auto& unp : updateTac) {
-               char *error = 0;
                int ret;
                int ret;
-               int count = 0;
+               int count = -1;
                if (tac_db) {
                        if (!dbOpen(tac_db, TAC_APP_LIST_DB)) {
                if (tac_db) {
                        if (!dbOpen(tac_db, TAC_APP_LIST_DB)) {
-                               return 0;
+                               _ERR("Sqlite open error");
+                               return -1;
                        }
                } else {
                        _ERR("Sqlite create error");
                        }
                } else {
                        _ERR("Sqlite create error");
-                       return 0;
+                       return -1;
                }
                std::string sql = "SELECT COUNT(NUGET) FROM TAC WHERE NUGET = '" + unp + "';";
                }
                std::string sql = "SELECT COUNT(NUGET) FROM TAC WHERE NUGET = '" + unp + "';";
-               ret = sqlite3_exec(tac_db, sql.c_str(), sqliteCb, &count, &error);
+               ret = sqlite3_exec(tac_db, sql.c_str(), sqliteCb, &count, NULL);
                if (ret != SQLITE_OK) {
                if (ret != SQLITE_OK) {
-                       _ERR("SQL error: %s", error);
-                       sqlite3_free(error);
+                       _ERR("Sqlite select error");
+                       return -1;
                }
                }
-               if (count < 1) {
-                       bf::path tac_version_dir_prev = concatPath(__TAC_DIR, unp);
-                       bf::path tac_version_dir_backup = concatPath(__TAC_DIR, unp) + ".bck";
+               if (count == 0) {
+                       std::string tac_version_dir_prev = concatPath(__TAC_DIR, unp);
+                       std::string tac_version_dir_backup = tac_version_dir_prev + ".bck";
                        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 (!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;
@@ -480,7 +426,7 @@ extern "C" int PKGMGR_MDPARSER_PLUGIN_UPGRADE(const char *pkgId, const char *app
                _INFO("App type is not dotnet");
                return 0;
        }
                _INFO("App type is not dotnet");
                return 0;
        }
-       if (getExecName(std::string(pkgId)) < 0) {
+       if (getExecName(std::string(pkgId), execName) < 0) {
                return 0;
        }
        if (getRootPath(std::string(pkgId), rootPath) < 0) {
                return 0;
        }
        if (getRootPath(std::string(pkgId), rootPath) < 0) {
@@ -491,8 +437,8 @@ extern "C" int PKGMGR_MDPARSER_PLUGIN_UPGRADE(const char *pkgId, const char *app
        if (!strcmp("removed", status.c_str())) {
                _INFO("Skipped to parse of deps.json");
        } else {
        if (!strcmp("removed", status.c_str())) {
                _INFO("Skipped to parse of deps.json");
        } else {
-               if (!metadataCheck(list)) {
-                       if (depsJsonParser()) {
+               if (metadataCheck(list)) {
+                       if (depsJsonParser() < 0) {
                                return 0;
                        }
                }
                                return 0;
                        }
                }
@@ -502,6 +448,7 @@ extern "C" int PKGMGR_MDPARSER_PLUGIN_UPGRADE(const char *pkgId, const char *app
        tac_db = dbCreate(TAC_APP_LIST_DB);
        if (tac_db) {
                if (!dbOpen(tac_db, TAC_APP_LIST_DB)) {
        tac_db = dbCreate(TAC_APP_LIST_DB);
        if (tac_db) {
                if (!dbOpen(tac_db, TAC_APP_LIST_DB)) {
+                       _ERR("Sqlite open error");
                        return 0;
                }
        } else {
                        return 0;
                }
        } else {
@@ -515,25 +462,18 @@ extern "C" int PKGMGR_MDPARSER_PLUGIN_UPGRADE(const char *pkgId, const char *app
        if (tacDB.empty()) {
                sql = "DELETE FROM TAC WHERE PKGID = '" + std::string(pkgId) + "';";
                dbDelete(tac_db, TAC_APP_LIST_DB, sql);
        if (tacDB.empty()) {
                sql = "DELETE FROM TAC WHERE PKGID = '" + std::string(pkgId) + "';";
                dbDelete(tac_db, TAC_APP_LIST_DB, sql);
-               if (updateTacDB(pkgId)) {
-                       return 0;
+               if (updateTacDB(pkgId) < 0) {
+                       return -1;
                }
        } else {
                }
        } else {
-               std::string tac_dir = concatPath(binPath, TAC_SYMLINK_SUB_DIR);
-               if (!bf::exists(tac_dir)) {
-                       if (!createDir(tac_dir)) {
-                               _INFO("Cannot create directory: %s", tac_dir.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());
 
                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 = concatPath(__TAC_DIR, np);
+                       std::string tac_version_dir = concatPath(__TAC_DIR, np);
+                       std::string sha256_info = concatPath(tac_version_dir, TAC_SHA_256_INFO);
                        isCreateDirectory = false;
                        if (!bf::exists(tac_version_dir)) {
                                _INFO("Create tac_version_dir [%s]", tac_version_dir.c_str());
                        isCreateDirectory = false;
                        if (!bf::exists(tac_version_dir)) {
                                _INFO("Create tac_version_dir [%s]", tac_version_dir.c_str());
@@ -542,8 +482,7 @@ extern "C" int PKGMGR_MDPARSER_PLUGIN_UPGRADE(const char *pkgId, const char *app
                                        return 0;
                                }
                                isCreateDirectory = true;
                                        return 0;
                                }
                                isCreateDirectory = true;
-                               createDirectories.push_back(tac_version_dir.string());
-                               std::string sha256_info = (tac_version_dir / TAC_SHA_256_INFO).string();
+                               createDirectories.push_back(tac_version_dir);
                                std::ofstream ofs2(sha256_info, std::ios::app);
                                int assembly_count = 0;
                                for (auto& npAssemblyShaR2R : nugetPackagesAssembliesShaR2R) {
                                std::ofstream ofs2(sha256_info, std::ios::app);
                                int assembly_count = 0;
                                for (auto& npAssemblyShaR2R : nugetPackagesAssembliesShaR2R) {
@@ -560,23 +499,22 @@ extern "C" int PKGMGR_MDPARSER_PLUGIN_UPGRADE(const char *pkgId, const char *app
                                }
                                ofs2 << assembly_count << std::endl;
                                ofs2.close();
                                }
                                ofs2 << assembly_count << std::endl;
                                ofs2.close();
-                               if (createSymlink(tac_version_dir, np)) {
-                                       return 0;
+                               if (createSymlink(tac_version_dir, np) < 0) {
+                                       _ERR("Failed to create symlink");
+                                       return -1;
                                }
 
                                }
 
-                               char *error = 0;
-                               int count = 0;
+                               int count = -1;
                                sql = "SELECT COUNT(NUGET) FROM TAC WHERE PKGID = '" + std::string(pkgId) + "' AND NAME = '" + tac_name + "';";
                                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);
+                               int ret = sqlite3_exec(tac_db, sql.c_str(), sqliteCb, &count, NULL);
                                if (ret != SQLITE_OK) {
                                if (ret != SQLITE_OK) {
-                                       _ERR("SQL error: %s", error);
-                                       sqlite3_free(error);
+                                       _ERR("Sqlite select error");
+                                       return -1;
                                }
                                }
-
                                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, TAC_APP_LIST_DB, sql);
                                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, TAC_APP_LIST_DB, sql);
-                               } else {
+                               } else if (count == 0) {
                                        sql = "INSERT INTO TAC (PKGID, NUGET, NAME, VERSION) " \
                                                "VALUES ('" + std::string(pkgId) + "', '" + np + "', '" + tac_name + "', '" + tac_version + "');";
                                        dbInsert(tac_db, TAC_APP_LIST_DB, sql);
                                        sql = "INSERT INTO TAC (PKGID, NUGET, NAME, VERSION) " \
                                                "VALUES ('" + std::string(pkgId) + "', '" + np + "', '" + tac_name + "', '" + tac_version + "');";
                                        dbInsert(tac_db, TAC_APP_LIST_DB, sql);
@@ -595,7 +533,6 @@ extern "C" int PKGMGR_MDPARSER_PLUGIN_UPGRADE(const char *pkgId, const char *app
                                        std::string r2r = npAssemblyShaR2R.substr(npAssemblyShaR2R.rfind('/') + 1);
                                        if (!strcmp(nuget_package.c_str(), np.c_str())) {
                                                assembly_count++;
                                        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 / TAC_SHA_256_INFO).string();
                                                std::ifstream ifs2(sha256_info);
                                                std::string get_str;
                                                if (ifs2.is_open()) {
                                                std::ifstream ifs2(sha256_info);
                                                std::string get_str;
                                                if (ifs2.is_open()) {
@@ -613,23 +550,22 @@ extern "C" int PKGMGR_MDPARSER_PLUGIN_UPGRADE(const char *pkgId, const char *app
                                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 (!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;
+                                       if (createSymlink(tac_version_dir, np) < 0) {
+                                               _ERR("Failed to create symlink");
+                                               return -1;
                                        }
 
                                        }
 
-                                       char *error = 0;
-                                       int count = 0;
+                                       int count = -1;
                                        std::string sql = "SELECT COUNT(NUGET) FROM TAC WHERE PKGID = '" + std::string(pkgId) + "' AND NAME = '" + tac_name + "';";
                                        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);
+                                       int ret = sqlite3_exec(tac_db, sql.c_str(), sqliteCb, &count, NULL);
                                        if (ret != SQLITE_OK) {
                                        if (ret != SQLITE_OK) {
-                                               _ERR("SQL error: %s", error);
-                                               sqlite3_free(error);
+                                               _ERR("Sqlite select error");
+                                               return -1;
                                        }
                                        }
-
                                        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, TAC_APP_LIST_DB, sql);
                                        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, TAC_APP_LIST_DB, sql);
-                                       } else {
+                                       } else if (count == 0) {
                                                sql = "INSERT INTO TAC (PKGID, NUGET, NAME, VERSION) " \
                                                        "VALUES ('" + std::string(pkgId) + "', '" + np + "', '" + tac_name + "', '" + tac_version + "');";
                                                dbInsert(tac_db, TAC_APP_LIST_DB, sql);
                                                sql = "INSERT INTO TAC (PKGID, NUGET, NAME, VERSION) " \
                                                        "VALUES ('" + std::string(pkgId) + "', '" + np + "', '" + tac_name + "', '" + tac_version + "');";
                                                dbInsert(tac_db, TAC_APP_LIST_DB, sql);
@@ -638,6 +574,11 @@ extern "C" int PKGMGR_MDPARSER_PLUGIN_UPGRADE(const char *pkgId, const char *app
                                        _INFO("Different : %s", tac_name.c_str());
                                }
                        }
                                        _INFO("Different : %s", tac_name.c_str());
                                }
                        }
+                       if (!bf::exists(sha256_info)) {
+                               if(!removeAll(tac_version_dir)) {
+                                       _ERR("Failed to remove of %s", tac_version_dir.c_str());
+                               }
+                       }
                }
                for (auto& unp : updateTac) {
                        bool isExits = false;
                }
                for (auto& unp : updateTac) {
                        bool isExits = false;
@@ -653,12 +594,8 @@ extern "C" int PKGMGR_MDPARSER_PLUGIN_UPGRADE(const char *pkgId, const char *app
                                dbDelete(tac_db, TAC_APP_LIST_DB, sql);
                        }
                }
                                dbDelete(tac_db, TAC_APP_LIST_DB, sql);
                        }
                }
-
-               if (removeOriginalAssembly()) {
-                       return 0;
-               }
-               if (updateTacDB(pkgId)) {
-                       return 0;
+               if (updateTacDB(pkgId) < 0) {
+                       return -1;
                }
        }
        return 0;
                }
        }
        return 0;
@@ -673,6 +610,7 @@ extern "C" int PKGMGR_MDPARSER_PLUGIN_UNINSTALL(const char *pkgId, const char *a
        tac_db = dbCreate(TAC_APP_LIST_DB);
        if (tac_db) {
                if (!dbOpen(tac_db, TAC_APP_LIST_DB)) {
        tac_db = dbCreate(TAC_APP_LIST_DB);
        if (tac_db) {
                if (!dbOpen(tac_db, TAC_APP_LIST_DB)) {
+                       _ERR("Sqlite open error");
                        return 0;
                }
        } else {
                        return 0;
                }
        } else {
@@ -686,8 +624,8 @@ extern "C" int PKGMGR_MDPARSER_PLUGIN_UNINSTALL(const char *pkgId, const char *a
        sql = "DELETE FROM TAC WHERE PKGID = '" + std::string(pkgId) + "';";
        dbDelete(tac_db, TAC_APP_LIST_DB, sql);
 
        sql = "DELETE FROM TAC WHERE PKGID = '" + std::string(pkgId) + "';";
        dbDelete(tac_db, TAC_APP_LIST_DB, sql);
 
-       if (updateTacDB(pkgId)) {
-               return 0;
+       if (updateTacDB(pkgId) < 0) {
+               return -1;
        }
        return 0;
 }
        }
        return 0;
 }
@@ -699,85 +637,61 @@ extern "C" int PKGMGR_MDPARSER_PLUGIN_REMOVED(const char *pkgId, const char *app
 
        status = "removed";
 
 
        status = "removed";
 
-       PKGMGR_MDPARSER_PLUGIN_UPGRADE(pkgId, appId, list);
-       return 0;
-}
-
-int install_Clean()
-{
-       return 0;
+       return PKGMGR_MDPARSER_PLUGIN_UPGRADE(pkgId, appId, list);
 }
 
 }
 
-int unInstall_Clean()
+void cleanStep(std::string tac)
 {
 {
-       for (auto& unp : updateTac) {
-               bf::path current_tac = bf::path(__TAC_DIR) / 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(), ".bck") != NULL) {
-                               if (!removeAll(bck.path().string())) {
-                                       _ERR("Failed to remove of %s", bck.path().c_str());
-                                       return 0;
-                               }
-                               break;
+       std::string current_tac = concatPath(__TAC_DIR, tac.substr(0, tac.find('/')));
+       for (auto& bck : bf::recursive_directory_iterator(current_tac)) {
+               if (bf::is_directory(bck.path()) && strstr(bck.path().c_str(), ".bck") != NULL) {
+                       if (!removeAll(bck.path().string())) {
+                               _ERR("Failed to remove of %s", bck.path().c_str());
                        }
                        }
+                       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(), ".bck") == NULL) {
-                               exist_directory_name.push_back(bck.path().string());
-                               break;
-                       }
+       }
+
+       bool isExist = false;
+       for (auto& bck : bf::recursive_directory_iterator(current_tac)) {
+               if (bf::exists(bck.path()) && bf::is_directory(bck.path()) && strstr(bck.path().c_str(), ".bck") == NULL) {
+                       isExist = true;
+                       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();
+       }
+       if (!isExist) {
+               if (!removeAll(current_tac)) {
+                       _ERR("Failed to remove of %s", current_tac.c_str());
                }
        }
                }
        }
-       return 0;
 }
 
 }
 
-int update_Clean()
+void install_Clean()
+{
+       return;
+}
+
+void unInstall_Clean()
+{
+       for (auto& unp : updateTac) {
+               cleanStep(unp);
+       }
+}
+
+void update_Clean()
 {
        if (!tacDB.empty()) {
                for (auto& np : tacDB) {
 {
        if (!tacDB.empty()) {
                for (auto& np : tacDB) {
-                       bf::path current_tac = bf::path(__TAC_DIR) / 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(), ".bck") != 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(), ".bck") == 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();
-                       }
+                       cleanStep(np);
                }
        }
        unInstall_Clean();
                }
        }
        unInstall_Clean();
-       return 0;
 }
 
 extern "C" int PKGMGR_MDPARSER_PLUGIN_CLEAN(const char *pkgId, const char *appId, GList *list)
 {
        _DBG("[===== PKGMGR_MDPARSER_PLUGIN_CLEAN =====]");
 }
 
 extern "C" int PKGMGR_MDPARSER_PLUGIN_CLEAN(const char *pkgId, const char *appId, GList *list)
 {
        _DBG("[===== PKGMGR_MDPARSER_PLUGIN_CLEAN =====]");
+       _INFO("PackageID : %s", pkgId);
 
        if (tac_db) {
                dbClose(tac_db);
 
        if (tac_db) {
                dbClose(tac_db);
@@ -793,63 +707,51 @@ extern "C" int PKGMGR_MDPARSER_PLUGIN_CLEAN(const char *pkgId, const char *appId
        return 0;
 }
 
        return 0;
 }
 
-int install_Undo()
+void undoStep(std::string tac)
+{
+       std::string current_tac = concatPath(__TAC_DIR, tac.substr(0, tac.find('/')));
+       for (auto& bck : bf::recursive_directory_iterator(current_tac)) {
+               if (bf::is_directory(bck.path()) && strstr(bck.path().c_str(), ".bck") != NULL) {
+                       if (!moveFile(bck.path(), bck.path().string().substr(0, bck.path().string().rfind(".bck")))) {
+                               _ERR("Failed to move %s to %s",
+                                       bck.path().c_str(), bck.path().string().substr(0, bck.path().string().rfind(".bck")).c_str());
+                       }
+                       break;
+               }
+       }
+}
+
+void install_Undo()
 {
        for (auto& cd : createDirectories) {
                if (!removeAll(cd)) {
                        _ERR("Failed to remove of %s", cd.c_str());
 {
        for (auto& cd : createDirectories) {
                if (!removeAll(cd)) {
                        _ERR("Failed to remove of %s", cd.c_str());
-                       return 0;
                }
        }
                }
        }
-       return 0;
 }
 
 }
 
-int unInstall_Undo()
+void unInstall_Undo()
 {
        for (auto& unp : updateTac) {
 {
        for (auto& unp : updateTac) {
-               for (auto& bck : bf::recursive_directory_iterator(bf::path(__TAC_DIR) / unp.substr(0, unp.find('/')))) {
-                       if (bf::exists(bck.path()) && bf::is_directory(bck.path()) && strstr(bck.path().c_str(), ".bck") != NULL) {
-                               if (!moveFile(bck.path(), bck.path().string().substr(0, bck.path().string().rfind(".bck")))) {
-                                       _ERR("Failed to move %s to %s",
-                                               bck.path().c_str(), bck.path().string().substr(0, bck.path().string().rfind(".bck")).c_str());
-                                       return 0;
-                               }
-                               break;
-                       }
-               }
+               undoStep(unp);
        }
        }
-       return 0;
 }
 
 }
 
-int update_Undo()
+void update_Undo()
 {
 {
-       for (auto& cd : createDirectories) {
-               if (!removeAll(cd)) {
-                       _ERR("Failed to remove of %s", cd.c_str());
-                       return 0;
-               }
-       }
+       install_Undo();
        if (!tacDB.empty()) {
                for (auto& np : tacDB) {
        if (!tacDB.empty()) {
                for (auto& np : tacDB) {
-                       for (auto& bck : bf::recursive_directory_iterator(bf::path(__TAC_DIR) / np.substr(0, np.find('/')))) {
-                               if (bf::exists(bck.path()) && bf::is_directory(bck.path()) && strstr(bck.path().c_str(), ".bck") != NULL) {
-                                       if (!moveFile(bck.path(), bck.path().string().substr(0, bck.path().string().rfind(".bck")))) {
-                                               _ERR("Failed to move %s to %s",
-                                                       bck.path().c_str(), bck.path().string().substr(0, bck.path().string().rfind(".bck")).c_str());
-                                               return 0;
-                                       }
-                                       break;
-                               }
-                       }
+                       undoStep(np);
                }
        }
        unInstall_Undo();
                }
        }
        unInstall_Undo();
-       return 0;
 }
 
 extern "C" int PKGMGR_MDPARSER_PLUGIN_UNDO(const char *pkgId, const char *appId, GList *list)
 {
        _DBG("[===== PKGMGR_MDPARSER_PLUGIN_UNDO =====]");
 }
 
 extern "C" int PKGMGR_MDPARSER_PLUGIN_UNDO(const char *pkgId, const char *appId, GList *list)
 {
        _DBG("[===== PKGMGR_MDPARSER_PLUGIN_UNDO =====]");
+       _INFO("PackageID : %s", pkgId);
 
        if (tac_db) {
                dbRollback(tac_db);
 
        if (tac_db) {
                dbRollback(tac_db);
diff --git a/NativeLauncher/tool/dotnettool.cc b/NativeLauncher/tool/dotnettool.cc
new file mode 100644 (file)
index 0000000..76ed563
--- /dev/null
@@ -0,0 +1,246 @@
+/*
+ * 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 "ni_common.h"
+#include "tac_common.h"
+
+#include <algorithm>
+#include <cstdio>
+#include <cstring>
+#include <fstream>
+#include <vector>
+
+#include <pkgmgr-info.h>
+#include <pkgmgr_installer_info.h>
+
+#ifdef  LOG_TAG
+#undef  LOG_TAG
+#endif
+#define LOG_TAG "DOTNET_INSTALLER_PLUGIN"
+
+std::vector<std::string> getCmdArgs(char** begin, char** end)
+{
+       std::vector<std::string> list;
+       for (char** itr = begin+1; itr != end; itr++) {
+               if (strncmp(*itr, "--", 2) != 0) {
+                       list.push_back(*itr);
+               }
+       }
+       return list;
+}
+
+static void help(const char *argv0)
+{
+       const char* helpDesc =
+               "Usage: %s [args] <root paths or pkg name>\n"
+               "       --help                 - Display this screen\n"
+               "       --ni-system            - Create NI under System DLLs\n"
+               "       --ni-dll               - Create NI for DLL\n"
+               "       --ni-pkg               - Create NI for package\n"
+               "       --ni-pkg-dll           - Create NI for DLL in package\n"
+               "       --ni-dir               - Create NI for directory\n"
+               "       --r2r                  - Use ready-to-run option (default: FNV)\n"
+               "                                (This option should be used with other options)\n"
+               "       --ni-reset-system      - Remove System NI files\n"
+               "       --ni-reset-pkg         - Remove App NI files\n"
+               "       --ni-regen-all-app     - Re-generate All App NI files\n"
+               "       --tac-regen-all        - Re-generate All TAC files\n"
+               "       --tac-restore-db       - Restore TAC Database\n"
+               "       --tac-disable-pkg      - Disable TAC for package\n"
+               "       --tac-enable-pkg       - Enable TAC for package\n"
+               "\n"
+               "Example:\n"
+               "1. Create native image for dlls and exes under platform directories\n"
+               "   # %s --ni-system\n"
+               "2. Create native image for dll\n"
+               "   # %s --ni-dll /usr/bin/Tizen.Runtime.dll\n"
+               "3. Create native image under the package's bin and lib directory\n"
+               "   # %s --ni-pkg org.tizen.FormsGallery\n"
+               "4. Regenerate native images for all installed .net packages with ready-to-run option\n"
+               "   # %s --r2r --ni-regen-all-app\n\n";
+       printf(helpDesc, argv0, argv0, argv0, argv0, argv0);
+}
+
+int main(int argc, char* argv[])
+{
+       bool pkgMode = false;
+       bool dllMode = false;
+       bool dirMode = false;
+       bool rmPkgMode = false;
+       bool enableR2R = false;
+       bool pkgDllMode = false;
+       bool disableTacMode = false;
+       bool enableTacMode = false;
+
+       bool doGenUniqueBaseSystem = true;
+
+       NiCommonOption option = {std::string(), std::string(), std::string()};
+       if (initNICommon(&option) != NI_ERROR_NONE) {
+               fprintf(stderr, "Fail to initialize NI Common\n");
+               return -1;
+       }
+
+       if (cmdOptionExists(argv, argv+argc, "--r2r")) {
+               enableR2R = true;
+       }
+
+       if (cmdOptionExists(argv, argv+argc, "--help")) {
+               help(argv[0]);
+               return 0;
+       } else if (cmdOptionExists(argv, argv+argc, "--ni-system")) {
+               createNiPlatform(enableR2R, doGenUniqueBaseSystem);
+               return 0;
+       } else if (cmdOptionExists(argv, argv+argc, "--ni-dll")) {
+               dllMode = true;
+       } else if (cmdOptionExists(argv, argv+argc, "--ni-pkg")) {
+               pkgMode = true;
+       } else if (cmdOptionExists(argv, argv+argc, "--ni-dir")) {
+               dirMode = true;
+       } else if (cmdOptionExists(argv, argv+argc, "--ni-reset-system")) {
+               removeNiPlatform();
+               return 0;
+       } else if (cmdOptionExists(argv, argv+argc, "--ni-reset-pkg")) {
+               rmPkgMode = true;
+       } else if (cmdOptionExists(argv, argv+argc, "--ni-pkg-dll")) {
+               pkgDllMode = true;
+       } else if (cmdOptionExists(argv, argv+argc, "--ni-regen-all-app")) {
+               regenerateAppNI(enableR2R);
+               return 0;
+       } else if (cmdOptionExists(argv, argv+argc, "--tac-regen-all")) {
+               regenerateTAC();
+               return 0;
+       } else if (cmdOptionExists(argv, argv+argc, "--tac-restore-db")) {
+               restoreTACDB();
+               return 0;
+       } else if (cmdOptionExists(argv, argv+argc, "--tac-disable-pkg")) {
+               disableTacMode = true;
+       } else if (cmdOptionExists(argv, argv+argc, "--tac-enable-pkg")) {
+               enableTacMode = true;
+       } else {
+               help(argv[0]);
+               return 0;
+       }
+
+       std::vector<std::string> args = getCmdArgs(argv, argv+argc);
+
+       if (args.size() < 1) {
+               if (pkgMode || rmPkgMode || disableTacMode || enableTacMode) {
+                       fprintf(stderr, "Package name is missed\n");
+               } else if (dllMode) {
+                       fprintf(stderr, "DLL path is missed\n");
+               }
+               help(argv[0]);
+               return 1;
+       } else if (args.size() < 2) {
+               if (pkgDllMode) {
+                       fprintf(stderr, "Package name or DLL path is missed\n");
+                       help(argv[0]);
+                       return 1;
+               }
+       }
+
+       if (pkgMode) {
+               for (const std::string pkg : args) {
+                       // if there is AOTed dlls under package root, that is skiped.
+                       int ret = createNiUnderPkgRoot(pkg, enableR2R);
+                       if (ret == NI_ERROR_INVALID_PACKAGE) {
+                               fprintf(stderr, "Failed to get root path from [%s]\n", pkg.c_str());
+                               return -1;
+                       } else if (ret != NI_ERROR_NONE) {
+                               fprintf(stderr, "Failed to generate NI file [%s]\n", pkg.c_str());
+                               return -1;
+                       }
+                       ret = createTACPackage(pkg);
+                       if (ret == TAC_ERROR_INVALID_PACKAGE) {
+                               fprintf(stderr, "Failed to get root path from [%s]\n", pkg.c_str());
+                               return -1;
+                       } else if (ret != TAC_ERROR_NONE) {
+                               fprintf(stderr, "Failed to generate symbolic link file [%s]\n", pkg.c_str());
+                               return -1;
+                       }
+               }
+       } else if (pkgDllMode) {
+               int ret = createNiDllUnderPkgRoot(args[0], args[1], enableR2R);
+               if (ret == NI_ERROR_INVALID_PACKAGE) {
+                       fprintf(stderr, "Failed to get root path from [%s]\n", args[0].c_str());
+                       return -1;
+               } else if (ret == NI_ERROR_ALREADY_EXIST) {
+                       // skip for already exist case
+                       return -1;
+               } else if (ret != NI_ERROR_NONE) {
+                       fprintf(stderr, "Failed to generate NI file [%s]\n", args[1].c_str());
+                       return -1;
+               }
+       } else if (rmPkgMode) {
+               for (const std::string pkg : args) {
+                       int ret = removeNiUnderPkgRoot(pkg);
+                       if (ret == NI_ERROR_INVALID_PACKAGE) {
+                               fprintf(stderr, "Failed to get root path from [%s]\n", pkg.c_str());
+                               return -1;
+                       } else if (ret != NI_ERROR_NONE) {
+                               fprintf(stderr, "Failed to remove dlls for given package [%s]\n", pkg.c_str());
+                               return -1;
+                       }
+                       ret = resetTACPackage(pkg);
+                       if (ret == TAC_ERROR_INVALID_PACKAGE) {
+                               fprintf(stderr, "Failed to get root path from [%s]\n", pkg.c_str());
+                               return -1;
+                       } else if (ret != TAC_ERROR_NONE) {
+                               fprintf(stderr, "Failed to remove symlink for given package [%s]\n", pkg.c_str());
+                               return -1;
+                       }
+               }
+       } else if (dllMode) {
+               // donot return error code for generation failure.
+               // we have to run crossgen for all input dlls.
+               for (const std::string dll : args) {
+                       int ret = createNiDll(dll, enableR2R, doGenUniqueBaseSystem);
+                       if (ret == NI_ERROR_ALREADY_EXIST) {
+                               // skip for already exist case
+                       } else if (ret != NI_ERROR_NONE) {
+                               fprintf(stderr, "Failed to generate NI file [%s]\n", dll.c_str());
+                       }
+               }
+       } else if (dirMode) {
+               createNiUnderDirs(args.data(), args.size(), enableR2R, doGenUniqueBaseSystem);
+       } else if (disableTacMode) {
+               for (const std::string pkg : args) {
+                       int ret = disableTACPackage(pkg);
+                       if (ret == TAC_ERROR_INVALID_PACKAGE) {
+                               fprintf(stderr, "Failed to get root path from [%s]\n", pkg.c_str());
+                               return -1;
+                       } else if (ret != TAC_ERROR_NONE) {
+                               fprintf(stderr, "Failed to disable tac [%s]\n", pkg.c_str());
+                               return -1;
+                       }
+               }
+       } else if (enableTacMode) {
+               for (const std::string pkg : args) {
+                       int ret = enableTACPackage(pkg);
+                       if (ret == TAC_ERROR_INVALID_PACKAGE) {
+                               fprintf(stderr, "Failed to get root path from [%s]\n", pkg.c_str());
+                               return -1;
+                       } else if (ret != TAC_ERROR_NONE) {
+                               fprintf(stderr, "Failed to enable tac [%s]\n", pkg.c_str());
+                               return -1;
+                       }
+               }
+       }
+       return 0;
+}
index 88fbb28..309f1cd 100644 (file)
@@ -36,6 +36,7 @@
 #include <string.h>
 
 #include "ni_common.h"
 #include <string.h>
 
 #include "ni_common.h"
+#include "tac_common.h"
 #include "path_manager.h"
 #include "plugin_manager.h"
 
 #include "path_manager.h"
 #include "plugin_manager.h"
 
@@ -323,19 +324,31 @@ static int appAotCb(pkgmgrinfo_appinfo_h handle, void *userData)
                return -1;
        }
 
                return -1;
        }
 
-       if (removeNiUnderPkgRoot(pkgId) != 0) {
+       if (removeNiUnderPkgRoot(pkgId) != NI_ERROR_NONE) {
                fprintf(stderr, "Failed to remove previous dlls from [%s]\n", pkgId);
                return -1;
        }
 
                fprintf(stderr, "Failed to remove previous dlls from [%s]\n", pkgId);
                return -1;
        }
 
+       if (resetTACPackage(pkgId) != TAC_ERROR_NONE) {
+               fprintf(stderr, "Failed to remove symlink for given package [%s]\n", pkgId);
+               return -1;
+       }
+
        // Regenerate ni files with R2R mode forcibiliy. (there is no way to now which option is used)
        // Regenerate ni files with R2R mode forcibiliy. (there is no way to now which option is used)
-       if (createNiUnderPkgRoot(pkgId, *enableR2R) != 0) {
-               fprintf(stderr, "Failed to get root path from [%s]\n", pkgId);
+       if (createNiUnderPkgRoot(pkgId, *enableR2R) != NI_ERROR_NONE) {
+               fprintf(stderr, "Failed to generate NI file [%s]\n", pkgId);
                return -1;
        } else {
                fprintf(stderr, "Complete make application to native image\n");
        }
 
                return -1;
        } else {
                fprintf(stderr, "Complete make application to native image\n");
        }
 
+       if (createTACPackage(pkgId) != TAC_ERROR_NONE) {
+               fprintf(stderr, "Failed to generate symbolic link file [%s]\n", pkgId);
+               return -1;
+       }else {
+               fprintf(stderr, "Complete make symbolic link file to tac\n");
+       }
+
        return 0;
 }
 
        return 0;
 }
 
@@ -488,8 +501,7 @@ void createNiUnderDirs(const std::string rootPaths[], int count, bool enableR2R,
 ni_error_e createNiUnderPkgRoot(const std::string& pkgId, bool enableR2R)
 {
        std::string pkgRoot;
 ni_error_e createNiUnderPkgRoot(const std::string& pkgId, bool enableR2R)
 {
        std::string pkgRoot;
-       if (getRootPath(pkgId, pkgRoot) != NI_ERROR_NONE) {
-               fprintf(stderr, "Failed to get root path from [%s]\n", pkgId.c_str());
+       if (getRootPath(pkgId, pkgRoot) < 0) {
                return NI_ERROR_INVALID_PACKAGE;
        }
 
                return NI_ERROR_INVALID_PACKAGE;
        }
 
@@ -507,16 +519,37 @@ ni_error_e createNiDllUnderPkgRoot(const std::string& pkgId, const std::string&
 {
        std::string pkgRoot;
        if (getRootPath(pkgId, pkgRoot) < 0) {
 {
        std::string pkgRoot;
        if (getRootPath(pkgId, pkgRoot) < 0) {
-               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");
                return NI_ERROR_INVALID_PACKAGE;
        }
 
        std::string binDir = concatPath(pkgRoot, "bin");
        std::string libDir = concatPath(pkgRoot, "lib");
-       std::string appTAC = concatPath(binDir, ".TAC.Release");
-       std::string paths = binDir + ":" + libDir + ":" + appTAC;
-
-       return crossgen(dllPath, paths, enableR2R, 0, true);
+       std::string tacDir = concatPath(binDir, TAC_SYMLINK_SUB_DIR);
+       std::string paths = binDir + ":" + libDir + ":" + tacDir;
+
+       if (bf::is_symlink(dllPath)) {
+               if (bf::exists(tacDir)) {
+                       if (!isNativeImage(dllPath)) {
+                               std::string originPath = bf::read_symlink(dllPath).string();
+                               std::string originNiPath = originPath.substr(0, originPath.rfind(".dll")) + ".ni.dll";
+                               if (!bf::exists(originNiPath)) {
+                                       if(createNiDll(originPath, false, false) != NI_ERROR_NONE) {
+                                               fprintf(stderr, "Failed to create NI file [%s]\n", originPath.c_str());
+                                               return NI_ERROR_UNKNOWN;
+                                       }
+                               }
+                               std::string setNiPath = dllPath.substr(0, dllPath.rfind(".dll")) + ".ni.dll";
+                               if (!bf::exists(setNiPath)) {
+                                       bf::create_symlink(originNiPath, setNiPath);
+                                       fprintf(stderr, "%s symbolic link file generated successfully.\n", setNiPath.c_str());
+                                       updateAssemblyInfo(tacDir.c_str(), setNiPath.c_str(), true);
+                               }
+                       }
+               }
+               return NI_ERROR_NONE;
+       } else {
+               return crossgen(dllPath, paths, enableR2R, 0, true);
+       }
 }
 
 void removeNiPlatform()
 }
 
 void removeNiPlatform()
@@ -567,7 +600,6 @@ ni_error_e removeNiUnderPkgRoot(const std::string& pkgId)
 {
        std::string pkgRoot;
        if (getRootPath(pkgId, pkgRoot) < 0) {
 {
        std::string pkgRoot;
        if (getRootPath(pkgId, pkgRoot) < 0) {
-               fprintf(stderr, "Failed to get root path from [%s]\n", pkgId.c_str());
                return NI_ERROR_INVALID_PACKAGE;
        }
 
                return NI_ERROR_INVALID_PACKAGE;
        }
 
index cadb864..53c5016 100644 (file)
@@ -36,28 +36,10 @@ std::vector<std::string> getCmdArgs(char** begin, char** end)
 static void help(const char *argv0)
 {
        const char* helpDesc =
 static void help(const char *argv0)
 {
        const char* helpDesc =
-               "Usage: %s [args] <root paths or pkg name>\n"
-               "       --help              - Display this screen\n"
-               "       --system            - Create NI under System DLLs\n"
-               "       --dll               - Create NI for DLL\n"
-               "       --pkg               - Create NI for package\n"
-               "       --dir               - Create NI for directory\n"
-               "       --r2r               - Use ready-to-run option (default: FNV)\n"
-               "                             (This option should be used with other options)\n"
-               "       --reset-system      - Remove System NI files\n"
-               "       --reset-pkg         - Remove App NI files\n"
-               "       --regen-all-app     - Re-generate All App NI files\n"
-               "\n"
+               "%s is deprecated. Please use dotnettool instead.\n"
                "Example:\n"
                "Example:\n"
-               "1. Create native image for dlls and exes under platform directories\n"
-               "   # %s --system\n"
-               "2. Create native image for dll\n"
-               "   # %s --dll /usr/bin/Tizen.Runtime.dll\n"
-               "3. Create native image under the package's bin and lib directory\n"
-               "   # %s --pkg org.tizen.FormsGallery\n"
-               "4. Regenerate native images for all installed .net packages with ready-to-run option\n"
-               "   # %s --r2r --regen-all-app\n\n";
-       printf(helpDesc, argv0, argv0, argv0, argv0, argv0);
+               "   # dotnettool --help\n\n";
+       printf(helpDesc, argv0);
 }
 
 int main(int argc, char* argv[])
 }
 
 int main(int argc, char* argv[])
@@ -127,7 +109,7 @@ int main(int argc, char* argv[])
                                fprintf(stderr, "Failed to get root path from [%s]\n", pkg.c_str());
                                return -1;
                        } else if (ret != NI_ERROR_NONE) {
                                fprintf(stderr, "Failed to get root path from [%s]\n", pkg.c_str());
                                return -1;
                        } else if (ret != NI_ERROR_NONE) {
-                               fprintf(stderr, "Failed to generate NI file [%s]\n", args[1].c_str());
+                               fprintf(stderr, "Failed to generate NI file [%s]\n", pkg.c_str());
                                return -1;
                        }
                }
                                return -1;
                        }
                }
diff --git a/NativeLauncher/tool/tac_common.cc b/NativeLauncher/tool/tac_common.cc
new file mode 100644 (file)
index 0000000..3c401ec
--- /dev/null
@@ -0,0 +1,444 @@
+/*
+ * 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 <fstream>
+#include <pkgmgr-info.h>
+#include <pkgmgr_installer_info.h>
+#include <json/json.h>
+
+#include "log.h"
+#include "utils.h"
+#include "ni_common.h"
+#include "tac_common.h"
+#include "db_manager.h"
+
+#ifdef  LOG_TAG
+#undef  LOG_TAG
+#endif
+#define LOG_TAG "DOTNET_INSTALLER_PLUGIN"
+
+#define __XSTR(x) #x
+#define __STR(x) __XSTR(x)
+static const char* __TAC_DIR = __STR(TAC_DIR);
+#undef __STR
+#undef __XSTR
+
+static sqlite3 *tac_db = NULL;
+std::vector<std::string> restoreNuget;
+std::vector<std::string> enableNuget;
+
+void cleanupDirectory()
+{
+       std::vector<std::string> removeNuget;
+       for (auto& nuget : bf::recursive_directory_iterator(__TAC_DIR)) {
+               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 (!removeAll(rm)) {
+                       _ERR("Failed to remove of %s", rm.c_str());
+               }
+       }
+       removeNuget.clear();
+}
+
+void depsJsonParser(std::string pkgId, std::string depsJsonPath, std::string execName, bool isRestore)
+{
+       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"];
+               const Json::Value nugetPackages = root["targets"][runtimeTargetName.asString().c_str()];
+               for (auto& nuget : nugetPackages.getMemberNames()) {
+                       if (strstr(nuget.c_str(), TIZEN_DOTNET_NUGET) != NULL ||
+                               strstr(nuget.c_str(), TIZEN_DOTNET_SDK_NUGET) != 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(), TIZEN_DOTNET_NUGET) != NULL ||
+                                                       strstr(dependency.c_str(), NET_STANDARD_LIBRARY_NUGET) != 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 + "');";
+                                               if (isRestore) {
+                                                       if (tac_db) {
+                                                               dbInsert(tac_db, TAC_APP_LIST_RESTORE_DB, sql);
+                                                               restoreNuget.push_back(concatPath(__TAC_DIR, name));
+                                                       }
+                                               } else {
+                                                       std::string nugetPath = concatPath(__TAC_DIR, nuget);
+                                                       if (bf::exists(nugetPath)) {
+                                                               for (auto& assembly : assemblies.getMemberNames()) {
+                                                                       std::string assemblyName = assembly.substr(assembly.rfind('/') + 1);
+                                                                       std::string originPath = concatPath(nugetPath, assemblyName);
+                                                                       if (bf::exists(originPath)) {
+                                                                               enableNuget.push_back(originPath);
+                                                                       }
+                                                               }
+                                                       }
+                                               }
+                                       }
+                               }
+                       }
+               }
+               ifs.close();
+       }
+}
+
+// callback function of "pkgmgrinfo_appinfo_metadata_filter_foreach"
+static int restoreDBCb(pkgmgrinfo_appinfo_h handle, void *userData)
+{
+       char *pkgId = NULL;
+       char *root = NULL;
+       char *exec = NULL;
+       std::string rootPath;
+       std::string execName;
+
+       int 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")) + ".deps.json";
+       std::string depsJsonPath = concatPath(rootPath, depsJsonName);
+       if (bf::exists(depsJsonPath)) {
+               depsJsonParser(pkgId, depsJsonPath, execName, true);
+       }
+       return 0;
+}
+
+tac_error_e restoreTACDB()
+{
+       if (!removeFile(TAC_APP_LIST_RESTORE_DB)) {
+               fprintf(stderr, "Failed to remove of %s", TAC_APP_LIST_RESTORE_DB);
+               return TAC_ERROR_UNKNOWN;
+       }
+
+       std::string dbRestoreJournal = TAC_APP_LIST_RESTORE_DB + std::string("-journal");
+       if (!removeFile(dbRestoreJournal)) {
+               fprintf(stderr, "Failed to remove of %s", dbRestoreJournal.c_str());
+               return TAC_ERROR_UNKNOWN;
+       }
+
+       tac_db = dbCreate(TAC_APP_LIST_RESTORE_DB);
+       if (tac_db) {
+               if (!dbOpen(tac_db, TAC_APP_LIST_RESTORE_DB)) {
+                       return TAC_ERROR_UNKNOWN;
+               }
+       } else {
+               return TAC_ERROR_UNKNOWN;
+       }
+
+       pkgmgrinfo_appinfo_metadata_filter_h handle;
+       int ret = pkgmgrinfo_appinfo_metadata_filter_create(&handle);
+       if (ret != PMINFO_R_OK) {
+               return TAC_ERROR_UNKNOWN;
+       }
+
+       ret = pkgmgrinfo_appinfo_metadata_filter_add(handle, TAC_METADATA_KEY, METADATA_VALUE);
+       if (ret != PMINFO_R_OK) {
+               pkgmgrinfo_appinfo_metadata_filter_destroy(handle);
+               return TAC_ERROR_UNKNOWN;
+       }
+
+       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 TAC_ERROR_UNKNOWN;
+       }
+       fprintf(stderr, "Success pkgmgrinfo_appinfo_metadata_filter_foreach\n");
+
+       pkgmgrinfo_appinfo_metadata_filter_destroy(handle);
+
+       if (tac_db) {
+               dbClose(tac_db);
+               tac_db = NULL;
+       }
+
+       if (!copyFile(TAC_APP_LIST_RESTORE_DB, TAC_APP_LIST_DB)) {
+               fprintf(stderr, "Failed to move of %s", TAC_APP_LIST_DB);
+               return TAC_ERROR_UNKNOWN;
+       }
+       if (!removeFile(TAC_APP_LIST_RESTORE_DB)) {
+               fprintf(stderr, "Failed to remove of %s", TAC_APP_LIST_RESTORE_DB);
+               return TAC_ERROR_UNKNOWN;
+       }
+
+       std::string dbJournal = TAC_APP_LIST_DB + std::string("-journal");
+       if (!copyFile(dbRestoreJournal, dbJournal)) {
+               fprintf(stderr, "Failed to move of %s", dbJournal.c_str());
+               return TAC_ERROR_UNKNOWN;
+       }
+       if (!removeFile(dbRestoreJournal)) {
+               fprintf(stderr, "Failed to remove of %s", dbRestoreJournal.c_str());
+               return TAC_ERROR_UNKNOWN;
+       }
+
+       cleanupDirectory();
+       return TAC_ERROR_NONE;
+}
+
+tac_error_e resetTACPackage(const std::string& pkgId)
+{
+       std::string pkgRoot;
+       if (getRootPath(pkgId, pkgRoot) < 0) {
+               return TAC_ERROR_INVALID_PACKAGE;
+       }
+
+       std::vector<std::string> tacNativeImage;
+       std::string binDir = concatPath(pkgRoot, "bin");
+       std::string tacDir = concatPath(binDir, TAC_SYMLINK_SUB_DIR);
+       if (bf::exists(tacDir)) {
+               for (auto& symlinkAssembly : bf::recursive_directory_iterator(tacDir)) {
+                       std::string symPath = symlinkAssembly.path().string();
+                       if (bf::is_symlink(symPath)) {
+                               if (isNativeImage(symPath)) {
+                                       tacNativeImage.push_back(symPath);
+                               }
+                       }
+               }
+               for (auto& path : tacNativeImage) {
+                       if (!removeFile(path)) {
+                               fprintf(stderr, "Failed to remove of %s", path.c_str());
+                               return TAC_ERROR_UNKNOWN;
+                       }
+               }
+       }
+       tacNativeImage.clear();
+       return TAC_ERROR_NONE;
+}
+
+tac_error_e createTACPackage(const std::string& pkgId)
+{
+       std::string pkgRoot;
+       if (getRootPath(pkgId, pkgRoot) < 0) {
+               return TAC_ERROR_INVALID_PACKAGE;
+       }
+
+       std::string binDir = concatPath(pkgRoot, "bin");
+       std::string tacDir = concatPath(binDir, TAC_SYMLINK_SUB_DIR);
+       std::string binNIDir = concatPath(binDir, APP_NI_SUB_DIR);
+       if (bf::exists(tacDir)) {
+               for (auto& symlinkAssembly : bf::recursive_directory_iterator(tacDir)) {
+                       std::string symPath = symlinkAssembly.path().string();
+                       if (bf::is_symlink(symPath)) {
+                               if (!isNativeImage(symPath)) {
+                                       std::string originPath = bf::read_symlink(symPath).string();
+                                       std::string originNiPath = originPath.substr(0, originPath.rfind(".dll")) + ".ni.dll";
+                                       if (!bf::exists(originNiPath)) {
+                                               if(createNiDll(originPath, false, false) != NI_ERROR_NONE) {
+                                                       fprintf(stderr, "Failed to create NI file [%s]\n", originPath.c_str());
+                                                       return TAC_ERROR_UNKNOWN;
+                                               }
+                                       }
+                                       std::string symNIPath = symPath.substr(0, symPath.rfind(".dll")) + ".ni.dll";
+                                       if (!bf::exists(symNIPath)) {
+                                               bf::create_symlink(originNiPath, symNIPath);
+                                               fprintf(stderr, "%s symbolic link file generated successfully.\n", symNIPath.c_str());
+                                               updateAssemblyInfo(tacDir.c_str(), symNIPath.c_str(), true);
+
+                                               std::string NIFileName = symNIPath.substr(symNIPath.rfind('/') + 1);
+                                               if (!removeFile(concatPath(binNIDir, NIFileName))) {
+                                                       fprintf(stderr, "Failed to remove of %s\n", concatPath(binNIDir, NIFileName).c_str());
+                                                       return TAC_ERROR_UNKNOWN;
+                                               }
+                                       }
+                               }
+                       }
+               }
+       }
+       return TAC_ERROR_NONE;
+}
+
+tac_error_e regenerateTAC()
+{
+       const std::string tacDir[] = {__TAC_DIR};
+       removeNiUnderDirs(tacDir, 1);
+
+       auto convert = [](const std::string& path, std::string name) {
+               if (strstr(path.c_str(), TAC_APP_LIST_DB) != NULL ||
+                       strstr(path.c_str(), TAC_APP_LIST_RESTORE_DB) != NULL ||
+                       strstr(path.c_str(), TAC_SHA_256_INFO) != NULL)
+                       return;
+               if(createNiDll(path, false, false) != NI_ERROR_NONE) {
+                       fprintf(stderr, "Failed to create NI file [%s]\n", path.c_str());
+                       return;
+               }
+       };
+       scanFilesInDir(tacDir[0], convert, -1);
+       return TAC_ERROR_NONE;
+}
+
+tac_error_e disableTACPackage(const std::string& pkgId)
+{
+       std::string pkgRoot;
+       if (getRootPath(pkgId, pkgRoot) < 0) {
+               return TAC_ERROR_INVALID_PACKAGE;
+       }
+
+       std::string binDir = concatPath(pkgRoot, "bin");
+       std::string tacDir = concatPath(binDir, TAC_SYMLINK_SUB_DIR);
+       std::string binNIDir = concatPath(binDir, APP_NI_SUB_DIR);
+       if (bf::exists(tacDir)) {
+               for (auto& symlinkAssembly : bf::recursive_directory_iterator(tacDir)) {
+                       std::string symPath = symlinkAssembly.path().string();
+                       std::string fileName = symlinkAssembly.path().filename().string();
+                       if (bf::is_symlink(symPath)) {
+                               std::string originPath = bf::read_symlink(symPath).string();
+                               if (!isNativeImage(symPath)) {
+                                       if (!copyFile(originPath, concatPath(binDir, fileName))) {
+                                               fprintf(stderr, "Failed to copy of %s\n", concatPath(binDir, fileName).c_str());
+                                               return TAC_ERROR_UNKNOWN;
+                                       }
+                                       updateAssemblyInfo(binDir.c_str(), concatPath(binDir, fileName).c_str());
+                               } else {
+                                       if (!copyFile(originPath, concatPath(binNIDir, fileName))) {
+                                               fprintf(stderr, "Failed to copy of %s\n", concatPath(binNIDir, fileName).c_str());
+                                               return TAC_ERROR_UNKNOWN;
+                                       }
+                                       updateAssemblyInfo(binDir.c_str(), concatPath(binNIDir, fileName).c_str());
+                               }
+                       }
+               }
+       }
+       if (!removeAll(tacDir)) {
+               fprintf(stderr, "Failed to remove of %s\n", tacDir.c_str());
+               return TAC_ERROR_UNKNOWN;
+       }
+       return TAC_ERROR_NONE;
+}
+
+tac_error_e enableTACPackage(const std::string& pkgId)
+{
+       std::string pkgRoot;
+       if (getRootPath(pkgId, pkgRoot) < 0) {
+               return TAC_ERROR_INVALID_PACKAGE;
+       }
+
+       std::string execName;
+       if (getExecName(pkgId, execName) < 0) {
+               return TAC_ERROR_INVALID_PACKAGE;
+       }
+
+       std::string metaValue;
+       if (getMetadataValue(pkgId, TAC_METADATA_KEY, metaValue) < 0) {
+               return TAC_ERROR_INVALID_PACKAGE;
+       }
+
+       if (!strcmp(metaValue.c_str(), "true")) {
+               std::string binDir = concatPath(pkgRoot, "bin");
+               std::string tacDir = concatPath(binDir, TAC_SYMLINK_SUB_DIR);
+               std::string binNIDir = concatPath(binDir, APP_NI_SUB_DIR);
+               if (!bf::exists(tacDir)) {
+                       if (!createDir(tacDir)) {
+                               fprintf(stderr, "Cannot create directory: %s\n", tacDir.c_str());
+                               return TAC_ERROR_UNKNOWN;
+                       }
+                       updateAssemblyInfo(binDir.c_str(), tacDir.c_str());
+
+                       std::string depsJsonName = execName.substr(0, execName.rfind(".dll")) + ".deps.json";
+                       std::string depsJsonPath = concatPath(pkgRoot, depsJsonName);
+                       if (bf::exists(depsJsonPath)) {
+                               depsJsonParser(pkgId, depsJsonPath, execName, false);
+                       }
+
+                       for (auto& originPath : enableNuget) {
+                               if (bf::exists(originPath)) {
+                                       std::string fileName = originPath.substr(originPath.rfind('/') + 1);
+                                       std::string NIFileName = fileName.substr(0, fileName.rfind(".dll")) + ".ni.dll";
+                                       if (bf::exists(binNIDir)) {
+                                               std::string originNIPath = originPath.substr(0, originPath.rfind(".dll")) + ".ni.dll";
+                                               if (bf::exists(originNIPath)) {
+                                                       bf::create_symlink(originNIPath, concatPath(tacDir, NIFileName));
+                                                       fprintf(stderr, "%s symbolic link file generated successfully.\n", concatPath(tacDir, NIFileName).c_str());
+                                                       updateAssemblyInfo(tacDir.c_str(), concatPath(tacDir, NIFileName).c_str(), true);
+
+                                                       if (!removeFile(concatPath(binNIDir, NIFileName))) {
+                                                               fprintf(stderr, "Failed to remove of %s\n", concatPath(binNIDir, NIFileName).c_str());
+                                                               return TAC_ERROR_UNKNOWN;
+                                                       }
+                                               }
+                                       }
+                                       bf::create_symlink(originPath, concatPath(tacDir, fileName));
+                                       fprintf(stderr, "%s symbolic link file generated successfully.\n", concatPath(tacDir, fileName).c_str());
+                                       updateAssemblyInfo(tacDir.c_str(), concatPath(tacDir, fileName).c_str(), true);
+
+                                       if (!removeFile(concatPath(binDir, fileName))) {
+                                               fprintf(stderr, "Failed to remove of %s\n", concatPath(binDir, fileName).c_str());
+                                               return TAC_ERROR_UNKNOWN;
+                                       }
+                               }
+                       }
+                       if (enableNuget.empty()) {
+                               if (!removeAll(tacDir)) {
+                                       _ERR("Failed to remove of %s", tacDir.c_str());
+                               }
+                       }
+               }
+       } else {
+               fprintf(stderr, "The metadata key is missing or the metadata value is false of [%s]\n", pkgId.c_str());
+       }
+       return TAC_ERROR_NONE;
+}
diff --git a/NativeLauncher/tool/tactool.cc b/NativeLauncher/tool/tactool.cc
deleted file mode 100644 (file)
index 25e150c..0000000
+++ /dev/null
@@ -1,268 +0,0 @@
-/*
- * 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;
-}
index ee22d0a..92075bb 100644 (file)
@@ -142,6 +142,77 @@ int getRootPath(std::string pkgId, std::string& rootPath)
        return 0;
 }
 
        return 0;
 }
 
+int getExecName(std::string pkgId, std::string& execName)
+{
+       char *exec = NULL;
+       char *appId = 0;
+
+       pkgmgrinfo_pkginfo_h pkg_handle;
+       int ret = pkgmgrinfo_pkginfo_get_pkginfo(pkgId.c_str(), &pkg_handle);
+       if (ret != PMINFO_R_OK) {
+               return -1;
+       }
+       ret = pkgmgrinfo_pkginfo_get_mainappid(pkg_handle, &appId);
+       if (ret != PMINFO_R_OK) {
+               pkgmgrinfo_pkginfo_destroy_pkginfo(pkg_handle);
+               return -1;
+       }
+
+       pkgmgrinfo_appinfo_h app_handle;
+       ret = pkgmgrinfo_appinfo_get_appinfo(appId, &app_handle);
+       if (ret != PMINFO_R_OK) {
+               pkgmgrinfo_pkginfo_destroy_pkginfo(pkg_handle);
+               return -1;
+       }
+       ret = pkgmgrinfo_appinfo_get_exec(app_handle, &exec);
+       if (ret != PMINFO_R_OK) {
+               pkgmgrinfo_appinfo_destroy_appinfo(app_handle);
+               pkgmgrinfo_pkginfo_destroy_pkginfo(pkg_handle);
+               return -1;
+       }
+       execName = std::string(exec).substr(std::string(exec).rfind('/') + 1);
+
+       pkgmgrinfo_appinfo_destroy_appinfo(app_handle);
+       pkgmgrinfo_pkginfo_destroy_pkginfo(pkg_handle);
+       return 0;
+}
+
+int getMetadataValue(std::string pkgId, std::string metadataKey, std::string& metadataValue)
+{
+       char *value = NULL;
+       char *appId = 0;
+
+       pkgmgrinfo_pkginfo_h pkg_handle;
+       int ret = pkgmgrinfo_pkginfo_get_pkginfo(pkgId.c_str(), &pkg_handle);
+       if (ret != PMINFO_R_OK) {
+               return -1;
+       }
+       ret = pkgmgrinfo_pkginfo_get_mainappid(pkg_handle, &appId);
+       if (ret != PMINFO_R_OK) {
+               pkgmgrinfo_pkginfo_destroy_pkginfo(pkg_handle);
+               return -1;
+       }
+
+       pkgmgrinfo_appinfo_h app_handle;
+       ret = pkgmgrinfo_appinfo_get_appinfo(appId, &app_handle);
+       if (ret != PMINFO_R_OK) {
+               pkgmgrinfo_pkginfo_destroy_pkginfo(pkg_handle);
+               return -1;
+       }
+       ret = pkgmgrinfo_appinfo_get_metadata_value(app_handle, metadataKey.c_str(), &value);
+       if (ret != PMINFO_R_OK) {
+               pkgmgrinfo_appinfo_destroy_appinfo(app_handle);
+               pkgmgrinfo_pkginfo_destroy_pkginfo(pkg_handle);
+               //Does not return error because the metadata key may not exist.
+               return 0;
+       }
+       metadataValue = std::string(value);
+
+       pkgmgrinfo_appinfo_destroy_appinfo(app_handle);
+       pkgmgrinfo_pkginfo_destroy_pkginfo(pkg_handle);
+       return 0;
+}
+
 std::string baseName(const std::string& path)
 {
        auto pos = path.find_last_of(PATH_SEPARATOR);
 std::string baseName(const std::string& path)
 {
        auto pos = path.find_last_of(PATH_SEPARATOR);
@@ -223,7 +294,7 @@ void scanFilesInDir(const std::string& directory, FileReader reader, unsigned in
        bool isDir;
 
        if (strstr(directory.c_str(), TAC_SYMLINK_SUB_DIR) != NULL)
        bool isDir;
 
        if (strstr(directory.c_str(), TAC_SYMLINK_SUB_DIR) != NULL)
-               return; // skip nitool --regen-all-app (--r2r)
+               return;
 
        dir = opendir(directory.c_str());
 
 
        dir = opendir(directory.c_str());
 
@@ -264,23 +335,39 @@ void scanFilesInDir(const std::string& directory, FileReader reader, unsigned in
        closedir(dir);
 }
 
        closedir(dir);
 }
 
-void updateAssemblyInfo(const std::string& getPath, const std::string& setPath)
+void updateAssemblyInfo(const std::string& getPath, const std::string& setPath, bool isSymlink)
 {
        char* label = NULL;
 {
        char* label = NULL;
+       struct stat info;
 
 
-       // change smack label
-       if (smack_getlabel(getPath.c_str(), &label, SMACK_LABEL_ACCESS) == 0) {
-               if (smack_setlabel(setPath.c_str(), label, SMACK_LABEL_ACCESS) < 0) {
-                       fprintf(stderr, "Fail to set smack label\n");
+       if (isSymlink) {
+               // change smack label for symbolic link.
+               if (smack_lgetlabel(getPath.c_str(), &label, SMACK_LABEL_ACCESS) == 0) {
+                       if (smack_lsetlabel(setPath.c_str(), label, SMACK_LABEL_ACCESS) < 0) {
+                               fprintf(stderr, "Fail to set smack label\n");
+                       }
+                       free(label);
                }
                }
-               free(label);
-       }
 
 
-       // change owner and groups for generated ni file.
-       struct stat info;
-       if (!stat(getPath.c_str(), &info)) {
-               if (chown(setPath.c_str(), info.st_uid, info.st_gid) == -1)
-                       fprintf(stderr, "Failed to change owner and group name\n");
+               // change owner and groups for symbolic link.
+               if (!stat(getPath.c_str(), &info)) {
+                       if (lchown(setPath.c_str(), info.st_uid, info.st_gid) == -1)
+                               fprintf(stderr, "Failed to change owner and group name\n");
+               }
+       } else {
+               // change smack label
+               if (smack_getlabel(getPath.c_str(), &label, SMACK_LABEL_ACCESS) == 0) {
+                       if (smack_setlabel(setPath.c_str(), label, SMACK_LABEL_ACCESS) < 0) {
+                               fprintf(stderr, "Fail to set smack label\n");
+                       }
+                       free(label);
+               }
+
+               // change owner and groups for generated ni file.
+               if (!stat(getPath.c_str(), &info)) {
+                       if (chown(setPath.c_str(), info.st_uid, info.st_gid) == -1)
+                               fprintf(stderr, "Failed to change owner and group name\n");
+               }
        }
 }
 
        }
 }
 
@@ -434,6 +521,9 @@ bool copyDir(const bf::path& path1, const bf::path& path2, FSFlag flags) {
 
 bool copyFile(const bf::path& path1, const bf::path& path2) {
        bs::error_code error;
 
 bool copyFile(const bf::path& path1, const bf::path& path2) {
        bs::error_code error;
+       if (!bf::exists(path1)) {
+               return false;
+       }
        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());
        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());
@@ -443,7 +533,7 @@ bool copyFile(const bf::path& path1, const bf::path& path2) {
 }
 
 bool moveFile(const bf::path& path1, const bf::path& path2) {
 }
 
 bool moveFile(const bf::path& path1, const bf::path& path2) {
-       if (bf::exists(path2)) {
+       if (!bf::exists(path1) || bf::exists(path2)) {
                return false;
        }
        bs::error_code error;
                return false;
        }
        bs::error_code error;
index ba2c27f..7cfc1c9 100644 (file)
@@ -140,8 +140,8 @@ install -m 0644 %{name}.conf %{buildroot}/etc/tmpfiles.d/%{name}.conf
 %post
 mkdir -p /opt/etc/skel/.dotnet
 chsmack -t -a User::App::Shared /opt/etc/skel/.dotnet
 %post
 mkdir -p /opt/etc/skel/.dotnet
 chsmack -t -a User::App::Shared /opt/etc/skel/.dotnet
-%{_bindir}/nitool --dll %{_runtime_dir}/System.Private.CoreLib.dll
 chsmack -a _ %{_system_base_addr_file}
 chsmack -a _ %{_system_base_addr_file}
+%{_bindir}/dotnettool --ni-dll %{_runtime_dir}/System.Private.CoreLib.dll
 
 %files
 %manifest dotnet-launcher.manifest
 
 %files
 %manifest dotnet-launcher.manifest
@@ -151,7 +151,7 @@ chsmack -a _ %{_system_base_addr_file}
 %{_native_lib_dir}/libsqlite3.so
 %{_bindir}/nitool
 %{_bindir}/tpatool
 %{_native_lib_dir}/libsqlite3.so
 %{_bindir}/nitool
 %{_bindir}/tpatool
-%{_bindir}/tactool
+%{_bindir}/dotnettool
 %{_install_mdplugin_dir}/libprefer_nuget_cache_plugin.so
 %{_install_mdplugin_dir}/libprefer_dotnet_aot_plugin.so
 %{_bindir}/dotnet-launcher
 %{_install_mdplugin_dir}/libprefer_nuget_cache_plugin.so
 %{_install_mdplugin_dir}/libprefer_dotnet_aot_plugin.so
 %{_bindir}/dotnet-launcher
@@ -167,6 +167,7 @@ chsmack -a _ %{_system_base_addr_file}
 %manifest dotnet-launcher.manifest
 %defattr(-,root,root,-)
 %{_includedir}/ni_common.h
 %manifest dotnet-launcher.manifest
 %defattr(-,root,root,-)
 %{_includedir}/ni_common.h
+%{_includedir}/tac_common.h
 %{_includedir}/dotnet_launcher_plugin.h
 %{_includedir}/coreclr_host.h
 %{_libdir}/libdotnet_launcher_util.so
 %{_includedir}/dotnet_launcher_plugin.h
 %{_includedir}/coreclr_host.h
 %{_libdir}/libdotnet_launcher_util.so