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