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