Remove compilation warning
[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 (stat64(pFilePath.get(), &statbuf) == -1)
335         {
336                 r = __ConvertNativeErrorToResult(errno);
337                 SysSecureLogException(NID_IO, r, "[%s] Failed to get file (%s) status. errno: %d (%s)",
338                                 GetErrorMessage(r), pFilePath.get(), errno, strerror(errno));
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