[Refactoring] Improve SAM score through DC and GV improvement
[platform/core/dotnet/launcher.git] / NativeLauncher / tool / tac_installer.cc
1 /*
2  * Copyright (c) 2022 Samsung Electronics Co., Ltd All Rights Reserved
3  *
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
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  */
16
17 #include "log.h"
18 #include "utils.h"
19 #include "db_manager.h"
20 #include "tac_common.h"
21 #include "tac_installer.h"
22
23 #include <cstring>
24 #include <fstream>
25 #include <regex>
26 #include <sstream>
27 #include <vector>
28 #include <boost/filesystem.hpp>
29 #include <json/json.h>
30 #include <pkgmgr-info.h>
31
32 #ifdef  LOG_TAG
33 #undef  LOG_TAG
34 #endif
35 #define LOG_TAG "DOTNET_INSTALLER_PLUGIN"
36
37 #define __XSTR(x) #x
38 #define __STR(x) __XSTR(x)
39 static const char* __DOTNET_DIR = __STR(DOTNET_DIR);
40 #undef __STR
41 #undef __XSTR
42
43 static std::vector<std::string> nugetPackagesAssembliesSha;
44 static std::vector<std::string> tacDB;
45 static std::vector<std::string> createDirectories;
46 static std::vector<std::string> createLibraries;
47 static std::vector<std::string> updateTac;
48 static tac_state tacState = TAC_STATE_NONE;
49 static sqlite3 *tac_db = NULL;
50 static sqlite3 *tlc_db = NULL;
51 static bool tacPluginInstalled = false;
52 static bool tacPluginFinished = false;
53
54 static void createSHA256Info(std::string sha256Info, std::string nugetPackage)
55 {
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;
65                         assembly_count++;
66                 }
67         }
68         ofs << assembly_count << std::endl;
69         ofs.close();
70 }
71
72 static bool compareSHA256Info(std::string sha256Info, std::string nugetPackage)
73 {
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())) {
83                         assembly_count++;
84                         std::ifstream ifs(sha256Info);
85                         std::string get_str;
86                         if (ifs.is_open()) {
87                                 while (getline(ifs, get_str)) {
88                                         if (!strcmp(get_str.c_str(), (assembly + ":" + sha).c_str())) {
89                                                 compare_count++;
90                                         }
91                                         sha256_count = get_str;
92                                 }
93                                 ifs.close();
94                         }
95                 }
96         }
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());
100                 return true;
101         }
102         return false;
103 }
104
105 static bool copyAssemblyCreateSymlink(std::string binPath, std::string tacDir, std::string nugetPackage, bool isCreateTacDir)
106 {
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;
122                                                 break;
123                                         }
124                                         if (exist(binNiPath) && !copyFile(concatPath(binNiPath, niFile), concatPath(tac_version_dir, niFile))) {
125                                                 _ERR("Failed to copy of %s", niFile.c_str());
126                                         }
127                                 }
128                                 bf::create_symlink(concatPath(tac_version_dir, assembly), concatPath(tacDir, assembly), error);
129                                 if (error) {
130                                         _ERR("Failed to create symlink %s file", concatPath(tacDir, assembly).c_str());
131                                         nuget_restoration = true;
132                                         break;
133                                 }
134                                 if (exist(concatPath(tac_version_dir, niFile)) && exist(binNiPath)) {
135                                         bf::create_symlink(concatPath(tac_version_dir, niFile), concatPath(tacDir, niFile), error);
136                                         if (error) {
137                                                 _ERR("Failed to create symlink %s file", concatPath(tacDir, niFile).c_str());
138                                         }
139                                 }
140
141                                 copySmackAndOwnership(tacDir, concatPath(tacDir, assembly), true);
142
143                                 if (!removeFile(concatPath(binPath, assembly))) {
144                                         _ERR("Failed to remove of %s", assembly.c_str());
145                                         nuget_restoration = true;
146                                         break;
147                                 }
148                                 if (!removeFile(concatPath(binNiPath, niFile))) {
149                                         _ERR("Failed to remove of %s", niFile.c_str());
150                                 }
151                         }
152                 }
153         }
154
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));
164                         }
165                 }
166         }
167
168         return nuget_restoration;
169 }
170
171 static void copyLibraryCreateSymlink(const std::string pkgId, std::vector<std::string> LibrariesInfo)
172 {
173         if (LibrariesInfo.empty()) {
174                 return;
175         }
176
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());
186                                 continue;
187                         }
188                         fileCopied = true;
189                         createLibraries.push_back(shaPath);
190                 }
191                 if (!removeFile(library)) {
192                         _ERR("Failed to remove of %s", library.c_str());
193                         if (fileCopied) {
194                                 removeFile(shaPath);
195                         }
196                         continue;
197                 }
198                 bs::error_code error;
199                 bf::create_symlink(shaPath, library, error);
200                 if (error) {
201                         _ERR("Failed to create symlink %s file", library.c_str());
202                         copyFile(shaPath, library);
203                         copySmackAndOwnership(getBaseName(library), library);
204                         if (fileCopied) {
205                                 removeFile(shaPath);
206                         }
207                         continue;
208                 }
209                 copySmackAndOwnership(getBaseName(library), library, true);
210
211                 char *sql = sqlite3_mprintf("INSERT INTO TLC (PKGID, LIBRARY) VALUES (%Q, %Q);", pkgId.c_str(), fileSha.c_str());
212                 if (!insertDB(tlc_db, sql)) {
213                         _ERR("Sqlite insert error");
214                         sqlite3_free(sql);
215                         copyFile(shaPath, library);
216                         copySmackAndOwnership(getBaseName(library), library);
217                         if (fileCopied) {
218                                 removeFile(shaPath);
219                         }
220                         continue;
221                 }
222                 sqlite3_free(sql);
223         }
224 }
225
226 static void checkDepsJson(std::string rootPath, std::string binPath, std::string execName)
227 {
228         for (auto& npAssembly : depsJsonParser(rootPath, execName)) {
229                 std::string nuget_package = npAssembly.substr(0, npAssembly.rfind(':'));
230                 std::string assembly_name = npAssembly.substr(npAssembly.rfind(':') + 1);
231                 tacDB.push_back(nuget_package);
232                 std::string buffer = SHA256(concatPath(binPath, assembly_name));
233                 nugetPackagesAssembliesSha.push_back(nuget_package + ":" + assembly_name + ":" + buffer);
234                 _INFO("Assembly : [%s] / SHA256 : [%s]", assembly_name.c_str(), buffer.c_str());
235         }
236         std::sort(tacDB.begin(), tacDB.end());
237         tacDB.erase(unique(tacDB.begin(), tacDB.end()), tacDB.end());
238 }
239
240 static int tac_createDB()
241 {
242         tac_db = createDB(TAC_APP_LIST_DB, CREATE_TAC_DB_TABLE);
243         if (!tac_db) {
244                 _ERR("Sqlite create error. So restore the database.");
245                 if (tac_restoreDB() != TAC_ERROR_NONE) {
246                         _ERR("Sqlite create error");
247                         return -1;
248                 }
249                 tac_db = createDB(TAC_APP_LIST_DB, CREATE_TAC_DB_TABLE);
250                 if (!tac_db) {
251                         _ERR("Sqlite create error");
252                         return -1;
253                 }
254         }
255         sqlite3_exec(tac_db, "BEGIN;", NULL, NULL, NULL);
256         return 0;
257 }
258
259 static int tac_openDB()
260 {
261         tac_db = openDB(TAC_APP_LIST_DB);
262         if (!tac_db) {
263                 _ERR("Sqlite open error. So restore the database.");
264                 if (tac_restoreDB() != TAC_ERROR_NONE) {
265                         _ERR("Sqlite open error");
266                         return -1;
267                 }
268                 tac_db = openDB(TAC_APP_LIST_DB);
269                 if (!tac_db) {
270                         _ERR("Sqlite open error");
271                         return -1;
272                 }
273         }
274         sqlite3_exec(tac_db, "BEGIN;", NULL, NULL, NULL);
275         return 0;
276 }
277
278 static int tac_insertDB(const std::string& pkgId, const std::string& np, const std::string& tac_name, const std::string& tac_version)
279 {
280         char *sql = sqlite3_mprintf(
281                 "INSERT INTO TAC (PKGID, NUGET, NAME, VERSION) " \
282                 "VALUES (%Q, %Q, %Q, %Q);", pkgId.c_str(), np.c_str(), tac_name.c_str(), tac_version.c_str());
283         if (!insertDB(tac_db, sql)) {
284                 _ERR("Sqlite insert error");
285                 sqlite3_free(sql);
286                 return -1;
287         }
288         sqlite3_free(sql);
289         return 0;
290 }
291
292 static int sqliteCb(void *count, int argc, char **argv, char **colName)
293 {
294         int *c = (int*)count;
295         *c = atoi(argv[0]);
296         return 0;
297 }
298
299 static int tac_countDB(const std::string& pkgId, const std::string& tac_name, int& count)
300 {
301         char *sql = sqlite3_mprintf(
302                 "SELECT COUNT(NUGET) FROM TAC WHERE PKGID = %Q AND NAME = %Q;", pkgId.c_str(), tac_name.c_str());
303         if (sqlite3_exec(tac_db, sql, sqliteCb, &count, NULL) != SQLITE_OK) {
304                 _ERR("Sqlite select error");
305                 sqlite3_free(sql);
306                 return -1;
307         }
308         sqlite3_free(sql);
309         return 0;
310 }
311
312 static void tac_selectDB(const std::string& pkgId)
313 {
314         char *sql = sqlite3_mprintf("SELECT * FROM TAC WHERE PKGID = %Q;", pkgId.c_str());
315         updateTac = selectDB(tac_db, sql);
316         sqlite3_free(sql);
317 }
318
319 static int tac_updateDB(const std::string& pkgId, const std::string& np, const std::string& tac_name, const std::string& tac_version)
320 {
321         char *sql = sqlite3_mprintf(
322                 "UPDATE TAC SET NAME = %Q, VERSION = %Q, NUGET = %Q WHERE PKGID = %Q AND NAME = %Q;",
323                 tac_name.c_str(), tac_version.c_str(), np.c_str(), pkgId.c_str(), tac_name.c_str());
324         if (!updateDB(tac_db, sql)) {
325                 _ERR("Sqlite update error");
326                 sqlite3_free(sql);
327                 return -1;
328         }
329         sqlite3_free(sql);
330         return 0;
331 }
332
333 static void tacUpdateDB(sqlite3 *sqlite)
334 {
335         for (auto& unp : updateTac) {
336                 int count = -1;
337                 char *sql = sqlite3_mprintf("SELECT COUNT(NUGET) FROM TAC WHERE NUGET = %Q;", unp.c_str());
338                 if (sqlite3_exec(sqlite, sql, sqliteCb, &count, NULL) != SQLITE_OK) {
339                         _ERR("Sqlite select error");
340                         sqlite3_free(sql);
341                         continue;
342                 }
343
344                 if (count == 0) {
345                         std::string tac_version_dir_prev = concatPath(__DOTNET_DIR, unp);
346                         std::string tac_version_dir_backup = tac_version_dir_prev + ".bck";
347                         if (!copyDir(tac_version_dir_prev, tac_version_dir_backup)) {
348                                 _ERR("Failed to copy of %s to %s", tac_version_dir_prev.c_str(), tac_version_dir_backup.c_str());
349                                 sqlite3_free(sql);
350                                 continue;
351                         }
352                         if (!removeAll(tac_version_dir_prev)) {
353                                 _ERR("Failed to remove of %s", tac_version_dir_prev.c_str());
354                                 sqlite3_free(sql);
355                                 continue;
356                         }
357                 }
358                 sqlite3_free(sql);
359         }
360 }
361
362 static int tac_deleteDB(const std::string& pkgId, const std::string& unp = "")
363 {
364         char *sql = NULL;
365         if (unp == "") {
366                 sql = sqlite3_mprintf("DELETE FROM TAC WHERE PKGID = %Q;", pkgId.c_str());
367         } else {
368                 sql = sqlite3_mprintf("DELETE FROM TAC WHERE PKGID = %Q AND NUGET = %Q;", pkgId.c_str(), unp.c_str());
369         }
370         if (!deleteDB(tac_db, sql)) {
371                 _ERR("Sqlite delete error");
372                 sqlite3_free(sql);
373                 return -1;
374         }
375         sqlite3_free(sql);
376         return 0;
377 }
378
379 static int tlc_createDB()
380 {
381         if (!createDir(TLC_LIBRARIES_DIR)) {
382                 _ERR("Cannot create directory: %s", TLC_LIBRARIES_DIR);
383                 return -1;
384         }
385         copySmackAndOwnership(__DOTNET_DIR, TLC_LIBRARIES_DIR);
386
387         tlc_db = createDB(TLC_APP_LIST_DB, CREATE_TLC_DB_TABLE);
388         if (!tlc_db) {
389                 _ERR("Sqlite create error. So restore the database.");
390                 if (tlc_restoreDB() != TAC_ERROR_NONE) {
391                         _ERR("Sqlite create error");
392                         return -1;
393                 }
394                 tlc_db = createDB(TLC_APP_LIST_DB, CREATE_TLC_DB_TABLE);
395                 if (!tlc_db) {
396                         _ERR("Sqlite create error");
397                         return -1;
398                 }
399         }
400         sqlite3_exec(tlc_db, "BEGIN;", NULL, NULL, NULL);
401         return 0;
402 }
403
404 static int tlc_openDB()
405 {
406         tlc_db = openDB(TLC_APP_LIST_DB);
407         if (!tlc_db) {
408                 _ERR("Sqlite open error. So restore the database.");
409                 if (tlc_restoreDB() != TAC_ERROR_NONE) {
410                         _ERR("Sqlite open error");
411                         return 0;
412                 }
413                 tlc_db = openDB(TLC_APP_LIST_DB);
414                 if (!tlc_db) {
415                         _ERR("Sqlite open error");
416                         return 0;
417                 }
418         }
419         sqlite3_exec(tlc_db, "BEGIN;", NULL, NULL, NULL);
420         return 0;
421 }
422
423 static void tlcUpdateDB(sqlite3 *sqlite, std::vector<std::string> updateTlc)
424 {
425         for (auto& ulp : updateTlc) {
426                 int count = -1;
427                 char *sql = sqlite3_mprintf("SELECT COUNT(LIBRARY) FROM TLC WHERE LIBRARY = %Q;", ulp.c_str());
428                 if (sqlite3_exec(sqlite, sql, sqliteCb, &count, NULL) != SQLITE_OK) {
429                         _ERR("Sqlite select error");
430                         sqlite3_free(sql);
431                         continue;
432                 }
433                 if (count == 0) {
434                         std::string library_prev = concatPath(TLC_LIBRARIES_DIR, ulp);
435                         std::string library_backup = library_prev + ".bck";
436                         if (!copyFile(library_prev, library_backup)) {
437                                 _ERR("Failed to copy of %s", library_prev.c_str());
438                                 sqlite3_free(sql);
439                                 continue;
440                         }
441                         if (!removeFile(library_prev)) {
442                                 _ERR("Failed to remove of %s", library_prev.c_str());
443                                 sqlite3_free(sql);
444                                 continue;
445                         }
446                 }
447                 sqlite3_free(sql);
448         }
449 }
450
451 static int tlc_deleteDB(const std::string& pkgId)
452 {
453         char *sql = sqlite3_mprintf("SELECT * FROM TLC WHERE PKGID = %Q;", pkgId.c_str());
454         std::vector<std::string> updateTlc = selectDB(tlc_db, sql);
455         sqlite3_free(sql);
456
457         sql = sqlite3_mprintf("DELETE FROM TLC WHERE PKGID = %Q;", pkgId.c_str());
458         if (!deleteDB(tlc_db, sql)) {
459                 _ERR("Sqlite delete error");
460                 sqlite3_free(sql);
461                 return -1;
462         }
463         sqlite3_free(sql);
464
465         tlcUpdateDB(tlc_db, updateTlc);
466         return 0;
467 }
468
469 static int generateTAC(const std::string& pkgId, const std::string& binPath)
470 {
471         std::string tac_dir = concatPath(binPath, TAC_SYMLINK_SUB_DIR);
472         if (!createDir(tac_dir)) {
473                 _ERR("Cannot create directory: %s", tac_dir.c_str());
474                 return 0;
475         }
476
477         copySmackAndOwnership(binPath.c_str(), tac_dir.c_str());
478
479         for (auto& np : tacDB) {
480                 std::string tac_name = np.substr(0, np.find('/'));
481                 std::string tac_version = np.substr(np.rfind('/') + 1);
482                 _INFO("TAC name : %s", tac_name.c_str());
483                 _INFO("TAC version : %s", tac_version.c_str());
484
485                 bs::error_code error;
486                 std::string tac_version_dir = concatPath(__DOTNET_DIR, np);
487                 std::string sha256_info = concatPath(tac_version_dir, TAC_SHA_256_INFO);
488                 bool isCreateTacDir = false;
489                 if (!exist(tac_version_dir)) {
490                         _INFO("Create tac_version_dir [%s]", tac_version_dir.c_str());
491
492                         if (!createDir(tac_version_dir)) {
493                                 _ERR("Cannot create directory: %s", tac_version_dir.c_str());
494                                 tacState = TAC_STATE_RESTORE;
495                                 return -1;
496                         }
497                         createDirectories.push_back(tac_version_dir);
498
499                         if (isSymlinkFile(sha256_info)) {
500                                 _ERR("Failed to create sha256_info. Symbolic link is detected");
501                                 tacState = TAC_STATE_RESTORE;
502                                 return -1;
503                         }
504
505                         createSHA256Info(sha256_info, np);
506
507                         if (!exist(sha256_info)) {
508                                 tacState = TAC_STATE_RESTORE;
509                                 return -1;
510                         }
511
512                         isCreateTacDir = true;
513                 } else {
514                         _INFO("Exists tac_version_dir [%s]", tac_version_dir.c_str());
515
516                         if (isSymlinkFile(sha256_info)) {
517                                 _ERR("Failed to create sha256_info. Symbolic link is detected");
518                                 tacState = TAC_STATE_RESTORE;
519                                 return -1;
520                         }
521
522                         if (!compareSHA256Info(sha256_info, np)) {
523                                 _INFO("Different nuget : %s", np.c_str());
524                                 continue;
525                         }
526
527                         isCreateTacDir = false;
528                 }
529
530                 if (copyAssemblyCreateSymlink(binPath, tac_dir, np, isCreateTacDir)) {
531                         _ERR("Failed to create symlink");
532                         tacState = TAC_STATE_RESTORE;
533                         return -1;
534                 }
535
536                 if (tacState == TAC_STATE_INSTALL) {
537                         if (tac_insertDB(pkgId, np, tac_name, tac_version) != 0) {
538                                 tacState = TAC_STATE_RESTORE;
539                                 return -1;
540                         }
541                 } else if (tacState == TAC_STATE_UPGRADE) {
542                         int count = -1;
543                         if (tac_countDB(pkgId, tac_name, count) != 0) {
544                                 tacState = TAC_STATE_RESTORE;
545                                 return -1;
546                         }
547                         if (count == 1) {
548                                 if (tac_updateDB(pkgId, np, tac_name, tac_version) != 0) {
549                                         tacState = TAC_STATE_RESTORE;
550                                         return -1;
551                                 }
552                         } else if (count == 0) {
553                                 if (tac_insertDB(pkgId, np, tac_name, tac_version) != 0) {
554                                         tacState = TAC_STATE_RESTORE;
555                                         return -1;
556                                 }
557                         }
558                 }
559         }
560         return 0;
561 }
562
563 int tacInstall(const std::string& pkgId, tac_state state, bool tacForce)
564 {
565         _DBG("[===== PKGMGR_MDPARSER_PLUGIN_INSTALL =====]");
566         _INFO("PackageID : %s", pkgId.c_str());
567
568         // Can be multiple apps in one package
569         if (tacPluginInstalled) {
570                 _INFO("TAC plugin already installed");
571                 return 0;
572         }
573         tacPluginInstalled = true;
574
575         std::string appType = getAppType(pkgId);
576         if (strstr(appType.c_str(), "dotnet") == NULL) {
577                 _ERR("App type is not dotnet");
578                 return 0;
579         }
580         std::string execName = getExecName(pkgId);
581         std::string rootPath = getRootPath(pkgId);
582         if (execName.empty() || rootPath.empty()) {
583                 return 0;
584         }
585
586         std::string binPath = concatPath(rootPath, "bin");
587         if (exist(concatPath(binPath, PRE_COMPILED_PACKAGE_FILE))) {
588                 _INFO("The %s is a Pre-Compiled package. So, skip the TAC", pkgId.c_str());
589                 return 0;
590         }
591
592         std::string metaValue = getMetadataValue(pkgId, TAC_METADATA_KEY);
593         if (!tacForce) {
594                 if (metaValue.empty()) {
595                         return 0;
596                 }
597         }
598         if (metaValue == METADATA_VALUE_TRUE || tacForce) {
599                 checkDepsJson(rootPath, binPath, execName);
600         }
601
602         tacState = state;
603         if (tacDB.empty()) {
604                 return 0;
605         }
606
607         if (tac_createDB() != 0) {
608                 return -1;
609         }
610
611         if (generateTAC(pkgId, binPath) != 0) {
612                 return -1;
613         }
614
615         ///// TLC /////
616         if (tlc_createDB() != 0) {
617                 return -1;
618         }
619
620         copyLibraryCreateSymlink(pkgId, getLibrariesInfo(rootPath));
621
622         return 0;
623 }
624
625 int tacUpgrade(const std::string& pkgId, tac_state state, bool tacForce)
626 {
627         _DBG("[===== PKGMGR_MDPARSER_PLUGIN_UPGRADE =====]");
628         _INFO("PackageID : %s", pkgId.c_str());
629
630         // Can be multiple apps in one package
631         if (tacPluginInstalled) {
632                 _INFO("TAC plugin already upgraded");
633                 return 0;
634         }
635         tacPluginInstalled = true;
636
637         std::string appType = getAppType(pkgId);
638         if (strstr(appType.c_str(), "dotnet") == NULL) {
639                 _ERR("App type is not dotnet");
640                 return 0;
641         }
642         std::string execName = getExecName(pkgId);
643         std::string rootPath = getRootPath(pkgId);
644         if (execName.empty() || rootPath.empty()) {
645                 return 0;
646         }
647
648         std::string binPath = concatPath(rootPath, "bin");
649         if (exist(concatPath(binPath, PRE_COMPILED_PACKAGE_FILE))) {
650                 _INFO("The %s is a Pre-Compiled package. So, skip the TAC", pkgId.c_str());
651                 state = TAC_STATE_REMOVED;
652         }
653
654         if (state == TAC_STATE_REMOVED) {
655                 _INFO("Skipped to parse of deps.json");
656         } else { //TAC_STATE_UPGRADE
657                 std::string metaValue = getMetadataValue(pkgId, TAC_METADATA_KEY);
658                 if (!tacForce) {
659                         if (metaValue.empty()) {
660                                 return 0;
661                         }
662                 }
663                 if (metaValue == METADATA_VALUE_TRUE || tacForce) {
664                         checkDepsJson(rootPath, binPath, execName);
665                 }
666         }
667
668         tacState = TAC_STATE_UPGRADE;
669         if (tac_createDB() != 0) {
670                 return -1;
671         }
672
673         tac_selectDB(pkgId);
674
675         bool skipTLC = false;
676         if (tacDB.empty()) {
677                 if (tac_deleteDB(pkgId) != 0) {
678                         return -1;
679                 }
680                 tacUpdateDB(tac_db);
681
682                 skipTLC = true;
683         } else {
684                 if (generateTAC(pkgId, binPath) != 0) {
685                         return -1;
686                 }
687
688                 for (auto& unp : updateTac) {
689                         bool isExits = false;
690                         for (auto& np : tacDB) {
691                                 if (!strcmp(unp.c_str(), np.c_str())) {
692                                         isExits = true;
693                                         break;
694                                 }
695                         }
696                         if (!isExits) {
697                                 if (tac_deleteDB(pkgId, unp) != 0) {
698                                         tacState = TAC_STATE_RESTORE;
699                                         return -1;
700                                 }
701                         }
702                 }
703                 tacUpdateDB(tac_db);
704         }
705
706         ///// TLC /////
707         if (tlc_createDB() != 0) {
708                 return -1;
709         }
710
711         if (tlc_deleteDB(pkgId) != 0) {
712                 return -1;
713         }
714
715         copyLibraryCreateSymlink(pkgId, skipTLC ? std::vector<std::string>() : getLibrariesInfo(rootPath));
716
717         return 0;
718 }
719
720 int tacUninstall(const std::string& pkgId, tac_state state)
721 {
722         _DBG("[===== PKGMGR_MDPARSER_PLUGIN_UNINSTALL =====]");
723         _INFO("PackageID : %s", pkgId.c_str());
724
725         // Can be multiple apps in one package
726         if (tacPluginInstalled) {
727                 _INFO("TAC plugin already uninstalled");
728                 return 0;
729         }
730         tacPluginInstalled = true;
731
732         tacState= state;
733         if (tac_openDB() != 0) {
734                 return -1;
735         }
736
737         tac_selectDB(pkgId);
738
739         if (tac_deleteDB(pkgId) != 0) {
740                 tacState = TAC_STATE_RESTORE;
741                 return -1;
742         }
743         tacUpdateDB(tac_db);
744
745         ///// TLC /////
746         if (tlc_openDB() != 0) {
747                 return -1;
748         }
749
750         return tlc_deleteDB(pkgId);
751 }
752
753 int tacRemoved(const std::string& pkgId)
754 {
755         _DBG("[===== PKGMGR_MDPARSER_PLUGIN_REMOVED =====]");
756         _INFO("PackageID : %s", pkgId.c_str());
757
758         return tacUpgrade(pkgId, TAC_STATE_REMOVED);
759 }
760
761 void undoStep(std::string tac)
762 {
763         std::string current_tac = concatPath(__DOTNET_DIR, tac.substr(0, tac.find('/')));
764         try {
765                 for (auto& bck : bf::recursive_directory_iterator(current_tac)) {
766                         std::string bck_path = bck.path().string();
767                         if (bf::is_directory(bck_path) && strstr(bck_path.c_str(), ".bck") != NULL) {
768                                 if (!moveFile(bck_path, bck_path.substr(0, bck_path.rfind(".bck")))) {
769                                         _ERR("Failed to move %s", bck_path.c_str());
770                                 }
771                                 break;
772                         }
773                 }
774         } catch (const bf::filesystem_error& error) {
775                 _ERR("Failed to recursive directory: %s", error.what());
776                 return;
777         }
778
779         ///// TLC /////
780         auto convert = [](const std::string& path, const std::string& filename) {
781                 if (filename.rfind(".bck") != std::string::npos) {
782                         if (!moveFile(path, replaceAll(path, ".bck", ""))) {
783                                 _ERR("Failed to move %s", path.c_str());
784                         }
785                 }
786         };
787
788         scanFilesInDirectory(TLC_LIBRARIES_DIR, convert, 0);
789 }
790
791 void install_Undo()
792 {
793         for (auto& cd : createDirectories) {
794                 if (!removeAll(cd)) {
795                         _ERR("Failed to remove of %s", cd.c_str());
796                 }
797         }
798
799         for (auto& cl : createLibraries) {
800                 if (!removeFile(cl)) {
801                         _ERR("Failed to remove of %s", cl.c_str());
802                 }
803         }
804 }
805
806 void unInstall_Undo()
807 {
808         for (auto& unp : updateTac) {
809                 undoStep(unp);
810         }
811 }
812
813 void update_Undo()
814 {
815         install_Undo();
816         if (!tacDB.empty()) {
817                 for (auto& np : tacDB) {
818                         undoStep(np);
819                 }
820         }
821         unInstall_Undo();
822 }
823
824 int tacUndo(const std::string& pkgId)
825 {
826         _DBG("[===== PKGMGR_MDPARSER_PLUGIN_UNDO =====]");
827         _INFO("PackageID : %s", pkgId.c_str());
828
829         // Can be multiple apps in one package
830         if (tacPluginFinished) {
831                 _INFO("TAC plugin already finished(UNDO)");
832                 return 0;
833         }
834         tacPluginFinished = true;
835
836         if (tacState == TAC_STATE_INSTALL) {
837                 install_Undo();
838         } else if (tacState == TAC_STATE_UPGRADE) {
839                 update_Undo();
840         } else if (tacState == TAC_STATE_UNINSTALL) {
841                 unInstall_Undo();
842         } else if (tacState == TAC_STATE_RESTORE) {
843                 update_Undo();
844         }
845
846         if (tac_db) {
847                 rollbackDB(tac_db);
848                 tac_db = NULL;
849         }
850
851         if (tlc_db) {
852                 rollbackDB(tlc_db);
853                 tlc_db = NULL;
854         }
855
856         return 0;
857 }
858
859 void changeOwnershipTAC(std::string current_tac)
860 {
861         copySmackAndOwnership(__DOTNET_DIR, current_tac);
862         try {
863                 for (auto& path : bf::recursive_directory_iterator(current_tac))
864                         copySmackAndOwnership(__DOTNET_DIR, path.path().string());
865         } catch (const bf::filesystem_error& error) {
866                 _ERR("Failed to recursive directory: %s", error.what());
867         }
868 }
869
870 void cleanStep(std::string tac)
871 {
872         std::string current_tac = concatPath(__DOTNET_DIR, tac.substr(0, tac.find('/')));
873         try {
874                 for (auto& bck : bf::recursive_directory_iterator(current_tac)) {
875                         std::string bck_path = bck.path().string();
876                         if (bf::is_directory(bck_path) && strstr(bck_path.c_str(), ".bck") != NULL) {
877                                 if (!removeAll(bck_path)) {
878                                         _ERR("Failed to remove of %s", bck_path.c_str());
879                                 }
880                                 break;
881                         }
882                 }
883
884                 bool isExist = false;
885                 for (auto& bck : bf::recursive_directory_iterator(current_tac)) {
886                         std::string bck_path = bck.path().string();
887                         if (exist(bck_path) && bf::is_directory(bck_path) && strstr(bck_path.c_str(), ".bck") == NULL) {
888                                 isExist = true;
889                                 break;
890                         }
891                 }
892                 if (!isExist) {
893                         if (!removeAll(current_tac)) {
894                                 _ERR("Failed to remove of %s", current_tac.c_str());
895                         }
896                 }
897         } catch (const bf::filesystem_error& error) {
898                 _ERR("Failed to recursive directory: %s", error.what());
899                 return;
900         }
901
902         ///// TLC /////
903         auto convert = [](const std::string& path, const std::string& filename) {
904                 if (filename.rfind(".bck") != std::string::npos) {
905                         if (!removeFile(path)) {
906                                 _ERR("Failed to remove of %s", path.c_str());
907                         }
908                 }
909         };
910
911         scanFilesInDirectory(TLC_LIBRARIES_DIR, convert, 0);
912 }
913
914 void install_Clean()
915 {
916         for (auto& cd : createDirectories) {
917                 changeOwnershipTAC(cd);
918                 copySmackAndOwnership(__DOTNET_DIR, cd.substr(0, cd.rfind('/')));
919         }
920
921         for (auto& cl : createLibraries) {
922                 copySmackAndOwnership(__DOTNET_DIR, cl);
923         }
924 }
925
926 void unInstall_Clean()
927 {
928         for (auto& unp : updateTac) {
929                 cleanStep(unp);
930         }
931 }
932
933 void update_Clean()
934 {
935         install_Clean();
936         if (!tacDB.empty()) {
937                 for (auto& np : tacDB) {
938                         cleanStep(np);
939                         changeOwnershipTAC(concatPath(__DOTNET_DIR, np.substr(0, np.find('/'))));
940                 }
941         }
942         unInstall_Clean();
943 }
944
945 int tacClean(const std::string& pkgId)
946 {
947         if (tacState == TAC_STATE_RESTORE) {
948                 disableTACPackage(pkgId);
949
950                 std::string rootPath = getRootPath(pkgId);
951                 if (!rootPath.empty()) {
952                         std::string binPath = concatPath(rootPath, "bin");
953                         removeAll(concatPath(binPath, TAC_SYMLINK_SUB_DIR));
954                 }
955
956                 std::string runtimesDir = concatPath(rootPath, "bin/runtimes");
957                 if (exist(runtimesDir)) {
958                         char buffer[128];
959                         sprintf(buffer, "(tizen|linux|unix|base|any)(.\\d.\\d.\\d)?(-%s)?", ARCHITECTURE_IDENTIFIER);
960                         std::regex pattern(buffer);
961
962                         try {
963                                 for (auto& path : bf::recursive_directory_iterator(runtimesDir)) {
964                                         std::string symPath = path.path().string();
965                                         if (isDirectory(symPath) || !isSymlinkFile(symPath))
966                                                 continue;
967                                         std::string targetDir = symPath.substr(symPath.rfind("/runtimes/") + 10);
968                                         if (!std::regex_match(targetDir.substr(0, targetDir.find('/')), pattern))
969                                                 continue;
970                                         if (symPath.rfind(".so") == std::string::npos)
971                                                 continue;
972                                         copyFile(bf::read_symlink(symPath).string(), symPath);
973                                 }
974                         } catch (const bf::filesystem_error& error) {
975                                 _ERR("Failed to recursive directory: %s", error.what());
976                         }
977                 }
978
979                 return tacUndo(pkgId);
980         }
981
982         _DBG("[===== PKGMGR_MDPARSER_PLUGIN_CLEAN =====]");
983         _INFO("PackageID : %s", pkgId.c_str());
984
985         // Can be multiple apps in one package
986         if (tacPluginFinished) {
987                 _INFO("TAC plugin already finished(CLEAN)");
988                 return 0;
989         }
990         tacPluginFinished = true;
991
992         if (tacState == TAC_STATE_INSTALL) {
993                 install_Clean();
994         } else if (tacState == TAC_STATE_UPGRADE) {
995                 update_Clean();
996         } else if (tacState == TAC_STATE_UNINSTALL) {
997                 unInstall_Clean();
998         }
999
1000         if (tac_db) {
1001                 closeDB(tac_db);
1002                 tac_db = NULL;
1003                 copySmackAndOwnership(__DOTNET_DIR, TAC_APP_LIST_DB);
1004                 copySmackAndOwnership(__DOTNET_DIR, TAC_APP_LIST_DB + std::string("-journal"));
1005         }
1006
1007         if (tlc_db) {
1008                 closeDB(tlc_db);
1009                 tlc_db = NULL;
1010                 copySmackAndOwnership(__DOTNET_DIR, TLC_APP_LIST_DB);
1011                 copySmackAndOwnership(__DOTNET_DIR, TLC_APP_LIST_DB + std::string("-journal"));
1012         }
1013
1014         return 0;
1015 }
1016