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