2 * Copyright (c) 2022 Samsung Electronics Co., Ltd All Rights Reserved
4 * Licensed under the Apache License, Version 2.0 (the License);
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an AS IS BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
19 #include "db_manager.h"
20 #include "tac_common.h"
21 #include "tac_installer.h"
29 #include <boost/filesystem.hpp>
30 #include <json/json.h>
31 #include <pkgmgr-info.h>
36 #define LOG_TAG "DOTNET_INSTALLER_PLUGIN"
39 #define __STR(x) __XSTR(x)
40 static const char* __DOTNET_DIR = __STR(DOTNET_DIR);
44 static std::vector<std::string> nugetPackagesAssembliesSha;
45 static std::vector<std::string> tacDB;
46 static std::vector<std::string> createDirectories;
47 static std::vector<std::string> createLibraries;
48 static std::vector<std::string> updateTac;
49 static std::vector<std::string> updateTlc;
50 static tac_state tacState = TAC_STATE_NONE;
51 static bool tacPluginInstalled = false;
52 static bool tacPluginFinished = false;
54 static void createSHA256Info(std::string sha256Info, std::string nugetPackage)
56 std::ofstream ofs(sha256Info, std::ios::app);
57 int assembly_count = 0;
58 for (auto& npAssemblySha : nugetPackagesAssembliesSha) {
59 std::string nuget_package_assembly = npAssemblySha.substr(0, npAssemblySha.rfind(':'));
60 std::string nuget_package = nuget_package_assembly.substr(0, nuget_package_assembly.rfind(':'));
61 std::string assembly = nuget_package_assembly.substr(nuget_package_assembly.rfind(':') + 1);
62 std::string sha = npAssemblySha.substr(npAssemblySha.rfind(':') + 1);
63 if (!strcmp(nuget_package.c_str(), nugetPackage.c_str())) {
64 ofs << assembly << ":" << sha << std::endl;
68 ofs << assembly_count << std::endl;
72 static bool compareSHA256Info(std::string sha256Info, std::string nugetPackage)
74 int compare_count = 0;
75 int assembly_count = 0;
76 std::string sha256_count = "0";
77 for (auto& npAssemblySha : nugetPackagesAssembliesSha) {
78 std::string nuget_package_assembly = npAssemblySha.substr(0, npAssemblySha.rfind(':'));
79 std::string nuget_package = nuget_package_assembly.substr(0, nuget_package_assembly.rfind(':'));
80 std::string assembly = nuget_package_assembly.substr(nuget_package_assembly.rfind(':') + 1);
81 std::string sha = npAssemblySha.substr(npAssemblySha.rfind(':') + 1);
82 if (!strcmp(nuget_package.c_str(), nugetPackage.c_str())) {
84 std::ifstream ifs(sha256Info);
87 while (getline(ifs, get_str)) {
88 if (!strcmp(get_str.c_str(), (assembly + ":" + sha).c_str())) {
91 sha256_count = get_str;
97 if (!strcmp(std::to_string(assembly_count).c_str(), std::to_string(compare_count).c_str()) &&
98 !strcmp(std::to_string(assembly_count).c_str(), sha256_count.c_str())) {
99 _INFO("Same nuget : %s", nugetPackage.c_str());
105 static bool copyAssemblyCreateSymlink(std::string binPath, std::string tacDir, std::string nugetPackage, bool isCreateTacDir)
107 std::string binNiPath = concatPath(binPath, APP_NI_SUB_DIR);
108 std::string tac_version_dir = concatPath(__DOTNET_DIR, nugetPackage);
109 bool nuget_restoration = false;
110 for (auto& npAssemblySha : nugetPackagesAssembliesSha) {
111 std::string nuget_package_assembly = npAssemblySha.substr(0, npAssemblySha.rfind(':'));
112 std::string nuget_package = nuget_package_assembly.substr(0, nuget_package_assembly.rfind(':'));
113 std::string assembly = nuget_package_assembly.substr(nuget_package_assembly.rfind(':') + 1);
114 if (!strcmp(nuget_package.c_str(), nugetPackage.c_str())) {
115 if (exist(concatPath(binPath, assembly))) {
116 std::string niFile = changeExtension(assembly, ".dll", ".ni.dll");
117 bs::error_code error;
118 if (isCreateTacDir) {
119 if (!copyFile(concatPath(binPath, assembly), concatPath(tac_version_dir, assembly))) {
120 _ERR("Failed to copy of %s", assembly.c_str());
121 nuget_restoration = true;
124 if (exist(binNiPath) && !copyFile(concatPath(binNiPath, niFile), concatPath(tac_version_dir, niFile))) {
125 _ERR("Failed to copy of %s", niFile.c_str());
128 bf::create_symlink(concatPath(tac_version_dir, assembly), concatPath(tacDir, assembly), error);
130 _ERR("Failed to create symlink %s file", concatPath(tacDir, assembly).c_str());
131 nuget_restoration = true;
134 if (exist(concatPath(tac_version_dir, niFile)) && exist(binNiPath)) {
135 bf::create_symlink(concatPath(tac_version_dir, niFile), concatPath(tacDir, niFile), error);
137 _ERR("Failed to create symlink %s file", concatPath(tacDir, niFile).c_str());
141 copySmackAndOwnership(tacDir, concatPath(tacDir, assembly), true);
143 if (!removeFile(concatPath(binPath, assembly))) {
144 _ERR("Failed to remove of %s", assembly.c_str());
145 nuget_restoration = true;
148 if (!removeFile(concatPath(binNiPath, niFile))) {
149 _ERR("Failed to remove of %s", niFile.c_str());
155 if (nuget_restoration) {
156 for (auto& npAssemblySha : nugetPackagesAssembliesSha) {
157 std::string nuget_package_assembly = npAssemblySha.substr(0, npAssemblySha.rfind(':'));
158 std::string nuget_package = nuget_package_assembly.substr(0, nuget_package_assembly.rfind(':'));
159 std::string assembly = nuget_package_assembly.substr(nuget_package_assembly.rfind(':') + 1);
160 if (!strcmp(nuget_package.c_str(), nugetPackage.c_str())) {
161 copyFile(concatPath(tac_version_dir, assembly), concatPath(binPath, assembly));
162 copySmackAndOwnership(binPath, concatPath(binPath, assembly));
163 removeFile(concatPath(tacDir, assembly));
168 return nuget_restoration;
171 static void copyLibraryCreateSymlink(const std::string pkgId, std::vector<std::string> LibrariesInfo)
173 if (LibrariesInfo.empty()) {
177 for (auto& librarySha : LibrariesInfo) {
178 std::string library = librarySha.substr(0, librarySha.find(':'));
179 std::string filename = library.substr(library.rfind('/') + 1);
180 std::string fileSha = filename + ".." + librarySha.substr(librarySha.find(':') + 1);
181 std::string shaPath = concatPath(TLC_LIBRARIES_DIR, fileSha);
182 bool fileCopied = false;
183 if (!exist(shaPath)) {
184 if (!copyFile(library, shaPath)) {
185 _ERR("Failed to copy of %s", filename.c_str());
189 createLibraries.push_back(shaPath);
191 if (!removeFile(library)) {
192 _ERR("Failed to remove of %s", library.c_str());
198 bs::error_code error;
199 bf::create_symlink(shaPath, library, error);
201 _ERR("Failed to create symlink %s file", library.c_str());
202 copyFile(shaPath, library);
203 copySmackAndOwnership(getBaseName(library), library);
209 copySmackAndOwnership(getBaseName(library), library, true);
211 if (tlc_insertDB(pkgId, fileSha) != 0) {
212 copyFile(shaPath, library);
213 copySmackAndOwnership(getBaseName(library), library);
222 static void checkDepsJson(std::string rootPath, std::string binPath, std::string execName)
224 for (auto& npAssembly : depsJsonParser(rootPath, execName)) {
225 std::string nuget_package = npAssembly.substr(0, npAssembly.rfind(':'));
226 std::string assembly_name = npAssembly.substr(npAssembly.rfind(':') + 1);
227 tacDB.push_back(nuget_package);
228 std::string buffer = SHA256(concatPath(binPath, assembly_name));
229 nugetPackagesAssembliesSha.push_back(nuget_package + ":" + assembly_name + ":" + buffer);
230 _INFO("Assembly : [%s] / SHA256 : [%s]", assembly_name.c_str(), buffer.c_str());
232 std::sort(tacDB.begin(), tacDB.end());
233 tacDB.erase(unique(tacDB.begin(), tacDB.end()), tacDB.end());
236 static int generateTAC(const std::string& pkgId, const std::string& binPath)
238 std::string tac_dir = concatPath(binPath, TAC_SYMLINK_SUB_DIR);
239 if (!createDir(tac_dir)) {
240 _ERR("Cannot create directory: %s", tac_dir.c_str());
244 copySmackAndOwnership(binPath.c_str(), tac_dir.c_str());
246 for (auto& np : tacDB) {
247 std::string tac_name = np.substr(0, np.find('/'));
248 std::string tac_version = np.substr(np.rfind('/') + 1);
249 _INFO("TAC name : %s", tac_name.c_str());
250 _INFO("TAC version : %s", tac_version.c_str());
252 bs::error_code error;
253 std::string tac_version_dir = concatPath(__DOTNET_DIR, np);
254 std::string sha256_info = concatPath(tac_version_dir, TAC_SHA_256_INFO);
255 bool isCreateTacDir = false;
256 if (!exist(tac_version_dir)) {
257 _INFO("Create tac_version_dir [%s]", tac_version_dir.c_str());
259 if (!createDir(tac_version_dir)) {
260 _ERR("Cannot create directory: %s", tac_version_dir.c_str());
261 tacState = TAC_STATE_RESTORE;
264 createDirectories.push_back(tac_version_dir);
266 if (isSymlinkFile(sha256_info)) {
267 _ERR("Failed to create sha256_info. Symbolic link is detected");
268 tacState = TAC_STATE_RESTORE;
272 createSHA256Info(sha256_info, np);
274 if (!exist(sha256_info)) {
275 tacState = TAC_STATE_RESTORE;
279 isCreateTacDir = true;
281 _INFO("Exists tac_version_dir [%s]", tac_version_dir.c_str());
283 if (isSymlinkFile(sha256_info)) {
284 _ERR("Failed to create sha256_info. Symbolic link is detected");
285 tacState = TAC_STATE_RESTORE;
289 if (!compareSHA256Info(sha256_info, np)) {
290 _INFO("Different nuget : %s", np.c_str());
294 isCreateTacDir = false;
297 if (copyAssemblyCreateSymlink(binPath, tac_dir, np, isCreateTacDir)) {
298 _ERR("Failed to create symlink");
299 tacState = TAC_STATE_RESTORE;
303 if (tacState == TAC_STATE_INSTALL) {
304 if (tac_insertDB(pkgId, np, tac_name, tac_version) != 0) {
305 tacState = TAC_STATE_RESTORE;
308 } else if (tacState == TAC_STATE_UPGRADE) {
310 if (tac_countDB(pkgId, tac_name, "", count) != 0) {
311 tacState = TAC_STATE_RESTORE;
315 if (tac_updateDB(pkgId, np, tac_name, tac_version) != 0) {
316 tacState = TAC_STATE_RESTORE;
319 } else if (count == 0) {
320 if (tac_insertDB(pkgId, np, tac_name, tac_version) != 0) {
321 tacState = TAC_STATE_RESTORE;
330 void tacUpdateDB(const std::string& pkgId)
332 for (auto& unp : updateTac) {
334 if (tac_countDB(pkgId, "", unp, count) != 0) {
339 std::string tac_version_dir_prev = concatPath(__DOTNET_DIR, unp);
340 std::string tac_version_dir_backup = tac_version_dir_prev + ".bck";
341 if (!copyDir(tac_version_dir_prev, tac_version_dir_backup)) {
342 _ERR("Failed to copy of %s to %s", tac_version_dir_prev.c_str(), tac_version_dir_backup.c_str());
345 if (!removeAll(tac_version_dir_prev)) {
346 _ERR("Failed to remove of %s", tac_version_dir_prev.c_str());
353 void tlcUpdateDB(const std::string& pkgId)
355 for (auto& ulp : updateTlc) {
357 if (tlc_countDB(pkgId, ulp, count) != 0) {
362 std::string library_prev = concatPath(TLC_LIBRARIES_DIR, ulp);
363 std::string library_backup = library_prev + ".bck";
364 if (!copyFile(library_prev, library_backup)) {
365 _ERR("Failed to copy of %s", library_prev.c_str());
368 if (!removeFile(library_prev)) {
369 _ERR("Failed to remove of %s", library_prev.c_str());
376 int tacInstall(const std::string& pkgId, tac_state state, bool tacForce)
378 _DBG("[===== PKGMGR_MDPARSER_PLUGIN_INSTALL =====]");
379 _INFO("PackageID : %s", pkgId.c_str());
381 // Can be multiple apps in one package
382 if (tacPluginInstalled) {
383 _INFO("TAC plugin already installed");
386 tacPluginInstalled = true;
388 std::string appType = getAppType(pkgId);
389 if (strstr(appType.c_str(), "dotnet") == NULL) {
390 _ERR("App type is not dotnet");
393 std::string execName = getExecName(pkgId);
394 std::string rootPath = getRootPath(pkgId);
395 if (execName.empty() || rootPath.empty()) {
399 std::string binPath = concatPath(rootPath, "bin");
400 if (exist(concatPath(binPath, PRE_COMPILED_PACKAGE_FILE))) {
401 _INFO("The %s is a Pre-Compiled package. So, skip the TAC", pkgId.c_str());
405 std::string metaValue = getMetadataValue(pkgId, TAC_METADATA_KEY);
407 if (metaValue.empty()) {
411 if (metaValue == METADATA_VALUE_TRUE || tacForce) {
412 checkDepsJson(rootPath, binPath, execName);
420 if (tac_createDB() != 0) {
424 if (generateTAC(pkgId, binPath) != 0) {
429 if (tlc_createDB() != 0) {
433 copyLibraryCreateSymlink(pkgId, getLibrariesInfo(rootPath));
438 int tacUpgrade(const std::string& pkgId, tac_state state, bool tacForce)
440 _DBG("[===== PKGMGR_MDPARSER_PLUGIN_UPGRADE =====]");
441 _INFO("PackageID : %s", pkgId.c_str());
443 // Can be multiple apps in one package
444 if (tacPluginInstalled) {
445 _INFO("TAC plugin already upgraded");
448 tacPluginInstalled = true;
450 std::string appType = getAppType(pkgId);
451 if (strstr(appType.c_str(), "dotnet") == NULL) {
452 _ERR("App type is not dotnet");
455 std::string execName = getExecName(pkgId);
456 std::string rootPath = getRootPath(pkgId);
457 if (execName.empty() || rootPath.empty()) {
461 std::string binPath = concatPath(rootPath, "bin");
462 if (exist(concatPath(binPath, PRE_COMPILED_PACKAGE_FILE))) {
463 _INFO("The %s is a Pre-Compiled package. So, skip the TAC", pkgId.c_str());
464 state = TAC_STATE_REMOVED;
467 if (state == TAC_STATE_REMOVED) {
468 _INFO("Skipped to parse of deps.json");
469 } else { //TAC_STATE_UPGRADE
470 std::string metaValue = getMetadataValue(pkgId, TAC_METADATA_KEY);
472 if (metaValue.empty()) {
476 if (metaValue == METADATA_VALUE_TRUE || tacForce) {
477 checkDepsJson(rootPath, binPath, execName);
481 tacState = TAC_STATE_UPGRADE;
482 if (tac_createDB() != 0) {
486 updateTac = tac_selectDB(pkgId);
488 bool skipTLC = false;
490 if (tac_deleteDB(pkgId, "") != 0) {
497 if (generateTAC(pkgId, binPath) != 0) {
501 for (auto& unp : updateTac) {
502 bool isExits = false;
503 for (auto& np : tacDB) {
504 if (!strcmp(unp.c_str(), np.c_str())) {
510 if (tac_deleteDB(pkgId, unp) != 0) {
511 tacState = TAC_STATE_RESTORE;
520 if (tlc_createDB() != 0) {
524 updateTlc = tlc_selectDB(pkgId);
526 if (tlc_deleteDB(pkgId) != 0) {
532 copyLibraryCreateSymlink(pkgId, skipTLC ? std::vector<std::string>() : getLibrariesInfo(rootPath));
537 int tacUninstall(const std::string& pkgId, tac_state state)
539 _DBG("[===== PKGMGR_MDPARSER_PLUGIN_UNINSTALL =====]");
540 _INFO("PackageID : %s", pkgId.c_str());
542 // Can be multiple apps in one package
543 if (tacPluginInstalled) {
544 _INFO("TAC plugin already uninstalled");
547 tacPluginInstalled = true;
550 if (tac_openDB() != 0) {
554 updateTac = tac_selectDB(pkgId);
556 if (tac_deleteDB(pkgId, "") != 0) {
557 tacState = TAC_STATE_RESTORE;
563 if (tlc_openDB() != 0) {
567 updateTlc = tlc_selectDB(pkgId);
569 if (tlc_deleteDB(pkgId) != 0) {
578 int tacRemoved(const std::string& pkgId)
580 _DBG("[===== PKGMGR_MDPARSER_PLUGIN_REMOVED =====]");
581 _INFO("PackageID : %s", pkgId.c_str());
583 return tacUpgrade(pkgId, TAC_STATE_REMOVED);
586 void undoStep(std::string tac)
588 std::string current_tac = concatPath(__DOTNET_DIR, tac.substr(0, tac.find('/')));
590 for (auto& bck : bf::recursive_directory_iterator(current_tac)) {
591 std::string bck_path = bck.path().string();
592 if (bf::is_directory(bck_path) && strstr(bck_path.c_str(), ".bck") != NULL) {
593 if (!moveFile(bck_path, bck_path.substr(0, bck_path.rfind(".bck")))) {
594 _ERR("Failed to move %s", bck_path.c_str());
599 } catch (const bf::filesystem_error& error) {
600 _ERR("Failed to recursive directory: %s", error.what());
605 auto convert = [](const std::string& path, const std::string& filename) {
606 if (filename.rfind(".bck") != std::string::npos) {
607 if (!moveFile(path, replaceAll(path, ".bck", ""))) {
608 _ERR("Failed to move %s", path.c_str());
613 scanFilesInDirectory(TLC_LIBRARIES_DIR, convert, 0);
618 for (auto& cd : createDirectories) {
619 if (!removeAll(cd)) {
620 _ERR("Failed to remove of %s", cd.c_str());
624 for (auto& cl : createLibraries) {
625 if (!removeFile(cl)) {
626 _ERR("Failed to remove of %s", cl.c_str());
631 void unInstall_Undo()
633 for (auto& unp : updateTac) {
641 if (!tacDB.empty()) {
642 for (auto& np : tacDB) {
649 int tacUndo(const std::string& pkgId)
651 _DBG("[===== PKGMGR_MDPARSER_PLUGIN_UNDO =====]");
652 _INFO("PackageID : %s", pkgId.c_str());
654 // Can be multiple apps in one package
655 if (tacPluginFinished) {
656 _INFO("TAC plugin already finished(UNDO)");
659 tacPluginFinished = true;
661 if (tacState == TAC_STATE_INSTALL) {
663 } else if (tacState == TAC_STATE_UPGRADE) {
665 } else if (tacState == TAC_STATE_UNINSTALL) {
667 } else if (tacState == TAC_STATE_RESTORE) {
678 void changeOwnershipTAC(std::string current_tac)
680 copySmackAndOwnership(__DOTNET_DIR, current_tac);
682 for (auto& path : bf::recursive_directory_iterator(current_tac))
683 copySmackAndOwnership(__DOTNET_DIR, path.path().string());
684 } catch (const bf::filesystem_error& error) {
685 _ERR("Failed to recursive directory: %s", error.what());
689 void cleanStep(std::string tac)
691 std::string current_tac = concatPath(__DOTNET_DIR, tac.substr(0, tac.find('/')));
693 for (auto& bck : bf::recursive_directory_iterator(current_tac)) {
694 std::string bck_path = bck.path().string();
695 if (bf::is_directory(bck_path) && strstr(bck_path.c_str(), ".bck") != NULL) {
696 if (!removeAll(bck_path)) {
697 _ERR("Failed to remove of %s", bck_path.c_str());
703 bool isExist = false;
704 for (auto& bck : bf::recursive_directory_iterator(current_tac)) {
705 std::string bck_path = bck.path().string();
706 if (exist(bck_path) && bf::is_directory(bck_path) && strstr(bck_path.c_str(), ".bck") == NULL) {
712 if (!removeAll(current_tac)) {
713 _ERR("Failed to remove of %s", current_tac.c_str());
716 } catch (const bf::filesystem_error& error) {
717 _ERR("Failed to recursive directory: %s", error.what());
722 auto convert = [](const std::string& path, const std::string& filename) {
723 if (filename.rfind(".bck") != std::string::npos) {
724 if (!removeFile(path)) {
725 _ERR("Failed to remove of %s", path.c_str());
730 scanFilesInDirectory(TLC_LIBRARIES_DIR, convert, 0);
735 for (auto& cd : createDirectories) {
736 changeOwnershipTAC(cd);
737 copySmackAndOwnership(__DOTNET_DIR, cd.substr(0, cd.rfind('/')));
740 for (auto& cl : createLibraries) {
741 copySmackAndOwnership(__DOTNET_DIR, cl);
745 void unInstall_Clean()
747 for (auto& unp : updateTac) {
755 if (!tacDB.empty()) {
756 for (auto& np : tacDB) {
758 changeOwnershipTAC(concatPath(__DOTNET_DIR, np.substr(0, np.find('/'))));
764 int tacClean(const std::string& pkgId)
766 if (tacState == TAC_STATE_RESTORE) {
767 disableTACPackage(pkgId);
769 std::string rootPath = getRootPath(pkgId);
770 if (!rootPath.empty()) {
771 std::string binPath = concatPath(rootPath, "bin");
772 removeAll(concatPath(binPath, TAC_SYMLINK_SUB_DIR));
775 std::string runtimesDir = concatPath(rootPath, "bin/runtimes");
776 if (exist(runtimesDir)) {
778 sprintf(buffer, "(tizen|linux|unix|base|any)(.\\d.\\d.\\d)?(-%s)?", ARCHITECTURE_IDENTIFIER);
779 std::regex pattern(buffer);
782 for (auto& path : bf::recursive_directory_iterator(runtimesDir)) {
783 std::string symPath = path.path().string();
784 if (isDirectory(symPath) || !isSymlinkFile(symPath))
786 std::string targetDir = symPath.substr(symPath.rfind("/runtimes/") + 10);
787 if (!std::regex_match(targetDir.substr(0, targetDir.find('/')), pattern))
789 if (symPath.rfind(".so") == std::string::npos)
791 copyFile(bf::read_symlink(symPath).string(), symPath);
793 } catch (const bf::filesystem_error& error) {
794 _ERR("Failed to recursive directory: %s", error.what());
798 return tacUndo(pkgId);
801 _DBG("[===== PKGMGR_MDPARSER_PLUGIN_CLEAN =====]");
802 _INFO("PackageID : %s", pkgId.c_str());
804 // Can be multiple apps in one package
805 if (tacPluginFinished) {
806 _INFO("TAC plugin already finished(CLEAN)");
809 tacPluginFinished = true;
811 if (tacState == TAC_STATE_INSTALL) {
813 } else if (tacState == TAC_STATE_UPGRADE) {
815 } else if (tacState == TAC_STATE_UNINSTALL) {
820 copySmackAndOwnership(__DOTNET_DIR, TAC_APP_LIST_DB);
821 copySmackAndOwnership(__DOTNET_DIR, TAC_APP_LIST_DB + std::string("-journal"));
825 copySmackAndOwnership(__DOTNET_DIR, TLC_APP_LIST_DB);
826 copySmackAndOwnership(__DOTNET_DIR, TLC_APP_LIST_DB + std::string("-journal"));