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