Modified function name for readability (#263)
[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 <sstream>
25 #include <vector>
26 #include <boost/filesystem.hpp>
27 #include <glib.h>
28 #include <json/json.h>
29 #include <pkgmgr-info.h>
30
31 #ifdef  LOG_TAG
32 #undef  LOG_TAG
33 #endif
34 #define LOG_TAG "DOTNET_INSTALLER_PLUGIN"
35
36 #define __XSTR(x) #x
37 #define __STR(x) __XSTR(x)
38 static const char* __DOTNET_DIR = __STR(DOTNET_DIR);
39 #undef __STR
40 #undef __XSTR
41
42 std::vector<std::string> nugetPackagesAssembliesSha;
43 std::vector<std::string> tacDB;
44 std::vector<std::string> createDirectories;
45 std::vector<std::string> createLibraries;
46 std::vector<std::string> updateTac;
47 std::string status = "";
48 static sqlite3 *tac_db = NULL;
49 static sqlite3 *tlc_db = NULL;
50 bool tacPluginInstalled = false;
51 bool tacPluginFinished = false;
52
53 static void createSHA256Info(std::string sha256Info, std::string nugetPackage)
54 {
55         std::ofstream ofs(sha256Info, std::ios::app);
56         int assembly_count = 0;
57         for (auto& npAssemblySha : nugetPackagesAssembliesSha) {
58                 std::string nuget_package_assembly = npAssemblySha.substr(0, npAssemblySha.rfind(':'));
59                 std::string nuget_package = nuget_package_assembly.substr(0, nuget_package_assembly.rfind(':'));
60                 std::string assembly = nuget_package_assembly.substr(nuget_package_assembly.rfind(':') + 1);
61                 std::string sha = npAssemblySha.substr(npAssemblySha.rfind(':') + 1);
62                 if (!strcmp(nuget_package.c_str(), nugetPackage.c_str())) {
63                         ofs << assembly << ":" << sha << std::endl;
64                         assembly_count++;
65                 }
66         }
67         ofs << assembly_count << std::endl;
68         ofs.close();
69 }
70
71 static bool compareSHA256Info(std::string sha256Info, std::string nugetPackage)
72 {
73         int compare_count = 0;
74         int assembly_count = 0;
75         std::string sha256_count = "0";
76         for (auto& npAssemblySha : nugetPackagesAssembliesSha) {
77                 std::string nuget_package_assembly = npAssemblySha.substr(0, npAssemblySha.rfind(':'));
78                 std::string nuget_package = nuget_package_assembly.substr(0, nuget_package_assembly.rfind(':'));
79                 std::string assembly = nuget_package_assembly.substr(nuget_package_assembly.rfind(':') + 1);
80                 std::string sha = npAssemblySha.substr(npAssemblySha.rfind(':') + 1);
81                 if (!strcmp(nuget_package.c_str(), nugetPackage.c_str())) {
82                         assembly_count++;
83                         std::ifstream ifs(sha256Info);
84                         std::string get_str;
85                         if (ifs.is_open()) {
86                                 while (getline(ifs, get_str)) {
87                                         if (!strcmp(get_str.c_str(), (assembly + ":" + sha).c_str())) {
88                                                 compare_count++;
89                                         }
90                                         sha256_count = get_str;
91                                 }
92                                 ifs.close();
93                         }
94                 }
95         }
96         if (!strcmp(std::to_string(assembly_count).c_str(), std::to_string(compare_count).c_str()) &&
97                 !strcmp(std::to_string(assembly_count).c_str(), sha256_count.c_str())) {
98                 _INFO("Same nuget : %s", nugetPackage.c_str());
99                 return true;
100         }
101         return false;
102 }
103
104 static int copyAssemblyCreateSymlink(std::string binPath, std::string tacVersionDir, std::string nugetPackage, bool isCreateTacDir)
105 {
106         std::string tac_dir = concatPath(binPath, TAC_SYMLINK_SUB_DIR);
107         if (!createDir(tac_dir)) {
108                 _ERR("Cannot create directory: %s", tac_dir.c_str());
109                 return -1;
110         }
111
112         for (auto& npAssemblySha : nugetPackagesAssembliesSha) {
113                 std::string nuget_package_assembly = npAssemblySha.substr(0, npAssemblySha.rfind(':'));
114                 std::string nuget_package = nuget_package_assembly.substr(0, nuget_package_assembly.rfind(':'));
115                 std::string assembly = nuget_package_assembly.substr(nuget_package_assembly.rfind(':') + 1);
116                 if (!strcmp(nuget_package.c_str(), nugetPackage.c_str())) {
117                         if (bf::exists(concatPath(binPath, assembly))) {
118                                 if (isCreateTacDir) {
119                                         if (!copyFile(concatPath(binPath, assembly), concatPath(tacVersionDir, assembly))) {
120                                                 _ERR("Failed to copy of %s", assembly.c_str());
121                                                 return -1;
122                                         }
123                                 }
124                                 bf::create_symlink(concatPath(tacVersionDir, assembly), concatPath(tac_dir, assembly));
125                                 if (!removeFile(concatPath(binPath, assembly))) {
126                                         _ERR("Failed to remove of %s", assembly.c_str());
127                                         return -1;
128                                 }
129                         }
130                 }
131         }
132         return 0;
133 }
134
135 static void copyLibraryCreateSymlink(const char* pkgId, std::vector<std::string> LibrariesInfo, std::string tlcDir)
136 {
137         if (LibrariesInfo.empty()) {
138                 _INFO("Not exist data for TLC in %s", pkgId);
139                 return;
140         }
141
142         for (auto& librarySha : LibrariesInfo) {
143                 std::string library = librarySha.substr(0, librarySha.find(':'));
144                 std::string filename = library.substr(library.rfind('/') + 1);
145                 std::string fileSha = filename + ".." + librarySha.substr(librarySha.find(':') + 1);
146                 bool fileCopied = false;
147                 if (!bf::exists(concatPath(tlcDir, fileSha))) {
148                         if (!copyFile(library, concatPath(tlcDir, fileSha))) {
149                                 _ERR("Failed to copy of %s", filename.c_str());
150                                 continue;
151                         }
152                         fileCopied = true;
153                         createLibraries.push_back(concatPath(tlcDir, fileSha));
154                 }
155                 if (!removeFile(library)) {
156                         _ERR("Failed to remove of %s", library.c_str());
157                         if (fileCopied) {
158                                 removeFile(concatPath(tlcDir, fileSha));
159                         }
160                         continue;
161                 }
162                 bf::create_symlink(concatPath(tlcDir, fileSha), library);
163
164                 char *sql = sqlite3_mprintf("INSERT INTO TLC (PKGID, LIBRARY) VALUES (%Q, %Q);", pkgId, fileSha.c_str());
165                 if (!insertDB(tlc_db, sql)) {
166                         _ERR("Sqlite insert error");
167                         sqlite3_free(sql);
168                         copyFile(concatPath(tlcDir, fileSha), library);
169                         if (fileCopied) {
170                                 removeFile(concatPath(tlcDir, fileSha));
171                         }
172                         continue;
173                 }
174                 sqlite3_free(sql);
175         }
176 }
177
178 static void checkDepsJson(std::string rootPath, std::string binPath, std::string execName)
179 {
180         for (auto& npAssembly : depsJsonParser(rootPath, execName)) {
181                 std::string nuget_package = npAssembly.substr(0, npAssembly.rfind(':'));
182                 std::string assembly_name = npAssembly.substr(npAssembly.rfind(':') + 1);
183                 tacDB.push_back(nuget_package);
184                 std::string buffer = SHA256(concatPath(binPath, assembly_name));
185                 nugetPackagesAssembliesSha.push_back(nuget_package + ":" + assembly_name + ":" + buffer);
186                 _INFO("Assembly : [%s] / SHA256 : [%s]", assembly_name.c_str(), buffer.c_str());
187         }
188         std::sort(tacDB.begin(), tacDB.end());
189         tacDB.erase(unique(tacDB.begin(), tacDB.end()), tacDB.end());
190 }
191
192 extern "C" int PKGMGR_MDPARSER_PLUGIN_INSTALL(const char *pkgId, const char *appId, GList *list)
193 {
194         _DBG("[===== PKGMGR_MDPARSER_PLUGIN_INSTALL =====]");
195         _INFO("PackageID : %s", pkgId);
196
197         // Can be multiple apps in one package
198         if (tacPluginInstalled) {
199                 _INFO("TAC plugin already installed");
200                 return 0;
201         }
202         tacPluginInstalled = true;
203
204         std::string appType = getAppType(std::string(pkgId));
205         if (strstr(appType.c_str(), "dotnet") == NULL) {
206                 _ERR("App type is not dotnet");
207                 return 0;
208         }
209         std::string execName = getExecName(std::string(pkgId));
210         std::string rootPath = getRootPath(std::string(pkgId));
211         if (execName.empty() || rootPath.empty()) {
212                 return 0;
213         }
214         std::string binPath = concatPath(rootPath, "bin");
215         std::string metaValue = getMetadataValue(std::string(pkgId), TAC_METADATA_KEY);
216         if (metaValue.empty()) {
217                 return 0;
218         }
219         if (metaValue == METADATA_VALUE) {
220                 checkDepsJson(rootPath, binPath, execName);
221         }
222
223         status = "install";
224         tac_db = createDB(TAC_APP_LIST_DB, CREATE_TAC_DB_TABLE);
225         if (!tac_db) {
226                 _ERR("Sqlite create error. So restore the database.");
227                 if (tac_restoreDB() != TAC_ERROR_NONE) {
228                         _ERR("Sqlite create error");
229                         return 0;
230                 }
231                 tac_db = createDB(TAC_APP_LIST_DB, CREATE_TAC_DB_TABLE);
232                 if (!tac_db) {
233                         _ERR("Sqlite create error");
234                         return 0;
235                 }
236         }
237         sqlite3_exec(tac_db, "BEGIN;", NULL, NULL, NULL);
238
239         if (tacDB.empty()) {
240                 _INFO("Not exist data for TAC in %s", pkgId);
241                 return 0;
242         }
243
244         for (auto& np : tacDB) {
245                 std::string tac_name = np.substr(0, np.find('/'));
246                 std::string tac_version = np.substr(np.rfind('/') + 1);
247                 _INFO("TAC name : %s", tac_name.c_str());
248                 _INFO("TAC version : %s", tac_version.c_str());
249
250                 std::string tac_version_dir = concatPath(__DOTNET_DIR, np);
251                 std::string sha256_info = concatPath(tac_version_dir, TAC_SHA_256_INFO);
252                 if (!bf::exists(tac_version_dir)) {
253                         _INFO("Create tac_version_dir [%s]", tac_version_dir.c_str());
254                         if (!createDir(tac_version_dir)) {
255                                 _ERR("Cannot create directory: %s", tac_version_dir.c_str());
256                                 return 0;
257                         }
258                         createDirectories.push_back(tac_version_dir);
259                         if (!bf::is_symlink(sha256_info)) {
260                                 createSHA256Info(sha256_info, np);
261                         } else {
262                                 _ERR("Failed to create sha256_info. Symbolic link is detected");
263                                 return -1;
264                         }
265
266                         if (copyAssemblyCreateSymlink(binPath, tac_version_dir, np, true) < 0) {
267                                 _ERR("Failed to create symlink");
268                                 return -1;
269                         }
270
271                         char *sql = sqlite3_mprintf(
272                                 "INSERT INTO TAC (PKGID, NUGET, NAME, VERSION) " \
273                                 "VALUES (%Q, %Q, %Q, %Q);", pkgId, np.c_str(), tac_name.c_str(), tac_version.c_str());
274                         insertDB(tac_db, sql);
275                         sqlite3_free(sql);
276                 } else {
277                         _INFO("Exists tac_version_dir [%s]", tac_version_dir.c_str());
278                         if (!bf::is_symlink(sha256_info)) {
279                                 if (compareSHA256Info(sha256_info, np)) {
280                                         if (copyAssemblyCreateSymlink(binPath, tac_version_dir, np, false) < 0) {
281                                                 _ERR("Failed to create symlink");
282                                                 return -1;
283                                         }
284
285                                         char *sql = sqlite3_mprintf(
286                                                 "INSERT INTO TAC (PKGID, NUGET, NAME, VERSION) " \
287                                                 "VALUES (%Q, %Q, %Q, %Q);", pkgId, np.c_str(), tac_name.c_str(), tac_version.c_str());
288                                         insertDB(tac_db, sql);
289                                         sqlite3_free(sql);
290                                 } else {
291                                         _INFO("Different nuget : %s", np.c_str());
292                                 }
293                         } else {
294                                 _ERR("Failed to create sha256_info. Symbolic link is detected");
295                                 return -1;
296                         }
297                 }
298                 if (!bf::exists(sha256_info)) {
299                         if (!removeAll(tac_version_dir)) {
300                                 _ERR("Failed to remove of %s", tac_version_dir.c_str());
301                         }
302                 }
303         }
304
305         ///// TLC /////
306         std::string tlcDir = concatPath(__DOTNET_DIR, TLC_LIBRARIES_DIR);
307         if (!createDir(tlcDir)) {
308                 _ERR("Cannot create directory: %s", tlcDir.c_str());
309                 return 0;
310         }
311
312         tlc_db = createDB(TLC_APP_LIST_DB, CREATE_TLC_DB_TABLE);
313         if (!tlc_db) {
314                 _ERR("Sqlite create error. So restore the database.");
315                 if (tlc_restoreDB() != TAC_ERROR_NONE) {
316                         _ERR("Sqlite create error");
317                         return 0;
318                 }
319                 tlc_db = createDB(TLC_APP_LIST_DB, CREATE_TLC_DB_TABLE);
320                 if (!tlc_db) {
321                         _ERR("Sqlite create error");
322                         return 0;
323                 }
324         }
325         sqlite3_exec(tlc_db, "BEGIN;", NULL, NULL, NULL);
326
327         copyLibraryCreateSymlink(pkgId, getLibrariesInfo(rootPath), tlcDir);
328
329         return 0;
330 }
331
332 static int sqliteCb(void *count, int argc, char **argv, char **colName)
333 {
334         int *c = (int*)count;
335         *c = atoi(argv[0]);
336         return 0;
337 }
338
339 static int tac_updateDB(sqlite3 *sqlite)
340 {
341         for (auto& unp : updateTac) {
342                 int count = -1;
343                 char *sql = sqlite3_mprintf("SELECT COUNT(NUGET) FROM TAC WHERE NUGET = %Q;", unp.c_str());
344                 int ret = sqlite3_exec(sqlite, sql, sqliteCb, &count, NULL);
345                 if (ret != SQLITE_OK) {
346                         _ERR("Sqlite select error");
347                         sqlite3_free(sql);
348                         return -1;
349                 }
350                 if (count == 0) {
351                         std::string tac_version_dir_prev = concatPath(__DOTNET_DIR, unp);
352                         std::string tac_version_dir_backup = tac_version_dir_prev + ".bck";
353                         if (!copyDir(tac_version_dir_prev, tac_version_dir_backup)) {
354                                 _ERR("Failed to copy of %s to %s", tac_version_dir_prev.c_str(), tac_version_dir_backup.c_str());
355                                 sqlite3_free(sql);
356                                 return -1;
357                         }
358                         if (!removeAll(tac_version_dir_prev)) {
359                                 _ERR("Failed to remove of %s", tac_version_dir_prev.c_str());
360                                 sqlite3_free(sql);
361                                 return -1;
362                         }
363                 }
364                 sqlite3_free(sql);
365         }
366         return 0;
367 }
368
369 static void tlc_updateDB(sqlite3 *sqlite, std::vector<std::string> updateTlc, std::string tlcDir)
370 {
371         for (auto& ulp : updateTlc) {
372                 int count = -1;
373                 char *sql = sqlite3_mprintf("SELECT COUNT(LIBRARY) FROM TLC WHERE LIBRARY = %Q;", ulp.c_str());
374                 int ret = sqlite3_exec(sqlite, sql, sqliteCb, &count, NULL);
375                 if (ret != SQLITE_OK) {
376                         _ERR("Sqlite select error");
377                         sqlite3_free(sql);
378                         continue;
379                 }
380                 if (count == 0) {
381                         std::string library_prev = concatPath(tlcDir, ulp);
382                         std::string library_backup = library_prev + ".bck";
383                         if (!copyFile(library_prev, library_backup)) {
384                                 _ERR("Failed to copy of %s", library_prev.c_str());
385                                 sqlite3_free(sql);
386                                 continue;
387                         }
388                         if (!removeFile(library_prev)) {
389                                 _ERR("Failed to remove of %s", library_prev.c_str());
390                                 sqlite3_free(sql);
391                                 continue;
392                         }
393                 }
394                 sqlite3_free(sql);
395         }
396 }
397
398 extern "C" int PKGMGR_MDPARSER_PLUGIN_UPGRADE(const char *pkgId, const char *appId, GList *list)
399 {
400         _DBG("[===== PKGMGR_MDPARSER_PLUGIN_UPGRADE =====]");
401         _INFO("PackageID : %s", pkgId);
402
403         // Can be multiple apps in one package
404         if (tacPluginInstalled) {
405                 _INFO("TAC plugin already upgraded");
406                 return 0;
407         }
408         tacPluginInstalled = true;
409
410         std::string appType = getAppType(std::string(pkgId));
411         if (strstr(appType.c_str(), "dotnet") == NULL) {
412                 _ERR("App type is not dotnet");
413                 return 0;
414         }
415         std::string execName = getExecName(std::string(pkgId));
416         std::string rootPath = getRootPath(std::string(pkgId));
417         if (execName.empty() || rootPath.empty()) {
418                 return 0;
419         }
420         std::string binPath = concatPath(rootPath, "bin");
421
422         if (!strcmp("removed", status.c_str())) {
423                 _INFO("Skipped to parse of deps.json");
424         } else {
425                 std::string metaValue = getMetadataValue(std::string(pkgId), TAC_METADATA_KEY);
426                 if (metaValue.empty()) {
427                         return 0;
428                 }
429                 if (metaValue == METADATA_VALUE) {
430                         checkDepsJson(rootPath, binPath, execName);
431                 }
432         }
433
434         status = "update";
435         tac_db = createDB(TAC_APP_LIST_DB, CREATE_TAC_DB_TABLE);
436         if (!tac_db) {
437                 _ERR("Sqlite create error. So restore the database.");
438                 if (tac_restoreDB() != TAC_ERROR_NONE) {
439                         _ERR("Sqlite create error");
440                         return 0;
441                 }
442                 tac_db = createDB(TAC_APP_LIST_DB, CREATE_TAC_DB_TABLE);
443                 if (!tac_db) {
444                         _ERR("Sqlite create error");
445                         return 0;
446                 }
447         }
448         sqlite3_exec(tac_db, "BEGIN;", NULL, NULL, NULL);
449
450         char *sql = sqlite3_mprintf("SELECT * FROM TAC WHERE PKGID = %Q;", pkgId);
451         updateTac = selectDB(tac_db, sql);
452         sqlite3_free(sql);
453
454         bool skipTLC = false;
455         if (tacDB.empty()) {
456                 sql = sqlite3_mprintf("DELETE FROM TAC WHERE PKGID = %Q;", pkgId);
457                 deleteDB(tac_db, sql);
458                 sqlite3_free(sql);
459                 if (tac_updateDB(tac_db) < 0) {
460                         return -1;
461                 }
462                 skipTLC = true;
463                 _INFO("Not exist data for TAC in %s", pkgId);
464         } else {
465                 for (auto& np : tacDB) {
466                         std::string tac_name = np.substr(0, np.find('/'));
467                         std::string tac_version = np.substr(np.rfind('/') + 1);
468                         _INFO("TAC name : %s", tac_name.c_str());
469                         _INFO("TAC version : %s", tac_version.c_str());
470
471                         std::string tac_version_dir = concatPath(__DOTNET_DIR, np);
472                         std::string sha256_info = concatPath(tac_version_dir, TAC_SHA_256_INFO);
473                         if (!bf::exists(tac_version_dir)) {
474                                 _INFO("Create tac_version_dir [%s]", tac_version_dir.c_str());
475                                 if (!createDir(tac_version_dir)) {
476                                         _ERR("Cannot create directory: %s", tac_version_dir.c_str());
477                                         return 0;
478                                 }
479                                 createDirectories.push_back(tac_version_dir);
480                                 if (!bf::is_symlink(sha256_info)) {
481                                         createSHA256Info(sha256_info, np);
482                                 } else {
483                                         _ERR("Failed to create sha256_info. Symbolic link is detected");
484                                         return -1;
485                                 }
486
487                                 if (copyAssemblyCreateSymlink(binPath, tac_version_dir, np, true) < 0) {
488                                         _ERR("Failed to create symlink");
489                                         return -1;
490                                 }
491
492                                 int count = -1;
493                                 sql = sqlite3_mprintf(
494                                                 "SELECT COUNT(NUGET) FROM TAC WHERE PKGID = %Q AND NAME = %Q;", pkgId, tac_name.c_str());
495                                 int ret = sqlite3_exec(tac_db, sql, sqliteCb, &count, NULL);
496                                 if (ret != SQLITE_OK) {
497                                         _ERR("Sqlite select error");
498                                         sqlite3_free(sql);
499                                         return -1;
500                                 }
501                                 sqlite3_free(sql);
502                                 if (count == 1) {
503                                         sql = sqlite3_mprintf(
504                                                 "UPDATE TAC SET NAME = %Q, VERSION = %Q, NUGET = %Q WHERE PKGID = %Q AND NAME = %Q;",
505                                                 tac_name.c_str(), tac_version.c_str(), np.c_str(), pkgId, tac_name.c_str());
506                                         updateDB(tac_db, sql);
507                                         sqlite3_free(sql);
508                                 } else if (count == 0) {
509                                         sql = sqlite3_mprintf(
510                                                 "INSERT INTO TAC (PKGID, NUGET, NAME, VERSION) " \
511                                                 "VALUES (%Q, %Q, %Q, %Q);", pkgId, np.c_str(), tac_name.c_str(), tac_version.c_str());
512                                         insertDB(tac_db, sql);
513                                         sqlite3_free(sql);
514                                 }
515                         } else {
516                                 _INFO("Exists tac_version_dir [%s]", tac_version_dir.c_str());
517                                 if (!bf::is_symlink(sha256_info)) {
518                                         if (compareSHA256Info(sha256_info, np)) {
519                                                 if (copyAssemblyCreateSymlink(binPath, tac_version_dir, np, false) < 0) {
520                                                         _ERR("Failed to create symlink");
521                                                         return -1;
522                                                 }
523
524                                                 int count = -1;
525                                                 char *sql = sqlite3_mprintf(
526                                                         "SELECT COUNT(NUGET) FROM TAC WHERE PKGID = %Q AND NAME = %Q;", pkgId, tac_name.c_str());
527                                                 int ret = sqlite3_exec(tac_db, sql, sqliteCb, &count, NULL);
528                                                 if (ret != SQLITE_OK) {
529                                                         _ERR("Sqlite select error");
530                                                         sqlite3_free(sql);
531                                                         return -1;
532                                                 }
533                                                 sqlite3_free(sql);
534                                                 if (count == 1) {
535                                                         sql = sqlite3_mprintf(
536                                                                 "UPDATE TAC SET NAME = %Q, VERSION = %Q, NUGET = %Q WHERE PKGID = %Q AND NAME = %Q;",
537                                                                 tac_name.c_str(), tac_version.c_str(), np.c_str(), pkgId, tac_name.c_str());
538                                                         updateDB(tac_db, sql);
539                                                         sqlite3_free(sql);
540                                                 } else if (count == 0) {
541                                                         sql = sqlite3_mprintf(
542                                                                 "INSERT INTO TAC (PKGID, NUGET, NAME, VERSION) " \
543                                                                 "VALUES (%Q, %Q, %Q, %Q);", pkgId, np.c_str(), tac_name.c_str(), tac_version.c_str());
544                                                         insertDB(tac_db, sql);
545                                                         sqlite3_free(sql);
546                                                 }
547                                         } else {
548                                                 _INFO("Different nuget : %s", np.c_str());
549                                         }
550                                 } else {
551                                         _ERR("Failed to create sha256_info. Symbolic link is detected");
552                                         return -1;
553                                 }
554                         }
555                         if (!bf::exists(sha256_info)) {
556                                 if (!removeAll(tac_version_dir)) {
557                                         _ERR("Failed to remove of %s", tac_version_dir.c_str());
558                                 }
559                         }
560                 }
561                 for (auto& unp : updateTac) {
562                         bool isExits = false;
563                         for (auto& np : tacDB) {
564                                 if (!strcmp(unp.c_str(), np.c_str())) {
565                                         isExits = true;
566                                         break;
567                                 }
568                         }
569                         if (!isExits) {
570                                 char *sql = sqlite3_mprintf("DELETE FROM TAC WHERE PKGID = %Q AND NUGET = %Q;", pkgId, unp.c_str());
571                                 deleteDB(tac_db, sql);
572                                 sqlite3_free(sql);
573                         }
574                 }
575                 if (tac_updateDB(tac_db) < 0) {
576                         return -1;
577                 }
578         }
579
580         ///// TLC /////
581         std::string tlcDir = concatPath(__DOTNET_DIR, TLC_LIBRARIES_DIR);
582         if (!createDir(tlcDir)) {
583                 _ERR("Cannot create directory: %s", tlcDir.c_str());
584                 return 0;
585         }
586
587         tlc_db = createDB(TLC_APP_LIST_DB, CREATE_TLC_DB_TABLE);
588         if (!tlc_db) {
589                 _ERR("Sqlite create error. So restore the database.");
590                 if (tlc_restoreDB() != TAC_ERROR_NONE) {
591                         _ERR("Sqlite create error");
592                         return 0;
593                 }
594                 tlc_db = createDB(TLC_APP_LIST_DB, CREATE_TLC_DB_TABLE);
595                 if (!tlc_db) {
596                         _ERR("Sqlite create error");
597                         return 0;
598                 }
599         }
600         sqlite3_exec(tlc_db, "BEGIN;", NULL, NULL, NULL);
601
602         sql = sqlite3_mprintf("SELECT * FROM TLC WHERE PKGID = %Q;", pkgId);
603         std::vector<std::string> updateTlc = selectDB(tlc_db, sql);
604         sqlite3_free(sql);
605
606         sql = sqlite3_mprintf("DELETE FROM TLC WHERE PKGID = %Q;", pkgId);
607         deleteDB(tlc_db, sql);
608         sqlite3_free(sql);
609
610         std::vector<std::string> librariesInfo = getLibrariesInfo(rootPath);
611         if (skipTLC) {
612                 librariesInfo.clear();
613         }
614
615         copyLibraryCreateSymlink(pkgId, librariesInfo, tlcDir);
616
617         tlc_updateDB(tlc_db, updateTlc, tlcDir);
618
619         return 0;
620 }
621
622 extern "C" int PKGMGR_MDPARSER_PLUGIN_UNINSTALL(const char *pkgId, const char *appId, GList *list)
623 {
624         _DBG("[===== PKGMGR_MDPARSER_PLUGIN_UNINSTALL =====]");
625         _INFO("PackageID : %s", pkgId);
626
627         // Can be multiple apps in one package
628         if (tacPluginInstalled) {
629                 _INFO("TAC plugin already uninstalled");
630                 return 0;
631         }
632         tacPluginInstalled = true;
633
634         status = "uninstall";
635         tac_db = openDB(TAC_APP_LIST_DB);
636         if (!tac_db) {
637                 _ERR("Sqlite open error. So restore the database.");
638                 if (tac_restoreDB() != TAC_ERROR_NONE) {
639                         _ERR("Sqlite open error");
640                         return 0;
641                 }
642                 tac_db = openDB(TAC_APP_LIST_DB);
643                 if (!tac_db) {
644                         _ERR("Sqlite open error");
645                         return 0;
646                 }
647         }
648         sqlite3_exec(tac_db, "BEGIN;", NULL, NULL, NULL);
649
650         char *sql = sqlite3_mprintf("SELECT * FROM TAC WHERE PKGID = %Q;", pkgId);
651         updateTac = selectDB(tac_db, sql);
652         sqlite3_free(sql);
653
654         sql = sqlite3_mprintf("DELETE FROM TAC WHERE PKGID = %Q;", pkgId);
655         deleteDB(tac_db, sql);
656         sqlite3_free(sql);
657
658         if (tac_updateDB(tac_db) < 0) {
659                 return -1;
660         }
661
662         ///// TLC /////
663         tlc_db = openDB(TLC_APP_LIST_DB);
664         if (!tlc_db) {
665                 _ERR("Sqlite open error. So restore the database.");
666                 if (tlc_restoreDB() != TAC_ERROR_NONE) {
667                         _ERR("Sqlite open error");
668                         return 0;
669                 }
670                 tlc_db = openDB(TLC_APP_LIST_DB);
671                 if (!tlc_db) {
672                         _ERR("Sqlite open error");
673                         return 0;
674                 }
675         }
676         sqlite3_exec(tlc_db, "BEGIN;", NULL, NULL, NULL);
677
678         sql = sqlite3_mprintf("SELECT * FROM TLC WHERE PKGID = %Q;", pkgId);
679         std::vector<std::string> updateTlc = selectDB(tlc_db, sql);
680         sqlite3_free(sql);
681
682         sql = sqlite3_mprintf("DELETE FROM TLC WHERE PKGID = %Q;", pkgId);
683         deleteDB(tlc_db, sql);
684         sqlite3_free(sql);
685
686         tlc_updateDB(tlc_db, updateTlc, concatPath(__DOTNET_DIR, TLC_LIBRARIES_DIR));
687
688         return 0;
689 }
690
691 extern "C" int PKGMGR_MDPARSER_PLUGIN_REMOVED(const char *pkgId, const char *appId, GList *list)
692 {
693         _DBG("[===== PKGMGR_MDPARSER_PLUGIN_REMOVED =====]");
694         _INFO("PackageID : %s", pkgId);
695
696         status = "removed";
697
698         return PKGMGR_MDPARSER_PLUGIN_UPGRADE(pkgId, appId, list);
699 }
700
701 void cleanStep(std::string tac)
702 {
703         std::string current_tac = concatPath(__DOTNET_DIR, tac.substr(0, tac.find('/')));
704         try {
705                 for (auto& bck : bf::recursive_directory_iterator(current_tac)) {
706                         std::string bck_path = bck.path().string();
707                         if (bf::is_directory(bck_path) && strstr(bck_path.c_str(), ".bck") != NULL) {
708                                 if (!removeAll(bck_path)) {
709                                         _ERR("Failed to remove of %s", bck_path.c_str());
710                                 }
711                                 break;
712                         }
713                 }
714
715                 bool isExist = false;
716                 for (auto& bck : bf::recursive_directory_iterator(current_tac)) {
717                         std::string bck_path = bck.path().string();
718                         if (bf::exists(bck_path) && bf::is_directory(bck_path) && strstr(bck_path.c_str(), ".bck") == NULL) {
719                                 isExist = true;
720                                 break;
721                         }
722                 }
723                 if (!isExist) {
724                         if (!removeAll(current_tac)) {
725                                 _ERR("Failed to remove of %s", current_tac.c_str());
726                         }
727                 }
728         } catch (const bf::filesystem_error& error) {
729                 _ERR("Failed to recursive directory: %s", error.what());
730                 return;
731         }
732
733         ///// TLC /////
734         auto convert = [](const std::string& path, const std::string& filename) {
735                 if (filename.rfind(".bck") != std::string::npos) {
736                         if (!removeFile(path)) {
737                                 _ERR("Failed to remove of %s", path.c_str());
738                         }
739                 }
740         };
741
742         scanFilesInDirectory(concatPath(__DOTNET_DIR, TLC_LIBRARIES_DIR), convert, 0);
743 }
744
745 void install_Clean()
746 {
747         return;
748 }
749
750 void unInstall_Clean()
751 {
752         for (auto& unp : updateTac) {
753                 cleanStep(unp);
754         }
755 }
756
757 void update_Clean()
758 {
759         if (!tacDB.empty()) {
760                 for (auto& np : tacDB) {
761                         cleanStep(np);
762                 }
763         }
764         unInstall_Clean();
765 }
766
767 extern "C" int PKGMGR_MDPARSER_PLUGIN_CLEAN(const char *pkgId, const char *appId, GList *list)
768 {
769         _DBG("[===== PKGMGR_MDPARSER_PLUGIN_CLEAN =====]");
770         _INFO("PackageID : %s", pkgId);
771
772         // Can be multiple apps in one package
773         if (tacPluginFinished) {
774                 _INFO("TAC plugin already finished(CLEAN)");
775                 return 0;
776         }
777         tacPluginFinished = true;
778
779         if (!strcmp("install", status.c_str())) {
780                 install_Clean();
781         } else if (!strcmp("update", status.c_str())) {
782                 update_Clean();
783         } else if (!strcmp("uninstall", status.c_str())) {
784                 unInstall_Clean();
785         }
786
787         if (tac_db) {
788                 closeDB(tac_db);
789                 tac_db = NULL;
790         }
791
792         if (tlc_db) {
793                 closeDB(tlc_db);
794                 tlc_db = NULL;
795         }
796
797         return 0;
798 }
799
800 void undoStep(std::string tac)
801 {
802         std::string current_tac = concatPath(__DOTNET_DIR, tac.substr(0, tac.find('/')));
803         try {
804                 for (auto& bck : bf::recursive_directory_iterator(current_tac)) {
805                         std::string bck_path = bck.path().string();
806                         if (bf::is_directory(bck_path) && strstr(bck_path.c_str(), ".bck") != NULL) {
807                                 if (!moveFile(bck_path, bck_path.substr(0, bck_path.rfind(".bck")))) {
808                                         _ERR("Failed to move %s", bck_path.c_str());
809                                 }
810                                 break;
811                         }
812                 }
813         } catch (const bf::filesystem_error& error) {
814                 _ERR("Failed to recursive directory: %s", error.what());
815                 return;
816         }
817
818         ///// TLC /////
819         auto convert = [](const std::string& path, const std::string& filename) {
820                 if (filename.rfind(".bck") != std::string::npos) {
821                         if (!moveFile(path, replaceAll(path, ".bck", ""))) {
822                                 _ERR("Failed to move %s", path.c_str());
823                         }
824                 }
825         };
826
827         scanFilesInDirectory(concatPath(__DOTNET_DIR, TLC_LIBRARIES_DIR), convert, 0);
828 }
829
830 void install_Undo()
831 {
832         for (auto& cd : createDirectories) {
833                 if (!removeAll(cd)) {
834                         _ERR("Failed to remove of %s", cd.c_str());
835                 }
836         }
837
838         for (auto& cl : createLibraries) {
839                 if (!removeFile(cl)) {
840                         _ERR("Failed to remove of %s", cl.c_str());
841                 }
842         }
843 }
844
845 void unInstall_Undo()
846 {
847         for (auto& unp : updateTac) {
848                 undoStep(unp);
849         }
850 }
851
852 void update_Undo()
853 {
854         install_Undo();
855         if (!tacDB.empty()) {
856                 for (auto& np : tacDB) {
857                         undoStep(np);
858                 }
859         }
860         unInstall_Undo();
861 }
862
863 extern "C" int PKGMGR_MDPARSER_PLUGIN_UNDO(const char *pkgId, const char *appId, GList *list)
864 {
865         _DBG("[===== PKGMGR_MDPARSER_PLUGIN_UNDO =====]");
866         _INFO("PackageID : %s", pkgId);
867
868         // Can be multiple apps in one package
869         if (tacPluginFinished) {
870                 _INFO("TAC plugin already finished(UNDO)");
871                 return 0;
872         }
873         tacPluginFinished = true;
874
875         if (!strcmp("install", status.c_str())) {
876                 install_Undo();
877         } else if (!strcmp("update", status.c_str())) {
878                 update_Undo();
879         } else if (!strcmp("uninstall", status.c_str())) {
880                 unInstall_Undo();
881         }
882
883         if (tac_db) {
884                 rollbackDB(tac_db);
885                 tac_db = NULL;
886         }
887
888         if (tlc_db) {
889                 rollbackDB(tlc_db);
890                 tlc_db = NULL;
891         }
892
893         return 0;
894 }