Merge "Support path beginning without / for OSP compatible application" 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                 SysSecureLogException(NID_IO, E_FILE_NOT_FOUND, "[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         char* pCopyBuf = null;
221         result r = E_SUCCESS;
222
223         unique_ptr<char[]> pSrcpath(_StringConverter::CopyToCharArrayN(srcFilePath));
224         SysTryReturn(NID_IO, pSrcpath != null, GetLastResult(), GetLastResult(),
225                            "[%s] Invalid source file path.", GetErrorMessage(GetLastResult()));
226
227         unique_ptr<char[]> pDstpath(_StringConverter::CopyToCharArrayN(destFilePath));
228         SysTryReturn(NID_IO, pDstpath != null, GetLastResult(), GetLastResult(),
229                            "[%s] Invalid destination file path.", GetErrorMessage(GetLastResult()));
230
231         SysTryReturnResult(NID_IO, _FileUtil::IsFileExist(srcFilePath) == true, E_FILE_NOT_FOUND,
232                            "Source file(%s) does not exist.", pSrcpath.get());
233
234         if ((_FileUtil::IsFileExist(destFilePath) == true) && (failIfExist == true))
235         {
236                 r = E_FILE_ALREADY_EXIST;
237                 SysLog(NID_IO, "[E_FILE_ALREADY_EXIST] Destination file already exists.");
238                 return r;
239         }
240
241         srcFd = open64(pSrcpath.get(), O_RDONLY);
242         if (srcFd == -1)
243         {
244                 r = __ConvertNativeErrorToResult(errno);
245                 SysLogException(NID_IO, r, "[%s] Failed to open file (%s).", GetErrorMessage(r), pSrcpath.get());
246                 return r;
247         }
248         dstFd = open64(pDstpath.get(), O_WRONLY | O_CREAT | O_TRUNC, 0644);
249         if (dstFd == -1)
250         {
251                 r = __ConvertNativeErrorToResult(errno);
252                 SysLogException(NID_IO, r, "[%s] Failed to open file (%s), errno: %d (%s)",
253                                    GetErrorMessage(r), pDstpath.get(), errno, strerror(errno));
254                 goto CATCH;
255         }
256
257         pBuffer = new (std::nothrow) char[_MAX_COPY_BYTES];
258         SysTryCatch(NID_IO, pBuffer != null, r = E_OUT_OF_MEMORY, E_OUT_OF_MEMORY, "[E_OUT_OF_MEMORY] The memory is insufficient.");
259
260         pCopyBuf = pBuffer;
261         do
262         {
263                 do
264                 {
265                         readBytes = read(srcFd, pCopyBuf, _MAX_COPY_BYTES);
266                 }
267                 while (readBytes < 0 && errno == EINTR);
268                 if (readBytes < 0)
269                 {
270                         r = __ConvertNativeErrorToResult(errno);
271                         SysLogException(NID_IO, r, "[%s] Failed to read from source file (%s), errno: %d (%s)",
272                                         GetErrorMessage(r), pSrcpath.get(), errno, strerror(errno));
273                         goto CATCH;
274                 }
275                 else if (readBytes == 0)
276                 {
277                         break;
278                 }
279                 remainingBytes = readBytes;
280 RETRY:
281                 do
282                 {
283                         writtenBytes = write(dstFd, pCopyBuf, remainingBytes);
284                 }
285                 while (writtenBytes < 0 && errno == EINTR);
286                 if (writtenBytes < 0)
287                 {
288                         r = __ConvertNativeErrorToResult(errno);
289                         SysLogException(NID_IO, r, "[%s] Failed to write to destination file (%s), errno: %d (%s)",
290                                         GetErrorMessage(r), pDstpath.get(), errno, strerror(errno));
291                         goto CATCH;
292                 }
293                 else if (writtenBytes < remainingBytes)
294                 {
295                         remainingBytes = remainingBytes - writtenBytes;
296                         pCopyBuf = const_cast< char* >(pCopyBuf) + writtenBytes;
297                         goto RETRY;
298                 }
299         }
300         while (readBytes);
301
302         // fall through
303 CATCH:
304         if (srcFd != -1)
305         {
306                 close(srcFd);
307         }
308         if (dstFd != -1)
309         {
310                 fsync(dstFd);
311                 close(dstFd);
312         }
313         delete[] pBuffer;
314
315         return r;
316 }
317
318 result
319 _FileUtil::GetAttributes(const String& filePath, FileAttributes& attribute)
320 {
321         DateTime dateTime;
322         DateTime modifiedTime;
323         off64_t fileSize = 0;
324         unsigned long attr = 0;
325         result r = E_SUCCESS;
326         struct tm* pTm = null;
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 (int ret = stat64(pFilePath.get(), &statbuf) == -1)
336         {
337                 r = __ConvertNativeErrorToResult(errno);
338                 SysLogException(NID_IO, r, "[%s] Failed to get file (%s) status.", GetErrorMessage(r), pFilePath.get());
339                 return r;
340         }
341
342         // size
343         fileSize = statbuf.st_size;
344
345         // attributes
346         attr = statbuf.st_mode;
347
348         pTm = localtime(&statbuf.st_mtime);
349         SysTryReturnResult(NID_IO, pTm != null, E_SYSTEM, "Failed to call localtime() (%s).", strerror(errno));
350         r = dateTime.SetValue(_BASE_YEAR + pTm->tm_year, 1 + pTm->tm_mon, pTm->tm_mday, pTm->tm_hour, pTm->tm_min, pTm->tm_sec);
351         SysTryReturn(NID_IO, (!IsFailed(r)), r, r, "[%s] Failed to set DateTime.", GetErrorMessage(r));
352
353         pTm = localtime(&statbuf.st_mtime);
354         SysTryReturnResult(NID_IO, pTm != null, E_SYSTEM, "Failed to call localtime() (%s).", strerror(errno));
355         r = modifiedTime.SetValue(_BASE_YEAR + pTm->tm_year, 1 + pTm->tm_mon, pTm->tm_mday, pTm->tm_hour, pTm->tm_min, pTm->tm_sec);
356         SysTryReturn(NID_IO, (!IsFailed(r)), r, r, "[%s] Failed to set DateTime.", GetErrorMessage(r));
357
358         fileName = _FileUtil::GetFileName(filePath);
359         if (fileName.StartsWith(L".", 0)) // including . and ..
360         {
361                 hidden = true;
362         }
363
364         _FileAttributesImpl::GetInstance(attribute)->Set(dateTime, modifiedTime, fileSize, attr, hidden);
365
366         return E_SUCCESS;
367 }
368
369 String
370 _FileUtil::GetFileName(const String& filePath)
371 {
372         String fileName;
373         int pos = -1;
374
375         result r = filePath.LastIndexOf(L'/', filePath.GetLength() - 1, pos);
376         SysTryReturn(NID_IO, r == E_SUCCESS || r == E_OBJ_NOT_FOUND, fileName, E_INVALID_ARG,
377                         "[E_INVALID_ARG] The file path is invalid.");
378
379         r = filePath.SubString(pos + 1, fileName);
380         SysTryReturn(NID_IO, !IsFailed(r), fileName, E_INVALID_ARG, "[E_INVALID_ARG] The file path is invalid.");
381         SysTryReturn(NID_IO, fileName.GetLength() > 0 && fileName.GetLength() <= NAME_MAX, fileName, E_INVALID_ARG,
382                         "[E_INVALID_ARG] The length of file name is zero or exceeds system limitations.");
383
384         SetLastResult(E_SUCCESS);
385         return fileName;
386 }
387
388 String
389 _FileUtil::GetFileExtension(const String& filePath)
390 {
391         String extName;
392         int pos = -1;
393
394         result r = filePath.LastIndexOf(L'/', filePath.GetLength() - 1, pos);
395         SysTryReturn(NID_IO, r == E_SUCCESS || r == E_OBJ_NOT_FOUND, extName, E_INVALID_ARG,
396                         "[E_INVALID_ARG] The file path is invalid.");
397
398         String fileName;
399         r = filePath.SubString(pos + 1, fileName);
400         SysTryReturn(NID_IO, !IsFailed(r), extName, E_INVALID_ARG, "[E_INVALID_ARG] The file path is invalid.");
401         SysTryReturn(NID_IO, fileName.GetLength() > 0 && fileName.GetLength() <= NAME_MAX, extName, E_INVALID_ARG,
402                         "[E_INVALID_ARG] The length of file name is zero or exceeds system limitations.");
403
404         r = fileName.LastIndexOf(L'.', fileName.GetLength() - 1, pos);
405         SysTryReturn(NID_IO, !IsFailed(r), extName, E_INVALID_ARG, "[E_INVALID_ARG] The file path is invalid.");
406
407         r = fileName.SubString(pos + 1, extName);
408         SysTryReturn(NID_IO, !IsFailed(r), extName, E_INVALID_ARG, "[E_INVALID_ARG] The file path is invalid.");
409
410         SetLastResult(E_SUCCESS);
411         return extName;
412 }
413
414 bool
415 _FileUtil::IsFileExist(const String& filePath)
416 {
417         int ret = 0;
418         result r = E_SUCCESS;
419
420         unique_ptr<char[]> pFilePath(_StringConverter::CopyToCharArrayN(filePath));
421         SysTryReturn(NID_IO, (pFilePath != null), false, GetLastResult(), ("[%s] Invalid file path."),
422                            GetErrorMessage(GetLastResult()));
423
424         ret = access(pFilePath.get(), F_OK);
425         if (ret != 0)
426         {
427                 switch (errno)
428                 {
429                 case ENAMETOOLONG:
430                         r = E_INVALID_ARG;
431                         break;
432                 case ENOENT:
433                         r = E_SUCCESS;
434                         break;
435                 default:
436                         r = __ConvertNativeErrorToResult(errno);
437                         break;
438                 }
439         }
440
441         SetLastResult(r);
442         return (ret == 0) ? true : false;
443 }
444
445 #if 0
446 bool
447 _FileUtil::IsEncrypted(const String& filePath)
448 {
449         result  r = E_SUCCESS;
450         // TODO: int    pathKind;
451         int     readItems = 0;
452         int     fileLength = 0;
453         bool    encrypted = false;
454         // TODO: bool   checkPrivilege = false;
455         byte    secureHeader[SECURE_FILE_HEADER_SIZE_V1 + SECURE_IO_LOF_SIZE];
456         byte    reservedValue[SECURE_IO_STATIC_BIN_LEN] = {0xCA, 0xFE, 0xBE, 0xBE, 0xDA, 0xEF, 0xEB, 0xEB};
457         char    magicNum1[SECURE_IO_MAGIC_NUMBER_SIZE] = {0xCA, 0xFE, 0xBE, 0xBE};
458         char    magicNum2[SECURE_IO_MAGIC_NUMBER_SIZE] = {0xDA, 0xEF, 0xEF, 0xEB};
459         FILE*   pFile = null;
460
461         unique_ptr<char[]> pFilePath(_StringConverter::CopyToCharArrayN(filePath));
462         SysTryReturn(NID_IO, pFilePath != null, false, E_INVALID_ARG, "[E_INVALID_ARG] CopyToCharArrayN failed!");
463
464         fileLength = strlen(pFilePath.get());
465         SysTryReturn(NID_IO, fileLength > 0, false, E_INVALID_ARG, "[E_INVALID_ARG] CopyToCharArrayN failed!");
466
467         if (pFilePath[fileLength - 1] == ('/'))
468         {
469                 pFilePath[fileLength - 1] = ('\0'); // remove last '/' character if exists.
470         }
471
472 //      // TODO: check accessibility to path
473 //      r = CheckAccessibilityToPath(pFilePath, &pathKind, 0);
474 //      if(IsFailed(r))
475 //              goto CATCH;
476 //
477 //      if(pathKind == __PATH_KIND_AUTHORIZED_MMC)
478 //      {
479 //              __CheckPrivilege(PRV_INSTALLATION, checkPrivilege);
480 //              if(!checkPrivilege)
481 //              {
482 //                      r = E_ILLEGAL_ACCESS;
483 //                      goto CATCH;
484 //              }
485 //      }
486 //      else if(pathKind == __PATH_KIND_AUTHORIZED_LINK || pathKind == __PATH_KIND_AUTHORIZED_NPKI ||
487 //                      pathKind == __PATH_KIND_AUTHORIZED_PRELOADED_MEDIA)
488 //      {
489 //              __CheckPrivilege(PRV_PRIVILEGED_IO, checkPrivilege);
490 //              if(!checkPrivilege)
491 //              {
492 //                      r = E_ILLEGAL_ACCESS;
493 //                      goto CATCH;
494 //              }
495 //      }
496 //      else if (pathKind == __PATH_KIND_APP_DENY)
497 //      {
498 //              r = E_ILLEGAL_ACCESS;
499 //              goto CATCH;
500 //      }
501
502         pFile = fopen(pFilePath.get(), "r");
503         if (pFile == null)
504         {
505                 r = __ConvertNativeErrorToResult(errno);
506                 SysLog(NID_IO, "[%s] Failed to open file (%s) in openMode (%s), (errno: %d).", GetErrorMessage(r), pFilePath.get(), "r", errno);
507                 goto CATCH;
508         }
509
510         readItems = fread(secureHeader, 1, SECURE_FILE_HEADER_SIZE_V1 + SECURE_IO_LOF_SIZE, pFile);
511
512         if (readItems < (SECURE_FILE_HEADER_SIZE_V1 + SECURE_IO_LOF_SIZE))
513         {
514                 int eof = feof((FILE*)pFile);
515                 if (eof)
516                 {
517                         //No error;
518                         encrypted = false;
519                         goto CATCH;
520                 }
521
522                 r = __ConvertNativeErrorToResult(errno);
523                 SysLog(NID_IO, "[%s] Failed to open file (%s) in openMode (%s), (errno: %d).", GetErrorMessage(r), pFilePath.get(), "r", errno);
524                 goto CATCH;
525         }
526
527         if (memcmp(secureHeader, SECURE_FILE_HEADER_STRING, SECURE_FILE_HEADER_STRING_SIZE) == 0 && \
528                 memcmp(secureHeader + SECURE_FILE_HEADER_STRING_SIZE, reservedValue, SECURE_IO_STATIC_BIN_LEN) == 0)
529         {
530                 encrypted = true;
531         }
532         else if (memcmp(secureHeader, SECURE_REG_HEADER_STRING, SECURE_REG_HEADER_STRING_SIZE) == 0 && \
533                 memcmp(secureHeader + SECURE_REG_HEADER_STRING_SIZE, reservedValue, SECURE_IO_STATIC_BIN_LEN) == 0)
534         {
535                 encrypted = true;
536         }
537         else if ((memcmp(secureHeader, magicNum1, SECURE_IO_MAGIC_NUMBER_SIZE) == 0) &&
538                         (memcmp(secureHeader + SECURE_IO_STATIC_BIN_LEN, magicNum2, SECURE_IO_MAGIC_NUMBER_SIZE) == 0))
539
540         {
541                 encrypted = true;
542         }
543         else
544         {
545                 encrypted = false;
546         }
547
548         // fall thru
549 CATCH:
550
551         if (pFile)
552         {
553                 fclose(pFile);
554         }
555
556         SetLastResult(r);
557         return encrypted;
558 }
559 #endif
560
561 bool
562 _FileUtil::IsAppPath(const String& filePath)
563 {
564         result r = E_SUCCESS;
565
566         if (VerifyFilePath(filePath, FILEPATH_TYPE_APP))
567         {
568                 SetLastResult(E_SUCCESS);
569                 return true;
570         }
571         r = GetLastResult();
572
573         SetLastResult(r);
574         return false;
575 }
576
577 bool
578 _FileUtil::IsMediaPath(const String& filePath)
579 {
580         result r = E_SUCCESS;
581
582         if (VerifyFilePath(filePath, FILEPATH_TYPE_MEDIA))
583         {
584                 SetLastResult(E_SUCCESS);
585                 return true;
586         }
587         r = GetLastResult();
588
589         SetLastResult(r);
590         return false;
591 }
592
593 bool
594 _FileUtil::IsSystemPath(const String& filePath)
595 {
596         result r = E_SUCCESS;
597
598         if (VerifyFilePath(filePath, FILEPATH_TYPE_SYSTEM))
599         {
600                 SetLastResult(E_SUCCESS);
601                 return true;
602         }
603         r = GetLastResult();
604
605         SetLastResult(r);
606         return false;
607 }
608
609 bool
610 _FileUtil::VerifyFilePath(const String& filePath, _FilePathType pathType)
611 {
612         result r = E_SUCCESS;
613         String tmpStr("");
614         String absolutePath("");
615         int i = 0;
616         int index = 0;
617         int pathCount = 0;
618         char** ppPathList = null;
619         bool candidateFound = false;
620         wchar_t ch = L'\0';
621
622         //TODO Apply realpath after data caging.
623         //
624         //char resolved_path[1024];
625         //char* pFilePath = _StringConverter::CopyToCharArrayN(filePath);
626         //
627         //r = GetLastResult();
628         //
629         //SysTryCatch(NID_IO, pFilePath != null,
630         //        r, r, "[%s] Failed to get file path", GetErrorMessage(r));
631
632
633         //SysLog(NID_IO, "convert: %s", pFilePath);
634         //if (realpath(pFilePath, resolved_path) !=0)
635         //{
636         //      r = __ConvertNativeErrorToResult(errno);
637         //      SysLog(NID_IO, "convert Error!!! [%s] %s", resolved_path, GetErrorMessage(r));
638         //      delete[] pFilePath;
639         //      return false;
640         //      }
641         //
642         //SysLog(NID_IO, "convert result: %s", resolved_path);
643         //absolutePath.Append(resolved_path);
644         //delete[] pFilePath;
645
646         absolutePath.Append(filePath);
647         // This code does not handle paths without prefix '/' ex: "Home/myfile"
648         // since it depends on cwd.
649         switch (pathType)
650         {
651         case FILEPATH_TYPE_APP:
652                 pathCount = MAX_FILEPATH_APP;
653                 ppPathList = const_cast <char**>(filePathAppPrefix);
654                 break;
655
656         case FILEPATH_TYPE_MEDIA:
657                 pathCount = MAX_FILEPATH_MEDIA;
658                 ppPathList = const_cast <char**>(filePathMediaPrefix);
659                 break;
660
661         case FILEPATH_TYPE_SYSTEM:
662                 pathCount = MAX_FILEPATH_SYSTEM;
663                 ppPathList = const_cast <char**>(filePathSystemPrefix);
664                 break;
665
666         default:
667                 r = E_INVALID_ARG;
668                 goto CATCH;
669         }
670
671         absolutePath.GetCharAt(absolutePath.GetLength() - 1, ch);
672         if (ch != L'/') // if last char of absolutePath is not '/' then append it to make path parsing easier
673         {
674                 absolutePath.Append(L'/');
675         }
676
677         for (i = 0; i < pathCount; i++)
678         {
679                 tmpStr.Clear();
680                 tmpStr.Append(ppPathList[i]);
681
682                 if (absolutePath.IndexOf(tmpStr, 0, index) == E_SUCCESS)
683                 {
684                         if (index == 0)
685                         {
686                                 ch = L'\0';
687                                 if (absolutePath.GetCharAt(tmpStr.GetLength(), ch) == E_SUCCESS)
688                                 {
689                                         if (ch == L'/') // validate exact path. paths like /Home123/file.txt is not supported.
690                                         {
691                                                 candidateFound = true;
692                                                 break;
693                                         }
694                                 }
695                         }
696                 }
697         }
698
699         if (candidateFound == true)
700         {
701                 r = E_SUCCESS;
702         }
703         else
704         {
705                 r = E_INVALID_ARG;
706         }
707
708         // fall thru
709 CATCH:
710         SetLastResult(r);
711
712         if (r == E_SUCCESS)
713         {
714                 return true;
715         }
716
717         return false;
718 }
719
720 result
721 _FileUtil::ConvertToSecureFile(const String& plainFilePath, const String& secureFilePath, const ByteBuffer* pKey)
722 {
723         SysTryReturnResult(NID_IO, plainFilePath.GetLength() > 0 && plainFilePath.GetLength() <= PATH_MAX, E_INVALID_ARG,
724                            "Invalid argument was passed. Given file name length is not correct!");
725         SysTryReturnResult(NID_IO, plainFilePath.EndsWith(L"/") == false, E_INVALID_ARG,
726                            "Invalid argument was passed. Given file name is not correct! - ends with '/'");
727
728         SysTryReturnResult(NID_IO, secureFilePath.GetLength() > 0 && secureFilePath.GetLength() <= PATH_MAX, E_INVALID_ARG,
729                            "Invalid argument was passed. Given file name length is not correct!");
730         SysTryReturnResult(NID_IO, secureFilePath.EndsWith(L"/") == false, E_INVALID_ARG,
731                            "Invalid argument was passed. Given file name is not correct! - ends with '/'");
732
733         int     fileSize = 0;
734         int     readSize = 0;
735         int lastBlockSize = 0;
736         int bufferSize = 0;
737         int blockCount = 0;
738         int count = 0;
739         unique_ptr<byte[]> pBuffer(null);
740         result  r = E_SUCCESS;
741
742         if (File::IsFileExist(secureFilePath))
743         {
744                 r = GetLastResult();
745                 if (!IsFailed(r))
746                 {
747                         r = E_FILE_ALREADY_EXIST;
748                         SysLog(NID_IO, "[E_FILE_ALREADY_EXIST] The secure file already exist.");
749                 }
750                 else
751                 {
752                         SysLog(NID_IO, "[%s] Propagated.", GetErrorMessage(r));
753                 }
754                 return r;
755         }
756
757         unique_ptr<File> pFile(new (std::nothrow) File());
758         SysTryReturnResult(NID_IO, pFile != null, E_OUT_OF_MEMORY, "Unable to create Io::File");
759
760         r = pFile->Construct(plainFilePath, L"r", false);
761         if (IsFailed(r))
762         {
763                 if (r == E_MAX_EXCEEDED)
764                 {
765                         r = E_IO;
766                 }
767                 SysLog(NID_IO, "[%s] Propagated.", GetErrorMessage(r));
768                 return r;
769         }
770
771         r = pFile->Seek(FILESEEKPOSITION_END, 0);
772         SysTryReturn(NID_IO, r == E_SUCCESS , r, r, "[%s] Propagated", GetErrorMessage(r));
773
774         fileSize = pFile->Tell();
775
776         r = pFile->Seek(FILESEEKPOSITION_BEGIN, 0);
777         SysTryReturn(NID_IO, r == E_SUCCESS , r, r, "[%s] Propagated", GetErrorMessage(r));
778
779         unique_ptr<File> pSecureFile(new (std::nothrow) File());
780         SysTryReturnResult(NID_IO, pSecureFile != null, E_OUT_OF_MEMORY,
781                         "Unable to create Io::File");
782
783         r = pSecureFile->Construct(secureFilePath, "w", *pKey);
784         SysTryReturn(NID_IO, r == E_SUCCESS , r, r, "[%s] Propagated", GetErrorMessage(r));
785
786         if (fileSize == 0)
787         {
788                 return r;
789         }
790
791         lastBlockSize = fileSize % CIPHER_BLOCK_SIZE;
792         if (lastBlockSize == 0)
793         {
794                 blockCount = fileSize / CIPHER_BLOCK_SIZE;
795                 lastBlockSize = CIPHER_BLOCK_SIZE;
796         }
797         else
798         {
799                 blockCount = fileSize / CIPHER_BLOCK_SIZE + 1;
800         }
801
802         for(count = 0; count < blockCount; count++)
803         {
804                 if (pBuffer != null)
805                 {
806                         memset(pBuffer.get(), 0, CIPHER_BLOCK_SIZE);
807                 }
808
809                 if ((count + 1) == blockCount && pBuffer == null)
810                 {
811                         pBuffer.reset(new (std::nothrow) byte[lastBlockSize]);
812                         SysTryReturnResult(NID_IO, pBuffer != null, E_OUT_OF_MEMORY, "The memory is insufficient.");
813                         memset(pBuffer.get(), 0, lastBlockSize);
814                         bufferSize = lastBlockSize;
815                 }
816
817                 else if ((count + 1) != blockCount && pBuffer == null)
818                 {
819                         pBuffer.reset(new (std::nothrow) byte[CIPHER_BLOCK_SIZE]);
820                         SysTryReturnResult(NID_IO, pBuffer != null, E_OUT_OF_MEMORY, "The memory is insufficient.");
821                         memset(pBuffer.get(), 0, CIPHER_BLOCK_SIZE);
822                         bufferSize = CIPHER_BLOCK_SIZE;
823                 }
824
825                 readSize = pFile->Read(pBuffer.get(), bufferSize);
826                 r = GetLastResult();
827                 if (IsFailed(r))
828                 {
829                         if (r == E_END_OF_FILE)
830                         {
831                                 r = E_IO;
832                         }
833                         SysLog(NID_IO, "[%s] Propagated.", GetErrorMessage(r));
834                         return r;
835                 }
836
837                 r = pSecureFile->Write(pBuffer.get(), readSize);
838                 SysTryReturn(NID_IO, r == E_SUCCESS , r, r, "[%s] Propagated", GetErrorMessage(r));
839         }
840
841         return E_SUCCESS;
842 }
843
844 }} // Tizen::Io
845