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