2f040d33510ed335a235bd402a89da4b26c54436
[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 <errno.h>
25 #include <unistd.h>
26 #include <unique_ptr.h>
27
28 #include <FBaseErrorDefine.h>
29 #include <FIoFile.h>
30 #include <FIoDirectory.h>
31 #include <FBase_StringConverter.h>
32
33 #include "InstallerDefs.h"
34 #include "InstallerUtil.h"
35 #include "InstallerManager.h"
36 #include "SmackManager.h"
37
38 using namespace Tizen::Base;
39 using namespace Tizen::Base::Collection;
40 using namespace Tizen::App;
41 using namespace Tizen::Io;
42
43 InstallerUtil::InstallerUtil(void)
44 {
45 }
46
47 InstallerUtil::~InstallerUtil(void)
48 {
49 }
50
51 bool
52 InstallerUtil::Remove(const Tizen::Base::String& filePath)
53 {
54         int err = -1;
55         result r = E_SUCCESS;
56         struct stat fileinfo;
57
58         std::unique_ptr<char[]> pFilePath(_StringConverter::CopyToCharArrayN(filePath));
59         TryReturn(pFilePath, false, "pFilePath is null");
60
61         err = lstat(pFilePath.get(), &fileinfo);
62         if (err < 0)
63         {
64                 AppLog("Remove(): [%s] - %s[errno(%d)]: skip", pFilePath.get(), strerror(errno), errno);
65                 return true;
66         }
67
68         if (S_ISLNK(fileinfo.st_mode))
69         {
70                 AppLog("Remove(): symlink, path=[%s]", pFilePath.get());
71                 err = unlink(pFilePath.get());
72                 TryReturn(err >= 0, false, "unlink() failed(%s), filepath=[%s]", strerror(errno), pFilePath.get());
73         }
74         else if (S_ISDIR(fileinfo.st_mode))
75         {
76                 AppLog("Remove(): directory, path=[%ls]", filePath.GetPointer());
77                 r = Directory::Remove(filePath, true);
78                 TryReturn(!IsFailed(r), false, "Directory::Remove() failed, filePath=%ls", filePath.GetPointer());
79         }
80         else
81         {
82                 AppLog("Remove(): file, path=[%ls]", filePath.GetPointer());
83                 r = File::Remove(filePath);
84                 TryReturn(!IsFailed(r), false, "File::Remove() failed, filePath=%ls", filePath.GetPointer());
85         }
86
87         return true;
88 }
89
90 bool
91 InstallerUtil::Copy(const String& srcFilePath, const String& destFilePath)
92 {
93         int bufSize = 4096;
94         int readBytes = 0;
95         result r = E_SUCCESS;
96
97         // AppLog("+ Copy(): src=[%ls], dest=[%ls]", srcFilePath.GetPointer(), destFilePath.GetPointer());
98
99         File srcFile;
100         File destFile;
101
102         std::unique_ptr<char[]> pBuf(new (std::nothrow) char[bufSize]);
103         TryReturn(pBuf, false, "pBuf is null");
104
105         r = srcFile.Construct(srcFilePath, L"r");
106         TryReturn(!IsFailed(r), false, "srcFile.Construct is failed");
107
108         r = destFile.Construct(destFilePath, L"w");
109         TryReturn(!IsFailed(r), false, "destFile.Construct is failed");
110
111         do
112         {
113                 readBytes = srcFile.Read(pBuf.get(), bufSize);
114                 if (readBytes > 0)
115                 {
116                         r = destFile.Write(pBuf.get(), readBytes);
117                         TryReturn(!IsFailed(r), false, "destFile.Write is failed");
118                 }
119         }
120         while (readBytes > 0);
121
122         return true;
123 }
124
125 bool
126 InstallerUtil::CopyDirectory(const String& srcFilePath, const String& destFilePath)
127 {
128         result r = E_SUCCESS;
129         bool res = false;
130
131         res = File::IsFileExist(srcFilePath);
132         if (res == false)
133         {
134                 AppLog("CopyDirectory(): src=[%ls]: skip", srcFilePath.GetPointer());
135                 return true;
136         }
137
138         std::unique_ptr<Directory> pDir(new (std::nothrow) Directory);
139         TryReturn(pDir, false, "pDir is null.");
140
141         r = pDir->Construct(srcFilePath);
142         TryReturn(!IsFailed(r), false, "pDir->Construct() failed, srcFilePath=[%ls].", srcFilePath.GetPointer());
143
144         std::unique_ptr<DirEnumerator> pDirEnum(pDir->ReadN());
145         TryReturn(pDirEnum, false, "pDirEnum is null.");
146
147         while (pDirEnum->MoveNext() == E_SUCCESS)
148         {
149                 DirEntry entry = pDirEnum->GetCurrentDirEntry();
150
151                 String entryName = entry.GetName();
152                 String srcEntryDir = srcFilePath;
153                 srcEntryDir += L"/";
154                 srcEntryDir += entryName;
155
156                 if (entryName == L"." || entryName == L"..")
157                 {
158                         continue;
159                 }
160
161                 // if file or directory is symbolic link, skip this.
162                 if (InstallerUtil::IsSymlink(srcEntryDir) == true)
163                 {
164                         continue;
165                 }
166
167                 String destEntryDir = destFilePath;
168                 destEntryDir += L"/";
169                 destEntryDir += entryName;
170
171                 if (entry.IsDirectory() == false)
172                 {
173                         // file
174                         Directory::Create(destFilePath, true);
175                         InstallerUtil::Copy(srcEntryDir, destEntryDir);
176                 }
177                 else
178                 {
179                         Directory::Create(destEntryDir, true);
180                         CopyDirectory(srcEntryDir, destEntryDir);
181                 }
182         }
183
184         AppLog("CopyDirectory(): src=[%ls], dest=[%ls]", srcFilePath.GetPointer(), destFilePath.GetPointer());
185         return true;
186 }
187
188 bool
189 InstallerUtil::IsSymlink(const Tizen::Base::String& filePath)
190 {
191         int err = -1;
192         struct stat fileinfo;
193
194         std::unique_ptr<char[]> pFilePath(_StringConverter::CopyToCharArrayN(filePath));
195         TryReturn(pFilePath, false, "pFilePath is null");
196
197         err = lstat(pFilePath.get(), &fileinfo);
198         TryReturn(err >= 0, false, "lstat() failed(%s), filepath=[%s]", strerror(errno), pFilePath.get());
199
200         if (S_ISLNK(fileinfo.st_mode))
201         {
202                 return true;
203         }
204
205         return false;
206 }
207
208 bool
209 InstallerUtil::GetRealPath(const String& filePath, String& realPath)
210 {
211         char* pRealPath = null;
212
213         std::unique_ptr<char[]> pFilePath(_StringConverter::CopyToCharArrayN(filePath));
214         TryReturn(pFilePath, false, "pFilePath is null");
215
216         char tmpPath[PATH_MAX] = {0};
217         pRealPath = realpath(pFilePath.get(), tmpPath);
218         TryReturn(pRealPath, false, "pRealPath is null");
219
220         realPath = tmpPath;
221
222         AppLog("GetRealPath(): path=[%ls], realPath=[%ls]", filePath.GetPointer(), realPath.GetPointer());
223
224         return true;
225 }
226
227 bool
228 InstallerUtil::CreateSymlink(const String& oldPath, const String& newPath)
229 {
230         int err = -1;
231         bool res = false;
232
233         res = File::IsFileExist(oldPath);
234         if (res == false)
235         {
236                 AppLog("CreateSymlink(): oldPath=[%ls] not found", oldPath.GetPointer());
237                 return true;
238         }
239
240         std::unique_ptr<char[]> pOldPath(_StringConverter::CopyToCharArrayN(oldPath));
241         TryReturn(pOldPath, false, "pOldPath is null");
242
243         std::unique_ptr<char[]> pNewPath(_StringConverter::CopyToCharArrayN(newPath));
244         TryReturn(pNewPath, false, "pNewPath is null");
245
246         err = symlink(pOldPath.get(), pNewPath.get());
247         TryReturn(err == 0, false, "symlink() is failed(%s), oldpath=[%s], newpath=[%s]", strerror(errno), pOldPath.get(), pNewPath.get());
248
249         SmackManager smackManager;
250         String label("_");
251         smackManager.AddLabelDir(label, newPath);
252
253         AppLog("CreateSymlink(): [%ls] -> [%ls]", newPath.GetPointer(), oldPath.GetPointer());
254
255         return true;
256 }
257
258 bool
259 InstallerUtil::ChangeMode(const String& filePath, int mode)
260 {
261         int err = -1;
262
263         std::unique_ptr<char[]> pFilePath(_StringConverter::CopyToCharArrayN(filePath));
264         TryReturn(pFilePath, false, "pFilePath is null");
265
266         err = chmod(pFilePath.get(), mode);
267         TryReturn(err == 0, false, "chmod() is failed(%s), filepath=[%s], mode=[%o]", strerror(errno), pFilePath.get(), mode);
268
269         return true;
270 }
271
272 bool
273 InstallerUtil::ChangeOwner(const String& filePath)
274 {
275         int err = -1;
276
277         std::unique_ptr<char[]> pFilePath(_StringConverter::CopyToCharArrayN(filePath));
278         TryReturn(pFilePath, false, "pFilePath is null");
279
280         err = chown(pFilePath.get(), APP_OWNER_ID, APP_GROUP_ID);
281         TryReturn(err == 0, false, "chown() is failed(%s), filepath=[%s]", strerror(errno), pFilePath.get());
282
283         return true;
284 }
285
286 bool
287 InstallerUtil::ChangeDirectoryPermission(const String& filePath, int mode, bool appOwner)
288 {
289         result r = E_SUCCESS;
290         bool res = false;
291
292         res = File::IsFileExist(filePath);
293         if (res == false)
294         {
295                 AppLog("path=[%ls]: skip", filePath.GetPointer());
296                 return true;
297         }
298
299         std::unique_ptr<Directory> pDir(new (std::nothrow) Directory);
300         TryReturn(pDir, false, "pDir is null.");
301
302         r = pDir->Construct(filePath);
303         TryReturn(!IsFailed(r), false, "pDir->Construct() failed, filePath=[%ls]", filePath.GetPointer());
304
305         std::unique_ptr<DirEnumerator> pDirEnum(pDir->ReadN());
306         TryReturn(pDirEnum, false, "pDirEnum is null.");
307
308         while (pDirEnum->MoveNext() == E_SUCCESS)
309         {
310                 DirEntry entry = pDirEnum->GetCurrentDirEntry();
311                 String entryName = entry.GetName();
312                 if (entryName.IsEmpty() == true)
313                 {
314                         AppLog("entryName is empty.", entryName.GetPointer());
315                         continue;
316                 }
317
318                 String entryDir = filePath;
319                 entryDir += L"/";
320                 entryDir += entryName;
321
322                 if (entryName == L".")
323                 {
324                         if (appOwner == true)
325                         {
326                                 InstallerUtil::ChangeOwner(entryDir);
327                         }
328                         InstallerUtil::ChangeMode(entryDir, mode | PERM_EXECUTE);
329                         continue;
330                 }
331                 else if (entryName == L"..")
332                 {
333                         continue;
334                 }
335
336                 if (entry.IsDirectory() == false)
337                 {
338                         if (appOwner == true)
339                         {
340                                 InstallerUtil::ChangeOwner(entryDir);
341                         }
342                         InstallerUtil::ChangeMode(entryDir, mode);
343                 }
344                 else
345                 {
346                         ChangeDirectoryPermission(entryDir, mode, appOwner);
347                         if (appOwner == true)
348                         {
349                                 InstallerUtil::ChangeOwner(entryDir);
350                         }
351                         InstallerUtil::ChangeMode(entryDir, mode | PERM_EXECUTE);
352                 }
353         }
354
355         AppLog("path=[%ls], mode=[%04o], appOwner=[%s]",
356                         filePath.GetPointer(), mode, appOwner?"true":"false");
357
358         return true;
359 }
360
361 bool
362 InstallerUtil::IsDrmFile(const String& path)
363 {
364         return false;
365 }
366
367 bool
368 InstallerUtil::DecryptPackage(const String& packagePath)
369 {
370         return true;
371 }
372
373 String
374 InstallerUtil::GetCategory(int categoryType)
375 {
376         String category;
377
378         if (categoryType == CATEGORY_TYPE_IME)
379         {
380                 category = L"Ime";
381         }
382         else if (categoryType == CATEGORY_TYPE_HOME_SCREEN)
383         {
384                 category = L"home-screen";
385         }
386         else if (categoryType == CATEGORY_TYPE_LOCK_SCREEN)
387         {
388                 category = L"lock-screen";
389         }
390
391         return category;
392 }
393
394 int
395 InstallerUtil::GetCategoryType(char* pCategory)
396 {
397         CategoryType category = CATEGORY_TYPE_NONE;
398
399         if (strcasecmp(pCategory, "Ime") == 0)
400         {
401                 category = CATEGORY_TYPE_IME;
402         }
403         else if (strcasecmp(pCategory, "home-screen") == 0)
404         {
405                 category = CATEGORY_TYPE_HOME_SCREEN;
406         }
407         else if (strcasecmp(pCategory, "lock-screen") == 0)
408         {
409                 category = CATEGORY_TYPE_LOCK_SCREEN;
410         }
411
412         return category;
413 }
414
415 bool
416 InstallerUtil::CreateSymlinkForAppDirectory(const String& inPath, String& outPath)
417 {
418         String appId;
419
420         int length = inPath.GetLength();
421         inPath.SubString(length - PACKAGE_ID_LENGTH, PACKAGE_ID_LENGTH, appId);
422
423         String newPath;
424         newPath = PATH_OPT_APPS;
425         newPath += L"/";
426         newPath += appId;
427
428         if (inPath != newPath)
429         {
430                 InstallerUtil::CreateSymlink(inPath, newPath);
431         }
432
433         outPath = newPath;
434         AppLog("CreateSymlinkForAppDirectory(): output path=[%ls]", outPath.GetPointer());
435
436         return true;
437 }
438
439 bool
440 InstallerUtil::CreateInfoFile(const String& filePath, const String* pContext)
441 {
442         result r = E_SUCCESS;
443         File file;
444
445         r = file.Construct(filePath, "w");
446         TryReturn(!IsFailed(r), false, "file.Construct() failed, filePath=[%ls]", filePath.GetPointer());
447
448         AppLog("------------------------------------------");
449         AppLog("CreateInfoFile(), filePath = [%ls]", filePath.GetPointer());
450
451         if (pContext)
452         {
453                 r = file.Write(*pContext);
454                 TryReturn(!IsFailed(r), false, "file.Write() failed, filePath=[%ls]", filePath.GetPointer());
455                 AppLog("string = [%ls]", pContext->GetPointer());
456         }
457         AppLog("------------------------------------------");
458
459         return true;
460 }
461
462 bool
463 InstallerUtil::DumpLog(const char* pBuf)
464 {
465         char temp[4096] = {0};
466         TryReturn(pBuf, false, "pBuf is null");
467
468         int bufLen = strlen(pBuf);
469         strncpy(temp, pBuf, sizeof(temp));
470
471         char *pStart = &temp[0];
472
473         for (int i = 0; i < bufLen; i++)
474         {
475                 if (temp[i] == '\n')
476                 {
477                         temp[i] = 0;
478                         AppLog("%s", pStart);
479                         pStart = temp + i + 1;
480                 }
481         }
482
483         return true;
484 }
485
486 #define LOG_PRINT_LINE_MAX 20
487 #define LOG_BUFFER_COUNT_MAX 4096
488 bool
489 InstallerUtil::DumpLogData(char *pData, int dataLen)
490 {
491         const char      *szData = (const char*)pData;
492         char            ch = 0;
493         int                     i = 0, j = 0, idx = 0, idx2 = 0, high = 0, low = 0, temp = 0;
494
495         char            buf[LOG_PRINT_LINE_MAX + 2]                     = {0};
496         char            buf2[(LOG_PRINT_LINE_MAX + 2) * 3]      = {0};
497         char            buf_out[sizeof(buf) + sizeof(buf2) + 1] = {0};
498
499
500         if (dataLen > LOG_BUFFER_COUNT_MAX)
501         {
502                 dataLen = LOG_BUFFER_COUNT_MAX;
503         }
504
505         // 16 characters by 20 line are proper. // too many logs decrease performance.
506 //      if (dataLen > 16*20)
507 //              dataLen = 16*20;
508
509         AppLog("------------------------------------------");
510
511         while (i < (int)dataLen)
512         {
513                 ch      = szData[i];
514
515                 /* make ascii table */
516                 if (ch >= 32 && ch <= 128)
517                 {
518                         buf[idx++]      = ch;
519                 }
520                 else
521                         buf[idx++]      = '.';
522
523                 // make binary table
524                 high = (ch & 0xf0)>>4;
525                 low = ch & 0x0f;
526
527                 buf2[idx2++]    = LogChangeHexToStr(high);
528                 buf2[idx2++]    = LogChangeHexToStr(low);
529                 buf2[idx2++]    = ' ';
530
531                 if (idx >= LOG_PRINT_LINE_MAX)
532                 {
533                         memcpy(buf_out, buf2, idx2);
534
535                         buf_out[idx2++] = ' ';
536                         buf_out[idx2++] = ' ';
537
538                         memcpy(buf_out + idx2, buf, idx);
539                         buf_out[idx2+idx]       = '\0';
540
541                         idx             = 0;
542                         idx2    = 0;
543
544                         AppLog("%s\n", buf_out);
545                 }
546
547                 i++;
548         }
549
550         // last line
551         if (idx > 0)
552         {
553                 memcpy(buf_out, buf2, idx2);
554                 temp    = idx2;
555
556                 for (j = 0; j < (LOG_PRINT_LINE_MAX * 3) - temp; j++)
557                 {
558                         buf_out[idx2++] = ' ';
559                 }
560
561                 buf_out[idx2++] = ' ';
562                 buf_out[idx2++] = ' ';
563
564                 memcpy(buf_out+idx2, buf, idx);
565                 buf_out[idx2+idx]       = '\0';
566
567                 AppLog("%s\n", buf_out);
568         }
569
570         AppLog("------------------------------------------");
571
572         return true;
573 }
574
575 char
576 InstallerUtil::LogChangeHexToStr(int hex)
577 {
578         char ch = '0';
579
580         const static char       hexValues[]     = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', 0};
581
582
583         if (hex >= 0 && hex <= 0x0F)
584         {
585                 ch      = hexValues[hex];
586         }
587         else
588         {
589                 AppLog("LogChangeHexToStr: Error! [Hex Val: %d]\n", hex);
590         }
591
592         return ch;
593 }
594
595 bool
596 InstallerUtil::CreateLog(const String& logFile)
597 {
598         File file;
599
600         result r = file.Construct(logFile, "w");
601         if (IsFailed(r))
602         {
603                 return false;
604         }
605
606         return true;
607 }
608
609 bool
610 InstallerUtil::AppendLog(const char* pFunction, int lineNumber, bool fatal, const char* pFormat, ...)
611 {
612         File file;
613
614         InstallerManager *pManager = InstallerManager::GetInstance();
615         if (pManager == null)
616         {
617                 return false;
618         }
619
620         if (pManager->IsFileLogOn() == false)
621         {
622                 return true;
623         }
624
625         String logFile = pManager->GetLogFilePath();
626         result r = file.Construct(logFile, "a");
627         if (IsFailed(r))
628         {
629                 return false;
630         }
631
632         va_list args;
633         va_start(args, pFormat);
634         const int bufSize = 1024;
635         char logs[bufSize+1] = {0};
636         char logs2[bufSize+1] = {0};
637         if (fatal == false)
638         {
639                 snprintf(logs, bufSize, "     | %s (%d). > %s", (char*)pFunction, lineNumber, pFormat);
640         }
641         else
642         {
643                 snprintf(logs, bufSize, "[TRY]| %s (%d). > %s", (char*)pFunction, lineNumber, pFormat);
644         }
645
646         vsnprintf(logs2, bufSize, logs, args);
647         int length = strlen(logs2);
648         logs2[length] = '\n';
649
650         r = file.Write(logs2, length+1);
651         if (IsFailed(r))
652         {
653                 va_end(args);
654                 return false;
655         }
656         va_end(args);
657
658         return true;
659 }
660
661 bool
662 InstallerUtil::PrintLog(const String& logFile)
663 {
664         InstallerManager *pManager = InstallerManager::GetInstance();
665         if (pManager == null)
666         {
667                 return false;
668         }
669
670         if (pManager->IsFileLogOn() == false)
671         {
672                 return true;
673         }
674
675         File file;
676         FileAttributes attribute;
677
678         result r = File::GetAttributes(logFile, attribute);
679         if (IsFailed(r))
680         {
681                 return false;
682         }
683
684         int bufSize = 4096;
685         std::unique_ptr<char[]> pBuf(new (std::nothrow) char[bufSize]);
686         if (pBuf == null)
687         {
688                 return false;
689         }
690
691         r = file.Construct(logFile, "r");
692         if (IsFailed(r))
693         {
694                 return false;
695         }
696
697         int readBytes = 0;
698         do
699         {
700                 memset(pBuf.get(), 0, bufSize);
701                 readBytes = file.Read(pBuf.get(), bufSize);
702                 if (readBytes > 0)
703                 {
704                         fprintf(stderr, "%s", pBuf.get());
705                 }
706         }
707         while (readBytes > 0);
708
709         return true;
710 }
711
712 bool
713 InstallerUtil::GetRdsList(const PackageId& packageId, IList* pDeletedList, IList* pAddedList, IList* pModifiedList)
714 {
715         bool res = true;
716         FILE* fp = null;
717         char rdsFilePath[1024] = {0};
718         char buffer[1024] = {0};
719         InstallerRdsState state = INSTALLER_RDS_STATE_NONE;
720
721         snprintf(rdsFilePath, sizeof(rdsFilePath), "%s/%ls/%s", DIR_APPLICATIONS_TMP, packageId.GetPointer(), INSTALLER_RDS_FILE_NAME);
722
723         fp = fopen(rdsFilePath, "r");
724         TryReturn(fp, false, "fp is null.");
725         AppLog(".rds_delta file");
726         int line = 1;
727
728         while (fgets(buffer, sizeof(buffer), fp) != null)
729         {
730                 bool isMetadata = false;
731
732                 if (buffer[0] == '#')
733                 {
734                         if (strcasestr(buffer, INSTALLER_RDS_DELETE_STR))
735                         {
736                                 state = INSTALLER_RDS_STATE_DELETE;
737                         }
738                         else if (strcasestr(buffer, INSTALLER_RDS_ADD_STR))
739                         {
740                                 state = INSTALLER_RDS_STATE_ADD;
741                         }
742                         else if (strcasestr(buffer, INSTALLER_RDS_MODIFY_STR))
743                         {
744                                 state = INSTALLER_RDS_STATE_MODIFY;
745                         }
746
747                         isMetadata = true;
748                 }
749
750                 if (state == INSTALLER_RDS_STATE_NONE)
751                 {
752                         AppLog("Unknown RDS State, INSTALLER_RDS_STATE_NONE");
753                         continue;
754                 }
755
756                 std::unique_ptr<String> pStr(new (std::nothrow) String(buffer));
757                 TryCatch(pStr, res = false, "pStr is null.");
758                 TryCatch(pStr->IsEmpty() == false, res = false, "pStr is empty.");
759
760                 pStr->Trim();
761                 AppLog(".rds_delta: line(%03d)=[%ls]", line, pStr->GetPointer());
762                 line++;
763
764                 if (isMetadata == true)
765                         continue;
766
767                 if (state == INSTALLER_RDS_STATE_DELETE)
768                 {
769                         pDeletedList->Add(pStr.release());
770                 }
771                 else if (state == INSTALLER_RDS_STATE_ADD)
772                 {
773                         pAddedList->Add(pStr.release());
774                 }
775                 else if (state == INSTALLER_RDS_STATE_MODIFY)
776                 {
777                         pModifiedList->Add(pStr.release());
778                 }
779
780                 memset(buffer, 0, sizeof(buffer));
781         }
782
783 CATCH:
784         fclose(fp);
785         return res;
786 }
787
788 const char*
789 InstallerUtil::GetInstallerOperationString(int operation)
790 {
791         if (operation == INSTALLER_OPERATION_INSTALL)
792         {
793                 return "Install";
794         }
795         else if (operation == INSTALLER_OPERATION_UNINSTALL)
796         {
797                 return "Uninstall";
798         }
799         else if (operation == INSTALLER_OPERATION_REINSTALL)
800         {
801                 return "Reinstall";
802         }
803
804         return "Unknown";
805 }
806