Merge "Update deprecated libprivilege-control API functions." into tizen
[platform/framework/native/appfw.git] / src / io / FIo_FileUtil.cpp
1 //
2 // Copyright (c) 2012 Samsung Electronics Co., Ltd.
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 /**
18  * @file        FIo_FileUtil.cpp
19  * @brief       This is the implementation file for _FileUtil class.
20  */
21
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <unistd.h>
25 #include <sys/mman.h>
26 #include <sys/types.h>
27 #include <sys/stat.h>
28 #include <fcntl.h>
29 #include <time.h>
30 #include <limits.h>
31 #include <errno.h>
32 #include <new>
33 #include <unique_ptr.h>
34
35 #include <FIoFile.h>
36 #include <FIoDirectory.h>
37 #include <FBaseResult.h>
38 #include <FBaseSysLog.h>
39 #include <FLclLocaleManager.h>
40 #include <FLclTimeZone.h>
41
42 #include <FBase_StringConverter.h>
43 #include <FBase_NativeError.h>
44 #include <FApp_AppInfo.h>
45 #include <FIo_FileAttributesImpl.h>
46 #include <FIo_SecureIoUtil.h>
47 #include <FIo_FileImpl.h>
48 #include <FIo_FileUtil.h>
49
50 using namespace std;
51 using namespace Tizen::Base;
52 using namespace Tizen::Locales;
53 using namespace Tizen::App;
54
55 namespace Tizen { namespace Io
56 {
57
58 static const int _BASE_YEAR = 1900;
59 static const int _MAX_COPY_BYTES = 4096;
60
61 //Holds app path prefixes
62 static const char* filePathAppPrefix[] =
63 {
64         "/Home",
65         "/Res",
66         "/Share",
67         "/Share2",
68         "/HomeExt",
69         "/ShareExt",
70         "/Share2Ext",
71         "/Clipboard",
72         "/NPKI",
73         "/Storagecard/NPKI",
74         "/system/Document",
75         "/system/Data/FWeb",
76         "/Storagecard/DownloadedAppPackages",
77         "/system/Media",
78         "/system/Ringtones",
79         "/system/Wallpapers",
80         "/EmailBox",
81         "/MmsBox"
82 };
83
84 //Holds Media path prefixes
85 static const char* filePathMediaPrefix[] =
86 {
87         "/Media",
88         "/Storagecard/Media"
89 };
90
91 //Holds system path prefixes
92 static const char* filePathSystemPrefix[] =
93 {
94         "/system/configuration",
95         "/SystemRw"
96 };
97
98 result
99 _FileUtil::Remove(const String& filePath)
100 {
101         result r = E_SUCCESS;
102         unique_ptr<char[]> pFilePath(_StringConverter::CopyToCharArrayN(filePath));
103         SysTryReturn(NID_IO, (pFilePath != null), GetLastResult(), GetLastResult(), ("[%s] Invalid file path."),
104                                 GetErrorMessage(GetLastResult()));
105
106         if (_FileUtil::IsFileExist(pFilePath.get()) == false)
107         {
108                 SysSecureLogException(NID_IO, E_FILE_NOT_FOUND, "[E_FILE_NOT_FOUND] File (%s) does not exist.", pFilePath.get());
109                 return E_FILE_NOT_FOUND;
110         }
111
112         char resolvedPath[PATH_MAX] = {0,};
113         if (realpath(pFilePath.get(), resolvedPath) == null)
114         {
115                 switch (errno)
116                 {
117                 case EACCES:
118                         r = E_ILLEGAL_ACCESS;
119                         break;
120                 case EINVAL:
121                         // fall through
122                 case ELOOP:
123                         // fall through
124                 case ENAMETOOLONG:
125                         // fall through
126                 case ENOTDIR:
127                         r = E_INVALID_ARG;
128                         break;
129                 case EIO:
130                         r = E_IO;
131                         break;
132                 case ENOENT:
133                         r = E_FILE_NOT_FOUND;
134                         break;
135                 default:
136                         r = E_SYSTEM;
137                         break;
138                 }
139
140                 SysLog(NID_IO, "[%s] Failed to produce canonical absolute path (%ls). errno: %d (%s)",
141                                 GetErrorMessage(r), filePath.GetPointer(), errno, strerror(errno));
142
143                 return r;
144         }
145
146         int ret = unlink(resolvedPath);
147         if (ret != 0)
148         {
149                 if (errno == EISDIR)
150                 {
151                         r = E_INVALID_ARG;
152                 }
153                 else
154                 {
155                         r = __ConvertNativeErrorToResult(errno);
156                         SysLog(NID_IO, "[%s] Failed to unlink(), errno: %d (%s)", GetErrorMessage(r), errno, strerror(errno));
157                 }
158         }
159
160         return r;
161 }
162
163 result
164 _FileUtil::Move(const String& oldFilePath, const String& newFilePath)
165 {
166         result r = E_SUCCESS;
167         struct stat64 statBuf;
168
169         unique_ptr<char[]> pOldPath(_StringConverter::CopyToCharArrayN(oldFilePath));
170         SysTryReturn(NID_IO, pOldPath != null, GetLastResult(), GetLastResult(),
171                            "[%s] Invalid old file path.", GetErrorMessage(GetLastResult()));
172
173         unique_ptr<char[]> pNewPath(_StringConverter::CopyToCharArrayN(newFilePath));
174         SysTryReturn(NID_IO, pNewPath != null, GetLastResult(), GetLastResult(),
175                            "[%s] Invalid new file path.", GetErrorMessage(GetLastResult()));
176
177         SysTryReturnResult(NID_IO, _FileUtil::IsFileExist(newFilePath) == false, E_FILE_ALREADY_EXIST,
178                            "New file already exists.");
179
180         SysTryReturnResult(NID_IO, _FileUtil::IsFileExist(oldFilePath) == true, E_FILE_NOT_FOUND,
181                            "Old filepath not found.");
182
183         if (stat64(pOldPath.get(), &statBuf) < 0)
184         {
185                 r = __ConvertNativeErrorToResult(errno);
186                 SysLogException(NID_IO, r, "[%s] stat64() failed, path: %s, errno: %d (%s)",
187                                 GetErrorMessage(r), pOldPath.get(), errno, strerror(errno));
188                 return r;
189         }
190         SysTryReturnResult(NID_IO, S_ISDIR(statBuf.st_mode) == false, E_INVALID_ARG,
191                            "The old path is a directory.");
192
193         int ret = rename(pOldPath.get(), pNewPath.get());
194         if (ret != 0 && errno != EXDEV)
195         {
196                 r = __ConvertNativeErrorToResult(errno);
197                 SysLog(NID_IO, "[%s] rename() failed, errno: %d (%s)", GetErrorMessage(r), errno, strerror(errno));
198                 return r;
199         }
200         else if (errno == EXDEV)
201         {
202                 r = File::Copy(oldFilePath, newFilePath, true);
203                 SysTryReturn(NID_IO, !IsFailed(r), r, r, "[%s] Propagating to caller...", GetErrorMessage(r));
204
205                 r = File::Remove(oldFilePath);
206                 SysTryReturn(NID_IO, !IsFailed(r), r, r, "[%s] Propagating to caller...", GetErrorMessage(r));
207         }
208
209         return E_SUCCESS;
210 }
211
212 result
213 _FileUtil::Copy(const String& srcFilePath, const String& destFilePath, bool failIfExist)
214 {
215         int srcFd = -1;
216         int dstFd = -1;
217         ssize_t readBytes = -1;
218         ssize_t writtenBytes = -1;
219         ssize_t remainingBytes = -1;
220         char* pBuffer = null;
221         char* pCopyBuf = null;
222         result r = E_SUCCESS;
223
224         unique_ptr<char[]> pSrcpath(_StringConverter::CopyToCharArrayN(srcFilePath));
225         SysTryReturn(NID_IO, pSrcpath != null, GetLastResult(), GetLastResult(),
226                            "[%s] Invalid source file path.", GetErrorMessage(GetLastResult()));
227
228         unique_ptr<char[]> pDstpath(_StringConverter::CopyToCharArrayN(destFilePath));
229         SysTryReturn(NID_IO, pDstpath != null, GetLastResult(), GetLastResult(),
230                            "[%s] Invalid destination file path.", GetErrorMessage(GetLastResult()));
231
232         SysTryReturnResult(NID_IO, _FileUtil::IsFileExist(srcFilePath) == true, E_FILE_NOT_FOUND,
233                            "Source file(%s) does not exist.", pSrcpath.get());
234
235         if ((_FileUtil::IsFileExist(destFilePath) == true) && (failIfExist == true))
236         {
237                 r = E_FILE_ALREADY_EXIST;
238                 SysLog(NID_IO, "[E_FILE_ALREADY_EXIST] Destination file already exists.");
239                 return r;
240         }
241
242         srcFd = open64(pSrcpath.get(), O_RDONLY);
243         if (srcFd == -1)
244         {
245                 r = __ConvertNativeErrorToResult(errno);
246                 SysLogException(NID_IO, r, "[%s] Failed to open file (%s).", GetErrorMessage(r), pSrcpath.get());
247                 return r;
248         }
249         dstFd = open64(pDstpath.get(), O_WRONLY | O_CREAT | O_TRUNC, 0644);
250         if (dstFd == -1)
251         {
252                 r = __ConvertNativeErrorToResult(errno);
253                 SysLogException(NID_IO, r, "[%s] Failed to open file (%s), errno: %d (%s)",
254                                    GetErrorMessage(r), pDstpath.get(), errno, strerror(errno));
255                 goto CATCH;
256         }
257
258         pBuffer = new (std::nothrow) char[_MAX_COPY_BYTES];
259         SysTryCatch(NID_IO, pBuffer != null, r = E_OUT_OF_MEMORY, E_OUT_OF_MEMORY, "[E_OUT_OF_MEMORY] The memory is insufficient.");
260
261         pCopyBuf = pBuffer;
262         do
263         {
264                 do
265                 {
266                         readBytes = read(srcFd, pCopyBuf, _MAX_COPY_BYTES);
267                 }
268                 while (readBytes < 0 && errno == EINTR);
269                 if (readBytes < 0)
270                 {
271                         r = __ConvertNativeErrorToResult(errno);
272                         SysLogException(NID_IO, r, "[%s] Failed to read from source file (%s), errno: %d (%s)",
273                                         GetErrorMessage(r), pSrcpath.get(), errno, strerror(errno));
274                         goto CATCH;
275                 }
276                 else if (readBytes == 0)
277                 {
278                         break;
279                 }
280                 remainingBytes = readBytes;
281 RETRY:
282                 do
283                 {
284                         writtenBytes = write(dstFd, pCopyBuf, remainingBytes);
285                 }
286                 while (writtenBytes < 0 && errno == EINTR);
287                 if (writtenBytes < 0)
288                 {
289                         r = __ConvertNativeErrorToResult(errno);
290                         SysLogException(NID_IO, r, "[%s] Failed to write to destination file (%s), errno: %d (%s)",
291                                         GetErrorMessage(r), pDstpath.get(), errno, strerror(errno));
292                         goto CATCH;
293                 }
294                 else if (writtenBytes < remainingBytes)
295                 {
296                         remainingBytes = remainingBytes - writtenBytes;
297                         pCopyBuf = const_cast< char* >(pCopyBuf) + writtenBytes;
298                         goto RETRY;
299                 }
300         }
301         while (readBytes);
302
303         // fall through
304 CATCH:
305         if (srcFd != -1)
306         {
307                 close(srcFd);
308         }
309         if (dstFd != -1)
310         {
311                 fsync(dstFd);
312                 close(dstFd);
313         }
314         delete[] pBuffer;
315
316         return r;
317 }
318
319 result
320 _FileUtil::GetAttributes(const String& filePath, FileAttributes& attribute)
321 {
322         DateTime dateTime;
323         DateTime modifiedTime;
324         off64_t fileSize = 0;
325         unsigned long attr = 0;
326         result r = E_SUCCESS;
327         String fileName = L"";
328         bool hidden = false;
329
330         unique_ptr<char[]> pFilePath(_StringConverter::CopyToCharArrayN(filePath));
331         SysTryReturn(NID_IO, (pFilePath != null), GetLastResult(), GetLastResult(), "[%s] Invalid source file path.",
332                            GetErrorMessage(GetLastResult()));
333
334         struct stat64 statbuf;
335         if (stat64(pFilePath.get(), &statbuf) == -1)
336         {
337                 r = __ConvertNativeErrorToResult(errno);
338                 SysSecureLogException(NID_IO, r, "[%s] Failed to get file (%s) status. errno: %d (%s)",
339                                 GetErrorMessage(r), pFilePath.get(), errno, strerror(errno));
340                 return r;
341         }
342
343         // size
344         fileSize = statbuf.st_size;
345
346         // attributes
347         attr = statbuf.st_mode;
348
349         struct tm resultTm;
350         struct tm* pTm = gmtime_r(&statbuf.st_mtime, &resultTm);
351         SysTryReturnResult(NID_IO, pTm != null, E_SYSTEM, "Failed to get local time (%s).", strerror(errno));
352
353         r = dateTime.SetValue(_BASE_YEAR + pTm->tm_year, 1 + pTm->tm_mon, pTm->tm_mday, pTm->tm_hour, pTm->tm_min, pTm->tm_sec);
354         SysTryReturn(NID_IO, !IsFailed(r), E_SYSTEM, r, "[%s] Failed to set DateTime.", GetErrorMessage(r));
355
356         r = modifiedTime.SetValue(_BASE_YEAR + pTm->tm_year, 1 + pTm->tm_mon, pTm->tm_mday, pTm->tm_hour, pTm->tm_min, pTm->tm_sec);
357         SysTryReturn(NID_IO, !IsFailed(r), E_SYSTEM, r, "[%s] Failed to set DateTime.", GetErrorMessage(r));
358
359         LocaleManager locMgr;
360         locMgr.Construct();
361
362         TimeZone tmZone = locMgr.GetSystemTimeZone();
363         DateTime locDateTime = tmZone.UtcTimeToWallTime(dateTime);
364         DateTime locModifiedTime = tmZone.UtcTimeToWallTime(modifiedTime);
365
366         fileName = _FileUtil::GetFileName(filePath);
367         if (fileName.StartsWith(L".", 0)) // including . and ..
368         {
369                 hidden = true;
370         }
371
372         _FileAttributesImpl::GetInstance(attribute)->Set(locDateTime, locModifiedTime, fileSize, attr, hidden);
373
374         return E_SUCCESS;
375 }
376
377 String
378 _FileUtil::GetFileName(const String& filePath)
379 {
380         String fileName;
381         int pos = -1;
382
383         result r = filePath.LastIndexOf(L'/', filePath.GetLength() - 1, pos);
384         SysTryReturn(NID_IO, r == E_SUCCESS || r == E_OBJ_NOT_FOUND, fileName, E_INVALID_ARG,
385                         "[E_INVALID_ARG] The file path is invalid.");
386
387         r = filePath.SubString(pos + 1, fileName);
388         SysTryReturn(NID_IO, !IsFailed(r), fileName, E_INVALID_ARG, "[E_INVALID_ARG] The file path is invalid.");
389         SysTryReturn(NID_IO, fileName.GetLength() > 0 && fileName.GetLength() <= NAME_MAX, fileName, E_INVALID_ARG,
390                         "[E_INVALID_ARG] The length of file name is zero or exceeds system limitations.");
391
392         SetLastResult(E_SUCCESS);
393         return fileName;
394 }
395
396 String
397 _FileUtil::GetFileExtension(const String& filePath)
398 {
399         String extName;
400         int pos = -1;
401
402         result r = filePath.LastIndexOf(L'/', filePath.GetLength() - 1, pos);
403         SysTryReturn(NID_IO, r == E_SUCCESS || r == E_OBJ_NOT_FOUND, extName, E_INVALID_ARG,
404                         "[E_INVALID_ARG] The file path is invalid.");
405
406         String fileName;
407         r = filePath.SubString(pos + 1, fileName);
408         SysTryReturn(NID_IO, !IsFailed(r), extName, E_INVALID_ARG, "[E_INVALID_ARG] The file path is invalid.");
409         SysTryReturn(NID_IO, fileName.GetLength() > 0 && fileName.GetLength() <= NAME_MAX, extName, E_INVALID_ARG,
410                         "[E_INVALID_ARG] The length of file name is zero or exceeds system limitations.");
411
412         r = fileName.LastIndexOf(L'.', fileName.GetLength() - 1, pos);
413         SysTryReturn(NID_IO, !IsFailed(r), extName, E_INVALID_ARG, "[E_INVALID_ARG] The file path is invalid.");
414
415         r = fileName.SubString(pos + 1, extName);
416         SysTryReturn(NID_IO, !IsFailed(r), extName, E_INVALID_ARG, "[E_INVALID_ARG] The file path is invalid.");
417
418         SetLastResult(E_SUCCESS);
419         return extName;
420 }
421
422 bool
423 _FileUtil::IsFileExist(const String& filePath)
424 {
425         int ret = 0;
426         result r = E_SUCCESS;
427
428         unique_ptr<char[]> pFilePath(_StringConverter::CopyToCharArrayN(filePath));
429         SysTryReturn(NID_IO, (pFilePath != null), false, GetLastResult(), ("[%s] Invalid file path."),
430                            GetErrorMessage(GetLastResult()));
431
432         ret = access(pFilePath.get(), F_OK);
433         if (ret != 0)
434         {
435                 switch (errno)
436                 {
437                 case ENAMETOOLONG:
438                         r = E_INVALID_ARG;
439                         break;
440                 case ENOENT:
441                         r = E_SUCCESS;
442                         break;
443                 default:
444                         r = __ConvertNativeErrorToResult(errno);
445                         break;
446                 }
447         }
448
449         SetLastResult(r);
450         return (ret == 0) ? true : false;
451 }
452
453 #if 0
454 bool
455 _FileUtil::IsEncrypted(const String& filePath)
456 {
457         result  r = E_SUCCESS;
458         // TODO: int    pathKind;
459         int     readItems = 0;
460         int     fileLength = 0;
461         bool    encrypted = false;
462         // TODO: bool   checkPrivilege = false;
463         byte    secureHeader[SECURE_FILE_HEADER_SIZE_V1 + SECURE_IO_LOF_SIZE];
464         byte    reservedValue[SECURE_IO_STATIC_BIN_LEN] = {0xCA, 0xFE, 0xBE, 0xBE, 0xDA, 0xEF, 0xEB, 0xEB};
465         char    magicNum1[SECURE_IO_MAGIC_NUMBER_SIZE] = {0xCA, 0xFE, 0xBE, 0xBE};
466         char    magicNum2[SECURE_IO_MAGIC_NUMBER_SIZE] = {0xDA, 0xEF, 0xEF, 0xEB};
467         FILE*   pFile = null;
468
469         unique_ptr<char[]> pFilePath(_StringConverter::CopyToCharArrayN(filePath));
470         SysTryReturn(NID_IO, pFilePath != null, false, E_INVALID_ARG, "[E_INVALID_ARG] CopyToCharArrayN failed!");
471
472         fileLength = strlen(pFilePath.get());
473         SysTryReturn(NID_IO, fileLength > 0, false, E_INVALID_ARG, "[E_INVALID_ARG] CopyToCharArrayN failed!");
474
475         if (pFilePath[fileLength - 1] == ('/'))
476         {
477                 pFilePath[fileLength - 1] = ('\0'); // remove last '/' character if exists.
478         }
479
480 //      // TODO: check accessibility to path
481 //      r = CheckAccessibilityToPath(pFilePath, &pathKind, 0);
482 //      if(IsFailed(r))
483 //              goto CATCH;
484 //
485 //      if(pathKind == __PATH_KIND_AUTHORIZED_MMC)
486 //      {
487 //              __CheckPrivilege(PRV_INSTALLATION, checkPrivilege);
488 //              if(!checkPrivilege)
489 //              {
490 //                      r = E_ILLEGAL_ACCESS;
491 //                      goto CATCH;
492 //              }
493 //      }
494 //      else if(pathKind == __PATH_KIND_AUTHORIZED_LINK || pathKind == __PATH_KIND_AUTHORIZED_NPKI ||
495 //                      pathKind == __PATH_KIND_AUTHORIZED_PRELOADED_MEDIA)
496 //      {
497 //              __CheckPrivilege(PRV_PRIVILEGED_IO, checkPrivilege);
498 //              if(!checkPrivilege)
499 //              {
500 //                      r = E_ILLEGAL_ACCESS;
501 //                      goto CATCH;
502 //              }
503 //      }
504 //      else if (pathKind == __PATH_KIND_APP_DENY)
505 //      {
506 //              r = E_ILLEGAL_ACCESS;
507 //              goto CATCH;
508 //      }
509
510         pFile = fopen(pFilePath.get(), "r");
511         if (pFile == null)
512         {
513                 r = __ConvertNativeErrorToResult(errno);
514                 SysLog(NID_IO, "[%s] Failed to open file (%s) in openMode (%s), (errno: %d).", GetErrorMessage(r), pFilePath.get(), "r", errno);
515                 goto CATCH;
516         }
517
518         readItems = fread(secureHeader, 1, SECURE_FILE_HEADER_SIZE_V1 + SECURE_IO_LOF_SIZE, pFile);
519
520         if (readItems < (SECURE_FILE_HEADER_SIZE_V1 + SECURE_IO_LOF_SIZE))
521         {
522                 int eof = feof((FILE*)pFile);
523                 if (eof)
524                 {
525                         //No error;
526                         encrypted = false;
527                         goto CATCH;
528                 }
529
530                 r = __ConvertNativeErrorToResult(errno);
531                 SysLog(NID_IO, "[%s] Failed to open file (%s) in openMode (%s), (errno: %d).", GetErrorMessage(r), pFilePath.get(), "r", errno);
532                 goto CATCH;
533         }
534
535         if (memcmp(secureHeader, SECURE_FILE_HEADER_STRING, SECURE_FILE_HEADER_STRING_SIZE) == 0 && \
536                 memcmp(secureHeader + SECURE_FILE_HEADER_STRING_SIZE, reservedValue, SECURE_IO_STATIC_BIN_LEN) == 0)
537         {
538                 encrypted = true;
539         }
540         else if (memcmp(secureHeader, SECURE_REG_HEADER_STRING, SECURE_REG_HEADER_STRING_SIZE) == 0 && \
541                 memcmp(secureHeader + SECURE_REG_HEADER_STRING_SIZE, reservedValue, SECURE_IO_STATIC_BIN_LEN) == 0)
542         {
543                 encrypted = true;
544         }
545         else if ((memcmp(secureHeader, magicNum1, SECURE_IO_MAGIC_NUMBER_SIZE) == 0) &&
546                         (memcmp(secureHeader + SECURE_IO_STATIC_BIN_LEN, magicNum2, SECURE_IO_MAGIC_NUMBER_SIZE) == 0))
547
548         {
549                 encrypted = true;
550         }
551         else
552         {
553                 encrypted = false;
554         }
555
556         // fall thru
557 CATCH:
558
559         if (pFile)
560         {
561                 fclose(pFile);
562         }
563
564         SetLastResult(r);
565         return encrypted;
566 }
567 #endif
568
569 bool
570 _FileUtil::IsAppPath(const String& filePath)
571 {
572         result r = E_SUCCESS;
573
574         if (VerifyFilePath(filePath, FILEPATH_TYPE_APP))
575         {
576                 SetLastResult(E_SUCCESS);
577                 return true;
578         }
579         r = GetLastResult();
580
581         SetLastResult(r);
582         return false;
583 }
584
585 bool
586 _FileUtil::IsMediaPath(const String& filePath)
587 {
588         result r = E_SUCCESS;
589
590         if (VerifyFilePath(filePath, FILEPATH_TYPE_MEDIA))
591         {
592                 SetLastResult(E_SUCCESS);
593                 return true;
594         }
595         r = GetLastResult();
596
597         SetLastResult(r);
598         return false;
599 }
600
601 bool
602 _FileUtil::IsSystemPath(const String& filePath)
603 {
604         result r = E_SUCCESS;
605
606         if (VerifyFilePath(filePath, FILEPATH_TYPE_SYSTEM))
607         {
608                 SetLastResult(E_SUCCESS);
609                 return true;
610         }
611         r = GetLastResult();
612
613         SetLastResult(r);
614         return false;
615 }
616
617 bool
618 _FileUtil::VerifyFilePath(const String& filePath, _FilePathType pathType)
619 {
620         result r = E_SUCCESS;
621         String tmpStr("");
622         String absolutePath("");
623         int i = 0;
624         int index = 0;
625         int pathCount = 0;
626         char** ppPathList = null;
627         bool candidateFound = false;
628         wchar_t ch = L'\0';
629
630         //TODO Apply realpath after data caging.
631         //
632         //char resolved_path[1024];
633         //char* pFilePath = _StringConverter::CopyToCharArrayN(filePath);
634         //
635         //r = GetLastResult();
636         //
637         //SysTryCatch(NID_IO, pFilePath != null,
638         //        r, r, "[%s] Failed to get file path", GetErrorMessage(r));
639
640
641         //SysLog(NID_IO, "convert: %s", pFilePath);
642         //if (realpath(pFilePath, resolved_path) !=0)
643         //{
644         //      r = __ConvertNativeErrorToResult(errno);
645         //      SysLog(NID_IO, "convert Error!!! [%s] %s", resolved_path, GetErrorMessage(r));
646         //      delete[] pFilePath;
647         //      return false;
648         //      }
649         //
650         //SysLog(NID_IO, "convert result: %s", resolved_path);
651         //absolutePath.Append(resolved_path);
652         //delete[] pFilePath;
653
654         absolutePath.Append(filePath);
655         // This code does not handle paths without prefix '/' ex: "Home/myfile"
656         // since it depends on cwd.
657         switch (pathType)
658         {
659         case FILEPATH_TYPE_APP:
660                 pathCount = MAX_FILEPATH_APP;
661                 ppPathList = const_cast <char**>(filePathAppPrefix);
662                 break;
663
664         case FILEPATH_TYPE_MEDIA:
665                 pathCount = MAX_FILEPATH_MEDIA;
666                 ppPathList = const_cast <char**>(filePathMediaPrefix);
667                 break;
668
669         case FILEPATH_TYPE_SYSTEM:
670                 pathCount = MAX_FILEPATH_SYSTEM;
671                 ppPathList = const_cast <char**>(filePathSystemPrefix);
672                 break;
673
674         default:
675                 r = E_INVALID_ARG;
676                 goto CATCH;
677         }
678
679         absolutePath.GetCharAt(absolutePath.GetLength() - 1, ch);
680         if (ch != L'/') // if last char of absolutePath is not '/' then append it to make path parsing easier
681         {
682                 absolutePath.Append(L'/');
683         }
684
685         for (i = 0; i < pathCount; i++)
686         {
687                 tmpStr.Clear();
688                 tmpStr.Append(ppPathList[i]);
689
690                 if (absolutePath.IndexOf(tmpStr, 0, index) == E_SUCCESS)
691                 {
692                         if (index == 0)
693                         {
694                                 ch = L'\0';
695                                 if (absolutePath.GetCharAt(tmpStr.GetLength(), ch) == E_SUCCESS)
696                                 {
697                                         if (ch == L'/') // validate exact path. paths like /Home123/file.txt is not supported.
698                                         {
699                                                 candidateFound = true;
700                                                 break;
701                                         }
702                                 }
703                         }
704                 }
705         }
706
707         if (candidateFound == true)
708         {
709                 r = E_SUCCESS;
710         }
711         else
712         {
713                 r = E_INVALID_ARG;
714         }
715
716         // fall thru
717 CATCH:
718         SetLastResult(r);
719
720         if (r == E_SUCCESS)
721         {
722                 return true;
723         }
724
725         return false;
726 }
727
728 result
729 _FileUtil::ConvertToSecureFile(const String& plainFilePath, const String& secureFilePath, const ByteBuffer* pKey)
730 {
731         SysTryReturnResult(NID_IO, plainFilePath.GetLength() > 0 && plainFilePath.GetLength() <= PATH_MAX, E_INVALID_ARG,
732                            "Invalid argument was passed. Given file name length is not correct!");
733         SysTryReturnResult(NID_IO, plainFilePath.EndsWith(L"/") == false, E_INVALID_ARG,
734                            "Invalid argument was passed. Given file name is not correct! - ends with '/'");
735
736         SysTryReturnResult(NID_IO, secureFilePath.GetLength() > 0 && secureFilePath.GetLength() <= PATH_MAX, E_INVALID_ARG,
737                            "Invalid argument was passed. Given file name length is not correct!");
738         SysTryReturnResult(NID_IO, secureFilePath.EndsWith(L"/") == false, E_INVALID_ARG,
739                            "Invalid argument was passed. Given file name is not correct! - ends with '/'");
740
741         int     fileSize = 0;
742         int     readSize = 0;
743         int lastBlockSize = 0;
744         int bufferSize = 0;
745         int blockCount = 0;
746         int count = 0;
747         unique_ptr<byte[]> pBuffer(null);
748         result  r = E_SUCCESS;
749
750         if (File::IsFileExist(secureFilePath))
751         {
752                 r = GetLastResult();
753                 if (!IsFailed(r))
754                 {
755                         r = E_FILE_ALREADY_EXIST;
756                         SysLog(NID_IO, "[E_FILE_ALREADY_EXIST] The secure file already exist.");
757                 }
758                 else
759                 {
760                         SysLog(NID_IO, "[%s] Propagated.", GetErrorMessage(r));
761                 }
762                 return r;
763         }
764
765         unique_ptr<File> pFile(new (std::nothrow) File());
766         SysTryReturnResult(NID_IO, pFile != null, E_OUT_OF_MEMORY, "Unable to create Io::File");
767
768         r = pFile->Construct(plainFilePath, L"r", false);
769         if (IsFailed(r))
770         {
771                 if (r == E_MAX_EXCEEDED)
772                 {
773                         r = E_IO;
774                 }
775                 SysLog(NID_IO, "[%s] Propagated.", GetErrorMessage(r));
776                 return r;
777         }
778
779         r = pFile->Seek(FILESEEKPOSITION_END, 0);
780         SysTryReturn(NID_IO, r == E_SUCCESS , r, r, "[%s] Propagated", GetErrorMessage(r));
781
782         fileSize = pFile->Tell();
783
784         r = pFile->Seek(FILESEEKPOSITION_BEGIN, 0);
785         SysTryReturn(NID_IO, r == E_SUCCESS , r, r, "[%s] Propagated", GetErrorMessage(r));
786
787         unique_ptr<File> pSecureFile(new (std::nothrow) File());
788         SysTryReturnResult(NID_IO, pSecureFile != null, E_OUT_OF_MEMORY,
789                         "Unable to create Io::File");
790
791         r = pSecureFile->Construct(secureFilePath, "w", *pKey);
792         SysTryReturn(NID_IO, r == E_SUCCESS , r, r, "[%s] Propagated", GetErrorMessage(r));
793
794         if (fileSize == 0)
795         {
796                 return r;
797         }
798
799         lastBlockSize = fileSize % CIPHER_BLOCK_SIZE;
800         if (lastBlockSize == 0)
801         {
802                 blockCount = fileSize / CIPHER_BLOCK_SIZE;
803                 lastBlockSize = CIPHER_BLOCK_SIZE;
804         }
805         else
806         {
807                 blockCount = fileSize / CIPHER_BLOCK_SIZE + 1;
808         }
809
810         for(count = 0; count < blockCount; count++)
811         {
812                 if (pBuffer != null)
813                 {
814                         memset(pBuffer.get(), 0, CIPHER_BLOCK_SIZE);
815                 }
816
817                 if ((count + 1) == blockCount && pBuffer == null)
818                 {
819                         pBuffer.reset(new (std::nothrow) byte[lastBlockSize]);
820                         SysTryReturnResult(NID_IO, pBuffer != null, E_OUT_OF_MEMORY, "The memory is insufficient.");
821                         memset(pBuffer.get(), 0, lastBlockSize);
822                         bufferSize = lastBlockSize;
823                 }
824
825                 else if ((count + 1) != blockCount && pBuffer == null)
826                 {
827                         pBuffer.reset(new (std::nothrow) byte[CIPHER_BLOCK_SIZE]);
828                         SysTryReturnResult(NID_IO, pBuffer != null, E_OUT_OF_MEMORY, "The memory is insufficient.");
829                         memset(pBuffer.get(), 0, CIPHER_BLOCK_SIZE);
830                         bufferSize = CIPHER_BLOCK_SIZE;
831                 }
832
833                 readSize = pFile->Read(pBuffer.get(), bufferSize);
834                 r = GetLastResult();
835                 if (IsFailed(r))
836                 {
837                         if (r == E_END_OF_FILE)
838                         {
839                                 r = E_IO;
840                         }
841                         SysLog(NID_IO, "[%s] Propagated.", GetErrorMessage(r));
842                         return r;
843                 }
844
845                 r = pSecureFile->Write(pBuffer.get(), readSize);
846                 SysTryReturn(NID_IO, r == E_SUCCESS , r, r, "[%s] Propagated", GetErrorMessage(r));
847         }
848
849         return E_SUCCESS;
850 }
851
852 }} // Tizen::Io
853