Osp-Installer merge changes from tizen_2.2
[platform/framework/native/installer.git] / src / Util / InstallerUtil.cpp
1 //
2 // Open Service Platform
3 // Copyright (c) 2012 Samsung Electronics Co., Ltd.
4 //
5 // Licensed under the Apache License, Version 2.0 (the License);
6 // you may not use this file except in compliance with the License.
7 // You may obtain a copy of the License at
8 //
9 //     http://www.apache.org/licenses/LICENSE-2.0
10 //
11 // Unless required by applicable law or agreed to in writing, software
12 // distributed under the License is distributed on an "AS IS" BASIS,
13 // WITHOUT  WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 // See the License for the specific language governing permissions and
15 // limitations under the License.
16 //
17 /**
18  * @file        InstallerUtil.cpp
19  * @brief       This is the implementation file for %InstallerUtil class.
20  */
21
22 #include <sys/stat.h>
23 #include <dirent.h>
24 #include <dlfcn.h>
25 #include <errno.h>
26 #include <unistd.h>
27 #include <unique_ptr.h>
28 #include <vconf.h>
29
30 #include <FBaseErrorDefine.h>
31 #include <FIoFile.h>
32 #include <FIoDirectory.h>
33 #include <FIoRegistry.h>
34 #include <FAppPkgPackageAppInfo.h>
35 #include <FAppPkgPackageInfo.h>
36 #include <FBase_StringConverter.h>
37 #include <FSecCryptoSha2Hash.h>
38 #include <FApp_Aul.h>
39 #include <FAppPkg_PackageManagerImpl.h>
40 #include <FAppPkg_PackageInfoImpl.h>
41 #include <FAppPkg_PackageAppInfoImpl.h>
42
43 #include "InstallerDefs.h"
44 #include "InstallerUtil.h"
45 #include "InstallerManager.h"
46 #include "SmackManager.h"
47 #include "DatabaseManager.h"
48
49 using namespace Tizen::Base;
50 using namespace Tizen::Base::Collection;
51 using namespace Tizen::Base::Utility;
52 using namespace Tizen::App;
53 using namespace Tizen::App::Package;
54 using namespace Tizen::Io;
55 using namespace Tizen::Security::Crypto;
56
57 InstallerUtil::InstallerUtil(void)
58 {
59 }
60
61 InstallerUtil::~InstallerUtil(void)
62 {
63 }
64
65 bool
66 InstallerUtil::Remove(const Tizen::Base::String& filePath)
67 {
68         int err = -1;
69         result r = E_SUCCESS;
70         struct stat fileinfo;
71
72         std::unique_ptr<char[]> pFilePath(_StringConverter::CopyToCharArrayN(filePath));
73         TryReturn(pFilePath, false, "pFilePath is null");
74
75         err = lstat(pFilePath.get(), &fileinfo);
76         if (err < 0)
77         {
78                 AppLog("Remove(): skip, path=[%s][%s](%d)", pFilePath.get(), strerror(errno), errno);
79                 return true;
80         }
81
82         if (S_ISLNK(fileinfo.st_mode))
83         {
84                 AppLog("Remove(): symlink=[%s]", pFilePath.get());
85                 err = unlink(pFilePath.get());
86                 TryReturn(err >= 0, false, "unlink() failed(%s), file=[%s]", strerror(errno), pFilePath.get());
87         }
88         else if (S_ISDIR(fileinfo.st_mode))
89         {
90                 AppLog("Remove(): directory=[%ls]", filePath.GetPointer());
91                 r = Directory::Remove(filePath, true);
92                 TryReturn(!IsFailed(r), false, "Directory::Remove() failed, filePath=%ls", filePath.GetPointer());
93         }
94         else
95         {
96                 AppLog("Remove(): file=[%ls]", filePath.GetPointer());
97                 r = File::Remove(filePath);
98                 TryReturn(!IsFailed(r), false, "File::Remove() failed, filePath=%ls", filePath.GetPointer());
99         }
100
101         return true;
102 }
103
104 bool
105 InstallerUtil::Copy(const String& srcFilePath, const String& destFilePath, bool failIfExist)
106 {
107         int bufSize = 4096;
108         int readBytes = 0;
109         result r = E_SUCCESS;
110
111         if (failIfExist == true)
112         {
113                 if (File::IsFileExist(destFilePath) == true)
114                 {
115                         AppLog("Copy(): des=[%ls]: skip", destFilePath.GetPointer());
116                         return true;
117                 }
118         }
119
120         File srcFile;
121         File destFile;
122
123         std::unique_ptr<char[]> pBuf(new (std::nothrow) char[bufSize]);
124         TryReturn(pBuf, false, "pBuf is null");
125
126         r = srcFile.Construct(srcFilePath, L"r");
127         TryReturn(!IsFailed(r), false, "srcFile.Construct is failed");
128
129         r = destFile.Construct(destFilePath, L"w");
130         TryReturn(!IsFailed(r), false, "destFile.Construct is failed");
131
132         do
133         {
134                 readBytes = srcFile.Read(pBuf.get(), bufSize);
135                 if (readBytes > 0)
136                 {
137                         r = destFile.Write(pBuf.get(), readBytes);
138                         TryReturn(!IsFailed(r), false, "destFile.Write is failed");
139                 }
140         }
141         while (readBytes > 0);
142
143         return true;
144 }
145
146 bool
147 InstallerUtil::CopyDirectory(const String& srcFilePath, const String& destFilePath, bool failIfExist)
148 {
149         result r = E_SUCCESS;
150         bool res = false;
151
152         res = File::IsFileExist(srcFilePath);
153         if (res == false)
154         {
155                 AppLog("CopyDirectory(): src=[%ls]: skip", srcFilePath.GetPointer());
156                 return true;
157         }
158
159         std::unique_ptr<Directory> pDir(new (std::nothrow) Directory);
160         TryReturn(pDir, false, "pDir is null.");
161
162         r = pDir->Construct(srcFilePath);
163         TryReturn(!IsFailed(r), false, "pDir->Construct() failed, srcFilePath=[%ls].", srcFilePath.GetPointer());
164
165         std::unique_ptr<DirEnumerator> pDirEnum(pDir->ReadN());
166         TryReturn(pDirEnum, false, "pDirEnum is null.");
167
168         while (pDirEnum->MoveNext() == E_SUCCESS)
169         {
170                 DirEntry entry = pDirEnum->GetCurrentDirEntry();
171
172                 String entryName = entry.GetName();
173                 String srcEntryDir = srcFilePath;
174                 srcEntryDir += L"/";
175                 srcEntryDir += entryName;
176
177                 if (entryName == L"." || entryName == L"..")
178                 {
179                         continue;
180                 }
181
182                 // if file or directory is symbolic link, skip this.
183                 if (InstallerUtil::IsSymlink(srcEntryDir) == true)
184                 {
185                         continue;
186                 }
187
188                 String destEntryDir = destFilePath;
189                 destEntryDir += L"/";
190                 destEntryDir += entryName;
191
192                 if (entry.IsDirectory() == false)
193                 {
194                         // file
195                         Directory::Create(destFilePath, true);
196                         InstallerUtil::Copy(srcEntryDir, destEntryDir, failIfExist);
197                 }
198                 else
199                 {
200                         Directory::Create(destEntryDir, true);
201                         CopyDirectory(srcEntryDir, destEntryDir, failIfExist);
202                 }
203         }
204
205         AppLog("CopyDirectory(): src=[%ls], dest=[%ls]", srcFilePath.GetPointer(), destFilePath.GetPointer());
206         return true;
207 }
208
209 bool
210 InstallerUtil::IsSymlink(const Tizen::Base::String& filePath)
211 {
212         int err = -1;
213         struct stat fileinfo;
214
215         std::unique_ptr<char[]> pFilePath(_StringConverter::CopyToCharArrayN(filePath));
216         TryReturn(pFilePath, false, "pFilePath is null");
217
218         err = lstat(pFilePath.get(), &fileinfo);
219         TryReturn(err >= 0, false, "lstat() failed(%s), file=[%s]", strerror(errno), pFilePath.get());
220
221         if (S_ISLNK(fileinfo.st_mode))
222         {
223                 return true;
224         }
225
226         return false;
227 }
228
229 bool
230 InstallerUtil::GetRealPath(const String& filePath, String& realPath)
231 {
232         char* pRealPath = null;
233
234         std::unique_ptr<char[]> pFilePath(_StringConverter::CopyToCharArrayN(filePath));
235         TryReturn(pFilePath, false, "pFilePath is null");
236
237         char tmpPath[PATH_MAX] = {0};
238         pRealPath = realpath(pFilePath.get(), tmpPath);
239         TryReturn(pRealPath, false, "pRealPath is null");
240
241         realPath = tmpPath;
242
243         AppLog("GetRealPath(): path=[%ls], realPath=[%ls]", filePath.GetPointer(), realPath.GetPointer());
244
245         return true;
246 }
247
248 bool
249 InstallerUtil::CreateSymlink(const String& oldPath, const String& newPath, bool SmackLabelToRealPath)
250 {
251         int err = -1;
252         bool res = false;
253
254         res = File::IsFileExist(oldPath);
255         if (res == false)
256         {
257                 AppLog("CreateSymlink(): oldPath=[%ls] not found.", oldPath.GetPointer());
258                 return true;
259         }
260
261         res = File::IsFileExist(newPath);
262         if (res == true)
263         {
264                 AppLog("CreateSymlink(): newPath=[%ls] is alreay exist.", oldPath.GetPointer());
265                 return true;
266         }
267
268         std::unique_ptr<char[]> pOldPath(_StringConverter::CopyToCharArrayN(oldPath));
269         TryReturn(pOldPath, false, "pOldPath is null");
270
271         std::unique_ptr<char[]> pNewPath(_StringConverter::CopyToCharArrayN(newPath));
272         TryReturn(pNewPath, false, "pNewPath is null");
273
274         err = symlink(pOldPath.get(), pNewPath.get());
275         TryReturn(err == 0, false, "symlink() is failed(%s), oldpath=[%s], newpath=[%s]", strerror(errno), pOldPath.get(), pNewPath.get());
276
277         SmackManager smackManager;
278         String label("_");
279
280         if (SmackLabelToRealPath == true)
281         {
282                 smackManager.AddLabelDir(label, newPath);
283         }
284         else
285         {
286                 smackManager.AddLabelSymlink(newPath);
287         }
288
289         AppLog("CreateSymlink(): [%ls] -> [%ls]", newPath.GetPointer(), oldPath.GetPointer());
290
291         return true;
292 }
293
294 bool
295 InstallerUtil::ChangeMode(const String& filePath, int mode)
296 {
297         int err = -1;
298
299         std::unique_ptr<char[]> pFilePath(_StringConverter::CopyToCharArrayN(filePath));
300         TryReturn(pFilePath, false, "pFilePath is null");
301
302         err = chmod(pFilePath.get(), mode);
303         TryReturn(err == 0, false, "chmod() is failed(%s), file=[%s], mode=[%o]", strerror(errno), pFilePath.get(), mode);
304
305         return true;
306 }
307
308 bool
309 InstallerUtil::ChangeOwner(const String& filePath)
310 {
311         int err = -1;
312
313         std::unique_ptr<char[]> pFilePath(_StringConverter::CopyToCharArrayN(filePath));
314         TryReturn(pFilePath, false, "pFilePath is null");
315
316         err = chown(pFilePath.get(), APP_OWNER_ID, APP_GROUP_ID);
317         TryReturn(err == 0, false, "chown() is failed(%s), file=[%s]", strerror(errno), pFilePath.get());
318
319         return true;
320 }
321
322 bool
323 InstallerUtil::ChangeDirectoryPermission(const String& file, int mode, bool appOwner)
324 {
325         result r = E_SUCCESS;
326         bool res = false;
327
328         res = File::IsFileExist(file);
329         if (res == false)
330         {
331                 AppLog("path=[%ls]: skip", file.GetPointer());
332                 return true;
333         }
334
335         std::unique_ptr<Directory> pDir(new (std::nothrow) Directory);
336         TryReturn(pDir, false, "pDir is null.");
337
338         r = pDir->Construct(file);
339         TryReturn(!IsFailed(r), false, "pDir->Construct() failed, file=[%ls]", file.GetPointer());
340
341         std::unique_ptr<DirEnumerator> pDirEnum(pDir->ReadN());
342         TryReturn(pDirEnum, false, "pDirEnum is null.");
343
344         while (pDirEnum->MoveNext() == E_SUCCESS)
345         {
346                 DirEntry entry = pDirEnum->GetCurrentDirEntry();
347                 String entryName = entry.GetName();
348                 if (entryName.IsEmpty() == true)
349                 {
350                         AppLog("entryName is empty.", entryName.GetPointer());
351                         continue;
352                 }
353
354                 String entryDir = file;
355                 entryDir += L"/";
356                 entryDir += entryName;
357
358                 if (entryName == L".")
359                 {
360                         if (appOwner == true)
361                         {
362                                 InstallerUtil::ChangeOwner(entryDir);
363                         }
364                         InstallerUtil::ChangeMode(entryDir, mode | PERM_EXECUTE);
365                         continue;
366                 }
367                 else if (entryName == L"..")
368                 {
369                         continue;
370                 }
371
372                 if (entry.IsDirectory() == false)
373                 {
374                         if (appOwner == true)
375                         {
376                                 InstallerUtil::ChangeOwner(entryDir);
377                         }
378                         InstallerUtil::ChangeMode(entryDir, mode);
379                 }
380                 else
381                 {
382                         ChangeDirectoryPermission(entryDir, mode, appOwner);
383                         if (appOwner == true)
384                         {
385                                 InstallerUtil::ChangeOwner(entryDir);
386                         }
387                         InstallerUtil::ChangeMode(entryDir, mode | PERM_EXECUTE);
388                 }
389         }
390
391         AppLog("path=[%ls], mode=[%04o], appOwner=[%s]",
392                         file.GetPointer(), mode, appOwner?"true":"false");
393
394         return true;
395 }
396
397 bool
398 InstallerUtil::IsDrmFile(const String& path)
399 {
400         int ret = 0;
401         void* pHandle = null;
402         char* pErrorMsg = null;
403         int (*drm_oem_sapps_is_drm_file)(const char* pDcfPath, int dcfPathLen);
404
405         std::unique_ptr<char[]> pFilePath(_StringConverter::CopyToCharArrayN(path));
406         TryReturn(pFilePath, false, "pFilePath is null.");
407
408         pHandle = dlopen("/usr/lib/libdrm-service-core-tizen.so", RTLD_LAZY | RTLD_GLOBAL);
409         if (!pHandle)
410         {
411                 AppLog("dlopen() failed. [%ls][%s]", path.GetPointer(), dlerror());
412                 return false;
413         }
414
415         drm_oem_sapps_is_drm_file = reinterpret_cast <int (*)(const char*, int)>(dlsym(pHandle, "drm_oem_sapps_is_drm_file"));
416         pErrorMsg = dlerror();
417         if ((pErrorMsg != null) || (drm_oem_sapps_is_drm_file == null))
418         {
419                 AppLog("dlsym() failed. [%ls][%s]", path.GetPointer(), pErrorMsg);
420                 dlclose(pHandle);
421                 return false;
422         }
423
424         AppLog("[drm] drm_oem_sapps_is_drm_file(%s, %d)", pFilePath.get(), strlen(pFilePath.get()));
425         ret = drm_oem_sapps_is_drm_file(pFilePath.get(), strlen(pFilePath.get()));
426         AppLog("[drm] drm_oem_sapps_is_drm_file(), result = [%d]", ret);
427
428         dlclose(pHandle);
429
430         if (ret == 1)
431         {
432                 AppLog("file[%ls] is DRM file.", path.GetPointer());
433                 return true;
434         }
435         else
436         {
437                 return false;
438         }
439 }
440
441 bool
442 InstallerUtil::DecryptPackage(const String& path, const String& decryptedPath)
443 {
444         int ret = 0;
445         void* pHandle = null;
446         char* pErrorMsg = null;
447         int (*drm_oem_sapps_decrypt_package)(const char* pDcfPath, int dcfPathLen, const char* pDecryptedFile, int decryptedFileLen);
448
449         std::unique_ptr<char[]> pFilePath(_StringConverter::CopyToCharArrayN(path));
450         TryReturn(pFilePath, false, "pFilePath is null.");
451
452         std::unique_ptr<char[]> pDecryptedPath(_StringConverter::CopyToCharArrayN(decryptedPath));
453         TryReturn(pDecryptedPath, false, "pDecryptedPath is null.");
454
455         pHandle = dlopen("/usr/lib/libdrm-service-core-tizen.so", RTLD_LAZY | RTLD_GLOBAL);
456         if (!pHandle)
457         {
458                 AppLog("dlopen() failed. [%ls][%s]", path.GetPointer(), dlerror());
459                 return false;
460         }
461
462         drm_oem_sapps_decrypt_package = reinterpret_cast <int (*)(const char*, int, const char*, int)>(dlsym(pHandle, "drm_oem_sapps_decrypt_package"));
463         pErrorMsg = dlerror();
464         if ((pErrorMsg != null) || (drm_oem_sapps_decrypt_package == null))
465         {
466                 AppLog("dlsym() failed. [%ls][%s]", path.GetPointer(), pErrorMsg);
467                 dlclose(pHandle);
468                 return false;
469         }
470
471         AppLog("[drm] drm_oem_sapps_decrypt_package(%s, %d, %s, %d)", pFilePath.get(), strlen(pFilePath.get()), pDecryptedPath.get(), strlen(pDecryptedPath.get()));
472         ret = drm_oem_sapps_decrypt_package(pFilePath.get(), strlen(pFilePath.get()), pDecryptedPath.get(), strlen(pDecryptedPath.get()));
473         AppLog("[drm] drm_oem_sapps_decrypt_package(), result = [%d]", ret);
474
475         dlclose(pHandle);
476
477         if (ret == 1)
478         {
479                 AppLog("[%ls] -> [%ls] is decrypted.", path.GetPointer(), decryptedPath.GetPointer());
480                 return true;
481         }
482         else
483         {
484                 return false;
485         }
486 }
487
488 String
489 InstallerUtil::GetCategory(int categoryType)
490 {
491         String category;
492
493         if (categoryType == CATEGORY_TYPE_IME)
494         {
495                 category = L"Ime";
496         }
497         else if (categoryType == CATEGORY_TYPE_HOME_SCREEN)
498         {
499                 category = L"home-screen";
500         }
501         else if (categoryType == CATEGORY_TYPE_LOCK_SCREEN)
502         {
503                 category = L"lock-screen";
504         }
505
506         return category;
507 }
508
509 int
510 InstallerUtil::GetCategoryType(char* pCategory)
511 {
512         CategoryType category = CATEGORY_TYPE_NONE;
513
514         if (strcasecmp(pCategory, "Ime") == 0)
515         {
516                 category = CATEGORY_TYPE_IME;
517         }
518         else if (strcasecmp(pCategory, "home-screen") == 0)
519         {
520                 category = CATEGORY_TYPE_HOME_SCREEN;
521         }
522         else if (strcasecmp(pCategory, "lock-screen") == 0)
523         {
524                 category = CATEGORY_TYPE_LOCK_SCREEN;
525         }
526
527         return category;
528 }
529
530 bool
531 InstallerUtil::CreateSymlinkForAppDirectory(const String& inPath, String& outPath)
532 {
533         String appId;
534
535         int length = inPath.GetLength();
536         inPath.SubString(length - PACKAGE_ID_LENGTH, PACKAGE_ID_LENGTH, appId);
537
538         String newPath;
539         newPath = PATH_OPT_APPS;
540         newPath += L"/";
541         newPath += appId;
542
543         if (inPath != newPath)
544         {
545                 InstallerUtil::CreateSymlink(inPath, newPath);
546         }
547
548         outPath = newPath;
549         AppLog("CreateSymlinkForAppDirectory(): output path=[%ls]", outPath.GetPointer());
550
551         return true;
552 }
553
554 bool
555 InstallerUtil::CreateInfoFile(const String& filePath, const String* pContext)
556 {
557         result r = E_SUCCESS;
558         File file;
559
560         r = file.Construct(filePath, "w");
561         TryReturn(!IsFailed(r), false, "file.Construct() failed, filePath=[%ls]", filePath.GetPointer());
562
563         AppLog("------------------------------------------");
564         AppLog("CreateInfoFile(), filePath = [%ls]", filePath.GetPointer());
565
566         if (pContext)
567         {
568                 r = file.Write(*pContext);
569                 TryReturn(!IsFailed(r), false, "file.Write() failed, filePath=[%ls]", filePath.GetPointer());
570                 AppLog("string = [%ls]", pContext->GetPointer());
571         }
572         AppLog("------------------------------------------");
573
574         return true;
575 }
576
577 bool
578 InstallerUtil::CreateFlagFile(const String& filePath)
579 {
580         bool res = true;
581         int fd = -1;
582         FILE* pFile = null;
583         File file;
584
585         std::unique_ptr<char[]> pFilePath(_StringConverter::CopyToCharArrayN(filePath));
586         TryCatch(pFilePath, res = false, "pFilePath is null.");
587
588         pFile = fopen(pFilePath.get(), "w");
589         TryCatch(pFile, res = false, "fopen(%s, w) failed.", pFilePath.get());
590
591         fd = fileno(pFile);
592         TryCatch(fd != -1, res = false, "fileno(%s) failed.", pFilePath.get());
593
594         fsync(fd);
595         AppLog("CreateFlagFile(), filePath = [%ls]", filePath.GetPointer());
596
597 CATCH:
598         if (pFile)
599         {
600                 fclose(pFile);
601         }
602
603         return res;
604 }
605
606 bool
607 InstallerUtil::DumpLog(const char* pBuf)
608 {
609         TryReturn(pBuf, false, "pBuf is null");
610
611         char temp[4096] = {0};
612         int bufLen = strlen(pBuf);
613         strncpy(temp, pBuf, sizeof(temp)-1);
614
615         char* pStart = &temp[0];
616
617         for (int i = 0; i < bufLen; i++)
618         {
619                 if (temp[i] == '\n')
620                 {
621                         temp[i] = 0;
622                         AppLog("%s", pStart);
623                         pStart = temp + i + 1;
624                 }
625         }
626
627         return true;
628 }
629
630 #define LOG_PRINT_LINE_MAX 20
631 #define LOG_BUFFER_COUNT_MAX 4096
632 bool
633 InstallerUtil::DumpLogData(char *pData, int dataLen)
634 {
635         const char      *szData = (const char*)pData;
636         char            ch = 0;
637         int                     i = 0, j = 0, idx = 0, idx2 = 0, high = 0, low = 0, temp = 0;
638
639         char            buf[LOG_PRINT_LINE_MAX + 2]                     = {0};
640         char            buf2[(LOG_PRINT_LINE_MAX + 2) * 3]      = {0};
641         char            buf_out[sizeof(buf) + sizeof(buf2) + 1] = {0};
642
643
644         if (dataLen > LOG_BUFFER_COUNT_MAX)
645         {
646                 dataLen = LOG_BUFFER_COUNT_MAX;
647         }
648
649         // 16 characters by 20 line are proper. // too many logs decrease performance.
650 //      if (dataLen > 16*20)
651 //              dataLen = 16*20;
652
653         AppLog("------------------------------------------");
654
655         while (i < (int)dataLen)
656         {
657                 ch      = szData[i];
658
659                 /* make ascii table */
660                 if (ch >= 32 && ch <= 128)
661                 {
662                         buf[idx++]      = ch;
663                 }
664                 else
665                         buf[idx++]      = '.';
666
667                 // make binary table
668                 high = (ch & 0xf0)>>4;
669                 low = ch & 0x0f;
670
671                 buf2[idx2++]    = LogChangeHexToStr(high);
672                 buf2[idx2++]    = LogChangeHexToStr(low);
673                 buf2[idx2++]    = ' ';
674
675                 if (idx >= LOG_PRINT_LINE_MAX)
676                 {
677                         memcpy(buf_out, buf2, idx2);
678
679                         buf_out[idx2++] = ' ';
680                         buf_out[idx2++] = ' ';
681
682                         memcpy(buf_out + idx2, buf, idx);
683                         buf_out[idx2+idx]       = '\0';
684
685                         idx             = 0;
686                         idx2    = 0;
687
688                         AppLog("%s\n", buf_out);
689                 }
690
691                 i++;
692         }
693
694         // last line
695         if (idx > 0)
696         {
697                 memcpy(buf_out, buf2, idx2);
698                 temp    = idx2;
699
700                 for (j = 0; j < (LOG_PRINT_LINE_MAX * 3) - temp; j++)
701                 {
702                         buf_out[idx2++] = ' ';
703                 }
704
705                 buf_out[idx2++] = ' ';
706                 buf_out[idx2++] = ' ';
707
708                 memcpy(buf_out+idx2, buf, idx);
709                 buf_out[idx2+idx]       = '\0';
710
711                 AppLog("%s\n", buf_out);
712         }
713
714         AppLog("------------------------------------------");
715
716         return true;
717 }
718
719 char
720 InstallerUtil::LogChangeHexToStr(int hex)
721 {
722         char ch = '0';
723
724         const static char       hexValues[]     = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', 0};
725
726
727         if (hex >= 0 && hex <= 0x0F)
728         {
729                 ch      = hexValues[hex];
730         }
731         else
732         {
733                 AppLog("LogChangeHexToStr: Error! [Hex Val: %d]\n", hex);
734         }
735
736         return ch;
737 }
738
739 bool
740 InstallerUtil::CreateLog(const String& logFile)
741 {
742         File file;
743
744         result r = file.Construct(logFile, "w");
745         if (IsFailed(r))
746         {
747                 return false;
748         }
749
750         return true;
751 }
752
753 bool
754 InstallerUtil::AppendLog(const char* pFunction, int lineNumber, bool fatal, const char* pFormat, ...)
755 {
756         File file;
757
758         InstallerManager *pManager = InstallerManager::GetInstance();
759         if (pManager == null)
760         {
761                 return false;
762         }
763
764         if (pManager->IsFileLogOn() == false)
765         {
766                 return true;
767         }
768
769         String logFile = pManager->GetLogFilePath();
770         result r = file.Construct(logFile, "a");
771         if (IsFailed(r))
772         {
773                 return false;
774         }
775
776         va_list args;
777         va_start(args, pFormat);
778         const int bufSize = 1024;
779         char logs[bufSize+1] = {0};
780         char logs2[bufSize+1] = {0};
781         if (fatal == false)
782         {
783                 snprintf(logs, bufSize, "     | %s (%d). > %s", (char*)pFunction, lineNumber, pFormat);
784         }
785         else
786         {
787                 snprintf(logs, bufSize, "[TRY]| %s (%d). > %s", (char*)pFunction, lineNumber, pFormat);
788         }
789
790         vsnprintf(logs2, bufSize, logs, args);
791         int length = strlen(logs2);
792         logs2[length] = '\n';
793
794         r = file.Write(logs2, length+1);
795         if (IsFailed(r))
796         {
797                 va_end(args);
798                 return false;
799         }
800
801         if (pManager->IsHistoryFileLogOn() == true)
802         {
803                 File historyLogFile;
804                 String historyLogFilePath = pManager->GetHistoryLogFilePath();
805                 r = historyLogFile.Construct(historyLogFilePath, "a");
806                 if (!IsFailed(r))
807                 {
808                         r = historyLogFile.Write(logs2, length+1);
809                         if (!IsFailed(r))
810                         {
811                                 // success
812                         }
813                 }
814         }
815
816         va_end(args);
817
818         return true;
819 }
820
821 bool
822 InstallerUtil::PrintLog(const String& logFile)
823 {
824         InstallerManager *pManager = InstallerManager::GetInstance();
825         if (pManager == null)
826         {
827                 return false;
828         }
829
830         if (pManager->IsFileLogOn() == false)
831         {
832                 return true;
833         }
834
835         File file;
836         FileAttributes attribute;
837
838         result r = File::GetAttributes(logFile, attribute);
839         if (IsFailed(r))
840         {
841                 return false;
842         }
843
844         int bufSize = 4096;
845         std::unique_ptr<char[]> pBuf(new (std::nothrow) char[bufSize]);
846         if (pBuf == null)
847         {
848                 return false;
849         }
850
851         r = file.Construct(logFile, "r");
852         if (IsFailed(r))
853         {
854                 return false;
855         }
856
857         int readBytes = 0;
858         do
859         {
860                 memset(pBuf.get(), 0, bufSize);
861                 readBytes = file.Read(pBuf.get(), bufSize);
862                 if (readBytes > 0)
863                 {
864                         fprintf(stderr, "%s", pBuf.get());
865                 }
866         }
867         while (readBytes > 0);
868
869         return true;
870 }
871
872 bool
873 InstallerUtil::GetRdsList(const PackageId& packageId, IList* pDeletedList, IList* pAddedList, IList* pModifiedList)
874 {
875         bool res = true;
876         FILE* fp = null;
877         char rdsFilePath[1024] = {0};
878         char buffer[1024] = {0};
879         InstallerRdsState state = INSTALLER_RDS_STATE_NONE;
880
881         snprintf(rdsFilePath, sizeof(rdsFilePath), "%s/%ls/%s", DIR_APPLICATIONS_TMP, packageId.GetPointer(), INSTALLER_RDS_FILE_NAME);
882
883         fp = fopen(rdsFilePath, "r");
884         TryReturn(fp, false, "fp is null.");
885         AppLog(".rds_delta file");
886         int line = 1;
887
888         while (fgets(buffer, sizeof(buffer), fp) != null)
889         {
890                 bool isMetadata = false;
891
892                 if (buffer[0] == '#')
893                 {
894                         if (strcasestr(buffer, INSTALLER_RDS_DELETE_STR))
895                         {
896                                 state = INSTALLER_RDS_STATE_DELETE;
897                         }
898                         else if (strcasestr(buffer, INSTALLER_RDS_ADD_STR))
899                         {
900                                 state = INSTALLER_RDS_STATE_ADD;
901                         }
902                         else if (strcasestr(buffer, INSTALLER_RDS_MODIFY_STR))
903                         {
904                                 state = INSTALLER_RDS_STATE_MODIFY;
905                         }
906
907                         isMetadata = true;
908                 }
909
910                 if (state == INSTALLER_RDS_STATE_NONE)
911                 {
912                         AppLog("Unknown RDS State, INSTALLER_RDS_STATE_NONE");
913                         continue;
914                 }
915
916                 std::unique_ptr<String> pStr(new (std::nothrow) String(buffer));
917                 TryCatch(pStr, res = false, "pStr is null.");
918                 TryCatch(pStr->IsEmpty() == false, res = false, "pStr is empty.");
919
920                 pStr->Trim();
921                 AppLog(".rds_delta: line(%03d)=[%ls]", line, pStr->GetPointer());
922                 line++;
923
924                 if (isMetadata == true)
925                         continue;
926
927                 if (state == INSTALLER_RDS_STATE_DELETE)
928                 {
929                         pDeletedList->Add(pStr.release());
930                 }
931                 else if (state == INSTALLER_RDS_STATE_ADD)
932                 {
933                         pAddedList->Add(pStr.release());
934                 }
935                 else if (state == INSTALLER_RDS_STATE_MODIFY)
936                 {
937                         pModifiedList->Add(pStr.release());
938                 }
939
940                 memset(buffer, 0, sizeof(buffer));
941         }
942
943 CATCH:
944         fclose(fp);
945         return res;
946 }
947
948 const char*
949 InstallerUtil::GetInstallerOperationString(int operation)
950 {
951         if (operation == INSTALLER_OPERATION_INSTALL)
952         {
953                 return "Install";
954         }
955         else if (operation == INSTALLER_OPERATION_UNINSTALL)
956         {
957                 return "Uninstall";
958         }
959         else if (operation == INSTALLER_OPERATION_REINSTALL)
960         {
961                 return "Reinstall";
962         }
963
964         return "Unknown";
965 }
966
967 bool
968 InstallerUtil::GetFileDigest(const String& filePath, String& digestValue)
969 {
970         const int bufSize = 64*1024;
971         int readBytes = 0;
972         result r = E_SUCCESS;
973
974         File file;
975         std::unique_ptr<Sha2Hash> pHash(new (std::nothrow) Sha2Hash());
976
977         r = pHash->SetAlgorithm("SHA2/256");
978         TryReturn(!IsFailed(r), false, "pHash->SetAlgorithm() is failed.");
979
980         r = pHash->Initialize();
981         TryReturn(!IsFailed(r), false, "pHash->Initialize() is failed.");
982
983         std::unique_ptr<char[]> pBuf(new (std::nothrow) char[bufSize]);
984         TryReturn(pBuf, false, "pBuf is null");
985
986         r = file.Construct(filePath, L"r");
987         TryReturn(!IsFailed(r), false, "file.Construct() is failed.");
988
989         do
990         {
991                 readBytes = file.Read(pBuf.get(), bufSize);
992                 AppLog("readBytes for Hash=[%d]", readBytes);
993
994                 if (readBytes > 0)
995                 {
996                         ByteBuffer buffer;
997                         r = buffer.Construct((const byte*)pBuf.get(), 0, readBytes, bufSize);
998                         TryReturn(!IsFailed(r), false, "buffer.Construct() is failed.");
999
1000                         r = pHash->Update(buffer);
1001                         TryReturn(!IsFailed(r), false, "pHash->Update() is failed.");
1002                 }
1003         }
1004         while (readBytes > 0);
1005
1006         std::unique_ptr<ByteBuffer> pResultBuf(pHash->FinalizeN());
1007         TryReturn(pResultBuf, false, "pResultBuf is null.");
1008
1009         r = StringUtil::EncodeToBase64String(*pResultBuf, digestValue);
1010         TryReturn(!IsFailed(r), false, "EncodeToBase64String() is failed.");
1011
1012         return true;
1013 }
1014
1015 IMap*
1016 InstallerUtil::ParseN(const String& str, const String& tokenDelimiter)
1017 {
1018         TryReturn(str.IsEmpty() == false, null, "str is empty.");
1019         TryReturn(tokenDelimiter.IsEmpty() == false, null, "tokenDelimiter is empty.");
1020
1021         std::unique_ptr< HashMap > pMap(new (std::nothrow) HashMap);
1022         TryReturn(pMap, null, "pMap is null.");
1023
1024         result r = pMap->Construct();
1025         TryReturn(!IsFailed(r), null, "pMap->Construct() is failed.");
1026
1027         StringTokenizer strTok(str, tokenDelimiter);
1028         while(strTok.HasMoreTokens() == true)
1029         {
1030                 String token;
1031                 r = strTok.GetNextToken(token);
1032                 TryReturn(!IsFailed(r), null, "strTok.GetNextToken() is failed.");
1033
1034                 AppLog("token = [%ls]", token.GetPointer());
1035
1036                 StringTokenizer infoTok(token, L"=");
1037
1038                 if (infoTok.GetTokenCount() != 2)
1039                 {
1040                         AppLog("'=' is not existed.");
1041                         continue;
1042                 }
1043
1044                 std::unique_ptr< String > pKey(new (std::nothrow) String);
1045                 r = infoTok.GetNextToken(*pKey);
1046                 TryReturn(!IsFailed(r), null, "infoTok.GetNextToken(*pKey) is failed.");
1047                 AppLog(" - key = [%ls]", pKey->GetPointer());
1048
1049                 std::unique_ptr< String > pValue(new (std::nothrow) String);
1050                 r = infoTok.GetNextToken(*pValue);
1051                 TryReturn(!IsFailed(r), null, "infoTok.GetNextToken(*pValue) is failed.");
1052                 AppLog(" - value = [%ls]", pValue->GetPointer());
1053
1054                 r = pMap->Add(pKey.release(), pValue.release());
1055                 TryReturn(!IsFailed(r), null, "pMap->Add() is failed.");
1056         }
1057
1058         if (pMap->GetCount() <= 0)
1059         {
1060                 AppLog("pMap->GetCount() is invalid.");
1061                 return null;
1062         }
1063
1064         return pMap.release();
1065 }
1066
1067 bool
1068 InstallerUtil::TerminateApp(const AppId& appId)
1069 {
1070         bool res = true;
1071
1072         if (_Aul::IsRunning(appId) == true)
1073         {
1074                 AppLog("App(%ls) is running.", appId.GetPointer());
1075
1076                 result r = _Aul::TerminateApplication(appId);
1077                 TryReturn(r == E_SUCCESS, false, "TerminateApplication() failed. [%ls]", appId.GetPointer());
1078
1079                 for (int j = 0; j < TERMINATE_RETRY_COUNT; j++)
1080                 {
1081                         res = _Aul::IsRunning(appId);
1082                         if (res == false)
1083                         {
1084                                 AppLog("App(%ls) is terminated.", appId.GetPointer());
1085                                 break;
1086                         }
1087                         else
1088                         {
1089                                 AppLog("App(%ls) is not terminated yet. wait count = [%d]", appId.GetPointer(), j);
1090                                 usleep(100000);
1091                         }
1092                 }
1093
1094                 if (res == true)
1095                 {
1096                         AppLog("App(%ls) can't be terminated.", appId.GetPointer());
1097                         return false;
1098                 }
1099         }
1100         else
1101         {
1102                 AppLog("App(%ls) is not running.", appId.GetPointer());
1103         }
1104
1105         return true;
1106 }
1107
1108 bool
1109 InstallerUtil::TerminateApps(const PackageId& packageId, bool DisableAutoRestart)
1110 {
1111         std::unique_ptr< PackageInfo > pPackageInfo(_PackageManagerImpl::GetInstance()->GetPackageInfoN(packageId));
1112         TryReturn(pPackageInfo, false, "GetPackageInfoN() failed.");
1113
1114         _PackageInfoImpl* pPackageInfoImpl = _PackageInfoImpl::GetInstance(pPackageInfo.get());
1115         TryReturn(pPackageInfoImpl, false, "GetInstance() failed.");
1116
1117         std::unique_ptr< IList > pPackageAppList(pPackageInfoImpl->GetPackageAppInfoListN());
1118         TryReturn(pPackageAppList, false, "GetPackageAppInfoListN() failed.");
1119
1120         for (int i = 0; i < pPackageAppList->GetCount(); i++)
1121         {
1122                 PackageAppInfo* pPackageAppInfo = dynamic_cast < PackageAppInfo* >(pPackageAppList->GetAt(i));
1123                 TryReturn(pPackageAppInfo, false, "pPackageAppList->GetAt(%d) failed.", i);
1124
1125                 AppId appId = pPackageAppInfo->GetAppId();
1126
1127                 if (DisableAutoRestart == true)
1128                 {
1129                         _PackageAppInfoImpl* pAppInfoImpl = _PackageAppInfoImpl::GetInstance(pPackageAppInfo);
1130                         TryReturn(pAppInfoImpl, false, "pAppInfoImpl is null.");
1131
1132                         String key("AutoRestart");
1133                         if (pAppInfoImpl->GetAppFeature(key) == L"True")
1134                         {
1135                                 AppLog("AutoRestart = [True]");
1136
1137                                 DatabaseManager databaseManager;
1138                                 databaseManager.DisableAutoRestart(appId);
1139
1140                                 AppLog("AutoRestart[%ls] is updated.", pAppInfoImpl->GetAppFeature(key).GetPointer());
1141                         }
1142                 }
1143
1144                 TerminateApp(appId);
1145         }
1146
1147         return true;
1148 }
1149
1150 bool
1151 InstallerUtil::IsUninstallable(const PackageId& packageId)
1152 {
1153         bool res = false;
1154
1155         std::unique_ptr< PackageInfo > pPackageInfo(_PackageManagerImpl::GetInstance()->GetPackageInfoN(packageId));
1156         TryReturn(pPackageInfo, false, "GetPackageInfoN() failed.");
1157
1158         _PackageInfoImpl* pPackageInfoImpl = _PackageInfoImpl::GetInstance(pPackageInfo.get());
1159         TryReturn(pPackageInfoImpl, false, "GetInstance() failed.");
1160
1161         res = pPackageInfoImpl->IsUninstallable();
1162
1163         AppLog("packageId[%ls]: Uninstallable = [%s]", packageId.GetPointer(), res?"true":"false");
1164
1165         return res;
1166 }
1167
1168 bool
1169 InstallerUtil::IsCscPackage(const PackageId& packageId, String& cscInfo)
1170 {
1171         bool res = false;
1172         int result = 0;
1173         char* pPath = null;
1174         pkgmgrinfo_pkginfo_h handle = null;
1175
1176         std::unique_ptr<char[]> pPackageId(_StringConverter::CopyToCharArrayN(packageId));
1177         TryReturn(pPackageId, false, "pPackageId is null.");
1178
1179         result = pkgmgrinfo_pkginfo_get_pkginfo(pPackageId.get(), &handle);
1180         TryReturn(result == PMINFO_R_OK, false, "pkgmgrinfo_pkginfo_get_pkginfo() failed. result=[%d], package=[%s]", result, pPackageId.get());
1181
1182         result = pkgmgrinfo_pkginfo_get_csc_path(handle, &pPath);
1183         TryReturn(result == PMINFO_R_OK, false, "pkgmgrinfo_pkginfo_get_csc_path() failed. result=[%d], package=[%s]", result, pPackageId.get());
1184
1185         AppLog("csc_path = [%s]", pPath);
1186
1187         cscInfo = pPath;
1188
1189         if (cscInfo.IsEmpty() == false)
1190         {
1191                 res = true;
1192                 AppLog("packageId[%ls]: cscInfo = [%ls]", packageId.GetPointer(), cscInfo.GetPointer());
1193         }
1194
1195         if (handle)
1196         {
1197                 pkgmgrinfo_pkginfo_destroy_pkginfo(handle);
1198         }
1199
1200         return res;
1201 }
1202
1203 bool
1204 InstallerUtil::IsDefaultExternalStorage()
1205 {
1206         int res = 0;
1207         int storage = 0;
1208         int mmcStatus = VCONFKEY_SYSMAN_MMC_REMOVED;
1209
1210         res = vconf_get_int("db/setting/default_memory/download_application", &storage);
1211         TryReturn(res == 0, false, "vconf_get_int(db/setting/default_memory/download_application) failed.");
1212
1213         AppLog("Storage = [%d]", storage);
1214
1215         if (storage == 1)
1216         {
1217                 res = vconf_get_int(VCONFKEY_SYSMAN_MMC_STATUS, &mmcStatus);
1218                 TryReturn(res == 0, false, "vconf_get_int(VCONFKEY_SYSMAN_MMC_STATUS) failed.");
1219
1220                 if ((mmcStatus == VCONFKEY_SYSMAN_MMC_REMOVED) || (mmcStatus == VCONFKEY_SYSMAN_MMC_INSERTED_NOT_MOUNTED))
1221                 {
1222                         AppLog("mmcStatus is MMC_REMOVED or NOT_MOUNTED.");
1223                 }
1224                 else
1225                 {
1226                         AppLog("mmcStatus is MMC_MOUNTED.");
1227                         return true;
1228                 }
1229         }
1230
1231         return false;
1232 }
1233
1234 bool
1235 InstallerUtil::IsSignatureVerificationEnabled()
1236 {
1237         result r;
1238         Registry reg;
1239         String section(L"feature");
1240         String entry(L"signature");
1241         String value;
1242
1243         r = reg.Construct(CONFIG_PATH, "r");
1244         TryReturn(!IsFailed(r), false, "CONFIG file is not found.");
1245
1246         r = reg.GetValue(section, entry, value);
1247         TryReturn(!IsFailed(r), false, "GetValue is failed. entry = [%ls]", entry.GetPointer());
1248
1249         AppLog("[%ls is %ls.]", entry.GetPointer(), value.GetPointer());
1250
1251         if (value == L"on")
1252         {
1253                 return true;
1254         }
1255
1256         return false;
1257 }
1258
1259 bool
1260 InstallerUtil::IsAuthorSignatureVerificationEnabled()
1261 {
1262         result r;
1263         Registry reg;
1264         String section(L"feature");
1265         String entry(L"author-signature");
1266         String value;
1267
1268         r = reg.Construct(CONFIG_PATH, "r");
1269         TryReturn(!IsFailed(r), false, "CONFIG file is not found.");
1270
1271         r = reg.GetValue(section, entry, value);
1272         TryReturn(!IsFailed(r), false, "GetValue is failed. entry = [%ls]", entry.GetPointer());
1273
1274         AppLog("[%ls is %ls.]", entry.GetPointer(), value.GetPointer());
1275
1276         if (value == L"on")
1277         {
1278                 return true;
1279         }
1280
1281         return false;
1282 }
1283
1284 long long
1285 InstallerUtil::GetDirectorySize(const String& rootPath)
1286 {
1287         long long total = 0;
1288         long long ret = 0;
1289         int q = 0;
1290         int r = 0;
1291         DIR *dp = NULL;
1292         struct dirent *ep = NULL;
1293         struct stat fileinfo;
1294         char file[FILENAME_MAX] = { 0, };
1295         char *pDirName = null;
1296
1297         pDirName = _StringConverter::CopyToCharArrayN(rootPath);
1298         TryCatch(pDirName, total = 0, "[osp-installer][libtpk] pDirName is null");
1299
1300         dp = opendir(pDirName);
1301         TryCatch(dp, total = 0, "[osp-installer][libtpk] dp is null");
1302
1303         while ((ep = readdir(dp)) != NULL)
1304         {
1305                 if (!strcmp(ep->d_name, ".") || !strcmp(ep->d_name, ".."))
1306                 {
1307                         continue;
1308                 }
1309
1310                 snprintf(file, FILENAME_MAX, "%s/%s", pDirName, ep->d_name);
1311
1312                 if (lstat(file, &fileinfo) < 0)
1313                 {
1314                         continue;
1315                 }
1316
1317                 if (S_ISLNK(fileinfo.st_mode))
1318                 {
1319                         AppLog("SYMLINK=%s", file);
1320                         total += INSTALLER_BLOCK_SIZE;
1321                         continue;
1322                 }
1323                 else if (S_ISDIR(fileinfo.st_mode))
1324                 {
1325                         ret = GetDirectorySize(file);
1326                         ret += fileinfo.st_size;
1327                         total += ret;
1328                         AppLog("DIR=%s, size=%d[%d KB],", file, (int)ret, (int)(ret/1024));
1329                 }
1330                 else
1331                 {
1332                         /*It is a file. Calculate the actual size occupied (in terms of 4096 blocks)*/
1333                         q = (fileinfo.st_size / INSTALLER_BLOCK_SIZE);
1334                         r = (fileinfo.st_size % INSTALLER_BLOCK_SIZE);
1335                         if (r)
1336                         {
1337                                 q++;
1338                         }
1339                         total += q * INSTALLER_BLOCK_SIZE;
1340
1341                         if (q)
1342                         {
1343                                 // AppLog("File=%s, size=%d[%d KB]", file, (q * INSTALLER_BLOCK_SIZE), (q * INSTALLER_BLOCK_SIZE)/1024);
1344                         }
1345                 }
1346         }
1347
1348         closedir(dp);
1349         dp = null;
1350
1351 CATCH:
1352         delete [] pDirName;
1353
1354         return total;
1355 }
1356
1357 String
1358 InstallerUtil::GetDisplaySize(const Tizen::Base::String& path)
1359 {
1360         long long int size = 0;
1361         float sizeRes = 0.0;
1362         String unitStr = L"0 B";
1363         result r = E_SUCCESS;
1364
1365         FileAttributes attr;
1366         r = File::GetAttributes(path, attr);
1367         TryReturn(!IsFailed(r), L"0.0KB", "File::GetAttributes() failed");
1368
1369         if (attr.IsDirectory())
1370         {
1371                 size = GetDirectorySize(path);
1372
1373                 // root directory
1374                 size += INSTALLER_BLOCK_SIZE;
1375                 AppLog("DIR=%ls, size=%d[%dKB],", path.GetPointer(), (int)size, (int)(size/1024));
1376         }
1377         else
1378         {
1379                 size = attr.GetFileSize();
1380         }
1381
1382         sizeRes = size / 1024.0;
1383
1384         String resStr;
1385         resStr.Format(128, L"%.1f", sizeRes);
1386
1387         int strLen = resStr.GetLength();
1388
1389         for (int i = strLen - 5; i > 0; i = i - 3)
1390         {
1391                 resStr.Insert(L",", i);
1392         }
1393
1394         resStr += L"KB";
1395
1396         return resStr;
1397 }
1398
1399 Tizen::Base::_ApiVisibility
1400 InstallerUtil::ConvertToNativeApiVisibility(int apiVisibility)
1401 {
1402         switch(apiVisibility)
1403         {
1404         case API_VISIBILITY_PUBLIC:
1405                 return Tizen::Base::_API_VISIBILITY_PUBLIC;
1406
1407         case API_VISIBILITY_PARTNER:
1408                 return Tizen::Base::_API_VISIBILITY_PARTNER;
1409
1410         case API_VISIBILITY_PLATFORM:
1411                 return Tizen::Base::_API_VISIBILITY_PLATFORM;
1412
1413         default:
1414                 return Tizen::Base::_API_VISIBILITY_NONE;
1415         }
1416 }
1417
1418 int
1419 InstallerUtil::GetPrivilegeLevel(int apiVisibility)
1420 {
1421         if (apiVisibility == _API_VISIBILITY_PLATFORM)
1422         {
1423                 return PRIVILEGE_LEVEL_PLATFORM;
1424         }
1425         else if (apiVisibility == _API_VISIBILITY_PARTNER)
1426         {
1427                 return PRIVILEGE_LEVEL_PARTNER;
1428         }
1429
1430         return PRIVILEGE_LEVEL_PUBLIC;
1431 }