From: j-h.choi Date: Tue, 15 Nov 2022 01:32:39 +0000 (+0900) Subject: Add TAC installer X-Git-Tag: accepted/tizen/unified/20221208.043843^0 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;ds=sidebyside;h=ad28ec22ddb18045ae65fac09feb9cb3aad19188;p=platform%2Fcore%2Fdotnet%2Flauncher.git Add TAC installer Change-Id: I69d7e46bdc9483b637664ece11213a91c0a99d25 --- diff --git a/NativeLauncher/CMakeLists.txt b/NativeLauncher/CMakeLists.txt index 302008a..0360af7 100644 --- a/NativeLauncher/CMakeLists.txt +++ b/NativeLauncher/CMakeLists.txt @@ -182,6 +182,7 @@ SET_TARGET_PROPERTIES(${DOTNET_HYDRA_LOADER} SET(TAC_COMMON "tac_common") SET(${TAC_COMMON}_SOURCE_FILES tool/tac_common.cc + tool/tac_installer.cc util/db_manager.cc ) ADD_LIBRARY(${TAC_COMMON} SHARED ${${TAC_COMMON}_SOURCE_FILES}) @@ -301,6 +302,7 @@ 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 inc/tac_installer.h DESTINATION ${INCLUDEDIR}) INSTALL(FILES inc/profile_common.h DESTINATION ${INCLUDEDIR}) INSTALL(FILES inc/privilege_common.h DESTINATION ${INCLUDEDIR}) INSTALL(FILES ../dotnet-launcher.pc DESTINATION ${LIBDIR}/pkgconfig) diff --git a/NativeLauncher/dotnet-launcher.pc.in b/NativeLauncher/dotnet-launcher.pc.in index cf3257d..9ab0305 100644 --- a/NativeLauncher/dotnet-launcher.pc.in +++ b/NativeLauncher/dotnet-launcher.pc.in @@ -5,5 +5,5 @@ includedir=@INCLUDEDIR@ Name: dotnet-launcher Description: Launchpad plugin for launching dotnet app and tools to generate ni files Version: @Version@ -Libs: -L${libdir} -ldotnet_launcher_util -lni_common +Libs: -L${libdir} -ldotnet_launcher_util -lni_common -ltac_common Cflags: -I${includedir} diff --git a/NativeLauncher/inc/launcher_env.h b/NativeLauncher/inc/launcher_env.h index 80f3253..8b481f2 100644 --- a/NativeLauncher/inc/launcher_env.h +++ b/NativeLauncher/inc/launcher_env.h @@ -21,7 +21,7 @@ #define ENV_FILE_PATH "/usr/share/dotnet.tizen/lib/coreclr_env.list" #define AOT_METADATA_KEY "http://tizen.org/metadata/prefer_dotnet_aot" #define TAC_METADATA_KEY "http://tizen.org/metadata/prefer_nuget_cache" -#define METADATA_VALUE "true" +#define METADATA_VALUE_TRUE "true" #define APP_NI_SUB_DIR ".native_image" #define TAC_SYMLINK_SUB_DIR ".tac_symlink" #define TAC_SHA_256_INFO ".SHA256.info" @@ -48,4 +48,4 @@ #error "Unknown target" #endif -#endif //__LAUNCHER_ENV_H_ \ No newline at end of file +#endif //__LAUNCHER_ENV_H_ diff --git a/NativeLauncher/inc/tac_installer.h b/NativeLauncher/inc/tac_installer.h new file mode 100644 index 0000000..7687704 --- /dev/null +++ b/NativeLauncher/inc/tac_installer.h @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2022 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_INSTALLER_H__ +#define __TAC_INSTALLER_H__ + +#include + +typedef enum { + TAC_STATE_NONE = 0, + TAC_STATE_INSTALL = 1, + TAC_STATE_UPGRADE = 2, + TAC_STATE_UNINSTALL = 3, + TAC_STATE_REMOVED = 4, + TAC_STATE_RESTORE = 5 +} tac_state; + +/** + * @brief Tac install + * @param[in] pkgId package ID + * @param[in] state state of tac + * @param[in] tacForce force TAC to package + * @return 0 if success, otherwise -1 + */ +int tacInstall(const std::string& pkgId, tac_state state, bool tacForce = false); + +/** + * @brief Tac upgrade + * @param[in] pkgId package ID + * @param[in] state state of tac + * @param[in] tacForce force TAC to package + * @return 0 if success, otherwise -1 + */ +int tacUpgrade(const std::string& pkgId, tac_state state, bool tacForce = false); + +/** + * @brief Tac uninstall + * @param[in] pkgId package ID + * @param[in] state state of tac + * @return 0 if success, otherwise -1 + */ +int tacUninstall(const std::string& pkgId, tac_state state); + +/** + * @brief Tac clean + * @param[in] pkgId package ID + * @return 0 if success, otherwise -1 + */ +int tacClean(const std::string& pkgId); + +/** + * @brief Tac remove + * @param[in] pkgId package ID + * @return 0 if success, otherwise -1 + */ +int tacRemoved(const std::string& pkgId); + +/** + * @brief Tac undo + * @param[in] pkgId package ID + * @return 0 if success, otherwise -1 + */ +int tacUndo(const std::string& pkgId); + +#endif /* __TAC_INSTALLER_H__ */ diff --git a/NativeLauncher/installer-plugin/prefer_dotnet_aot_plugin.cc b/NativeLauncher/installer-plugin/prefer_dotnet_aot_plugin.cc index 2ebd35f..91928a7 100644 --- a/NativeLauncher/installer-plugin/prefer_dotnet_aot_plugin.cc +++ b/NativeLauncher/installer-plugin/prefer_dotnet_aot_plugin.cc @@ -17,10 +17,11 @@ #include "ni_common.h" #include "log.h" #include "utils.h" -#include #include #include + +#include #include #include @@ -55,7 +56,7 @@ extern "C" int PKGMGR_MDPARSER_PLUGIN_INSTALL(const char *pkgId, const char *app return -1; } - if (metaValue == METADATA_VALUE) { + if (metaValue == METADATA_VALUE_TRUE) { _DBG("Prefer dotnet application AOT set TRUE"); if (initNICommon() != NI_ERROR_NONE) { diff --git a/NativeLauncher/installer-plugin/prefer_nuget_cache_plugin.cc b/NativeLauncher/installer-plugin/prefer_nuget_cache_plugin.cc index 0e785ce..02de1f4 100644 --- a/NativeLauncher/installer-plugin/prefer_nuget_cache_plugin.cc +++ b/NativeLauncher/installer-plugin/prefer_nuget_cache_plugin.cc @@ -14,1052 +14,41 @@ * limitations under the License. */ -#include "log.h" -#include "utils.h" -#include "db_manager.h" -#include "tac_common.h" +#include "tac_installer.h" -#include -#include -#include -#include -#include -#include #include -#include -#include #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* __DOTNET_DIR = __STR(DOTNET_DIR); -#undef __STR -#undef __XSTR - -std::vector nugetPackagesAssembliesSha; -std::vector tacDB; -std::vector createDirectories; -std::vector createLibraries; -std::vector updateTac; -std::string status = ""; -static sqlite3 *tac_db = NULL; -static sqlite3 *tlc_db = NULL; -bool tacPluginInstalled = false; -bool tacPluginFinished = false; - -static void createSHA256Info(std::string sha256Info, std::string nugetPackage) -{ - std::ofstream ofs(sha256Info, std::ios::app); - int assembly_count = 0; - for (auto& npAssemblySha : nugetPackagesAssembliesSha) { - std::string nuget_package_assembly = npAssemblySha.substr(0, npAssemblySha.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 sha = npAssemblySha.substr(npAssemblySha.rfind(':') + 1); - if (!strcmp(nuget_package.c_str(), nugetPackage.c_str())) { - ofs << assembly << ":" << sha << std::endl; - assembly_count++; - } - } - ofs << assembly_count << std::endl; - ofs.close(); -} - -static bool compareSHA256Info(std::string sha256Info, std::string nugetPackage) -{ - int compare_count = 0; - int assembly_count = 0; - std::string sha256_count = "0"; - for (auto& npAssemblySha : nugetPackagesAssembliesSha) { - std::string nuget_package_assembly = npAssemblySha.substr(0, npAssemblySha.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 sha = npAssemblySha.substr(npAssemblySha.rfind(':') + 1); - if (!strcmp(nuget_package.c_str(), nugetPackage.c_str())) { - assembly_count++; - std::ifstream ifs(sha256Info); - std::string get_str; - if (ifs.is_open()) { - while (getline(ifs, get_str)) { - if (!strcmp(get_str.c_str(), (assembly + ":" + sha).c_str())) { - compare_count++; - } - sha256_count = get_str; - } - ifs.close(); - } - } - } - if (!strcmp(std::to_string(assembly_count).c_str(), std::to_string(compare_count).c_str()) && - !strcmp(std::to_string(assembly_count).c_str(), sha256_count.c_str())) { - _INFO("Same nuget : %s", nugetPackage.c_str()); - return true; - } - return false; -} - -static bool copyAssemblyCreateSymlink(std::string binPath, std::string tacDir, std::string nugetPackage, bool isCreateTacDir) -{ - std::string tac_version_dir = concatPath(__DOTNET_DIR, nugetPackage); - bool nuget_restoration = false; - for (auto& npAssemblySha : nugetPackagesAssembliesSha) { - std::string nuget_package_assembly = npAssemblySha.substr(0, npAssemblySha.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); - if (!strcmp(nuget_package.c_str(), nugetPackage.c_str())) { - if (exist(concatPath(binPath, assembly))) { - if (isCreateTacDir) { - if (!copyFile(concatPath(binPath, assembly), concatPath(tac_version_dir, assembly))) { - _ERR("Failed to copy of %s", assembly.c_str()); - nuget_restoration = true; - break; - } - } - bs::error_code error; - bf::create_symlink(concatPath(tac_version_dir, assembly), concatPath(tacDir, assembly), error); - if (error) { - _ERR("Failed to create symlink %s file", concatPath(tacDir, assembly).c_str()); - nuget_restoration = true; - break; - } - copySmackAndOwnership(tacDir, concatPath(tacDir, assembly), true); - - if (!removeFile(concatPath(binPath, assembly))) { - _ERR("Failed to remove of %s", assembly.c_str()); - nuget_restoration = true; - break; - } - } - } - } - - if (nuget_restoration) { - for (auto& npAssemblySha : nugetPackagesAssembliesSha) { - std::string nuget_package_assembly = npAssemblySha.substr(0, npAssemblySha.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); - if (!strcmp(nuget_package.c_str(), nugetPackage.c_str())) { - copyFile(concatPath(tac_version_dir, assembly), concatPath(binPath, assembly)); - copySmackAndOwnership(binPath, concatPath(binPath, assembly)); - removeFile(concatPath(tacDir, assembly)); - } - } - } - - return nuget_restoration; -} - -static void copyLibraryCreateSymlink(const char* pkgId, std::vector LibrariesInfo, std::string tlcDir) -{ - if (LibrariesInfo.empty()) { - return; - } - - for (auto& librarySha : LibrariesInfo) { - std::string library = librarySha.substr(0, librarySha.find(':')); - std::string filename = library.substr(library.rfind('/') + 1); - std::string fileSha = filename + ".." + librarySha.substr(librarySha.find(':') + 1); - bool fileCopied = false; - if (!exist(concatPath(tlcDir, fileSha))) { - if (!copyFile(library, concatPath(tlcDir, fileSha))) { - _ERR("Failed to copy of %s", filename.c_str()); - continue; - } - fileCopied = true; - createLibraries.push_back(concatPath(tlcDir, fileSha)); - } - if (!removeFile(library)) { - _ERR("Failed to remove of %s", library.c_str()); - if (fileCopied) { - removeFile(concatPath(tlcDir, fileSha)); - } - continue; - } - bs::error_code error; - bf::create_symlink(concatPath(tlcDir, fileSha), library, error); - if (error) { - _ERR("Failed to create symlink %s file", library.c_str()); - copyFile(concatPath(tlcDir, fileSha), library); - copySmackAndOwnership(getBaseName(library), library); - if (fileCopied) { - removeFile(concatPath(tlcDir, fileSha)); - } - continue; - } - copySmackAndOwnership(getBaseName(library), library, true); - - char *sql = sqlite3_mprintf("INSERT INTO TLC (PKGID, LIBRARY) VALUES (%Q, %Q);", pkgId, fileSha.c_str()); - if (!insertDB(tlc_db, sql)) { - _ERR("Sqlite insert error"); - sqlite3_free(sql); - copyFile(concatPath(tlcDir, fileSha), library); - copySmackAndOwnership(getBaseName(library), library); - if (fileCopied) { - removeFile(concatPath(tlcDir, fileSha)); - } - continue; - } - sqlite3_free(sql); - } -} - -static void checkDepsJson(std::string rootPath, std::string binPath, std::string execName) -{ - for (auto& npAssembly : depsJsonParser(rootPath, execName)) { - std::string nuget_package = npAssembly.substr(0, npAssembly.rfind(':')); - std::string assembly_name = npAssembly.substr(npAssembly.rfind(':') + 1); - tacDB.push_back(nuget_package); - std::string buffer = SHA256(concatPath(binPath, assembly_name)); - nugetPackagesAssembliesSha.push_back(nuget_package + ":" + assembly_name + ":" + buffer); - _INFO("Assembly : [%s] / SHA256 : [%s]", assembly_name.c_str(), buffer.c_str()); - } - std::sort(tacDB.begin(), tacDB.end()); - tacDB.erase(unique(tacDB.begin(), tacDB.end()), tacDB.end()); -} - extern "C" int PKGMGR_MDPARSER_PLUGIN_INSTALL(const char *pkgId, const char *appId, GList *list) { - _DBG("[===== PKGMGR_MDPARSER_PLUGIN_INSTALL =====]"); - _INFO("PackageID : %s", pkgId); - - // Can be multiple apps in one package - if (tacPluginInstalled) { - _INFO("TAC plugin already installed"); - return 0; - } - tacPluginInstalled = true; - - std::string appType = getAppType(std::string(pkgId)); - if (strstr(appType.c_str(), "dotnet") == NULL) { - _ERR("App type is not dotnet"); - return 0; - } - std::string execName = getExecName(std::string(pkgId)); - std::string rootPath = getRootPath(std::string(pkgId)); - if (execName.empty() || rootPath.empty()) { - return 0; - } - std::string binPath = concatPath(rootPath, "bin"); - std::string metaValue = getMetadataValue(std::string(pkgId), TAC_METADATA_KEY); - if (metaValue.empty()) { - return 0; - } - if (metaValue == METADATA_VALUE) { - checkDepsJson(rootPath, binPath, execName); - } - - status = "install"; - if (tacDB.empty()) { - return 0; - } - - tac_db = createDB(TAC_APP_LIST_DB, CREATE_TAC_DB_TABLE); - if (!tac_db) { - _ERR("Sqlite create error. So restore the database."); - if (tac_restoreDB() != TAC_ERROR_NONE) { - _ERR("Sqlite create error"); - return -1; - } - tac_db = createDB(TAC_APP_LIST_DB, CREATE_TAC_DB_TABLE); - if (!tac_db) { - _ERR("Sqlite create error"); - return -1; - } - } - sqlite3_exec(tac_db, "BEGIN;", NULL, NULL, NULL); - - std::string tac_dir = concatPath(binPath, TAC_SYMLINK_SUB_DIR); - if (!createDir(tac_dir)) { - _ERR("Cannot create directory: %s", tac_dir.c_str()); - return 0; - } - copySmackAndOwnership(binPath.c_str(), tac_dir.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()); - - bs::error_code error; - std::string tac_version_dir = concatPath(__DOTNET_DIR, np); - std::string sha256_info = concatPath(tac_version_dir, TAC_SHA_256_INFO); - if (!exist(tac_version_dir)) { - _INFO("Create tac_version_dir [%s]", tac_version_dir.c_str()); - if (!createDir(tac_version_dir)) { - _ERR("Cannot create directory: %s", tac_version_dir.c_str()); - status = "restore"; - return -1; - } - createDirectories.push_back(tac_version_dir); - if (!isSymlinkFile(sha256_info)) { - createSHA256Info(sha256_info, np); - } else { - _ERR("Failed to create sha256_info. Symbolic link is detected"); - status = "restore"; - return -1; - } - - if (!exist(sha256_info)) { - status = "restore"; - return -1; - } - - if (copyAssemblyCreateSymlink(binPath, tac_dir, np, true)) { - _ERR("Failed to create symlink"); - status = "restore"; - return -1; - } - - char *sql = sqlite3_mprintf( - "INSERT INTO TAC (PKGID, NUGET, NAME, VERSION) " \ - "VALUES (%Q, %Q, %Q, %Q);", pkgId, np.c_str(), tac_name.c_str(), tac_version.c_str()); - if (!insertDB(tac_db, sql)) { - _ERR("Sqlite insert error"); - sqlite3_free(sql); - status = "restore"; - return -1; - } - sqlite3_free(sql); - } else { - _INFO("Exists tac_version_dir [%s]", tac_version_dir.c_str()); - if (!isSymlinkFile(sha256_info)) { - if (compareSHA256Info(sha256_info, np)) { - if (copyAssemblyCreateSymlink(binPath, tac_dir, np, false)) { - _ERR("Failed to create symlink"); - status = "restore"; - return -1; - } - - char *sql = sqlite3_mprintf( - "INSERT INTO TAC (PKGID, NUGET, NAME, VERSION) " \ - "VALUES (%Q, %Q, %Q, %Q);", pkgId, np.c_str(), tac_name.c_str(), tac_version.c_str()); - if (!insertDB(tac_db, sql)) { - _ERR("Sqlite insert error"); - sqlite3_free(sql); - status = "restore"; - return -1; - } - sqlite3_free(sql); - } else { - _INFO("Different nuget : %s", np.c_str()); - continue; - } - } else { - _ERR("Failed to create sha256_info. Symbolic link is detected"); - status = "restore"; - return -1; - } - } - } - - ///// TLC ///// - std::string tlcDir = concatPath(__DOTNET_DIR, TLC_LIBRARIES_DIR); - if (!createDir(tlcDir)) { - _ERR("Cannot create directory: %s", tlcDir.c_str()); - return 0; - } - copySmackAndOwnership(__DOTNET_DIR, tlcDir); - - tlc_db = createDB(TLC_APP_LIST_DB, CREATE_TLC_DB_TABLE); - if (!tlc_db) { - _ERR("Sqlite create error. So restore the database."); - if (tlc_restoreDB() != TAC_ERROR_NONE) { - _ERR("Sqlite create error"); - return 0; - } - tlc_db = createDB(TLC_APP_LIST_DB, CREATE_TLC_DB_TABLE); - if (!tlc_db) { - _ERR("Sqlite create error"); - return 0; - } - } - sqlite3_exec(tlc_db, "BEGIN;", NULL, NULL, NULL); - - copyLibraryCreateSymlink(pkgId, getLibrariesInfo(rootPath), tlcDir); - - return 0; -} - -static int sqliteCb(void *count, int argc, char **argv, char **colName) -{ - int *c = (int*)count; - *c = atoi(argv[0]); - return 0; -} - -static void tac_updateDB(sqlite3 *sqlite) -{ - for (auto& unp : updateTac) { - int count = -1; - char *sql = sqlite3_mprintf("SELECT COUNT(NUGET) FROM TAC WHERE NUGET = %Q;", unp.c_str()); - int ret = sqlite3_exec(sqlite, sql, sqliteCb, &count, NULL); - if (ret != SQLITE_OK) { - _ERR("Sqlite select error"); - sqlite3_free(sql); - continue; - } - if (count == 0) { - std::string tac_version_dir_prev = concatPath(__DOTNET_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()); - sqlite3_free(sql); - continue; - } - if (!removeAll(tac_version_dir_prev)) { - _ERR("Failed to remove of %s", tac_version_dir_prev.c_str()); - sqlite3_free(sql); - continue; - } - } - sqlite3_free(sql); - } -} - -static void tlc_updateDB(sqlite3 *sqlite, std::vector updateTlc, std::string tlcDir) -{ - for (auto& ulp : updateTlc) { - int count = -1; - char *sql = sqlite3_mprintf("SELECT COUNT(LIBRARY) FROM TLC WHERE LIBRARY = %Q;", ulp.c_str()); - int ret = sqlite3_exec(sqlite, sql, sqliteCb, &count, NULL); - if (ret != SQLITE_OK) { - _ERR("Sqlite select error"); - sqlite3_free(sql); - continue; - } - if (count == 0) { - std::string library_prev = concatPath(tlcDir, ulp); - std::string library_backup = library_prev + ".bck"; - if (!copyFile(library_prev, library_backup)) { - _ERR("Failed to copy of %s", library_prev.c_str()); - sqlite3_free(sql); - continue; - } - if (!removeFile(library_prev)) { - _ERR("Failed to remove of %s", library_prev.c_str()); - sqlite3_free(sql); - continue; - } - } - sqlite3_free(sql); - } + return tacInstall(std::string(pkgId), TAC_STATE_INSTALL); } extern "C" int PKGMGR_MDPARSER_PLUGIN_UPGRADE(const char *pkgId, const char *appId, GList *list) { - _DBG("[===== PKGMGR_MDPARSER_PLUGIN_UPGRADE =====]"); - _INFO("PackageID : %s", pkgId); - - // Can be multiple apps in one package - if (tacPluginInstalled) { - _INFO("TAC plugin already upgraded"); - return 0; - } - tacPluginInstalled = true; - - std::string appType = getAppType(std::string(pkgId)); - if (strstr(appType.c_str(), "dotnet") == NULL) { - _ERR("App type is not dotnet"); - return 0; - } - std::string execName = getExecName(std::string(pkgId)); - std::string rootPath = getRootPath(std::string(pkgId)); - if (execName.empty() || rootPath.empty()) { - return 0; - } - std::string binPath = concatPath(rootPath, "bin"); - - if (!strcmp("removed", status.c_str())) { - _INFO("Skipped to parse of deps.json"); - } else { - std::string metaValue = getMetadataValue(std::string(pkgId), TAC_METADATA_KEY); - if (metaValue.empty()) { - return 0; - } - if (metaValue == METADATA_VALUE) { - checkDepsJson(rootPath, binPath, execName); - } - } - - status = "update"; - tac_db = createDB(TAC_APP_LIST_DB, CREATE_TAC_DB_TABLE); - if (!tac_db) { - _ERR("Sqlite create error. So restore the database."); - if (tac_restoreDB() != TAC_ERROR_NONE) { - _ERR("Sqlite create error"); - return -1; - } - tac_db = createDB(TAC_APP_LIST_DB, CREATE_TAC_DB_TABLE); - if (!tac_db) { - _ERR("Sqlite create error"); - return -1; - } - } - sqlite3_exec(tac_db, "BEGIN;", NULL, NULL, NULL); - - char *sql = sqlite3_mprintf("SELECT * FROM TAC WHERE PKGID = %Q;", pkgId); - updateTac = selectDB(tac_db, sql); - sqlite3_free(sql); - - bool skipTLC = false; - if (tacDB.empty()) { - sql = sqlite3_mprintf("DELETE FROM TAC WHERE PKGID = %Q;", pkgId); - if (!deleteDB(tac_db, sql)) { - _ERR("Sqlite delete error"); - sqlite3_free(sql); - return -1; - } - sqlite3_free(sql); - - tac_updateDB(tac_db); - - skipTLC = true; - } else { - std::string tac_dir = concatPath(binPath, TAC_SYMLINK_SUB_DIR); - if (!createDir(tac_dir)) { - _ERR("Cannot create directory: %s", tac_dir.c_str()); - return 0; - } - copySmackAndOwnership(binPath.c_str(), tac_dir.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()); - - bs::error_code error; - std::string tac_version_dir = concatPath(__DOTNET_DIR, np); - std::string sha256_info = concatPath(tac_version_dir, TAC_SHA_256_INFO); - if (!exist(tac_version_dir)) { - _INFO("Create tac_version_dir [%s]", tac_version_dir.c_str()); - if (!createDir(tac_version_dir)) { - _ERR("Cannot create directory: %s", tac_version_dir.c_str()); - status = "restore"; - return -1; - } - createDirectories.push_back(tac_version_dir); - if (!isSymlinkFile(sha256_info)) { - createSHA256Info(sha256_info, np); - } else { - _ERR("Failed to create sha256_info. Symbolic link is detected"); - status = "restore"; - return -1; - } - - if (!exist(sha256_info)) { - status = "restore"; - return -1; - } - - if (copyAssemblyCreateSymlink(binPath, tac_dir, np, true)) { - _ERR("Failed to create symlink"); - status = "restore"; - return -1; - } - - int count = -1; - sql = sqlite3_mprintf( - "SELECT COUNT(NUGET) FROM TAC WHERE PKGID = %Q AND NAME = %Q;", pkgId, tac_name.c_str()); - int ret = sqlite3_exec(tac_db, sql, sqliteCb, &count, NULL); - if (ret != SQLITE_OK) { - _ERR("Sqlite select error"); - sqlite3_free(sql); - status = "restore"; - return -1; - } - sqlite3_free(sql); - if (count == 1) { - sql = sqlite3_mprintf( - "UPDATE TAC SET NAME = %Q, VERSION = %Q, NUGET = %Q WHERE PKGID = %Q AND NAME = %Q;", - tac_name.c_str(), tac_version.c_str(), np.c_str(), pkgId, tac_name.c_str()); - if (!updateDB(tac_db, sql)) { - _ERR("Sqlite update error"); - sqlite3_free(sql); - status = "restore"; - return -1; - } - sqlite3_free(sql); - } else if (count == 0) { - sql = sqlite3_mprintf( - "INSERT INTO TAC (PKGID, NUGET, NAME, VERSION) " \ - "VALUES (%Q, %Q, %Q, %Q);", pkgId, np.c_str(), tac_name.c_str(), tac_version.c_str()); - if (!insertDB(tac_db, sql)) { - _ERR("Sqlite insert error"); - sqlite3_free(sql); - status = "restore"; - return -1; - } - sqlite3_free(sql); - } - } else { - _INFO("Exists tac_version_dir [%s]", tac_version_dir.c_str()); - if (!isSymlinkFile(sha256_info)) { - if (compareSHA256Info(sha256_info, np)) { - if (copyAssemblyCreateSymlink(binPath, tac_dir, np, false)) { - _ERR("Failed to create symlink"); - status = "restore"; - return -1; - } - - int count = -1; - char *sql = sqlite3_mprintf( - "SELECT COUNT(NUGET) FROM TAC WHERE PKGID = %Q AND NAME = %Q;", pkgId, tac_name.c_str()); - int ret = sqlite3_exec(tac_db, sql, sqliteCb, &count, NULL); - if (ret != SQLITE_OK) { - _ERR("Sqlite select error"); - sqlite3_free(sql); - status = "restore"; - return -1; - } - sqlite3_free(sql); - if (count == 1) { - sql = sqlite3_mprintf( - "UPDATE TAC SET NAME = %Q, VERSION = %Q, NUGET = %Q WHERE PKGID = %Q AND NAME = %Q;", - tac_name.c_str(), tac_version.c_str(), np.c_str(), pkgId, tac_name.c_str()); - if (!updateDB(tac_db, sql)) { - _ERR("Sqlite update error"); - sqlite3_free(sql); - status = "restore"; - return -1; - } - sqlite3_free(sql); - } else if (count == 0) { - sql = sqlite3_mprintf( - "INSERT INTO TAC (PKGID, NUGET, NAME, VERSION) " \ - "VALUES (%Q, %Q, %Q, %Q);", pkgId, np.c_str(), tac_name.c_str(), tac_version.c_str()); - if (!insertDB(tac_db, sql)) { - _ERR("Sqlite insert error"); - sqlite3_free(sql); - status = "restore"; - return -1; - } - sqlite3_free(sql); - } - } else { - _INFO("Different nuget : %s", np.c_str()); - continue; - } - } else { - _ERR("Failed to create sha256_info. Symbolic link is detected"); - status = "restore"; - return -1; - } - } - } - for (auto& unp : updateTac) { - bool isExits = false; - for (auto& np : tacDB) { - if (!strcmp(unp.c_str(), np.c_str())) { - isExits = true; - break; - } - } - if (!isExits) { - char *sql = sqlite3_mprintf("DELETE FROM TAC WHERE PKGID = %Q AND NUGET = %Q;", pkgId, unp.c_str()); - if (!deleteDB(tac_db, sql)) { - _ERR("Sqlite delete error"); - sqlite3_free(sql); - status = "restore"; - return -1; - } - sqlite3_free(sql); - } - } - tac_updateDB(tac_db); - } - - ///// TLC ///// - std::string tlcDir = concatPath(__DOTNET_DIR, TLC_LIBRARIES_DIR); - if (!createDir(tlcDir)) { - _ERR("Cannot create directory: %s", tlcDir.c_str()); - return 0; - } - copySmackAndOwnership(__DOTNET_DIR, tlcDir); - - tlc_db = createDB(TLC_APP_LIST_DB, CREATE_TLC_DB_TABLE); - if (!tlc_db) { - _ERR("Sqlite create error. So restore the database."); - if (tlc_restoreDB() != TAC_ERROR_NONE) { - _ERR("Sqlite create error"); - return 0; - } - tlc_db = createDB(TLC_APP_LIST_DB, CREATE_TLC_DB_TABLE); - if (!tlc_db) { - _ERR("Sqlite create error"); - return 0; - } - } - sqlite3_exec(tlc_db, "BEGIN;", NULL, NULL, NULL); - - sql = sqlite3_mprintf("SELECT * FROM TLC WHERE PKGID = %Q;", pkgId); - std::vector updateTlc = selectDB(tlc_db, sql); - sqlite3_free(sql); - - sql = sqlite3_mprintf("DELETE FROM TLC WHERE PKGID = %Q;", pkgId); - if (!deleteDB(tlc_db, sql)) { - _ERR("Sqlite delete error"); - sqlite3_free(sql); - return 0; - } - sqlite3_free(sql); - - std::vector librariesInfo; - if (!skipTLC) { - librariesInfo = getLibrariesInfo(rootPath); - } - - copyLibraryCreateSymlink(pkgId, librariesInfo, tlcDir); - - tlc_updateDB(tlc_db, updateTlc, tlcDir); - - return 0; + return tacUpgrade(std::string(pkgId), TAC_STATE_UPGRADE); } extern "C" int PKGMGR_MDPARSER_PLUGIN_UNINSTALL(const char *pkgId, const char *appId, GList *list) { - _DBG("[===== PKGMGR_MDPARSER_PLUGIN_UNINSTALL =====]"); - _INFO("PackageID : %s", pkgId); - - // Can be multiple apps in one package - if (tacPluginInstalled) { - _INFO("TAC plugin already uninstalled"); - return 0; - } - tacPluginInstalled = true; - - status = "uninstall"; - tac_db = openDB(TAC_APP_LIST_DB); - if (!tac_db) { - _ERR("Sqlite open error. So restore the database."); - if (tac_restoreDB() != TAC_ERROR_NONE) { - _ERR("Sqlite open error"); - return -1; - } - tac_db = openDB(TAC_APP_LIST_DB); - if (!tac_db) { - _ERR("Sqlite open error"); - return -1; - } - } - sqlite3_exec(tac_db, "BEGIN;", NULL, NULL, NULL); - - char *sql = sqlite3_mprintf("SELECT * FROM TAC WHERE PKGID = %Q;", pkgId); - updateTac = selectDB(tac_db, sql); - sqlite3_free(sql); - - sql = sqlite3_mprintf("DELETE FROM TAC WHERE PKGID = %Q;", pkgId); - - if (!deleteDB(tac_db, sql)) { - _ERR("Sqlite delete error"); - sqlite3_free(sql); - status = "restore"; - return -1; - } - sqlite3_free(sql); - - tac_updateDB(tac_db); - - ///// TLC ///// - tlc_db = openDB(TLC_APP_LIST_DB); - if (!tlc_db) { - _ERR("Sqlite open error. So restore the database."); - if (tlc_restoreDB() != TAC_ERROR_NONE) { - _ERR("Sqlite open error"); - return 0; - } - tlc_db = openDB(TLC_APP_LIST_DB); - if (!tlc_db) { - _ERR("Sqlite open error"); - return 0; - } - } - sqlite3_exec(tlc_db, "BEGIN;", NULL, NULL, NULL); - - sql = sqlite3_mprintf("SELECT * FROM TLC WHERE PKGID = %Q;", pkgId); - std::vector updateTlc = selectDB(tlc_db, sql); - sqlite3_free(sql); - - sql = sqlite3_mprintf("DELETE FROM TLC WHERE PKGID = %Q;", pkgId); - if (!deleteDB(tlc_db, sql)) { - _ERR("Sqlite delete error"); - sqlite3_free(sql); - return 0; - } - sqlite3_free(sql); - - tlc_updateDB(tlc_db, updateTlc, concatPath(__DOTNET_DIR, TLC_LIBRARIES_DIR)); - - return 0; + return tacUninstall(std::string(pkgId), TAC_STATE_UNINSTALL); } extern "C" int PKGMGR_MDPARSER_PLUGIN_REMOVED(const char *pkgId, const char *appId, GList *list) { - _DBG("[===== PKGMGR_MDPARSER_PLUGIN_REMOVED =====]"); - _INFO("PackageID : %s", pkgId); - - status = "removed"; - - return PKGMGR_MDPARSER_PLUGIN_UPGRADE(pkgId, appId, list); -} - -void undoStep(std::string tac) -{ - std::string current_tac = concatPath(__DOTNET_DIR, tac.substr(0, tac.find('/'))); - try { - for (auto& bck : bf::recursive_directory_iterator(current_tac)) { - std::string bck_path = bck.path().string(); - if (bf::is_directory(bck_path) && strstr(bck_path.c_str(), ".bck") != NULL) { - if (!moveFile(bck_path, bck_path.substr(0, bck_path.rfind(".bck")))) { - _ERR("Failed to move %s", bck_path.c_str()); - } - break; - } - } - } catch (const bf::filesystem_error& error) { - _ERR("Failed to recursive directory: %s", error.what()); - return; - } - - ///// TLC ///// - auto convert = [](const std::string& path, const std::string& filename) { - if (filename.rfind(".bck") != std::string::npos) { - if (!moveFile(path, replaceAll(path, ".bck", ""))) { - _ERR("Failed to move %s", path.c_str()); - } - } - }; - - scanFilesInDirectory(concatPath(__DOTNET_DIR, TLC_LIBRARIES_DIR), convert, 0); -} - -void install_Undo() -{ - for (auto& cd : createDirectories) { - if (!removeAll(cd)) { - _ERR("Failed to remove of %s", cd.c_str()); - } - } - - for (auto& cl : createLibraries) { - if (!removeFile(cl)) { - _ERR("Failed to remove of %s", cl.c_str()); - } - } -} - -void unInstall_Undo() -{ - for (auto& unp : updateTac) { - undoStep(unp); - } -} - -void update_Undo() -{ - install_Undo(); - if (!tacDB.empty()) { - for (auto& np : tacDB) { - undoStep(np); - } - } - unInstall_Undo(); + return tacRemoved(std::string(pkgId)); } extern "C" int PKGMGR_MDPARSER_PLUGIN_UNDO(const char *pkgId, const char *appId, GList *list) { - _DBG("[===== PKGMGR_MDPARSER_PLUGIN_UNDO =====]"); - _INFO("PackageID : %s", pkgId); - - // Can be multiple apps in one package - if (tacPluginFinished) { - _INFO("TAC plugin already finished(UNDO)"); - return 0; - } - tacPluginFinished = true; - - if (!strcmp("install", status.c_str())) { - install_Undo(); - } else if (!strcmp("update", status.c_str())) { - update_Undo(); - } else if (!strcmp("uninstall", status.c_str())) { - unInstall_Undo(); - } else if (!strcmp("restore", status.c_str())) { - update_Undo(); - } - - if (tac_db) { - rollbackDB(tac_db); - tac_db = NULL; - } - - if (tlc_db) { - rollbackDB(tlc_db); - tlc_db = NULL; - } - - return 0; -} - -void changeOwnershipTAC(std::string current_tac) -{ - copySmackAndOwnership(__DOTNET_DIR, current_tac); - try { - for (auto& path : bf::recursive_directory_iterator(current_tac)) - copySmackAndOwnership(__DOTNET_DIR, path.path().string()); - } catch (const bf::filesystem_error& error) { - _ERR("Failed to recursive directory: %s", error.what()); - } -} - -void cleanStep(std::string tac) -{ - std::string current_tac = concatPath(__DOTNET_DIR, tac.substr(0, tac.find('/'))); - try { - for (auto& bck : bf::recursive_directory_iterator(current_tac)) { - std::string bck_path = bck.path().string(); - if (bf::is_directory(bck_path) && strstr(bck_path.c_str(), ".bck") != NULL) { - if (!removeAll(bck_path)) { - _ERR("Failed to remove of %s", bck_path.c_str()); - } - break; - } - } - - bool isExist = false; - for (auto& bck : bf::recursive_directory_iterator(current_tac)) { - std::string bck_path = bck.path().string(); - if (exist(bck_path) && bf::is_directory(bck_path) && strstr(bck_path.c_str(), ".bck") == NULL) { - isExist = true; - break; - } - } - if (!isExist) { - if (!removeAll(current_tac)) { - _ERR("Failed to remove of %s", current_tac.c_str()); - } - } - } catch (const bf::filesystem_error& error) { - _ERR("Failed to recursive directory: %s", error.what()); - return; - } - - ///// TLC ///// - auto convert = [](const std::string& path, const std::string& filename) { - if (filename.rfind(".bck") != std::string::npos) { - if (!removeFile(path)) { - _ERR("Failed to remove of %s", path.c_str()); - } - } - }; - - scanFilesInDirectory(concatPath(__DOTNET_DIR, TLC_LIBRARIES_DIR), convert, 0); -} - -void install_Clean() -{ - for (auto& cd : createDirectories) { - changeOwnershipTAC(cd); - copySmackAndOwnership(__DOTNET_DIR, cd.substr(0, cd.rfind('/'))); - } - - for (auto& cl : createLibraries) { - changeOwnershipTAC(cl); - } -} - -void unInstall_Clean() -{ - for (auto& unp : updateTac) { - cleanStep(unp); - } -} - -void update_Clean() -{ - install_Clean(); - if (!tacDB.empty()) { - for (auto& np : tacDB) { - cleanStep(np); - changeOwnershipTAC(concatPath(__DOTNET_DIR, np.substr(0, np.find('/')))); - } - } - unInstall_Clean(); + return tacUndo(std::string(pkgId)); } extern "C" int PKGMGR_MDPARSER_PLUGIN_CLEAN(const char *pkgId, const char *appId, GList *list) { - if (!strcmp("restore", status.c_str())) { - disableTACPackage(pkgId); - - std::string rootPath = getRootPath(std::string(pkgId)); - if (!rootPath.empty()) { - std::string binPath = concatPath(rootPath, "bin"); - removeAll(concatPath(binPath, TAC_SYMLINK_SUB_DIR)); - } - - std::string runtimesDir = concatPath(rootPath, "bin/runtimes"); - if (exist(runtimesDir)) { - char buffer[128]; - sprintf(buffer, "(tizen|linux|unix|base|any)(.\\d.\\d.\\d)?(-%s)?", ARCHITECTURE_IDENTIFIER); - std::regex pattern(buffer); - - try { - for (auto& path : bf::recursive_directory_iterator(runtimesDir)) { - std::string symPath = path.path().string(); - if (isDirectory(symPath) || !isSymlinkFile(symPath)) - continue; - std::string targetDir = symPath.substr(symPath.rfind("/runtimes/") + 10); - if (!std::regex_match(targetDir.substr(0, targetDir.find('/')), pattern)) - continue; - if (symPath.rfind(".so") == std::string::npos) - continue; - copyFile(bf::read_symlink(symPath).string(), symPath); - } - } catch (const bf::filesystem_error& error) { - _ERR("Failed to recursive directory: %s", error.what()); - } - } - - return PKGMGR_MDPARSER_PLUGIN_UNDO(pkgId, appId, list); - } - - _DBG("[===== PKGMGR_MDPARSER_PLUGIN_CLEAN =====]"); - _INFO("PackageID : %s", pkgId); - - // Can be multiple apps in one package - if (tacPluginFinished) { - _INFO("TAC plugin already finished(CLEAN)"); - return 0; - } - tacPluginFinished = true; - - if (!strcmp("install", status.c_str())) { - install_Clean(); - } else if (!strcmp("update", status.c_str())) { - update_Clean(); - } else if (!strcmp("uninstall", status.c_str())) { - unInstall_Clean(); - } - - if (tac_db) { - closeDB(tac_db); - tac_db = NULL; - copySmackAndOwnership(__DOTNET_DIR, TAC_APP_LIST_DB); - copySmackAndOwnership(__DOTNET_DIR, TAC_APP_LIST_DB + std::string("-journal")); - } - - if (tlc_db) { - closeDB(tlc_db); - tlc_db = NULL; - copySmackAndOwnership(__DOTNET_DIR, TLC_APP_LIST_DB); - copySmackAndOwnership(__DOTNET_DIR, TLC_APP_LIST_DB + std::string("-journal")); - } - - return 0; + return tacClean(std::string(pkgId)); } diff --git a/NativeLauncher/tool/ni_common.cc b/NativeLauncher/tool/ni_common.cc index 54e1c0b..9fe6e18 100644 --- a/NativeLauncher/tool/ni_common.cc +++ b/NativeLauncher/tool/ni_common.cc @@ -1171,7 +1171,7 @@ ni_error_e regenerateAppNI(NIOption* opt) if (ret != PMINFO_R_OK) return NI_ERROR_UNKNOWN; - ret = pkgmgrinfo_appinfo_metadata_filter_add(handle, AOT_METADATA_KEY, METADATA_VALUE); + ret = pkgmgrinfo_appinfo_metadata_filter_add(handle, AOT_METADATA_KEY, METADATA_VALUE_TRUE); if (ret != PMINFO_R_OK) { pkgmgrinfo_appinfo_metadata_filter_destroy(handle); return NI_ERROR_UNKNOWN; @@ -1240,7 +1240,7 @@ ni_error_e regenerateTACNI(NIOption* opt) return NI_ERROR_UNKNOWN; } - ret = pkgmgrinfo_appinfo_metadata_filter_add(handle, TAC_METADATA_KEY, METADATA_VALUE); + ret = pkgmgrinfo_appinfo_metadata_filter_add(handle, TAC_METADATA_KEY, METADATA_VALUE_TRUE); if (ret != PMINFO_R_OK) { pkgmgrinfo_appinfo_metadata_filter_destroy(handle); return NI_ERROR_UNKNOWN; diff --git a/NativeLauncher/tool/tac_common.cc b/NativeLauncher/tool/tac_common.cc index cea457c..7755565 100644 --- a/NativeLauncher/tool/tac_common.cc +++ b/NativeLauncher/tool/tac_common.cc @@ -163,7 +163,7 @@ tac_error_e tac_restoreDB() return TAC_ERROR_UNKNOWN; } - ret = pkgmgrinfo_appinfo_metadata_filter_add(handle, TAC_METADATA_KEY, METADATA_VALUE); + ret = pkgmgrinfo_appinfo_metadata_filter_add(handle, TAC_METADATA_KEY, METADATA_VALUE_TRUE); if (ret != PMINFO_R_OK) { pkgmgrinfo_appinfo_metadata_filter_destroy(handle); return TAC_ERROR_UNKNOWN; @@ -273,7 +273,7 @@ tac_error_e enableTACPackage(const std::string& pkgId) return TAC_ERROR_INVALID_PACKAGE; } - if (!strcmp(metaValue.c_str(), "true")) { + if (!strcmp(metaValue.c_str(), METADATA_VALUE_TRUE)) { std::string binDir = concatPath(rootPath, "bin"); std::string tacDir = concatPath(binDir, TAC_SYMLINK_SUB_DIR); std::string binNIDir = concatPath(binDir, APP_NI_SUB_DIR); @@ -504,7 +504,7 @@ tac_error_e tlc_restoreDB() return TAC_ERROR_UNKNOWN; } - ret = pkgmgrinfo_appinfo_metadata_filter_add(handle, TAC_METADATA_KEY, METADATA_VALUE); + ret = pkgmgrinfo_appinfo_metadata_filter_add(handle, TAC_METADATA_KEY, METADATA_VALUE_TRUE); if (ret != PMINFO_R_OK) { pkgmgrinfo_appinfo_metadata_filter_destroy(handle); return TAC_ERROR_UNKNOWN; diff --git a/NativeLauncher/tool/tac_installer.cc b/NativeLauncher/tool/tac_installer.cc new file mode 100644 index 0000000..6e7d377 --- /dev/null +++ b/NativeLauncher/tool/tac_installer.cc @@ -0,0 +1,1084 @@ +/* + * Copyright (c) 2022 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 "tac_common.h" +#include "tac_installer.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#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* __DOTNET_DIR = __STR(DOTNET_DIR); +#undef __STR +#undef __XSTR + +std::vector nugetPackagesAssembliesSha; +std::vector tacDB; +std::vector createDirectories; +std::vector createLibraries; +std::vector updateTac; +tac_state tacState = TAC_STATE_NONE; +static sqlite3 *tac_db = NULL; +static sqlite3 *tlc_db = NULL; +bool tacPluginInstalled = false; +bool tacPluginFinished = false; + +static void createSHA256Info(std::string sha256Info, std::string nugetPackage) +{ + std::ofstream ofs(sha256Info, std::ios::app); + int assembly_count = 0; + for (auto& npAssemblySha : nugetPackagesAssembliesSha) { + std::string nuget_package_assembly = npAssemblySha.substr(0, npAssemblySha.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 sha = npAssemblySha.substr(npAssemblySha.rfind(':') + 1); + if (!strcmp(nuget_package.c_str(), nugetPackage.c_str())) { + ofs << assembly << ":" << sha << std::endl; + assembly_count++; + } + } + ofs << assembly_count << std::endl; + ofs.close(); +} + +static bool compareSHA256Info(std::string sha256Info, std::string nugetPackage) +{ + int compare_count = 0; + int assembly_count = 0; + std::string sha256_count = "0"; + for (auto& npAssemblySha : nugetPackagesAssembliesSha) { + std::string nuget_package_assembly = npAssemblySha.substr(0, npAssemblySha.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 sha = npAssemblySha.substr(npAssemblySha.rfind(':') + 1); + if (!strcmp(nuget_package.c_str(), nugetPackage.c_str())) { + assembly_count++; + std::ifstream ifs(sha256Info); + std::string get_str; + if (ifs.is_open()) { + while (getline(ifs, get_str)) { + if (!strcmp(get_str.c_str(), (assembly + ":" + sha).c_str())) { + compare_count++; + } + sha256_count = get_str; + } + ifs.close(); + } + } + } + if (!strcmp(std::to_string(assembly_count).c_str(), std::to_string(compare_count).c_str()) && + !strcmp(std::to_string(assembly_count).c_str(), sha256_count.c_str())) { + _INFO("Same nuget : %s", nugetPackage.c_str()); + return true; + } + return false; +} + +static bool copyAssemblyCreateSymlink(std::string binPath, std::string tacDir, std::string nugetPackage, bool isCreateTacDir) +{ + std::string binNiPath = concatPath(binPath, APP_NI_SUB_DIR); + std::string tac_version_dir = concatPath(__DOTNET_DIR, nugetPackage); + bool nuget_restoration = false; + for (auto& npAssemblySha : nugetPackagesAssembliesSha) { + std::string nuget_package_assembly = npAssemblySha.substr(0, npAssemblySha.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); + if (!strcmp(nuget_package.c_str(), nugetPackage.c_str())) { + if (exist(concatPath(binPath, assembly))) { + std::string niFile = changeExtension(assembly, ".dll", ".ni.dll"); + bs::error_code error; + if (isCreateTacDir) { + if (!copyFile(concatPath(binPath, assembly), concatPath(tac_version_dir, assembly))) { + _ERR("Failed to copy of %s", assembly.c_str()); + nuget_restoration = true; + break; + } + if (!copyFile(concatPath(binNiPath, niFile), concatPath(tac_version_dir, niFile))) { + _ERR("Failed to copy of %s", niFile.c_str()); + } + } + bf::create_symlink(concatPath(tac_version_dir, assembly), concatPath(tacDir, assembly), error); + if (error) { + _ERR("Failed to create symlink %s file", concatPath(tacDir, assembly).c_str()); + nuget_restoration = true; + break; + } + if (exist(concatPath(tac_version_dir, niFile))) { + bf::create_symlink(concatPath(tac_version_dir, niFile), concatPath(tacDir, niFile), error); + if (error) { + _ERR("Failed to create symlink %s file", concatPath(tacDir, niFile).c_str()); + } + } + + copySmackAndOwnership(tacDir, concatPath(tacDir, assembly), true); + + if (!removeFile(concatPath(binPath, assembly))) { + _ERR("Failed to remove of %s", assembly.c_str()); + nuget_restoration = true; + break; + } + if (!removeFile(concatPath(binNiPath, niFile))) { + _ERR("Failed to remove of %s", niFile.c_str()); + } + } + } + } + + if (nuget_restoration) { + for (auto& npAssemblySha : nugetPackagesAssembliesSha) { + std::string nuget_package_assembly = npAssemblySha.substr(0, npAssemblySha.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); + if (!strcmp(nuget_package.c_str(), nugetPackage.c_str())) { + copyFile(concatPath(tac_version_dir, assembly), concatPath(binPath, assembly)); + copySmackAndOwnership(binPath, concatPath(binPath, assembly)); + removeFile(concatPath(tacDir, assembly)); + } + } + } + + return nuget_restoration; +} + +static void copyLibraryCreateSymlink(const std::string pkgId, std::vector LibrariesInfo, std::string tlcDir) +{ + if (LibrariesInfo.empty()) { + return; + } + + for (auto& librarySha : LibrariesInfo) { + std::string library = librarySha.substr(0, librarySha.find(':')); + std::string filename = library.substr(library.rfind('/') + 1); + std::string fileSha = filename + ".." + librarySha.substr(librarySha.find(':') + 1); + bool fileCopied = false; + if (!exist(concatPath(tlcDir, fileSha))) { + if (!copyFile(library, concatPath(tlcDir, fileSha))) { + _ERR("Failed to copy of %s", filename.c_str()); + continue; + } + fileCopied = true; + createLibraries.push_back(concatPath(tlcDir, fileSha)); + } + if (!removeFile(library)) { + _ERR("Failed to remove of %s", library.c_str()); + if (fileCopied) { + removeFile(concatPath(tlcDir, fileSha)); + } + continue; + } + bs::error_code error; + bf::create_symlink(concatPath(tlcDir, fileSha), library, error); + if (error) { + _ERR("Failed to create symlink %s file", library.c_str()); + copyFile(concatPath(tlcDir, fileSha), library); + copySmackAndOwnership(getBaseName(library), library); + if (fileCopied) { + removeFile(concatPath(tlcDir, fileSha)); + } + continue; + } + copySmackAndOwnership(getBaseName(library), library, true); + + char *sql = sqlite3_mprintf("INSERT INTO TLC (PKGID, LIBRARY) VALUES (%Q, %Q);", pkgId.c_str(), fileSha.c_str()); + if (!insertDB(tlc_db, sql)) { + _ERR("Sqlite insert error"); + sqlite3_free(sql); + copyFile(concatPath(tlcDir, fileSha), library); + copySmackAndOwnership(getBaseName(library), library); + if (fileCopied) { + removeFile(concatPath(tlcDir, fileSha)); + } + continue; + } + sqlite3_free(sql); + } +} + +static void checkDepsJson(std::string rootPath, std::string binPath, std::string execName) +{ + for (auto& npAssembly : depsJsonParser(rootPath, execName)) { + std::string nuget_package = npAssembly.substr(0, npAssembly.rfind(':')); + std::string assembly_name = npAssembly.substr(npAssembly.rfind(':') + 1); + tacDB.push_back(nuget_package); + std::string buffer = SHA256(concatPath(binPath, assembly_name)); + nugetPackagesAssembliesSha.push_back(nuget_package + ":" + assembly_name + ":" + buffer); + _INFO("Assembly : [%s] / SHA256 : [%s]", assembly_name.c_str(), buffer.c_str()); + } + std::sort(tacDB.begin(), tacDB.end()); + tacDB.erase(unique(tacDB.begin(), tacDB.end()), tacDB.end()); +} + +int tacInstall(const std::string& pkgId, tac_state state, bool tacForce) +{ + _DBG("[===== PKGMGR_MDPARSER_PLUGIN_INSTALL =====]"); + _INFO("PackageID : %s", pkgId.c_str()); + + // Can be multiple apps in one package + if (tacPluginInstalled) { + _INFO("TAC plugin already installed"); + return 0; + } + tacPluginInstalled = true; + + std::string appType = getAppType(pkgId); + if (strstr(appType.c_str(), "dotnet") == NULL) { + _ERR("App type is not dotnet"); + return 0; + } + std::string execName = getExecName(pkgId); + std::string rootPath = getRootPath(pkgId); + if (execName.empty() || rootPath.empty()) { + return 0; + } + + std::string binPath = concatPath(rootPath, "bin"); + std::string metaValue = getMetadataValue(pkgId, TAC_METADATA_KEY); + if (!tacForce) { + if (metaValue.empty()) { + return 0; + } + } + if (metaValue == METADATA_VALUE_TRUE || tacForce) { + checkDepsJson(rootPath, binPath, execName); + } + + tacState = state; + if (tacDB.empty()) { + return 0; + } + + tac_db = createDB(TAC_APP_LIST_DB, CREATE_TAC_DB_TABLE); + if (!tac_db) { + _ERR("Sqlite create error. So restore the database."); + if (tac_restoreDB() != TAC_ERROR_NONE) { + _ERR("Sqlite create error"); + return -1; + } + tac_db = createDB(TAC_APP_LIST_DB, CREATE_TAC_DB_TABLE); + if (!tac_db) { + _ERR("Sqlite create error"); + return -1; + } + } + sqlite3_exec(tac_db, "BEGIN;", NULL, NULL, NULL); + + std::string tac_dir = concatPath(binPath, TAC_SYMLINK_SUB_DIR); + if (!createDir(tac_dir)) { + _ERR("Cannot create directory: %s", tac_dir.c_str()); + return 0; + } + copySmackAndOwnership(binPath.c_str(), tac_dir.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()); + + bs::error_code error; + std::string tac_version_dir = concatPath(__DOTNET_DIR, np); + std::string sha256_info = concatPath(tac_version_dir, TAC_SHA_256_INFO); + if (!exist(tac_version_dir)) { + _INFO("Create tac_version_dir [%s]", tac_version_dir.c_str()); + if (!createDir(tac_version_dir)) { + _ERR("Cannot create directory: %s", tac_version_dir.c_str()); + tacState = TAC_STATE_RESTORE; + return -1; + } + createDirectories.push_back(tac_version_dir); + if (!isSymlinkFile(sha256_info)) { + createSHA256Info(sha256_info, np); + } else { + _ERR("Failed to create sha256_info. Symbolic link is detected"); + tacState = TAC_STATE_RESTORE; + return -1; + } + + if (!exist(sha256_info)) { + tacState = TAC_STATE_RESTORE; + return -1; + } + + if (copyAssemblyCreateSymlink(binPath, tac_dir, np, true)) { + _ERR("Failed to create symlink"); + tacState = TAC_STATE_RESTORE; + return -1; + } + + char *sql = sqlite3_mprintf( + "INSERT INTO TAC (PKGID, NUGET, NAME, VERSION) " \ + "VALUES (%Q, %Q, %Q, %Q);", pkgId.c_str(), np.c_str(), tac_name.c_str(), tac_version.c_str()); + if (!insertDB(tac_db, sql)) { + _ERR("Sqlite insert error"); + sqlite3_free(sql); + tacState = TAC_STATE_RESTORE; + return -1; + } + sqlite3_free(sql); + } else { + _INFO("Exists tac_version_dir [%s]", tac_version_dir.c_str()); + if (!isSymlinkFile(sha256_info)) { + if (compareSHA256Info(sha256_info, np)) { + if (copyAssemblyCreateSymlink(binPath, tac_dir, np, false)) { + _ERR("Failed to create symlink"); + tacState = TAC_STATE_RESTORE; + return -1; + } + + char *sql = sqlite3_mprintf( + "INSERT INTO TAC (PKGID, NUGET, NAME, VERSION) " \ + "VALUES (%Q, %Q, %Q, %Q);", pkgId.c_str(), np.c_str(), tac_name.c_str(), tac_version.c_str()); + if (!insertDB(tac_db, sql)) { + _ERR("Sqlite insert error"); + sqlite3_free(sql); + tacState = TAC_STATE_RESTORE; + return -1; + } + sqlite3_free(sql); + } else { + _INFO("Different nuget : %s", np.c_str()); + continue; + } + } else { + _ERR("Failed to create sha256_info. Symbolic link is detected"); + tacState = TAC_STATE_RESTORE; + return -1; + } + } + } + + ///// TLC ///// + std::string tlcDir = concatPath(__DOTNET_DIR, TLC_LIBRARIES_DIR); + if (!createDir(tlcDir)) { + _ERR("Cannot create directory: %s", tlcDir.c_str()); + return 0; + } + copySmackAndOwnership(__DOTNET_DIR, tlcDir); + + tlc_db = createDB(TLC_APP_LIST_DB, CREATE_TLC_DB_TABLE); + if (!tlc_db) { + _ERR("Sqlite create error. So restore the database."); + if (tlc_restoreDB() != TAC_ERROR_NONE) { + _ERR("Sqlite create error"); + return 0; + } + tlc_db = createDB(TLC_APP_LIST_DB, CREATE_TLC_DB_TABLE); + if (!tlc_db) { + _ERR("Sqlite create error"); + return 0; + } + } + sqlite3_exec(tlc_db, "BEGIN;", NULL, NULL, NULL); + + copyLibraryCreateSymlink(pkgId, getLibrariesInfo(rootPath), tlcDir); + + return 0; +} + +static int sqliteCb(void *count, int argc, char **argv, char **colName) +{ + int *c = (int*)count; + *c = atoi(argv[0]); + return 0; +} + +static void tac_updateDB(sqlite3 *sqlite) +{ + for (auto& unp : updateTac) { + int count = -1; + char *sql = sqlite3_mprintf("SELECT COUNT(NUGET) FROM TAC WHERE NUGET = %Q;", unp.c_str()); + int ret = sqlite3_exec(sqlite, sql, sqliteCb, &count, NULL); + if (ret != SQLITE_OK) { + _ERR("Sqlite select error"); + sqlite3_free(sql); + continue; + } + if (count == 0) { + std::string tac_version_dir_prev = concatPath(__DOTNET_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()); + sqlite3_free(sql); + continue; + } + if (!removeAll(tac_version_dir_prev)) { + _ERR("Failed to remove of %s", tac_version_dir_prev.c_str()); + sqlite3_free(sql); + continue; + } + } + sqlite3_free(sql); + } +} + +static void tlc_updateDB(sqlite3 *sqlite, std::vector updateTlc, std::string tlcDir) +{ + for (auto& ulp : updateTlc) { + int count = -1; + char *sql = sqlite3_mprintf("SELECT COUNT(LIBRARY) FROM TLC WHERE LIBRARY = %Q;", ulp.c_str()); + int ret = sqlite3_exec(sqlite, sql, sqliteCb, &count, NULL); + if (ret != SQLITE_OK) { + _ERR("Sqlite select error"); + sqlite3_free(sql); + continue; + } + if (count == 0) { + std::string library_prev = concatPath(tlcDir, ulp); + std::string library_backup = library_prev + ".bck"; + if (!copyFile(library_prev, library_backup)) { + _ERR("Failed to copy of %s", library_prev.c_str()); + sqlite3_free(sql); + continue; + } + if (!removeFile(library_prev)) { + _ERR("Failed to remove of %s", library_prev.c_str()); + sqlite3_free(sql); + continue; + } + } + sqlite3_free(sql); + } +} + +int tacUpgrade(const std::string& pkgId, tac_state state, bool tacForce) +{ + _DBG("[===== PKGMGR_MDPARSER_PLUGIN_UPGRADE =====]"); + _INFO("PackageID : %s", pkgId.c_str()); + + // Can be multiple apps in one package + if (tacPluginInstalled) { + _INFO("TAC plugin already upgraded"); + return 0; + } + tacPluginInstalled = true; + + std::string appType = getAppType(pkgId); + if (strstr(appType.c_str(), "dotnet") == NULL) { + _ERR("App type is not dotnet"); + return 0; + } + std::string execName = getExecName(pkgId); + std::string rootPath = getRootPath(pkgId); + if (execName.empty() || rootPath.empty()) { + return 0; + } + + std::string binPath = concatPath(rootPath, "bin"); + if (state == TAC_STATE_REMOVED) { + _INFO("Skipped to parse of deps.json"); + } else { //TAC_STATE_UPGRADE + std::string metaValue = getMetadataValue(pkgId, TAC_METADATA_KEY); + if (!tacForce) { + if (metaValue.empty()) { + return 0; + } + } + if (metaValue == METADATA_VALUE_TRUE || tacForce) { + checkDepsJson(rootPath, binPath, execName); + } + } + + tacState = TAC_STATE_UPGRADE; + tac_db = createDB(TAC_APP_LIST_DB, CREATE_TAC_DB_TABLE); + if (!tac_db) { + _ERR("Sqlite create error. So restore the database."); + if (tac_restoreDB() != TAC_ERROR_NONE) { + _ERR("Sqlite create error"); + return -1; + } + tac_db = createDB(TAC_APP_LIST_DB, CREATE_TAC_DB_TABLE); + if (!tac_db) { + _ERR("Sqlite create error"); + return -1; + } + } + sqlite3_exec(tac_db, "BEGIN;", NULL, NULL, NULL); + + char *sql = sqlite3_mprintf("SELECT * FROM TAC WHERE PKGID = %Q;", pkgId.c_str()); + updateTac = selectDB(tac_db, sql); + sqlite3_free(sql); + + bool skipTLC = false; + if (tacDB.empty()) { + sql = sqlite3_mprintf("DELETE FROM TAC WHERE PKGID = %Q;", pkgId.c_str()); + if (!deleteDB(tac_db, sql)) { + _ERR("Sqlite delete error"); + sqlite3_free(sql); + return -1; + } + sqlite3_free(sql); + + tac_updateDB(tac_db); + + skipTLC = true; + } else { + std::string tac_dir = concatPath(binPath, TAC_SYMLINK_SUB_DIR); + if (!createDir(tac_dir)) { + _ERR("Cannot create directory: %s", tac_dir.c_str()); + return 0; + } + copySmackAndOwnership(binPath.c_str(), tac_dir.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()); + + bs::error_code error; + std::string tac_version_dir = concatPath(__DOTNET_DIR, np); + std::string sha256_info = concatPath(tac_version_dir, TAC_SHA_256_INFO); + if (!exist(tac_version_dir)) { + _INFO("Create tac_version_dir [%s]", tac_version_dir.c_str()); + if (!createDir(tac_version_dir)) { + _ERR("Cannot create directory: %s", tac_version_dir.c_str()); + tacState = TAC_STATE_RESTORE; + return -1; + } + createDirectories.push_back(tac_version_dir); + if (!isSymlinkFile(sha256_info)) { + createSHA256Info(sha256_info, np); + } else { + _ERR("Failed to create sha256_info. Symbolic link is detected"); + tacState = TAC_STATE_RESTORE; + return -1; + } + + if (!exist(sha256_info)) { + tacState = TAC_STATE_RESTORE; + return -1; + } + + if (copyAssemblyCreateSymlink(binPath, tac_dir, np, true)) { + _ERR("Failed to create symlink"); + tacState = TAC_STATE_RESTORE; + return -1; + } + + int count = -1; + sql = sqlite3_mprintf( + "SELECT COUNT(NUGET) FROM TAC WHERE PKGID = %Q AND NAME = %Q;", pkgId.c_str(), tac_name.c_str()); + int ret = sqlite3_exec(tac_db, sql, sqliteCb, &count, NULL); + if (ret != SQLITE_OK) { + _ERR("Sqlite select error"); + sqlite3_free(sql); + tacState = TAC_STATE_RESTORE; + return -1; + } + sqlite3_free(sql); + if (count == 1) { + sql = sqlite3_mprintf( + "UPDATE TAC SET NAME = %Q, VERSION = %Q, NUGET = %Q WHERE PKGID = %Q AND NAME = %Q;", + tac_name.c_str(), tac_version.c_str(), np.c_str(), pkgId.c_str(), tac_name.c_str()); + if (!updateDB(tac_db, sql)) { + _ERR("Sqlite update error"); + sqlite3_free(sql); + tacState = TAC_STATE_RESTORE; + return -1; + } + sqlite3_free(sql); + } else if (count == 0) { + sql = sqlite3_mprintf( + "INSERT INTO TAC (PKGID, NUGET, NAME, VERSION) " \ + "VALUES (%Q, %Q, %Q, %Q);", pkgId.c_str(), np.c_str(), tac_name.c_str(), tac_version.c_str()); + if (!insertDB(tac_db, sql)) { + _ERR("Sqlite insert error"); + sqlite3_free(sql); + tacState = TAC_STATE_RESTORE; + return -1; + } + sqlite3_free(sql); + } + } else { + _INFO("Exists tac_version_dir [%s]", tac_version_dir.c_str()); + if (!isSymlinkFile(sha256_info)) { + if (compareSHA256Info(sha256_info, np)) { + if (copyAssemblyCreateSymlink(binPath, tac_dir, np, false)) { + _ERR("Failed to create symlink"); + tacState = TAC_STATE_RESTORE; + return -1; + } + + int count = -1; + char *sql = sqlite3_mprintf( + "SELECT COUNT(NUGET) FROM TAC WHERE PKGID = %Q AND NAME = %Q;", pkgId.c_str(), tac_name.c_str()); + int ret = sqlite3_exec(tac_db, sql, sqliteCb, &count, NULL); + if (ret != SQLITE_OK) { + _ERR("Sqlite select error"); + sqlite3_free(sql); + tacState = TAC_STATE_RESTORE; + return -1; + } + sqlite3_free(sql); + if (count == 1) { + sql = sqlite3_mprintf( + "UPDATE TAC SET NAME = %Q, VERSION = %Q, NUGET = %Q WHERE PKGID = %Q AND NAME = %Q;", + tac_name.c_str(), tac_version.c_str(), np.c_str(), pkgId.c_str(), tac_name.c_str()); + if (!updateDB(tac_db, sql)) { + _ERR("Sqlite update error"); + sqlite3_free(sql); + tacState = TAC_STATE_RESTORE; + return -1; + } + sqlite3_free(sql); + } else if (count == 0) { + sql = sqlite3_mprintf( + "INSERT INTO TAC (PKGID, NUGET, NAME, VERSION) " \ + "VALUES (%Q, %Q, %Q, %Q);", pkgId.c_str(), np.c_str(), tac_name.c_str(), tac_version.c_str()); + if (!insertDB(tac_db, sql)) { + _ERR("Sqlite insert error"); + sqlite3_free(sql); + tacState = TAC_STATE_RESTORE; + return -1; + } + sqlite3_free(sql); + } + } else { + _INFO("Different nuget : %s", np.c_str()); + continue; + } + } else { + _ERR("Failed to create sha256_info. Symbolic link is detected"); + tacState = TAC_STATE_RESTORE; + return -1; + } + } + } + for (auto& unp : updateTac) { + bool isExits = false; + for (auto& np : tacDB) { + if (!strcmp(unp.c_str(), np.c_str())) { + isExits = true; + break; + } + } + if (!isExits) { + char *sql = sqlite3_mprintf("DELETE FROM TAC WHERE PKGID = %Q AND NUGET = %Q;", pkgId.c_str(), unp.c_str()); + if (!deleteDB(tac_db, sql)) { + _ERR("Sqlite delete error"); + sqlite3_free(sql); + tacState = TAC_STATE_RESTORE; + return -1; + } + sqlite3_free(sql); + } + } + tac_updateDB(tac_db); + } + + ///// TLC ///// + std::string tlcDir = concatPath(__DOTNET_DIR, TLC_LIBRARIES_DIR); + if (!createDir(tlcDir)) { + _ERR("Cannot create directory: %s", tlcDir.c_str()); + return 0; + } + copySmackAndOwnership(__DOTNET_DIR, tlcDir); + + tlc_db = createDB(TLC_APP_LIST_DB, CREATE_TLC_DB_TABLE); + if (!tlc_db) { + _ERR("Sqlite create error. So restore the database."); + if (tlc_restoreDB() != TAC_ERROR_NONE) { + _ERR("Sqlite create error"); + return 0; + } + tlc_db = createDB(TLC_APP_LIST_DB, CREATE_TLC_DB_TABLE); + if (!tlc_db) { + _ERR("Sqlite create error"); + return 0; + } + } + sqlite3_exec(tlc_db, "BEGIN;", NULL, NULL, NULL); + + sql = sqlite3_mprintf("SELECT * FROM TLC WHERE PKGID = %Q;", pkgId.c_str()); + std::vector updateTlc = selectDB(tlc_db, sql); + sqlite3_free(sql); + + sql = sqlite3_mprintf("DELETE FROM TLC WHERE PKGID = %Q;", pkgId.c_str()); + if (!deleteDB(tlc_db, sql)) { + _ERR("Sqlite delete error"); + sqlite3_free(sql); + return 0; + } + sqlite3_free(sql); + + std::vector librariesInfo; + if (!skipTLC) { + librariesInfo = getLibrariesInfo(rootPath); + } + + copyLibraryCreateSymlink(pkgId, librariesInfo, tlcDir); + + tlc_updateDB(tlc_db, updateTlc, tlcDir); + + return 0; +} + +int tacUninstall(const std::string& pkgId, tac_state state) +{ + _DBG("[===== PKGMGR_MDPARSER_PLUGIN_UNINSTALL =====]"); + _INFO("PackageID : %s", pkgId.c_str()); + + // Can be multiple apps in one package + if (tacPluginInstalled) { + _INFO("TAC plugin already uninstalled"); + return 0; + } + tacPluginInstalled = true; + + tacState= state; + tac_db = openDB(TAC_APP_LIST_DB); + if (!tac_db) { + _ERR("Sqlite open error. So restore the database."); + if (tac_restoreDB() != TAC_ERROR_NONE) { + _ERR("Sqlite open error"); + return -1; + } + tac_db = openDB(TAC_APP_LIST_DB); + if (!tac_db) { + _ERR("Sqlite open error"); + return -1; + } + } + sqlite3_exec(tac_db, "BEGIN;", NULL, NULL, NULL); + + char *sql = sqlite3_mprintf("SELECT * FROM TAC WHERE PKGID = %Q;", pkgId.c_str()); + updateTac = selectDB(tac_db, sql); + sqlite3_free(sql); + + sql = sqlite3_mprintf("DELETE FROM TAC WHERE PKGID = %Q;", pkgId.c_str()); + + if (!deleteDB(tac_db, sql)) { + _ERR("Sqlite delete error"); + sqlite3_free(sql); + tacState = TAC_STATE_RESTORE; + return -1; + } + sqlite3_free(sql); + + tac_updateDB(tac_db); + + ///// TLC ///// + tlc_db = openDB(TLC_APP_LIST_DB); + if (!tlc_db) { + _ERR("Sqlite open error. So restore the database."); + if (tlc_restoreDB() != TAC_ERROR_NONE) { + _ERR("Sqlite open error"); + return 0; + } + tlc_db = openDB(TLC_APP_LIST_DB); + if (!tlc_db) { + _ERR("Sqlite open error"); + return 0; + } + } + sqlite3_exec(tlc_db, "BEGIN;", NULL, NULL, NULL); + + sql = sqlite3_mprintf("SELECT * FROM TLC WHERE PKGID = %Q;", pkgId.c_str()); + std::vector updateTlc = selectDB(tlc_db, sql); + sqlite3_free(sql); + + sql = sqlite3_mprintf("DELETE FROM TLC WHERE PKGID = %Q;", pkgId.c_str()); + if (!deleteDB(tlc_db, sql)) { + _ERR("Sqlite delete error"); + sqlite3_free(sql); + return 0; + } + sqlite3_free(sql); + + tlc_updateDB(tlc_db, updateTlc, concatPath(__DOTNET_DIR, TLC_LIBRARIES_DIR)); + + return 0; +} + +int tacRemoved(const std::string& pkgId) +{ + _DBG("[===== PKGMGR_MDPARSER_PLUGIN_REMOVED =====]"); + _INFO("PackageID : %s", pkgId.c_str()); + + return tacUpgrade(pkgId, TAC_STATE_REMOVED); +} + +void undoStep(std::string tac) +{ + std::string current_tac = concatPath(__DOTNET_DIR, tac.substr(0, tac.find('/'))); + try { + for (auto& bck : bf::recursive_directory_iterator(current_tac)) { + std::string bck_path = bck.path().string(); + if (bf::is_directory(bck_path) && strstr(bck_path.c_str(), ".bck") != NULL) { + if (!moveFile(bck_path, bck_path.substr(0, bck_path.rfind(".bck")))) { + _ERR("Failed to move %s", bck_path.c_str()); + } + break; + } + } + } catch (const bf::filesystem_error& error) { + _ERR("Failed to recursive directory: %s", error.what()); + return; + } + + ///// TLC ///// + auto convert = [](const std::string& path, const std::string& filename) { + if (filename.rfind(".bck") != std::string::npos) { + if (!moveFile(path, replaceAll(path, ".bck", ""))) { + _ERR("Failed to move %s", path.c_str()); + } + } + }; + + scanFilesInDirectory(concatPath(__DOTNET_DIR, TLC_LIBRARIES_DIR), convert, 0); +} + +void install_Undo() +{ + for (auto& cd : createDirectories) { + if (!removeAll(cd)) { + _ERR("Failed to remove of %s", cd.c_str()); + } + } + + for (auto& cl : createLibraries) { + if (!removeFile(cl)) { + _ERR("Failed to remove of %s", cl.c_str()); + } + } +} + +void unInstall_Undo() +{ + for (auto& unp : updateTac) { + undoStep(unp); + } +} + +void update_Undo() +{ + install_Undo(); + if (!tacDB.empty()) { + for (auto& np : tacDB) { + undoStep(np); + } + } + unInstall_Undo(); +} + +int tacUndo(const std::string& pkgId) +{ + _DBG("[===== PKGMGR_MDPARSER_PLUGIN_UNDO =====]"); + _INFO("PackageID : %s", pkgId.c_str()); + + // Can be multiple apps in one package + if (tacPluginFinished) { + _INFO("TAC plugin already finished(UNDO)"); + return 0; + } + tacPluginFinished = true; + + if (tacState == TAC_STATE_INSTALL) { + install_Undo(); + } else if (tacState == TAC_STATE_UPGRADE) { + update_Undo(); + } else if (tacState == TAC_STATE_UNINSTALL) { + unInstall_Undo(); + } else if (tacState == TAC_STATE_RESTORE) { + update_Undo(); + } + + if (tac_db) { + rollbackDB(tac_db); + tac_db = NULL; + } + + if (tlc_db) { + rollbackDB(tlc_db); + tlc_db = NULL; + } + + return 0; +} + +void changeOwnershipTAC(std::string current_tac) +{ + copySmackAndOwnership(__DOTNET_DIR, current_tac); + try { + for (auto& path : bf::recursive_directory_iterator(current_tac)) + copySmackAndOwnership(__DOTNET_DIR, path.path().string()); + } catch (const bf::filesystem_error& error) { + _ERR("Failed to recursive directory: %s", error.what()); + } +} + +void cleanStep(std::string tac) +{ + std::string current_tac = concatPath(__DOTNET_DIR, tac.substr(0, tac.find('/'))); + try { + for (auto& bck : bf::recursive_directory_iterator(current_tac)) { + std::string bck_path = bck.path().string(); + if (bf::is_directory(bck_path) && strstr(bck_path.c_str(), ".bck") != NULL) { + if (!removeAll(bck_path)) { + _ERR("Failed to remove of %s", bck_path.c_str()); + } + break; + } + } + + bool isExist = false; + for (auto& bck : bf::recursive_directory_iterator(current_tac)) { + std::string bck_path = bck.path().string(); + if (exist(bck_path) && bf::is_directory(bck_path) && strstr(bck_path.c_str(), ".bck") == NULL) { + isExist = true; + break; + } + } + if (!isExist) { + if (!removeAll(current_tac)) { + _ERR("Failed to remove of %s", current_tac.c_str()); + } + } + } catch (const bf::filesystem_error& error) { + _ERR("Failed to recursive directory: %s", error.what()); + return; + } + + ///// TLC ///// + auto convert = [](const std::string& path, const std::string& filename) { + if (filename.rfind(".bck") != std::string::npos) { + if (!removeFile(path)) { + _ERR("Failed to remove of %s", path.c_str()); + } + } + }; + + scanFilesInDirectory(concatPath(__DOTNET_DIR, TLC_LIBRARIES_DIR), convert, 0); +} + +void install_Clean() +{ + for (auto& cd : createDirectories) { + changeOwnershipTAC(cd); + copySmackAndOwnership(__DOTNET_DIR, cd.substr(0, cd.rfind('/'))); + } + + for (auto& cl : createLibraries) { + changeOwnershipTAC(cl); + } +} + +void unInstall_Clean() +{ + for (auto& unp : updateTac) { + cleanStep(unp); + } +} + +void update_Clean() +{ + install_Clean(); + if (!tacDB.empty()) { + for (auto& np : tacDB) { + cleanStep(np); + changeOwnershipTAC(concatPath(__DOTNET_DIR, np.substr(0, np.find('/')))); + } + } + unInstall_Clean(); +} + +int tacClean(const std::string& pkgId) +{ + if (tacState == TAC_STATE_RESTORE) { + disableTACPackage(pkgId); + + std::string rootPath = getRootPath(pkgId); + if (!rootPath.empty()) { + std::string binPath = concatPath(rootPath, "bin"); + removeAll(concatPath(binPath, TAC_SYMLINK_SUB_DIR)); + } + + std::string runtimesDir = concatPath(rootPath, "bin/runtimes"); + if (exist(runtimesDir)) { + char buffer[128]; + sprintf(buffer, "(tizen|linux|unix|base|any)(.\\d.\\d.\\d)?(-%s)?", ARCHITECTURE_IDENTIFIER); + std::regex pattern(buffer); + + try { + for (auto& path : bf::recursive_directory_iterator(runtimesDir)) { + std::string symPath = path.path().string(); + if (isDirectory(symPath) || !isSymlinkFile(symPath)) + continue; + std::string targetDir = symPath.substr(symPath.rfind("/runtimes/") + 10); + if (!std::regex_match(targetDir.substr(0, targetDir.find('/')), pattern)) + continue; + if (symPath.rfind(".so") == std::string::npos) + continue; + copyFile(bf::read_symlink(symPath).string(), symPath); + } + } catch (const bf::filesystem_error& error) { + _ERR("Failed to recursive directory: %s", error.what()); + } + } + + return tacUndo(pkgId); + } + + _DBG("[===== PKGMGR_MDPARSER_PLUGIN_CLEAN =====]"); + _INFO("PackageID : %s", pkgId.c_str()); + + // Can be multiple apps in one package + if (tacPluginFinished) { + _INFO("TAC plugin already finished(CLEAN)"); + return 0; + } + tacPluginFinished = true; + + if (tacState == TAC_STATE_INSTALL) { + install_Clean(); + } else if (tacState == TAC_STATE_UPGRADE) { + update_Clean(); + } else if (tacState == TAC_STATE_UNINSTALL) { + unInstall_Clean(); + } + + if (tac_db) { + closeDB(tac_db); + tac_db = NULL; + copySmackAndOwnership(__DOTNET_DIR, TAC_APP_LIST_DB); + copySmackAndOwnership(__DOTNET_DIR, TAC_APP_LIST_DB + std::string("-journal")); + } + + if (tlc_db) { + closeDB(tlc_db); + tlc_db = NULL; + copySmackAndOwnership(__DOTNET_DIR, TLC_APP_LIST_DB); + copySmackAndOwnership(__DOTNET_DIR, TLC_APP_LIST_DB + std::string("-journal")); + } + + return 0; +} + diff --git a/packaging/dotnet-launcher.spec b/packaging/dotnet-launcher.spec index 50b48f9..83533a5 100644 --- a/packaging/dotnet-launcher.spec +++ b/packaging/dotnet-launcher.spec @@ -235,6 +235,7 @@ chsmack -a User /usr/bin/dotnet-nui-loader %defattr(-,root,root,-) %{_includedir}/ni_common.h %{_includedir}/tac_common.h +%{_includedir}/tac_installer.h %{_includedir}/profile_common.h %{_includedir}/privilege_common.h %{_includedir}/dotnet_launcher_plugin.h