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