Code cleanup (#251)
[platform/core/dotnet/launcher.git] / NativeLauncher / installer-plugin / prefer_nuget_cache_plugin.cc
1 /*
2  * Copyright (c) 2019 Samsung Electronics Co., Ltd All Rights Reserved
3  *
4  * Licensed under the Apache License, Version 2.0 (the License);
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an AS IS BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #include "log.h"
18 #include "utils.h"
19 #include "db_manager.h"
20 #include "path_manager.h"
21 #include "plugin_manager.h"
22 #include "tac_common.h"
23
24 #include <cstring>
25 #include <fstream>
26 #include <sstream>
27 #include <vector>
28 #include <boost/filesystem.hpp>
29 #include <glib.h>
30 #include <json/json.h>
31 #include <pkgmgr-info.h>
32 #include <pkgmgr_installer_info.h>
33 #include <openssl/sha.h>
34
35 #ifdef  LOG_TAG
36 #undef  LOG_TAG
37 #endif
38 #define LOG_TAG "DOTNET_INSTALLER_PLUGIN"
39
40 #define __XSTR(x) #x
41 #define __STR(x) __XSTR(x)
42 static const char* __DOTNET_DIR = __STR(DOTNET_DIR);
43 #undef __STR
44 #undef __XSTR
45
46 std::vector<std::string> nugetPackagesAssembliesSha;
47 std::vector<std::string> tacDB;
48 std::vector<std::string> createDirectories;
49 std::vector<std::string> updateTac;
50 std::string status = "";
51 static sqlite3 *tac_db = NULL;
52 bool tacPluginInstalled = false;
53 bool tacPluginFinished = false;
54
55 static void SHA256(std::string path, char outputBuffer[65])
56 {
57         FILE *file = fopen(path.c_str(), "rb");
58         if (!file) {
59                 return;
60         }
61
62         unsigned char hash[SHA256_DIGEST_LENGTH];
63         SHA256_CTX sha256;
64         SHA256_Init(&sha256);
65         int bytesRead = 0;
66         const int bufSize = 32768;
67         char *buffer = (char*)malloc(bufSize);
68         if (!buffer) {
69                 fclose(file);
70                 return;
71         }
72
73         while ((bytesRead = fread(buffer, 1, bufSize, file))) {
74                 SHA256_Update(&sha256, buffer, bytesRead);
75         }
76         SHA256_Final(hash, &sha256);
77         for (int i = 0; i < SHA256_DIGEST_LENGTH; i++) {
78                 snprintf(outputBuffer + (i * 2), 3, "%02x", hash[i]);
79         }
80         outputBuffer[64] = 0;
81
82         fclose(file);
83         free(buffer);
84 }
85
86 static void createSHA256Info(std::string sha256Info, std::string nugetPackage)
87 {
88         std::ofstream ofs(sha256Info, std::ios::app);
89         int assembly_count = 0;
90         for (auto& npAssemblySha : nugetPackagesAssembliesSha) {
91                 std::string nuget_package_assembly = npAssemblySha.substr(0, npAssemblySha.rfind(':'));
92                 std::string nuget_package = nuget_package_assembly.substr(0, nuget_package_assembly.rfind(':'));
93                 std::string assembly = nuget_package_assembly.substr(nuget_package_assembly.rfind(':') + 1);
94                 std::string sha = npAssemblySha.substr(npAssemblySha.rfind(':') + 1);
95                 if (!strcmp(nuget_package.c_str(), nugetPackage.c_str())) {
96                         ofs << assembly << ":" << sha << std::endl;
97                         assembly_count++;
98                 }
99         }
100         ofs << assembly_count << std::endl;
101         ofs.close();
102 }
103
104 static int compareSHA256Info(std::string sha256Info, std::string nugetPackage)
105 {
106         int compare_count = 0;
107         int assembly_count = 0;
108         std::string sha256_count = "0";
109         for (auto& npAssemblySha : nugetPackagesAssembliesSha) {
110                 std::string nuget_package_assembly = npAssemblySha.substr(0, npAssemblySha.rfind(':'));
111                 std::string nuget_package = nuget_package_assembly.substr(0, nuget_package_assembly.rfind(':'));
112                 std::string assembly = nuget_package_assembly.substr(nuget_package_assembly.rfind(':') + 1);
113                 std::string sha = npAssemblySha.substr(npAssemblySha.rfind(':') + 1);
114                 if (!strcmp(nuget_package.c_str(), nugetPackage.c_str())) {
115                         assembly_count++;
116                         std::ifstream ifs(sha256Info);
117                         std::string get_str;
118                         if (ifs.is_open()) {
119                                 while (getline(ifs, get_str)) {
120                                         if (!strcmp(get_str.c_str(), (assembly + ":" + sha).c_str())) {
121                                                 compare_count++;
122                                         }
123                                         sha256_count = get_str;
124                                 }
125                                 ifs.close();
126                         }
127                 }
128         }
129         if (!strcmp(std::to_string(assembly_count).c_str(), std::to_string(compare_count).c_str()) &&
130                 !strcmp(std::to_string(assembly_count).c_str(), sha256_count.c_str())) {
131                 _INFO("Same nuget : %s", nugetPackage.c_str());
132                 return 1;
133         }
134         return 0;
135 }
136
137 static int copyNCreateSymlink(std::string binPath, std::string tacVersionDir, std::string nugetPackage, bool isCreateTacDir)
138 {
139         uid_t g_uid = 0;
140         gid_t g_gid = 0;
141         if (pkgmgr_installer_info_get_target_uid(&g_uid) < 0) {
142                 _ERR("Failed to get UID");
143                 return -1;
144         }
145
146         std::string tac_dir = concatPath(binPath, TAC_SYMLINK_SUB_DIR);
147         if (!createDir(tac_dir)) {
148                 _ERR("Cannot create directory: %s", tac_dir.c_str());
149                 return -1;
150         }
151
152         for (auto& npAssemblySha : nugetPackagesAssembliesSha) {
153                 std::string nuget_package_assembly = npAssemblySha.substr(0, npAssemblySha.rfind(':'));
154                 std::string nuget_package = nuget_package_assembly.substr(0, nuget_package_assembly.rfind(':'));
155                 std::string assembly = nuget_package_assembly.substr(nuget_package_assembly.rfind(':') + 1);
156                 if (!strcmp(nuget_package.c_str(), nugetPackage.c_str())) {
157                         if (bf::exists(concatPath(binPath, assembly))) {
158                                 if (isCreateTacDir) {
159                                         if (!copyFile(concatPath(binPath, assembly), concatPath(tacVersionDir, assembly))) {
160                                                 _ERR("Failed to copy of %s", assembly.c_str());
161                                                 return -1;
162                                         }
163                                 }
164                                 bf::create_symlink(concatPath(tacVersionDir, assembly), concatPath(tac_dir, assembly));
165                                 if (lchown(concatPath(tac_dir, assembly).c_str(), g_uid, g_gid)) {
166                                         _ERR("Failed to change owner of: %s", concatPath(tac_dir, assembly).c_str());
167                                         return -1;
168                                 }
169                                 if (!removeFile(concatPath(binPath, assembly))) {
170                                         _ERR("Failed to remove of %s", assembly.c_str());
171                                         return -1;
172                                 }
173                         }
174                 }
175         }
176         return 0;
177 }
178
179 static void depsJsonCheck(std::string rootPath, std::string binPath, std::string execName)
180 {
181         for (auto& npAssembly : depsJsonParser(rootPath, execName, getTPA())) {
182                 std::string nuget_package = npAssembly.substr(0, npAssembly.rfind(':'));
183                 std::string assembly_name = npAssembly.substr(npAssembly.rfind(':') + 1);
184                 tacDB.push_back(nuget_package);
185                 char buffer[65] = {0};
186                 SHA256(concatPath(binPath, assembly_name), buffer);
187                 nugetPackagesAssembliesSha.push_back(nuget_package + ":" + assembly_name + ":" + buffer);
188                 _INFO("Assembly : [%s] / SHA256 : [%s]", assembly_name.c_str(), buffer);
189         }
190         std::sort(tacDB.begin(), tacDB.end());
191         tacDB.erase(unique(tacDB.begin(), tacDB.end()), tacDB.end());
192 }
193
194 extern "C" int PKGMGR_MDPARSER_PLUGIN_INSTALL(const char *pkgId, const char *appId, GList *list)
195 {
196         _DBG("[===== PKGMGR_MDPARSER_PLUGIN_INSTALL =====]");
197         _INFO("PackageID : %s", pkgId);
198
199         // Can be multiple apps in one package
200         if (tacPluginInstalled) {
201                 _INFO("TAC plugin already installed");
202                 return 0;
203         }
204         tacPluginInstalled = true;
205
206         if (initializePathManager(std::string(), std::string(), std::string())) {
207                 _ERR("Fail to initialize PathManger");
208                 return 0;
209         }
210
211         std::string appType = getAppType(std::string(pkgId));
212         if (strstr(appType.c_str(), "dotnet") == NULL) {
213                 _ERR("App type is not dotnet");
214                 return 0;
215         }
216         std::string execName = getExecName(std::string(pkgId));
217         std::string rootPath = getRootPath(std::string(pkgId));
218         if (execName.empty() || rootPath.empty()) {
219                 return 0;
220         }
221         std::string binPath = concatPath(rootPath, "bin");
222         std::string metaValue = getMetadataValue(std::string(pkgId), TAC_METADATA_KEY);
223         if (metaValue.empty()) {
224                 return 0;
225         }
226         if (metaValue == METADATA_VALUE) {
227                 depsJsonCheck(rootPath, binPath, execName);
228         }
229
230         status = "install";
231         tac_db = dbCreate(TAC_APP_LIST_DB, CREATE_TAC_DB_TABLE);
232         if (!tac_db) {
233                 _ERR("Sqlite create error");
234                 return 0;
235         }
236
237         if (tacDB.empty()) {
238                 _INFO("Not exist data for TAC in %s", pkgId);
239                 return 0;
240         }
241
242         for (auto& np : tacDB) {
243                 std::string tac_name = np.substr(0, np.find('/'));
244                 std::string tac_version = np.substr(np.rfind('/') + 1);
245                 _INFO("TAC name : %s", tac_name.c_str());
246                 _INFO("TAC version : %s", tac_version.c_str());
247
248                 std::string tac_version_dir = concatPath(__DOTNET_DIR, np);
249                 std::string sha256_info = concatPath(tac_version_dir, TAC_SHA_256_INFO);
250                 if (!bf::exists(tac_version_dir)) {
251                         _INFO("Create tac_version_dir [%s]", tac_version_dir.c_str());
252                         if (!createDir(tac_version_dir)) {
253                                 _ERR("Cannot create directory: %s", tac_version_dir.c_str());
254                                 return 0;
255                         }
256                         createDirectories.push_back(tac_version_dir);
257                         if (!bf::is_symlink(sha256_info)) {
258                                 createSHA256Info(sha256_info, np);
259                         } else {
260                                 _ERR("Failed to create sha256_info. Symbolic link is detected");
261                                 return -1;
262                         }
263
264                         if (copyNCreateSymlink(binPath, tac_version_dir, np, true) < 0) {
265                                 _ERR("Failed to create symlink");
266                                 return -1;
267                         }
268
269                         char *sql = sqlite3_mprintf(
270                                 "INSERT INTO TAC (PKGID, NUGET, NAME, VERSION) " \
271                                 "VALUES (%Q, %Q, %Q, %Q);", pkgId, np.c_str(), tac_name.c_str(), tac_version.c_str());
272                         dbInsert(tac_db, TAC_APP_LIST_DB, sql);
273                         sqlite3_free(sql);
274                 } else {
275                         _INFO("Exists tac_version_dir [%s]", tac_version_dir.c_str());
276                         if (!bf::is_symlink(sha256_info)) {
277                                 if (compareSHA256Info(sha256_info, np)) {
278                                         if (copyNCreateSymlink(binPath, tac_version_dir, np, false) < 0) {
279                                                 _ERR("Failed to create symlink");
280                                                 return -1;
281                                         }
282
283                                         char *sql = sqlite3_mprintf(
284                                                 "INSERT INTO TAC (PKGID, NUGET, NAME, VERSION) " \
285                                                 "VALUES (%Q, %Q, %Q, %Q);", pkgId, np.c_str(), tac_name.c_str(), tac_version.c_str());
286                                         dbInsert(tac_db, TAC_APP_LIST_DB, sql);
287                                         sqlite3_free(sql);
288                                 } else {
289                                         _INFO("Different nuget : %s", np.c_str());
290                                 }
291                         } else {
292                                 _ERR("Failed to create sha256_info. Symbolic link is detected");
293                                 return -1;
294                         }
295                 }
296                 if (!bf::exists(sha256_info)) {
297                         if (!removeAll(tac_version_dir)) {
298                                 _ERR("Failed to remove of %s", tac_version_dir.c_str());
299                         }
300                 }
301         }
302         return 0;
303 }
304
305 static int sqliteCb(void *count, int argc, char **argv, char **colName)
306 {
307         int *c = (int*)count;
308         *c = atoi(argv[0]);
309         return 0;
310 }
311
312 static int updateTacDB(sqlite3 *sqlite)
313 {
314         for (auto& unp : updateTac) {
315                 int count = -1;
316                 char *sql = sqlite3_mprintf("SELECT COUNT(NUGET) FROM TAC WHERE NUGET = %Q;", unp.c_str());
317                 int ret = sqlite3_exec(sqlite, sql, sqliteCb, &count, NULL);
318                 if (ret != SQLITE_OK) {
319                         _ERR("Sqlite select error");
320                         sqlite3_free(sql);
321                         return -1;
322                 }
323                 if (count == 0) {
324                         std::string tac_version_dir_prev = concatPath(__DOTNET_DIR, unp);
325                         std::string tac_version_dir_backup = tac_version_dir_prev + ".bck";
326                         if (!copyDir(tac_version_dir_prev, tac_version_dir_backup)) {
327                                 _ERR("Failed to copy of %s to %s", tac_version_dir_prev.c_str(), tac_version_dir_backup.c_str());
328                                 sqlite3_free(sql);
329                                 return -1;
330                         }
331                         if (!removeAll(tac_version_dir_prev)) {
332                                 _ERR("Failed to remove of %s", tac_version_dir_prev.c_str());
333                                 sqlite3_free(sql);
334                                 return -1;
335                         }
336                 }
337                 sqlite3_free(sql);
338         }
339         return 0;
340 }
341
342 extern "C" int PKGMGR_MDPARSER_PLUGIN_UPGRADE(const char *pkgId, const char *appId, GList *list)
343 {
344         _DBG("[===== PKGMGR_MDPARSER_PLUGIN_UPGRADE =====]");
345         _INFO("PackageID : %s", pkgId);
346
347         // Can be multiple apps in one package
348         if (tacPluginInstalled) {
349                 _INFO("TAC plugin already upgraded");
350                 return 0;
351         }
352         tacPluginInstalled = true;
353
354         if (initializePathManager(std::string(), std::string(), std::string())) {
355                 _ERR("Fail to initialize PathManger");
356                 return 0;
357         }
358
359         std::string appType = getAppType(std::string(pkgId));
360         if (strstr(appType.c_str(), "dotnet") == NULL) {
361                 _ERR("App type is not dotnet");
362                 return 0;
363         }
364         std::string execName = getExecName(std::string(pkgId));
365         std::string rootPath = getRootPath(std::string(pkgId));
366         if (execName.empty() || rootPath.empty()) {
367                 return 0;
368         }
369         std::string binPath = concatPath(rootPath, "bin");
370
371         if (!strcmp("removed", status.c_str())) {
372                 _INFO("Skipped to parse of deps.json");
373         } else {
374                 std::string metaValue = getMetadataValue(std::string(pkgId), TAC_METADATA_KEY);
375                 if (metaValue.empty()) {
376                         return 0;
377                 }
378                 if (metaValue == METADATA_VALUE) {
379                         depsJsonCheck(rootPath, binPath, execName);
380                 }
381         }
382
383         status = "update";
384         tac_db = dbCreate(TAC_APP_LIST_DB, CREATE_TAC_DB_TABLE);
385         if (!tac_db) {
386                 _ERR("Sqlite open error");
387                 return 0;
388         }
389
390         char *sql = sqlite3_mprintf("SELECT * FROM TAC WHERE PKGID = %Q;", pkgId);
391         updateTac = dbSelect(tac_db, TAC_APP_LIST_DB, sql);
392         sqlite3_free(sql);
393
394         if (tacDB.empty()) {
395                 sql = sqlite3_mprintf("DELETE FROM TAC WHERE PKGID = %Q;", pkgId);
396                 dbDelete(tac_db, TAC_APP_LIST_DB, sql);
397                 sqlite3_free(sql);
398                 if (updateTacDB(tac_db) < 0) {
399                         return -1;
400                 }
401                 _INFO("Not exist data for TAC in %s", pkgId);
402                 return 0;
403         } else {
404                 for (auto& np : tacDB) {
405                         std::string tac_name = np.substr(0, np.find('/'));
406                         std::string tac_version = np.substr(np.rfind('/') + 1);
407                         _INFO("TAC name : %s", tac_name.c_str());
408                         _INFO("TAC version : %s", tac_version.c_str());
409
410                         std::string tac_version_dir = concatPath(__DOTNET_DIR, np);
411                         std::string sha256_info = concatPath(tac_version_dir, TAC_SHA_256_INFO);
412                         if (!bf::exists(tac_version_dir)) {
413                                 _INFO("Create tac_version_dir [%s]", tac_version_dir.c_str());
414                                 if (!createDir(tac_version_dir)) {
415                                         _ERR("Cannot create directory: %s", tac_version_dir.c_str());
416                                         return 0;
417                                 }
418                                 createDirectories.push_back(tac_version_dir);
419                                 if (!bf::is_symlink(sha256_info)) {
420                                         createSHA256Info(sha256_info, np);
421                                 } else {
422                                         _ERR("Failed to create sha256_info. Symbolic link is detected");
423                                         return -1;
424                                 }
425
426                                 if (copyNCreateSymlink(binPath, tac_version_dir, np, true) < 0) {
427                                         _ERR("Failed to create symlink");
428                                         return -1;
429                                 }
430
431                                 int count = -1;
432                                 sql = sqlite3_mprintf(
433                                                 "SELECT COUNT(NUGET) FROM TAC WHERE PKGID = %Q AND NAME = %Q;", pkgId, tac_name.c_str());
434                                 int ret = sqlite3_exec(tac_db, sql, sqliteCb, &count, NULL);
435                                 if (ret != SQLITE_OK) {
436                                         _ERR("Sqlite select error");
437                                         sqlite3_free(sql);
438                                         return -1;
439                                 }
440                                 sqlite3_free(sql);
441                                 if (count == 1) {
442                                         sql = sqlite3_mprintf(
443                                                 "UPDATE TAC SET NAME = %Q, VERSION = %Q, NUGET = %Q WHERE PKGID = %Q AND NAME = %Q;",
444                                                 tac_name.c_str(), tac_version.c_str(), np.c_str(), pkgId, tac_name.c_str());
445                                         dbUpdate(tac_db, TAC_APP_LIST_DB, sql);
446                                         sqlite3_free(sql);
447                                 } else if (count == 0) {
448                                         sql = sqlite3_mprintf(
449                                                 "INSERT INTO TAC (PKGID, NUGET, NAME, VERSION) " \
450                                                 "VALUES (%Q, %Q, %Q, %Q);", pkgId, np.c_str(), tac_name.c_str(), tac_version.c_str());
451                                         dbInsert(tac_db, TAC_APP_LIST_DB, sql);
452                                         sqlite3_free(sql);
453                                 }
454                         } else {
455                                 _INFO("Exists tac_version_dir [%s]", tac_version_dir.c_str());
456                                 if (!bf::is_symlink(sha256_info)) {
457                                         if (compareSHA256Info(sha256_info, np)) {
458                                                 if (copyNCreateSymlink(binPath, tac_version_dir, np, false) < 0) {
459                                                         _ERR("Failed to create symlink");
460                                                         return -1;
461                                                 }
462
463                                                 int count = -1;
464                                                 char *sql = sqlite3_mprintf(
465                                                         "SELECT COUNT(NUGET) FROM TAC WHERE PKGID = %Q AND NAME = %Q;", pkgId, tac_name.c_str());
466                                                 int ret = sqlite3_exec(tac_db, sql, sqliteCb, &count, NULL);
467                                                 if (ret != SQLITE_OK) {
468                                                         _ERR("Sqlite select error");
469                                                         sqlite3_free(sql);
470                                                         return -1;
471                                                 }
472                                                 sqlite3_free(sql);
473                                                 if (count == 1) {
474                                                         sql = sqlite3_mprintf(
475                                                                 "UPDATE TAC SET NAME = %Q, VERSION = %Q, NUGET = %Q WHERE PKGID = %Q AND NAME = %Q;",
476                                                                 tac_name.c_str(), tac_version.c_str(), np.c_str(), pkgId, tac_name.c_str());
477                                                         dbUpdate(tac_db, TAC_APP_LIST_DB, sql);
478                                                         sqlite3_free(sql);
479                                                 } else if (count == 0) {
480                                                         sql = sqlite3_mprintf(
481                                                                 "INSERT INTO TAC (PKGID, NUGET, NAME, VERSION) " \
482                                                                 "VALUES (%Q, %Q, %Q, %Q);", pkgId, np.c_str(), tac_name.c_str(), tac_version.c_str());
483                                                         dbInsert(tac_db, TAC_APP_LIST_DB, sql);
484                                                         sqlite3_free(sql);
485                                                 }
486                                         } else {
487                                                 _INFO("Different nuget : %s", np.c_str());
488                                         }
489                                 } else {
490                                         _ERR("Failed to create sha256_info. Symbolic link is detected");
491                                         return -1;
492                                 }
493                         }
494                         if (!bf::exists(sha256_info)) {
495                                 if (!removeAll(tac_version_dir)) {
496                                         _ERR("Failed to remove of %s", tac_version_dir.c_str());
497                                 }
498                         }
499                 }
500                 for (auto& unp : updateTac) {
501                         bool isExits = false;
502                         for (auto& np : tacDB) {
503                                 if (!strcmp(unp.c_str(), np.c_str())) {
504                                         isExits = true;
505                                         break;
506                                 }
507                         }
508                         if (!isExits) {
509                                 char *sql = sqlite3_mprintf("DELETE FROM TAC WHERE PKGID = %Q AND NUGET = %Q;", pkgId, unp.c_str());
510                                 dbDelete(tac_db, TAC_APP_LIST_DB, sql);
511                                 sqlite3_free(sql);
512                         }
513                 }
514                 if (updateTacDB(tac_db) < 0) {
515                         return -1;
516                 }
517         }
518         return 0;
519 }
520
521 extern "C" int PKGMGR_MDPARSER_PLUGIN_UNINSTALL(const char *pkgId, const char *appId, GList *list)
522 {
523         _DBG("[===== PKGMGR_MDPARSER_PLUGIN_UNINSTALL =====]");
524         _INFO("PackageID : %s", pkgId);
525
526         // Can be multiple apps in one package
527         if (tacPluginInstalled) {
528                 _INFO("TAC plugin already uninstalled");
529                 return 0;
530         }
531         tacPluginInstalled = true;
532
533         status = "uninstall";
534         tac_db = dbOpen(TAC_APP_LIST_DB);
535         if (!tac_db) {
536                 _ERR("Sqlite open error");
537                 return 0;
538         }
539
540         char *sql = sqlite3_mprintf("SELECT * FROM TAC WHERE PKGID = %Q;", pkgId);
541         updateTac = dbSelect(tac_db, TAC_APP_LIST_DB, sql);
542         sqlite3_free(sql);
543
544         sql = sqlite3_mprintf("DELETE FROM TAC WHERE PKGID = %Q;", pkgId);
545         dbDelete(tac_db, TAC_APP_LIST_DB, sql);
546         sqlite3_free(sql);
547
548         if (updateTacDB(tac_db) < 0) {
549                 return -1;
550         }
551         return 0;
552 }
553
554 extern "C" int PKGMGR_MDPARSER_PLUGIN_REMOVED(const char *pkgId, const char *appId, GList *list)
555 {
556         _DBG("[===== PKGMGR_MDPARSER_PLUGIN_REMOVED =====]");
557         _INFO("PackageID : %s", pkgId);
558
559         status = "removed";
560
561         return PKGMGR_MDPARSER_PLUGIN_UPGRADE(pkgId, appId, list);
562 }
563
564 void cleanStep(std::string tac)
565 {
566         std::string current_tac = concatPath(__DOTNET_DIR, tac.substr(0, tac.find('/')));
567         try {
568                 for (auto& bck : bf::recursive_directory_iterator(current_tac)) {
569                         std::string bck_path = bck.path().string();
570                         if (bf::is_directory(bck_path) && strstr(bck_path.c_str(), ".bck") != NULL) {
571                                 if (!removeAll(bck_path)) {
572                                         _ERR("Failed to remove of %s", bck_path.c_str());
573                                 }
574                                 break;
575                         }
576                 }
577
578                 bool isExist = false;
579                 for (auto& bck : bf::recursive_directory_iterator(current_tac)) {
580                         std::string bck_path = bck.path().string();
581                         if (bf::exists(bck_path) && bf::is_directory(bck_path) && strstr(bck_path.c_str(), ".bck") == NULL) {
582                                 isExist = true;
583                                 break;
584                         }
585                 }
586                 if (!isExist) {
587                         if (!removeAll(current_tac)) {
588                                 _ERR("Failed to remove of %s", current_tac.c_str());
589                         }
590                 }
591         } catch (const bf::filesystem_error& error) {
592                 _ERR("Failed to recursive directory: %s", error.what());
593                 return;
594         }
595 }
596
597 void install_Clean()
598 {
599         return;
600 }
601
602 void unInstall_Clean()
603 {
604         for (auto& unp : updateTac) {
605                 cleanStep(unp);
606         }
607 }
608
609 void update_Clean()
610 {
611         if (!tacDB.empty()) {
612                 for (auto& np : tacDB) {
613                         cleanStep(np);
614                 }
615         }
616         unInstall_Clean();
617 }
618
619 extern "C" int PKGMGR_MDPARSER_PLUGIN_CLEAN(const char *pkgId, const char *appId, GList *list)
620 {
621         _DBG("[===== PKGMGR_MDPARSER_PLUGIN_CLEAN =====]");
622         _INFO("PackageID : %s", pkgId);
623
624         // Can be multiple apps in one package
625         if (tacPluginFinished) {
626                 _INFO("TAC plugin already finished(CLEAN)");
627                 return 0;
628         }
629         tacPluginFinished = true;
630
631         if (tac_db) {
632                 dbClose(tac_db);
633                 tac_db = NULL;
634         }
635         if (!strcmp("install", status.c_str())) {
636                 install_Clean();
637         } else if (!strcmp("update", status.c_str())) {
638                 update_Clean();
639         } else if (!strcmp("uninstall", status.c_str())) {
640                 unInstall_Clean();
641         }
642         return 0;
643 }
644
645 void undoStep(std::string tac)
646 {
647         std::string current_tac = concatPath(__DOTNET_DIR, tac.substr(0, tac.find('/')));
648         try {
649                 for (auto& bck : bf::recursive_directory_iterator(current_tac)) {
650                         std::string bck_path = bck.path().string();
651                         if (bf::is_directory(bck_path) && strstr(bck_path.c_str(), ".bck") != NULL) {
652                                 if (!moveFile(bck_path, bck_path.substr(0, bck_path.rfind(".bck")))) {
653                                         _ERR("Failed to move %s", bck_path.c_str());
654                                 }
655                                 break;
656                         }
657                 }
658         } catch (const bf::filesystem_error& error) {
659                 _ERR("Failed to recursive directory: %s", error.what());
660                 return;
661         }
662 }
663
664 void install_Undo()
665 {
666         for (auto& cd : createDirectories) {
667                 if (!removeAll(cd)) {
668                         _ERR("Failed to remove of %s", cd.c_str());
669                 }
670         }
671 }
672
673 void unInstall_Undo()
674 {
675         for (auto& unp : updateTac) {
676                 undoStep(unp);
677         }
678 }
679
680 void update_Undo()
681 {
682         install_Undo();
683         if (!tacDB.empty()) {
684                 for (auto& np : tacDB) {
685                         undoStep(np);
686                 }
687         }
688         unInstall_Undo();
689 }
690
691 extern "C" int PKGMGR_MDPARSER_PLUGIN_UNDO(const char *pkgId, const char *appId, GList *list)
692 {
693         _DBG("[===== PKGMGR_MDPARSER_PLUGIN_UNDO =====]");
694         _INFO("PackageID : %s", pkgId);
695
696         // Can be multiple apps in one package
697         if (tacPluginFinished) {
698                 _INFO("TAC plugin already finished(UNDO)");
699                 return 0;
700         }
701         tacPluginFinished = true;
702
703         if (tac_db) {
704                 dbRollback(tac_db);
705                 tac_db = NULL;
706         }
707         if (!strcmp("install", status.c_str())) {
708                 install_Undo();
709         } else if (!strcmp("update", status.c_str())) {
710                 update_Undo();
711         } else if (!strcmp("uninstall", status.c_str())) {
712                 unInstall_Undo();
713         }
714         return 0;
715 }