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