/* * 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 #include #include #include "log.h" #include "utils.h" #include "ni_common.h" #include "tac_common.h" #include "db_manager.h" #include "path_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 restoreNuget; void cleanupDirectory() { std::vector removeNuget; try { for (auto& nuget : bf::recursive_directory_iterator(__TAC_DIR)) { bool isExist = false; std::string nugetPath = nuget.path().string(); for (auto& restore : restoreNuget) { if (!bf::is_directory(nugetPath)) { isExist = true; } if (strstr(nugetPath.c_str(), restore.c_str()) != NULL) { isExist = true; break; } } if (!isExist) { removeNuget.push_back(nugetPath); } } for (auto& rm : removeNuget) { if (!removeAll(rm)) { _ERR("Failed to remove of %s", rm.c_str()); } } removeNuget.clear(); } catch (const bf::filesystem_error& error) { _ERR("Failed to recursive directory: %s", error.what()); return; } } // 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::vector parserData; for (auto& npAssembly : depsJsonParser(rootPath, execName, getTPA())) { std::string nugetPackage = npAssembly.substr(0, npAssembly.rfind(':')); parserData.push_back(nugetPackage); } std::sort(parserData.begin(), parserData.end()); parserData.erase(unique(parserData.begin(), parserData.end()), parserData.end()); for (auto& nuget : parserData) { if (tac_db) { 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 ('" + std::string(pkgId) + "', '" + nuget + "', '" + name + "', '" + version + "');"; dbInsert(tac_db, TAC_APP_LIST_RESTORE_DB, sql); restoreNuget.push_back(concatPath(__TAC_DIR, name)); } } parserData.clear(); 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; } if (initializePathManager(std::string(), std::string(), std::string())) { fprintf(stderr, "Fail to initialize PathManger"); 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 copy 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 copy 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 tacNativeImage; std::string binDir = concatPath(pkgRoot, "bin"); std::string tacDir = concatPath(binDir, TAC_SYMLINK_SUB_DIR); if (bf::exists(tacDir)) { try { 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(); } catch (const bf::filesystem_error& error) { _ERR("Failed to recursive directory: %s", error.what()); return TAC_ERROR_UNKNOWN; } } 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)) { try { 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) != 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; } } } } } } catch (const bf::filesystem_error& error) { _ERR("Failed to recursive directory: %s", error.what()); 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) != 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)) { try { 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)) { std::string dllPath = concatPath(binDir, fileName); if (!copyFile(originPath, dllPath)) { fprintf(stderr, "Failed to copy of %s\n", dllPath.c_str()); return TAC_ERROR_UNKNOWN; } updateAssemblyInfo(binDir.c_str(), concatPath(binDir, fileName).c_str()); } else { std::string niPath = concatPath(binNIDir, fileName); if (!copyFile(originPath, niPath)) { fprintf(stderr, "Failed to copy of %s\n", niPath.c_str()); return TAC_ERROR_UNKNOWN; } updateAssemblyInfo(binDir.c_str(), niPath.c_str()); } } } if (!removeAll(tacDir)) { fprintf(stderr, "Failed to remove of %s\n", tacDir.c_str()); return TAC_ERROR_UNKNOWN; } } catch (const bf::filesystem_error& error) { _ERR("Failed to recursive directory: %s", error.what()); return TAC_ERROR_UNKNOWN; } } return TAC_ERROR_NONE; } tac_error_e enableTACPackage(const std::string& pkgId) { std::string rootPath; if (getRootPath(pkgId, rootPath) < 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 (initializePathManager(std::string(), std::string(), std::string())) { fprintf(stderr, "Fail to initialize PathManger"); return TAC_ERROR_UNKNOWN; } if (!strcmp(metaValue.c_str(), "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); 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::vector enableNuget; for (auto& npAssembly : depsJsonParser(rootPath, execName, getTPA())) { std::string nugetPackage = npAssembly.substr(0, npAssembly.rfind(':')); std::string assemblyName = npAssembly.substr(npAssembly.rfind(':') + 1); std::string nugetPath = concatPath(__TAC_DIR, nugetPackage); if (bf::exists(nugetPath)) { std::string originPath = concatPath(nugetPath, assemblyName); if (bf::exists(originPath)) { enableNuget.push_back(originPath); } } } 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()); } } enableNuget.clear(); } } else { fprintf(stderr, "The metadata key is missing or the metadata value is false of [%s]\n", pkgId.c_str()); } return TAC_ERROR_NONE; }