1f9c76b2e61d4152bfc9e35d9679c712ec577b19
[platform/core/dotnet/launcher.git] / NativeLauncher / tool / tac_common.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 <fstream>
18 #include <pkgmgr-info.h>
19 #include <pkgmgr_installer_info.h>
20
21 #include "log.h"
22 #include "utils.h"
23 #include "ni_common.h"
24 #include "tac_common.h"
25 #include "db_manager.h"
26 #include "path_manager.h"
27
28 #ifdef  LOG_TAG
29 #undef  LOG_TAG
30 #endif
31 #define LOG_TAG "DOTNET_INSTALLER_PLUGIN"
32
33 #define __XSTR(x) #x
34 #define __STR(x) __XSTR(x)
35 static const char* __TAC_DIR = __STR(TAC_DIR);
36 #undef __STR
37 #undef __XSTR
38
39 static sqlite3 *tac_db = NULL;
40 std::vector<std::string> restoreNuget;
41
42 void cleanupDirectory()
43 {
44         std::vector<std::string> removeNuget;
45         for (auto& nuget : bf::recursive_directory_iterator(__TAC_DIR)) {
46                 bool isExist = false;
47                 std::string nugetPath = nuget.path().string();
48                 for (auto& restore : restoreNuget) {
49                         if (!bf::is_directory(nugetPath)) {
50                                 isExist = true;
51                         }
52                         if (strstr(nugetPath.c_str(), restore.c_str()) != NULL) {
53                                 isExist = true;
54                                 break;
55                         }
56                 }
57                 if (!isExist) {
58                         removeNuget.push_back(nugetPath);
59                 }
60         }
61
62         for (auto& rm : removeNuget) {
63                 if (!removeAll(rm)) {
64                         _ERR("Failed to remove of %s", rm.c_str());
65                 }
66         }
67         removeNuget.clear();
68 }
69
70 // callback function of "pkgmgrinfo_appinfo_metadata_filter_foreach"
71 static int restoreDBCb(pkgmgrinfo_appinfo_h handle, void *userData)
72 {
73         char *pkgId = NULL;
74         char *root = NULL;
75         char *exec = NULL;
76         std::string rootPath;
77         std::string execName;
78
79         int ret = pkgmgrinfo_appinfo_get_pkgid(handle, &pkgId);
80         if (ret != PMINFO_R_OK) {
81                 fprintf(stderr, "Failed to get pkgid\n");
82                 return -1;
83         }
84
85         ret = pkgmgrinfo_appinfo_get_root_path(handle, &root);
86         if (ret != PMINFO_R_OK) {
87                 fprintf(stderr, "Failed to get root path\n");
88                 return -1;
89         }
90         rootPath = root;
91
92         ret = pkgmgrinfo_appinfo_get_exec(handle, &exec);
93         if (ret != PMINFO_R_OK) {
94                 fprintf(stderr, "Failed to get exec name\n");
95                 return -1;
96         }
97         execName = std::string(exec).substr(std::string(exec).rfind('/') + 1);
98
99         std::vector<std::string> parserData;
100         for (auto& npAssembly : depsJsonParser(rootPath, execName, getTPA())) {
101                 std::string nugetPackage = npAssembly.substr(0, npAssembly.rfind(':'));
102                 parserData.push_back(nugetPackage);
103         }
104         std::sort(parserData.begin(), parserData.end());
105         parserData.erase(unique(parserData.begin(), parserData.end()), parserData.end());
106
107         for (auto& nuget : parserData) {
108                 if (tac_db) {
109                         std::string name = nuget.substr(0, nuget.find('/'));
110                         std::string version = nuget.substr(nuget.rfind('/') + 1);
111                         std::string sql = "INSERT INTO TAC (PKGID, NUGET, NAME, VERSION) " \
112                                                 "VALUES ('" + std::string(pkgId) + "', '" + nuget + "', '" + name + "', '" + version + "');";
113                         dbInsert(tac_db, TAC_APP_LIST_RESTORE_DB, sql);
114                         restoreNuget.push_back(concatPath(__TAC_DIR, name));
115                 }
116         }
117         parserData.clear();
118         return 0;
119 }
120
121 tac_error_e restoreTACDB()
122 {
123         if (!removeFile(TAC_APP_LIST_RESTORE_DB)) {
124                 fprintf(stderr, "Failed to remove of %s", TAC_APP_LIST_RESTORE_DB);
125                 return TAC_ERROR_UNKNOWN;
126         }
127
128         std::string dbRestoreJournal = TAC_APP_LIST_RESTORE_DB + std::string("-journal");
129         if (!removeFile(dbRestoreJournal)) {
130                 fprintf(stderr, "Failed to remove of %s", dbRestoreJournal.c_str());
131                 return TAC_ERROR_UNKNOWN;
132         }
133
134         if (initializePathManager(std::string(), std::string(), std::string())) {
135                 fprintf(stderr, "Fail to initialize PathManger");
136                 return TAC_ERROR_UNKNOWN;
137         }
138
139         tac_db = dbCreate(TAC_APP_LIST_RESTORE_DB);
140         if (tac_db) {
141                 if (!dbOpen(tac_db, TAC_APP_LIST_RESTORE_DB)) {
142                         return TAC_ERROR_UNKNOWN;
143                 }
144         } else {
145                 return TAC_ERROR_UNKNOWN;
146         }
147
148         pkgmgrinfo_appinfo_metadata_filter_h handle;
149         int ret = pkgmgrinfo_appinfo_metadata_filter_create(&handle);
150         if (ret != PMINFO_R_OK) {
151                 return TAC_ERROR_UNKNOWN;
152         }
153
154         ret = pkgmgrinfo_appinfo_metadata_filter_add(handle, TAC_METADATA_KEY, METADATA_VALUE);
155         if (ret != PMINFO_R_OK) {
156                 pkgmgrinfo_appinfo_metadata_filter_destroy(handle);
157                 return TAC_ERROR_UNKNOWN;
158         }
159
160         ret = pkgmgrinfo_appinfo_metadata_filter_foreach(handle, restoreDBCb, NULL);
161         if (ret != PMINFO_R_OK) {
162                 fprintf(stderr, "Failed pkgmgrinfo_appinfo_metadata_filter_foreach\n");
163                 pkgmgrinfo_appinfo_metadata_filter_destroy(handle);
164                 return TAC_ERROR_UNKNOWN;
165         }
166         fprintf(stderr, "Success pkgmgrinfo_appinfo_metadata_filter_foreach\n");
167
168         pkgmgrinfo_appinfo_metadata_filter_destroy(handle);
169
170         if (tac_db) {
171                 dbClose(tac_db);
172                 tac_db = NULL;
173         }
174
175         if (!copyFile(TAC_APP_LIST_RESTORE_DB, TAC_APP_LIST_DB)) {
176                 fprintf(stderr, "Failed to copy of %s", TAC_APP_LIST_DB);
177                 return TAC_ERROR_UNKNOWN;
178         }
179         if (!removeFile(TAC_APP_LIST_RESTORE_DB)) {
180                 fprintf(stderr, "Failed to remove of %s", TAC_APP_LIST_RESTORE_DB);
181                 return TAC_ERROR_UNKNOWN;
182         }
183
184         std::string dbJournal = TAC_APP_LIST_DB + std::string("-journal");
185         if (!copyFile(dbRestoreJournal, dbJournal)) {
186                 fprintf(stderr, "Failed to copy of %s", dbJournal.c_str());
187                 return TAC_ERROR_UNKNOWN;
188         }
189         if (!removeFile(dbRestoreJournal)) {
190                 fprintf(stderr, "Failed to remove of %s", dbRestoreJournal.c_str());
191                 return TAC_ERROR_UNKNOWN;
192         }
193
194         cleanupDirectory();
195         return TAC_ERROR_NONE;
196 }
197
198 tac_error_e resetTACPackage(const std::string& pkgId)
199 {
200         std::string pkgRoot;
201         if (getRootPath(pkgId, pkgRoot) < 0) {
202                 return TAC_ERROR_INVALID_PACKAGE;
203         }
204
205         std::vector<std::string> tacNativeImage;
206         std::string binDir = concatPath(pkgRoot, "bin");
207         std::string tacDir = concatPath(binDir, TAC_SYMLINK_SUB_DIR);
208         if (bf::exists(tacDir)) {
209                 for (auto& symlinkAssembly : bf::recursive_directory_iterator(tacDir)) {
210                         std::string symPath = symlinkAssembly.path().string();
211                         if (bf::is_symlink(symPath)) {
212                                 if (isNativeImage(symPath)) {
213                                         tacNativeImage.push_back(symPath);
214                                 }
215                         }
216                 }
217                 for (auto& path : tacNativeImage) {
218                         if (!removeFile(path)) {
219                                 fprintf(stderr, "Failed to remove of %s", path.c_str());
220                                 return TAC_ERROR_UNKNOWN;
221                         }
222                 }
223         }
224         tacNativeImage.clear();
225         return TAC_ERROR_NONE;
226 }
227
228 tac_error_e createTACPackage(const std::string& pkgId)
229 {
230         std::string pkgRoot;
231         if (getRootPath(pkgId, pkgRoot) < 0) {
232                 return TAC_ERROR_INVALID_PACKAGE;
233         }
234
235         std::string binDir = concatPath(pkgRoot, "bin");
236         std::string tacDir = concatPath(binDir, TAC_SYMLINK_SUB_DIR);
237         std::string binNIDir = concatPath(binDir, APP_NI_SUB_DIR);
238         if (bf::exists(tacDir)) {
239                 for (auto& symlinkAssembly : bf::recursive_directory_iterator(tacDir)) {
240                         std::string symPath = symlinkAssembly.path().string();
241                         if (bf::is_symlink(symPath)) {
242                                 if (!isNativeImage(symPath)) {
243                                         std::string originPath = bf::read_symlink(symPath).string();
244                                         std::string originNiPath = originPath.substr(0, originPath.rfind(".dll")) + ".ni.dll";
245                                         if (!bf::exists(originNiPath)) {
246                                                 if(createNiDll(originPath, false) != NI_ERROR_NONE) {
247                                                         fprintf(stderr, "Failed to create NI file [%s]\n", originPath.c_str());
248                                                         return TAC_ERROR_UNKNOWN;
249                                                 }
250                                         }
251                                         std::string symNIPath = symPath.substr(0, symPath.rfind(".dll")) + ".ni.dll";
252                                         if (!bf::exists(symNIPath)) {
253                                                 bf::create_symlink(originNiPath, symNIPath);
254                                                 fprintf(stderr, "%s symbolic link file generated successfully.\n", symNIPath.c_str());
255                                                 updateAssemblyInfo(tacDir.c_str(), symNIPath.c_str(), true);
256
257                                                 std::string NIFileName = symNIPath.substr(symNIPath.rfind('/') + 1);
258                                                 if (!removeFile(concatPath(binNIDir, NIFileName))) {
259                                                         fprintf(stderr, "Failed to remove of %s\n", concatPath(binNIDir, NIFileName).c_str());
260                                                         return TAC_ERROR_UNKNOWN;
261                                                 }
262                                         }
263                                 }
264                         }
265                 }
266         }
267         return TAC_ERROR_NONE;
268 }
269
270 tac_error_e regenerateTAC()
271 {
272         const std::string tacDir[] = {__TAC_DIR};
273         removeNiUnderDirs(tacDir, 1);
274
275         auto convert = [](const std::string& path, std::string name) {
276                 if (strstr(path.c_str(), TAC_APP_LIST_DB) != NULL ||
277                         strstr(path.c_str(), TAC_APP_LIST_RESTORE_DB) != NULL ||
278                         strstr(path.c_str(), TAC_SHA_256_INFO) != NULL)
279                         return;
280                 if(createNiDll(path, false) != NI_ERROR_NONE) {
281                         fprintf(stderr, "Failed to create NI file [%s]\n", path.c_str());
282                         return;
283                 }
284         };
285         scanFilesInDir(tacDir[0], convert, -1);
286         return TAC_ERROR_NONE;
287 }
288
289 tac_error_e disableTACPackage(const std::string& pkgId)
290 {
291         std::string pkgRoot;
292         if (getRootPath(pkgId, pkgRoot) < 0) {
293                 return TAC_ERROR_INVALID_PACKAGE;
294         }
295
296         std::string binDir = concatPath(pkgRoot, "bin");
297         std::string tacDir = concatPath(binDir, TAC_SYMLINK_SUB_DIR);
298         std::string binNIDir = concatPath(binDir, APP_NI_SUB_DIR);
299         if (bf::exists(tacDir)) {
300                 for (auto& symlinkAssembly : bf::recursive_directory_iterator(tacDir)) {
301                         std::string symPath = symlinkAssembly.path().string();
302                         std::string fileName = symlinkAssembly.path().filename().string();
303                         if (bf::is_symlink(symPath)) {
304                                 std::string originPath = bf::read_symlink(symPath).string();
305                                 if (!isNativeImage(symPath)) {
306                                         if (!copyFile(originPath, concatPath(binDir, fileName))) {
307                                                 fprintf(stderr, "Failed to copy of %s\n", concatPath(binDir, fileName).c_str());
308                                                 return TAC_ERROR_UNKNOWN;
309                                         }
310                                         updateAssemblyInfo(binDir.c_str(), concatPath(binDir, fileName).c_str());
311                                 } else {
312                                         if (!copyFile(originPath, concatPath(binNIDir, fileName))) {
313                                                 fprintf(stderr, "Failed to copy of %s\n", concatPath(binNIDir, fileName).c_str());
314                                                 return TAC_ERROR_UNKNOWN;
315                                         }
316                                         updateAssemblyInfo(binDir.c_str(), concatPath(binNIDir, fileName).c_str());
317                                 }
318                         }
319                 }
320         }
321         if (!removeAll(tacDir)) {
322                 fprintf(stderr, "Failed to remove of %s\n", tacDir.c_str());
323                 return TAC_ERROR_UNKNOWN;
324         }
325         return TAC_ERROR_NONE;
326 }
327
328 tac_error_e enableTACPackage(const std::string& pkgId)
329 {
330         std::string rootPath;
331         if (getRootPath(pkgId, rootPath) < 0) {
332                 return TAC_ERROR_INVALID_PACKAGE;
333         }
334
335         std::string execName;
336         if (getExecName(pkgId, execName) < 0) {
337                 return TAC_ERROR_INVALID_PACKAGE;
338         }
339
340         std::string metaValue;
341         if (getMetadataValue(pkgId, TAC_METADATA_KEY, metaValue) < 0) {
342                 return TAC_ERROR_INVALID_PACKAGE;
343         }
344
345         if (initializePathManager(std::string(), std::string(), std::string())) {
346                 fprintf(stderr, "Fail to initialize PathManger");
347                 return TAC_ERROR_UNKNOWN;
348         }
349
350         if (!strcmp(metaValue.c_str(), "true")) {
351                 std::string binDir = concatPath(rootPath, "bin");
352                 std::string tacDir = concatPath(binDir, TAC_SYMLINK_SUB_DIR);
353                 std::string binNIDir = concatPath(binDir, APP_NI_SUB_DIR);
354                 if (!bf::exists(tacDir)) {
355                         if (!createDir(tacDir)) {
356                                 fprintf(stderr, "Cannot create directory: %s\n", tacDir.c_str());
357                                 return TAC_ERROR_UNKNOWN;
358                         }
359                         updateAssemblyInfo(binDir.c_str(), tacDir.c_str());
360
361                         std::vector<std::string> enableNuget;
362                         for (auto& npAssembly : depsJsonParser(rootPath, execName, getTPA())) {
363                                 std::string nugetPackage = npAssembly.substr(0, npAssembly.rfind(':'));
364                                 std::string assemblyName = npAssembly.substr(npAssembly.rfind(':') + 1);
365                                 std::string nugetPath = concatPath(__TAC_DIR, nugetPackage);
366                                 if (bf::exists(nugetPath)) {
367                                         std::string originPath = concatPath(nugetPath, assemblyName);
368                                         if (bf::exists(originPath)) {
369                                                 enableNuget.push_back(originPath);
370                                         }
371                                 }
372                         }
373
374                         for (auto& originPath : enableNuget) {
375                                 if (bf::exists(originPath)) {
376                                         std::string fileName = originPath.substr(originPath.rfind('/') + 1);
377                                         std::string NIFileName = fileName.substr(0, fileName.rfind(".dll")) + ".ni.dll";
378                                         if (bf::exists(binNIDir)) {
379                                                 std::string originNIPath = originPath.substr(0, originPath.rfind(".dll")) + ".ni.dll";
380                                                 if (bf::exists(originNIPath)) {
381                                                         bf::create_symlink(originNIPath, concatPath(tacDir, NIFileName));
382                                                         fprintf(stderr, "%s symbolic link file generated successfully.\n", concatPath(tacDir, NIFileName).c_str());
383                                                         updateAssemblyInfo(tacDir.c_str(), concatPath(tacDir, NIFileName).c_str(), true);
384
385                                                         if (!removeFile(concatPath(binNIDir, NIFileName))) {
386                                                                 fprintf(stderr, "Failed to remove of %s\n", concatPath(binNIDir, NIFileName).c_str());
387                                                                 return TAC_ERROR_UNKNOWN;
388                                                         }
389                                                 }
390                                         }
391                                         bf::create_symlink(originPath, concatPath(tacDir, fileName));
392                                         fprintf(stderr, "%s symbolic link file generated successfully.\n", concatPath(tacDir, fileName).c_str());
393                                         updateAssemblyInfo(tacDir.c_str(), concatPath(tacDir, fileName).c_str(), true);
394
395                                         if (!removeFile(concatPath(binDir, fileName))) {
396                                                 fprintf(stderr, "Failed to remove of %s\n", concatPath(binDir, fileName).c_str());
397                                                 return TAC_ERROR_UNKNOWN;
398                                         }
399                                 }
400                         }
401                         if (enableNuget.empty()) {
402                                 if (!removeAll(tacDir)) {
403                                         _ERR("Failed to remove of %s", tacDir.c_str());
404                                 }
405                         }
406                         enableNuget.clear();
407                 }
408         } else {
409                 fprintf(stderr, "The metadata key is missing or the metadata value is false of [%s]\n", pkgId.c_str());
410         }
411         return TAC_ERROR_NONE;
412 }