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