Merge pull request #72 from j-h-choi/tac_env
[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 "ni_common.h"
19 #include "utils.h"
20 #include "db_manager.h"
21
22 #include <cstring>
23 #include <fstream>
24 #include <sstream>
25 #include <vector>
26 #include <boost/filesystem.hpp>
27 #include <glib.h>
28 #include <json/json.h>
29 #include <pkgmgr-info.h>
30 #include <pkgmgr_installer_info.h>
31 #include <openssl/sha.h>
32
33 #ifdef  LOG_TAG
34 #undef  LOG_TAG
35 #endif
36 #define LOG_TAG "DOTNET_INSTALLER_PLUGIN"
37
38 #define __XSTR(x) #x
39 #define __STR(x) __XSTR(x)
40 static const char* __TAC_DIR = __STR(TAC_DIR);
41 #undef __STR
42 #undef __XSTR
43
44 typedef struct Metadata {
45         const char *key;
46         const char *value;
47 } Metadata;
48
49 std::vector<std::string> nugetPackagesAssembliesShaR2R;
50 std::vector<std::string> tacDB;
51 std::vector<std::string> createDirectories;
52 std::vector<std::string> updateTac;
53 std::string status = "";
54 std::string rootPath;
55 std::string execName;
56 std::string binPath;
57 bool isCreateDirectory = false;
58 static sqlite3 *tac_db = NULL;
59
60 int metadataCheck(GList *list)
61 {
62         GList *tag = NULL;
63         Metadata *mdInfo = NULL;
64         tag = g_list_first(list);
65         mdInfo = (Metadata*)tag->data;
66         if (strcmp(mdInfo->key, TAC_METADATA_KEY) == 0 && strcmp(mdInfo->value, METADATA_VALUE) == 0) {
67                 _DBG("Prefer nuget cache set TRUE");
68                 NiCommonOption option = {std::string(), std::string(), std::string()};
69                 if (initNICommon(&option) < 0) {
70                         _ERR("Fail to initialize NI Common");
71                         return -1;
72                 }
73                 return 0;
74         } else {
75                 return -1;
76         }
77 }
78
79 int appTypeCheck(std::string pkgId)
80 {
81         uid_t uid = 0;
82         if (pkgmgr_installer_info_get_target_uid(&uid) < 0) {
83                 _ERR("Failed to get UID");
84                 return 0;
85         }
86
87         pkgmgrinfo_pkginfo_h handle;
88         int ret = pkgmgrinfo_pkginfo_get_usr_pkginfo(pkgId.c_str(), uid, &handle);
89         if (ret != PMINFO_R_OK) {
90                 _ERR("Failed to get pkg info");
91                 return 0;
92         }
93
94         bool isDotnetAppType = false;
95         auto dotnetAppCounter = [] (pkgmgrinfo_appinfo_h handle, void *userData) -> int {
96                 char* type = nullptr;
97                 bool* dotnet = static_cast<bool*>(userData);
98                 if (pkgmgrinfo_appinfo_get_apptype(handle, &type) != PMINFO_R_OK) {
99                         _ERR("Failed to get app type : %s", type);
100                         return 0;
101                 }
102                 if (strcmp(type, "dotnet") == 0) {
103                         *dotnet = true;
104                 }
105                 return 0;
106         };
107
108         if (pkgmgrinfo_appinfo_get_usr_list(handle, PMINFO_ALL_APP, dotnetAppCounter, &isDotnetAppType, uid) != PMINFO_R_OK) {
109                 _ERR("Failed to get list of app in pkg : %s", pkgId.c_str());
110                 return -1;
111         }
112
113         pkgmgrinfo_pkginfo_destroy_pkginfo(handle);
114         return isDotnetAppType;
115 }
116
117 int getExecName(std::string pkgId)
118 {
119         uid_t uid = 0;
120         if (pkgmgr_installer_info_get_target_uid(&uid) < 0) {
121                 _ERR("Failed to get UID");
122                 return 0;
123         }
124
125         pkgmgrinfo_pkginfo_h handle;
126         int ret = pkgmgrinfo_pkginfo_get_usr_pkginfo(pkgId.c_str(), uid, &handle);
127         if (ret != PMINFO_R_OK) {
128                 _ERR("Failed to get pkg info");
129                 return 0;
130         }
131
132         auto dotnetAppCounter = [] (pkgmgrinfo_appinfo_h handle, void *userData) -> int {
133                 char* exec = nullptr;
134                 if (pkgmgrinfo_appinfo_get_exec(handle, &exec) != PMINFO_R_OK) {
135                         _ERR("Failed to get exec : %s", exec);
136                         return 0;
137                 }
138                 execName = std::string(exec).substr(std::string(exec).rfind('/') + 1);
139                 return 0;
140         };
141
142         if (pkgmgrinfo_appinfo_get_usr_list(handle, PMINFO_ALL_APP, dotnetAppCounter, NULL, uid) != PMINFO_R_OK) {
143                 _ERR("Failed to get list of app in pkg : %s", pkgId.c_str());
144                 return -1;
145         }
146
147         pkgmgrinfo_pkginfo_destroy_pkginfo(handle);
148         return 0;
149 }
150
151 int SHA256(std::string path, char outputBuffer[65])
152 {
153         FILE *file = fopen(path.c_str(), "rb");
154         if (!file) {
155                 return -1;
156         }
157
158         unsigned char hash[SHA256_DIGEST_LENGTH];
159         SHA256_CTX sha256;
160         SHA256_Init(&sha256);
161         int bytesRead = 0;
162         const int bufSize = 32768;
163         char *buffer = (char*)malloc(bufSize);
164         if (!buffer) {
165                 fclose(file);
166                 return -1;
167         }
168
169         while ((bytesRead = fread(buffer, 1, bufSize, file))) {
170                 SHA256_Update(&sha256, buffer, bytesRead);
171         }
172         SHA256_Final(hash, &sha256);
173         for (int i = 0; i < SHA256_DIGEST_LENGTH; i++) {
174                 sprintf(outputBuffer + (i * 2), "%02x", hash[i]);
175         }
176         outputBuffer[64] = 0;
177
178         fclose(file);
179         free(buffer);
180         return 0;
181 }
182
183 int depsJsonParser()
184 {
185         std::string deps_json_name = execName.substr(0, execName.rfind(".dll")) + ".deps.json";
186         if (bf::exists(concatPath(rootPath, deps_json_name))) {
187                 std::string deps_json_path = concatPath(rootPath, deps_json_name);
188                 std::ifstream ifs(deps_json_path);
189                 Json::CharReaderBuilder reader;
190                 Json::Value root;
191                 std::string error;
192                 if (ifs.is_open()) {
193                         if (!Json::parseFromStream(reader, ifs, &root, &error)) {
194                                 _INFO("Failed to parse of deps.json");
195                                 ifs.close();
196                                 return -1;
197                         }
198                         const Json::Value runtimeTargetName = root["runtimeTarget"]["name"];
199                         std::string runtimeTarget_name = runtimeTargetName.asString();
200                         const Json::Value nugetPackages = root["targets"][runtimeTarget_name.c_str()];
201                         for (auto& nuget : nugetPackages.getMemberNames()) {
202                                 if (strstr(nuget.c_str(), TIZEN_DOTNET_NUGET) != NULL ||
203                                         strstr(nuget.c_str(), TIZEN_DOTNET_SDK_NUGET) != NULL ||
204                                         strstr(nuget.c_str(), (execName.substr(0, execName.find(".Tizen."))).c_str()) != NULL ||
205                                         strstr(nuget.c_str(), (execName.substr(0, execName.find(".dll"))).c_str()) != NULL) {
206                                         continue;
207                                 } else {
208                                         const Json::Value assemblies = nugetPackages[nuget.c_str()]["runtime"];
209                                         if (assemblies != Json::nullValue) {
210                                                 const Json::Value dependencies = nugetPackages[nuget.c_str()]["dependencies"];
211                                                 std::string r2r = "";
212                                                 for (auto& dependency : dependencies.getMemberNames()) {
213                                                         if (strstr(dependency.c_str(), TIZEN_DOTNET_NUGET) != NULL ||
214                                                                 strstr(dependency.c_str(), NET_STANDARD_LIBRARY_NUGET) != NULL) {
215                                                                 continue;
216                                                         } else {
217                                                                 r2r = "--r2r";
218                                                         }
219                                                 }
220                                                 if (strcmp(r2r.c_str(), "--r2r") != 0) {
221                                                         tacDB.push_back(nuget);
222                                                         _INFO("Nuget package : %s", nuget.c_str());
223                                                         for (auto& assembly : assemblies.getMemberNames()) {
224                                                                 std::string assembly_name = assembly.substr(assembly.rfind('/') + 1);
225                                                                 char buffer[65];
226                                                                 SHA256(concatPath(binPath, assembly_name), buffer);
227                                                                 nugetPackagesAssembliesShaR2R.push_back(nuget + "/" + assembly_name + "/" + buffer + "/" + r2r);
228                                                                 _INFO("Assembly / SHA256 : %s / %s", assembly_name.c_str(), buffer);
229                                                         }
230                                                 }
231                                         }
232                                 }
233                         }
234                         ifs.close();
235                 }
236         }
237         return 0;
238 }
239
240 int createSymlink(bf::path tac_version_dir, std::string np)
241 {
242         bs::error_code error;
243         uid_t uid = 0;
244         for (auto& npAssemblyShaR2R : nugetPackagesAssembliesShaR2R) {
245                 std::string nuget_package_assembly_sha = npAssemblyShaR2R.substr(0, npAssemblyShaR2R.rfind('/'));
246                 std::string sha = nuget_package_assembly_sha.substr(nuget_package_assembly_sha.rfind('/') + 1);
247                 std::string nuget_package_assembly = nuget_package_assembly_sha.substr(0, nuget_package_assembly_sha.rfind('/'));
248                 std::string nuget_package = nuget_package_assembly.substr(0, nuget_package_assembly.rfind('/'));
249                 std::string assembly = nuget_package_assembly.substr(nuget_package_assembly.rfind('/') + 1);
250                 std::string r2r = npAssemblyShaR2R.substr(npAssemblyShaR2R.rfind('/') + 1);
251                 if (!strcmp(nuget_package.c_str(), np.c_str())) {
252                         if (bf::exists(concatPath(binPath, assembly))) {
253                                 if (isCreateDirectory) {
254                                         if (!copyFile(concatPath(binPath, assembly), tac_version_dir / assembly)) {
255                                                 _ERR("Failed to move of %s", assembly.c_str());
256                                                 return -1;
257                                         }
258                                 }
259                                 if (pkgmgr_installer_info_get_target_uid(&uid) < 0) {
260                                         _ERR("Failed to get UID");
261                                         return -1;
262                                 }
263                                 std::string tac_dir = concatPath(binPath, TAC_SYMLINK_SUB_DIR);
264                                 bf::create_symlink(tac_version_dir / assembly, concatPath(tac_dir, assembly), error);
265                                 if (error) {
266                                         _ERR("Failed to create symlink");
267                                         return -1;
268                                 }
269                                 if (lchown(concatPath(tac_dir, assembly).c_str(), uid, 0)) {
270                                         _ERR("Failed to change owner of: %s", concatPath(tac_dir, assembly).c_str());
271                                         return -1;
272                                 }
273                         }
274                 }
275         }
276         return 0;
277 }
278
279 int removeOriginalAssembly() {
280         for (auto& npAssemblyShaR2R : nugetPackagesAssembliesShaR2R) {
281                 std::string nuget_package_assembly_sha = npAssemblyShaR2R.substr(0, npAssemblyShaR2R.rfind('/'));
282                 std::string sha = nuget_package_assembly_sha.substr(nuget_package_assembly_sha.rfind('/') + 1);
283                 std::string nuget_package_assembly = nuget_package_assembly_sha.substr(0, nuget_package_assembly_sha.rfind('/'));
284                 std::string nuget_package = nuget_package_assembly.substr(0, nuget_package_assembly.rfind('/'));
285                 std::string assembly = nuget_package_assembly.substr(nuget_package_assembly.rfind('/') + 1);
286                 std::string r2r = npAssemblyShaR2R.substr(npAssemblyShaR2R.rfind('/') + 1);
287                 if (bf::exists(concatPath(binPath, assembly))) {
288                         if (!removeFile(concatPath(binPath, assembly))) {
289                                 _ERR("Failed to remove of %s", assembly.c_str());
290                                 return -1;
291                         }
292                 }
293         }
294         return 0;
295 }
296
297 extern "C" int PKGMGR_MDPARSER_PLUGIN_INSTALL(const char *pkgId, const char *appId, GList *list)
298 {
299         _DBG("[===== PKGMGR_MDPARSER_PLUGIN_INSTALL =====]");
300         _INFO("PackageID : %s", pkgId);
301
302         if (!appTypeCheck(std::string(pkgId))) {
303                 _INFO("App type is not dotnet");
304                 return 0;
305         }
306         if (getExecName(std::string(pkgId)) < 0) {
307                 return 0;
308         }
309         if (getRootPath(std::string(pkgId), rootPath) < 0) {
310                 return 0;
311         } else {
312                 binPath = concatPath(rootPath, "bin");
313         }
314         if (!metadataCheck(list)) {
315                 if (depsJsonParser()) {
316                         return 0;
317                 }
318         }
319
320         status = "install";
321         tac_db = dbCreate(TAC_APP_LIST_DB);
322         if (tac_db) {
323                 if (!dbOpen(tac_db, TAC_APP_LIST_DB)) {
324                         return 0;
325                 }
326         } else {
327                 _ERR("Sqlite create error");
328                 return 0;
329         }
330
331         if (tacDB.empty()) {
332                 _ERR("Not exist .deps.json file");
333                 return 0;
334         }
335         std::string tac_dir = concatPath(binPath, TAC_SYMLINK_SUB_DIR);
336         if (!bf::exists(tac_dir)) {
337                 if (!createDir(tac_dir)) {
338                         _INFO("Cannot create directory: %s", tac_dir.c_str());
339                         return 0;
340                 }
341         }
342
343         for (auto& np : tacDB) {
344                 std::string tac_name = np.substr(0, np.find('/'));
345                 std::string tac_version = np.substr(np.rfind('/') + 1);
346                 _INFO("TAC name : %s", tac_name.c_str());
347                 _INFO("TAC version : %s", tac_version.c_str());
348
349                 bf::path tac_version_dir = concatPath(__TAC_DIR, np);
350                 isCreateDirectory = false;
351                 if (!bf::exists(tac_version_dir)) {
352                         _INFO("Create tac_version_dir [%s]", tac_version_dir.c_str());
353                         if (!createDir(tac_version_dir)) {
354                                 _ERR("Cannot create directory: %s", tac_version_dir.c_str());
355                                 return 0;
356                         }
357                         isCreateDirectory = true;
358                         createDirectories.push_back(tac_version_dir.string());
359                         std::string sha256_info = (tac_version_dir / TAC_SHA_256_INFO).string();
360                         std::ofstream ofs(sha256_info, std::ios::app);
361                         int assembly_count = 0;
362                         for (auto& npAssemblyShaR2R : nugetPackagesAssembliesShaR2R) {
363                                 std::string nuget_package_assembly_sha = npAssemblyShaR2R.substr(0, npAssemblyShaR2R.rfind('/'));
364                                 std::string sha = nuget_package_assembly_sha.substr(nuget_package_assembly_sha.rfind('/') + 1);
365                                 std::string nuget_package_assembly = nuget_package_assembly_sha.substr(0, nuget_package_assembly_sha.rfind('/'));
366                                 std::string nuget_package = nuget_package_assembly.substr(0, nuget_package_assembly.rfind('/'));
367                                 std::string assembly = nuget_package_assembly.substr(nuget_package_assembly.rfind('/') + 1);
368                                 std::string r2r = npAssemblyShaR2R.substr(npAssemblyShaR2R.rfind('/') + 1);
369                                 if (!strcmp(nuget_package.c_str(), np.c_str())) {
370                                         ofs << assembly << ";" << sha << std::endl;
371                                         assembly_count++;
372                                 }
373                         }
374                         ofs << assembly_count << std::endl;
375                         ofs.close();
376
377                         if (createSymlink(tac_version_dir, np)) {
378                                 _ERR("Failed to create symlink");
379                                 return 0;
380                         }
381                         std::string sql = "INSERT INTO TAC (PKGID, NUGET, NAME, VERSION) " \
382                                         "VALUES ('" + std::string(pkgId) + "', '" + np + "', '" + tac_name + "', '" + tac_version + "');";
383                         dbInsert(tac_db, TAC_APP_LIST_DB, sql);
384                 } else {
385                         _INFO("Exists tac_version_dir [%s]", tac_version_dir.c_str());
386                         int compare_count = 0;
387                         int assembly_count = 0;
388                         std::string sha256_count = "0";
389                         for (auto& npAssemblyShaR2R : nugetPackagesAssembliesShaR2R) {
390                                 std::string nuget_package_assembly_sha = npAssemblyShaR2R.substr(0, npAssemblyShaR2R.rfind('/'));
391                                 std::string sha = nuget_package_assembly_sha.substr(nuget_package_assembly_sha.rfind('/') + 1);
392                                 std::string nuget_package_assembly = nuget_package_assembly_sha.substr(0, nuget_package_assembly_sha.rfind('/'));
393                                 std::string nuget_package = nuget_package_assembly.substr(0, nuget_package_assembly.rfind('/'));
394                                 std::string assembly = nuget_package_assembly.substr(nuget_package_assembly.rfind('/') + 1);
395                                 std::string r2r = npAssemblyShaR2R.substr(npAssemblyShaR2R.rfind('/') + 1);
396                                 if (!strcmp(nuget_package.c_str(), np.c_str())) {
397                                         assembly_count++;
398                                         std::string sha256_info = (tac_version_dir / TAC_SHA_256_INFO).string();
399                                         std::ifstream ifs(sha256_info);
400                                         std::string get_str;
401                                         if (ifs.is_open()) {
402                                                 while (getline(ifs, get_str)) {
403                                                         if (!strcmp(get_str.c_str(), (assembly + ";" + sha).c_str())) {
404                                                                 compare_count++;
405                                                         }
406                                                         sha256_count = get_str;
407                                                 }
408                                                 ifs.close();
409                                         }
410                                 }
411                         }
412                         if (!strcmp(std::to_string(assembly_count).c_str(), std::to_string(compare_count).c_str()) &&
413                                 !strcmp(std::to_string(assembly_count).c_str(), sha256_count.c_str())) {
414                                 _INFO("Same : %s", tac_name.c_str());
415                                 if (createSymlink(tac_version_dir, np)) {
416                                         return 0;
417                                 }
418                                 std::string sql = "INSERT INTO TAC (PKGID, NUGET, NAME, VERSION) " \
419                                                 "VALUES ('" + std::string(pkgId) + "', '" + np + "', '" + tac_name + "', '" + tac_version + "');";
420                                 dbInsert(tac_db, TAC_APP_LIST_DB, sql);
421                         } else {
422                                 _INFO("Different : %s", tac_name.c_str());
423                         }
424                 }
425         }
426         if (removeOriginalAssembly()) {
427                 return 0;
428         }
429         return 0;
430 }
431
432 static int sqliteCb(void *count, int argc, char **argv, char **azColName) {
433         int *c = (int*)count;
434         *c = atoi(argv[0]);
435         return 0;
436 }
437
438 int updateTacDB(const char *pkgId)
439 {
440         for (auto& unp : updateTac) {
441                 char *error = 0;
442                 int ret;
443                 int count = 0;
444                 if (tac_db) {
445                         if (!dbOpen(tac_db, TAC_APP_LIST_DB)) {
446                                 return 0;
447                         }
448                 } else {
449                         _ERR("Sqlite create error");
450                         return 0;
451                 }
452                 std::string sql = "SELECT COUNT(NUGET) FROM TAC WHERE NUGET = '" + unp + "';";
453                 ret = sqlite3_exec(tac_db, sql.c_str(), sqliteCb, &count, &error);
454                 if (ret != SQLITE_OK) {
455                         _ERR("SQL error: %s", error);
456                         sqlite3_free(error);
457                 }
458                 if (count < 1) {
459                         bf::path tac_version_dir_prev = concatPath(__TAC_DIR, unp);
460                         bf::path tac_version_dir_backup = concatPath(__TAC_DIR, unp) + ".bck";
461                         if (!copyDir(tac_version_dir_prev, tac_version_dir_backup)) {
462                                 _ERR("Failed to copy of %s to %s", tac_version_dir_prev.c_str(), tac_version_dir_backup.c_str());
463                                 return -1;
464                         }
465                         if (!removeAll(tac_version_dir_prev)) {
466                                 _ERR("Failed to remove of %s", tac_version_dir_prev.c_str());
467                                 return -1;
468                         }
469                 }
470         }
471         return 0;
472 }
473
474 extern "C" int PKGMGR_MDPARSER_PLUGIN_UPGRADE(const char *pkgId, const char *appId, GList *list)
475 {
476         _DBG("[===== PKGMGR_MDPARSER_PLUGIN_UPGRADE =====]");
477         _INFO("PackageID : %s", pkgId);
478
479         if (!appTypeCheck(std::string(pkgId))) {
480                 _INFO("App type is not dotnet");
481                 return 0;
482         }
483         if (getExecName(std::string(pkgId)) < 0) {
484                 return 0;
485         }
486         if (getRootPath(std::string(pkgId), rootPath) < 0) {
487                 return 0;
488         } else {
489                 binPath = concatPath(rootPath, "bin");
490         }
491         if (!strcmp("removed", status.c_str())) {
492                 _INFO("Skipped to parse of deps.json");
493         } else {
494                 if (!metadataCheck(list)) {
495                         if (depsJsonParser()) {
496                                 return 0;
497                         }
498                 }
499         }
500
501         status = "update";
502         tac_db = dbCreate(TAC_APP_LIST_DB);
503         if (tac_db) {
504                 if (!dbOpen(tac_db, TAC_APP_LIST_DB)) {
505                         return 0;
506                 }
507         } else {
508                 _ERR("Sqlite create error");
509                 return 0;
510         }
511
512         std::string sql = "SELECT * FROM TAC WHERE PKGID = '" + std::string(pkgId) + "';";
513         updateTac = dbSelect(tac_db, TAC_APP_LIST_DB, sql);
514
515         if (tacDB.empty()) {
516                 sql = "DELETE FROM TAC WHERE PKGID = '" + std::string(pkgId) + "';";
517                 dbDelete(tac_db, TAC_APP_LIST_DB, sql);
518                 if (updateTacDB(pkgId)) {
519                         return 0;
520                 }
521         } else {
522                 std::string tac_dir = concatPath(binPath, TAC_SYMLINK_SUB_DIR);
523                 if (!bf::exists(tac_dir)) {
524                         if (!createDir(tac_dir)) {
525                                 _INFO("Cannot create directory: %s", tac_dir.c_str());
526                                 return 0;
527                         }
528                 }
529
530                 for (auto& np : tacDB) {
531                         std::string tac_name = np.substr(0, np.find('/'));
532                         std::string tac_version = np.substr(np.rfind('/') + 1);
533                         _INFO("TAC name : %s", tac_name.c_str());
534                         _INFO("TAC version : %s", tac_version.c_str());
535
536                         bf::path tac_version_dir = concatPath(__TAC_DIR, np);
537                         isCreateDirectory = false;
538                         if (!bf::exists(tac_version_dir)) {
539                                 _INFO("Create tac_version_dir [%s]", tac_version_dir.c_str());
540                                 if (!createDir(tac_version_dir)) {
541                                         _ERR("Cannot create directory: %s", tac_version_dir.c_str());
542                                         return 0;
543                                 }
544                                 isCreateDirectory = true;
545                                 createDirectories.push_back(tac_version_dir.string());
546                                 std::string sha256_info = (tac_version_dir / TAC_SHA_256_INFO).string();
547                                 std::ofstream ofs2(sha256_info, std::ios::app);
548                                 int assembly_count = 0;
549                                 for (auto& npAssemblyShaR2R : nugetPackagesAssembliesShaR2R) {
550                                         std::string nuget_package_assembly_sha = npAssemblyShaR2R.substr(0, npAssemblyShaR2R.rfind('/'));
551                                         std::string sha = nuget_package_assembly_sha.substr(nuget_package_assembly_sha.rfind('/') + 1);
552                                         std::string nuget_package_assembly = nuget_package_assembly_sha.substr(0, nuget_package_assembly_sha.rfind('/'));
553                                         std::string nuget_package = nuget_package_assembly.substr(0, nuget_package_assembly.rfind('/'));
554                                         std::string assembly = nuget_package_assembly.substr(nuget_package_assembly.rfind('/') + 1);
555                                         std::string r2r = npAssemblyShaR2R.substr(npAssemblyShaR2R.rfind('/') + 1);
556                                         if (!strcmp(nuget_package.c_str(), np.c_str())) {
557                                                 ofs2 << assembly << ";" << sha << std::endl;
558                                                 assembly_count++;
559                                         }
560                                 }
561                                 ofs2 << assembly_count << std::endl;
562                                 ofs2.close();
563                                 if (createSymlink(tac_version_dir, np)) {
564                                         return 0;
565                                 }
566
567                                 char *error = 0;
568                                 int count = 0;
569                                 sql = "SELECT COUNT(NUGET) FROM TAC WHERE PKGID = '" + std::string(pkgId) + "' AND NAME = '" + tac_name + "';";
570                                 int ret = sqlite3_exec(tac_db, sql.c_str(), sqliteCb, &count, &error);
571                                 if (ret != SQLITE_OK) {
572                                         _ERR("SQL error: %s", error);
573                                         sqlite3_free(error);
574                                 }
575
576                                 if (count == 1) {
577                                         sql = "UPDATE TAC SET NAME = '" + tac_name + "', VERSION = '" + tac_version + "', NUGET = '" + np + "' WHERE PKGID = '" + std::string(pkgId) + "' AND NAME = '" + tac_name + "';";
578                                         dbUpdate(tac_db, TAC_APP_LIST_DB, sql);
579                                 } else {
580                                         sql = "INSERT INTO TAC (PKGID, NUGET, NAME, VERSION) " \
581                                                 "VALUES ('" + std::string(pkgId) + "', '" + np + "', '" + tac_name + "', '" + tac_version + "');";
582                                         dbInsert(tac_db, TAC_APP_LIST_DB, sql);
583                                 }
584                         } else {
585                                 _INFO("Exists tac_version_dir [%s]", tac_version_dir.c_str());
586                                 int compare_count = 0;
587                                 int assembly_count = 0;
588                                 std::string sha256_count = "0";
589                                 for (auto& npAssemblyShaR2R : nugetPackagesAssembliesShaR2R) {
590                                         std::string nuget_package_assembly_sha = npAssemblyShaR2R.substr(0, npAssemblyShaR2R.rfind('/'));
591                                         std::string sha = nuget_package_assembly_sha.substr(nuget_package_assembly_sha.rfind('/') + 1);
592                                         std::string nuget_package_assembly = nuget_package_assembly_sha.substr(0, nuget_package_assembly_sha.rfind('/'));
593                                         std::string nuget_package = nuget_package_assembly.substr(0, nuget_package_assembly.rfind('/'));
594                                         std::string assembly = nuget_package_assembly.substr(nuget_package_assembly.rfind('/') + 1);
595                                         std::string r2r = npAssemblyShaR2R.substr(npAssemblyShaR2R.rfind('/') + 1);
596                                         if (!strcmp(nuget_package.c_str(), np.c_str())) {
597                                                 assembly_count++;
598                                                 std::string sha256_info = (tac_version_dir / TAC_SHA_256_INFO).string();
599                                                 std::ifstream ifs2(sha256_info);
600                                                 std::string get_str;
601                                                 if (ifs2.is_open()) {
602                                                         while (getline(ifs2, get_str)) {
603                                                                 if (!strcmp(get_str.c_str(), (assembly + ";" + sha).c_str())) {
604                                                                         compare_count++;
605                                                                 }
606                                                                 sha256_count = get_str;
607                                                         }
608                                                         ifs2.close();
609                                                 }
610                                         }
611                                 }
612
613                                 if (!strcmp(std::to_string(assembly_count).c_str(), std::to_string(compare_count).c_str()) &&
614                                         !strcmp(std::to_string(assembly_count).c_str(), sha256_count.c_str())) {
615                                         _INFO("Same : %s", tac_name.c_str());
616                                         if (createSymlink(tac_version_dir, np)) {
617                                                 return 0;
618                                         }
619
620                                         char *error = 0;
621                                         int count = 0;
622                                         std::string sql = "SELECT COUNT(NUGET) FROM TAC WHERE PKGID = '" + std::string(pkgId) + "' AND NAME = '" + tac_name + "';";
623                                         int ret = sqlite3_exec(tac_db, sql.c_str(), sqliteCb, &count, &error);
624                                         if (ret != SQLITE_OK) {
625                                                 _ERR("SQL error: %s", error);
626                                                 sqlite3_free(error);
627                                         }
628
629                                         if (count == 1) {
630                                                 sql = "UPDATE TAC SET NAME = '" + tac_name + "', VERSION = '" + tac_version + "', NUGET = '" + np + "' WHERE PKGID = '" + std::string(pkgId) + "' AND NAME = '" + tac_name + "';";
631                                                 dbUpdate(tac_db, TAC_APP_LIST_DB, sql);
632                                         } else {
633                                                 sql = "INSERT INTO TAC (PKGID, NUGET, NAME, VERSION) " \
634                                                         "VALUES ('" + std::string(pkgId) + "', '" + np + "', '" + tac_name + "', '" + tac_version + "');";
635                                                 dbInsert(tac_db, TAC_APP_LIST_DB, sql);
636                                         }
637                                 } else {
638                                         _INFO("Different : %s", tac_name.c_str());
639                                 }
640                         }
641                 }
642                 for (auto& unp : updateTac) {
643                         bool isExits = false;
644                         for (auto& np : tacDB) {
645                                 if (!strcmp(unp.c_str(), np.c_str())) {
646                                         isExits = true;
647                                         break;
648                                 }
649                         }
650
651                         if (!isExits) {
652                                 std::string sql = "DELETE FROM TAC WHERE PKGID = '" + std::string(pkgId) + "' AND NUGET = '" + unp + "';";
653                                 dbDelete(tac_db, TAC_APP_LIST_DB, sql);
654                         }
655                 }
656
657                 if (removeOriginalAssembly()) {
658                         return 0;
659                 }
660                 if (updateTacDB(pkgId)) {
661                         return 0;
662                 }
663         }
664         return 0;
665 }
666
667 extern "C" int PKGMGR_MDPARSER_PLUGIN_UNINSTALL(const char *pkgId, const char *appId, GList *list)
668 {
669         _DBG("[===== PKGMGR_MDPARSER_PLUGIN_UNINSTALL =====]");
670         _INFO("PackageID : %s", pkgId);
671
672         status = "uninstall";
673         tac_db = dbCreate(TAC_APP_LIST_DB);
674         if (tac_db) {
675                 if (!dbOpen(tac_db, TAC_APP_LIST_DB)) {
676                         return 0;
677                 }
678         } else {
679                 _ERR("Sqlite create error");
680                 return 0;
681         }
682
683         std::string sql = "SELECT * FROM TAC WHERE PKGID = '" + std::string(pkgId) + "';";
684         updateTac = dbSelect(tac_db, TAC_APP_LIST_DB, sql);
685
686         sql = "DELETE FROM TAC WHERE PKGID = '" + std::string(pkgId) + "';";
687         dbDelete(tac_db, TAC_APP_LIST_DB, sql);
688
689         if (updateTacDB(pkgId)) {
690                 return 0;
691         }
692         return 0;
693 }
694
695 extern "C" int PKGMGR_MDPARSER_PLUGIN_REMOVED(const char *pkgId, const char *appId, GList *list)
696 {
697         _DBG("[===== PKGMGR_MDPARSER_PLUGIN_REMOVED =====]");
698         _INFO("PackageID : %s", pkgId);
699
700         status = "removed";
701
702         PKGMGR_MDPARSER_PLUGIN_UPGRADE(pkgId, appId, list);
703         return 0;
704 }
705
706 int install_Clean()
707 {
708         return 0;
709 }
710
711 int unInstall_Clean()
712 {
713         for (auto& unp : updateTac) {
714                 bf::path current_tac = bf::path(__TAC_DIR) / unp.substr(0, unp.find('/'));
715                 std::vector<std::string> exist_directory_name;
716                 for (auto& bck : bf::recursive_directory_iterator(current_tac)) {
717                         if (bf::exists(bck.path()) && bf::is_directory(bck.path()) && strstr(bck.path().c_str(), ".bck") != NULL) {
718                                 if (!removeAll(bck.path().string())) {
719                                         _ERR("Failed to remove of %s", bck.path().c_str());
720                                         return 0;
721                                 }
722                                 break;
723                         }
724                 }
725                 for (auto& bck : bf::recursive_directory_iterator(current_tac)) {
726                         if (bf::exists(bck.path()) && bf::is_directory(bck.path()) && strstr(bck.path().c_str(), ".bck") == NULL) {
727                                 exist_directory_name.push_back(bck.path().string());
728                                 break;
729                         }
730                 }
731                 if (exist_directory_name.empty()) {
732                         if (!removeAll(current_tac)) {
733                                 _ERR("Failed to remove of %s", current_tac.c_str());
734                                 return 0;
735                         }
736                 } else {
737                         exist_directory_name.clear();
738                 }
739         }
740         return 0;
741 }
742
743 int update_Clean()
744 {
745         if (!tacDB.empty()) {
746                 for (auto& np : tacDB) {
747                         bf::path current_tac = bf::path(__TAC_DIR) / np.substr(0, np.find('/'));
748                         std::vector<std::string> exist_directory_name;
749                         for (auto& bck : bf::recursive_directory_iterator(current_tac)) {
750                                 if (bf::exists(bck.path()) && bf::is_directory(bck.path()) && strstr(bck.path().c_str(), ".bck") != NULL) {
751                                         if (!removeAll(bck.path().string())) {
752                                                 _ERR("Failed to remove of %s", bck.path().c_str());
753                                                 return 0;
754                                         }
755                                         break;
756                                 }
757                         }
758                         for (auto& bck : bf::recursive_directory_iterator(current_tac)) {
759                                 if (bf::exists(bck.path()) && bf::is_directory(bck.path()) && strstr(bck.path().c_str(), ".bck") == NULL) {
760                                         exist_directory_name.push_back(bck.path().string());
761                                         break;
762                                 }
763                         }
764                         if (exist_directory_name.empty()) {
765                                 if (!removeAll(current_tac)) {
766                                         _ERR("Failed to remove of %s", current_tac.c_str());
767                                         return 0;
768                                 }
769                         } else {
770                                 exist_directory_name.clear();
771                         }
772                 }
773         }
774         unInstall_Clean();
775         return 0;
776 }
777
778 extern "C" int PKGMGR_MDPARSER_PLUGIN_CLEAN(const char *pkgId, const char *appId, GList *list)
779 {
780         _DBG("[===== PKGMGR_MDPARSER_PLUGIN_CLEAN =====]");
781
782         if (tac_db) {
783                 dbClose(tac_db);
784                 tac_db = NULL;
785         }
786         if (!strcmp("install", status.c_str())) {
787                 install_Clean();
788         } else if (!strcmp("update", status.c_str())) {
789                 update_Clean();
790         } else if (!strcmp("uninstall", status.c_str())) {
791                 unInstall_Clean();
792         }
793         return 0;
794 }
795
796 int install_Undo()
797 {
798         for (auto& cd : createDirectories) {
799                 if (!removeAll(cd)) {
800                         _ERR("Failed to remove of %s", cd.c_str());
801                         return 0;
802                 }
803         }
804         return 0;
805 }
806
807 int unInstall_Undo()
808 {
809         for (auto& unp : updateTac) {
810                 for (auto& bck : bf::recursive_directory_iterator(bf::path(__TAC_DIR) / unp.substr(0, unp.find('/')))) {
811                         if (bf::exists(bck.path()) && bf::is_directory(bck.path()) && strstr(bck.path().c_str(), ".bck") != NULL) {
812                                 if (!moveFile(bck.path(), bck.path().string().substr(0, bck.path().string().rfind(".bck")))) {
813                                         _ERR("Failed to move %s to %s",
814                                                 bck.path().c_str(), bck.path().string().substr(0, bck.path().string().rfind(".bck")).c_str());
815                                         return 0;
816                                 }
817                                 break;
818                         }
819                 }
820         }
821         return 0;
822 }
823
824 int update_Undo()
825 {
826         for (auto& cd : createDirectories) {
827                 if (!removeAll(cd)) {
828                         _ERR("Failed to remove of %s", cd.c_str());
829                         return 0;
830                 }
831         }
832         if (!tacDB.empty()) {
833                 for (auto& np : tacDB) {
834                         for (auto& bck : bf::recursive_directory_iterator(bf::path(__TAC_DIR) / np.substr(0, np.find('/')))) {
835                                 if (bf::exists(bck.path()) && bf::is_directory(bck.path()) && strstr(bck.path().c_str(), ".bck") != NULL) {
836                                         if (!moveFile(bck.path(), bck.path().string().substr(0, bck.path().string().rfind(".bck")))) {
837                                                 _ERR("Failed to move %s to %s",
838                                                         bck.path().c_str(), bck.path().string().substr(0, bck.path().string().rfind(".bck")).c_str());
839                                                 return 0;
840                                         }
841                                         break;
842                                 }
843                         }
844                 }
845         }
846         unInstall_Undo();
847         return 0;
848 }
849
850 extern "C" int PKGMGR_MDPARSER_PLUGIN_UNDO(const char *pkgId, const char *appId, GList *list)
851 {
852         _DBG("[===== PKGMGR_MDPARSER_PLUGIN_UNDO =====]");
853
854         if (tac_db) {
855                 dbRollback(tac_db);
856                 tac_db = NULL;
857         }
858         if (!strcmp("install", status.c_str())) {
859                 install_Undo();
860         } else if (!strcmp("update", status.c_str())) {
861                 update_Undo();
862         } else if (!strcmp("uninstall", status.c_str())) {
863                 unInstall_Undo();
864         }
865         return 0;
866 }