2 // Copyright (c) 2012 Samsung Electronics Co., Ltd.
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
8 // http://www.apache.org/licenses/LICENSE-2.0
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.
18 * @file FIo_SecureFile.cpp
19 * @brief This is the implementation file for _SecureFile class.
26 #include <sys/types.h>
33 #include <unique_ptr.h>
34 #include <FBaseResult.h>
36 #include <FBase_StringConverter.h>
37 #include <FBase_NativeError.h>
38 #include <FBaseSysLog.h>
39 #include <FIo_FileImpl.h>
40 #include <FIo_NormalFile.h>
41 #include <FIo_SecureFile.h>
42 #include <FIo_SecureIoUtil.h>
45 using namespace Tizen::Base;
47 namespace Tizen { namespace Io
50 _SecureFile::_SecureFile(void)
52 , __virtualFilePointer(0)
57 _SecureFile::_SecureFile(bool read, bool write, bool truncate, bool append)
59 , __virtualFilePointer(0)
68 _SecureFile::~_SecureFile(void)
75 _SecureFile::Construct(const String& filePath, const char* pOpenMode, const ByteBuffer* pKeyBuffer)
77 SysAssertf(__pNormalFile == null, "Already constructed. Calling Construct() twice or more on a same instance is not allowed for this class\n");
81 SysTryReturnResult(NID_IO, !(pKeyBuffer && pKeyBuffer->GetRemaining() <= 0), E_INVALID_ARG,
82 "Invalid Key parameter");
84 unique_ptr< Tizen::Base::ByteBuffer > pKey(_SecureIoUtil::GetSecureKeyN(pKeyBuffer));
85 SysTryReturnResult(NID_IO, !(pKey == null || (pKey != null && pKey->GetRemaining() < ONE_BLOCK_SIZE)), E_INVALID_ARG, "Unable to generate key!");
87 unique_ptr< _NormalFile > pNormalFile(new (std::nothrow) _NormalFile());
88 SysTryReturnResult(NID_IO, pNormalFile != null, E_OUT_OF_MEMORY, "The memory is insufficient.");
92 unique_ptr< char[] > pMode(new char[strlen(pOpenMode) + 2]);
93 strcpy(pMode.get(), pOpenMode);
94 strcat(pMode.get(), "+\0");
95 r = pNormalFile->Construct(filePath, pMode.get());
99 r = pNormalFile->Construct(filePath, pOpenMode);
101 SysSecureTryReturn(NID_IO, !IsFailed(r), r, r, "[%s] Failed to open file (%ls) in openmode (%s).",
102 GetErrorMessage(r), filePath.GetPointer(), pOpenMode);
106 r = _SecureIoUtil::GetDataLengh(pNormalFile.get(), &__virtualFilePointer);
109 if (r == E_END_OF_FILE)
111 r = E_IO; //for security error
117 if (!(_SecureIoUtil::IsEmpty(filePath)))
119 Tizen::Io::_FlagState flag;
121 r = _SecureIoUtil::CheckFlag(pNormalFile.get(), &flag);
122 SysTryReturn(NID_IO, !IsFailed(r), r, r, "[%s] Failed to check flags in file header.", GetErrorMessage(r));
124 if (flag == FLAG_STATE_CVF_CTF)
126 r = _SecureIoUtil::DeleteBlockReplica(pNormalFile.get(), filePath);
127 SysTryReturn(NID_IO, !IsFailed(r), r, r, "[%s] Failed to delete block replica of file.", GetErrorMessage(r));
129 r = _SecureIoUtil::SetFlag(pNormalFile.get(), FLAG_STATE_CVF);
130 SysTryReturn(NID_IO, !IsFailed(r), r, r, "[%s] Failed to set flags in file header.", GetErrorMessage(r));
132 else if (flag == FLAG_STATE_CTF)
134 r = _SecureIoUtil::RestoreCorruptBlock(pNormalFile.get(), filePath);
135 SysTryReturnResult(NID_IO, !IsFailed(r), E_IO, "Failed to set flags in file header.");
137 r = _SecureIoUtil::DeleteBlockReplica(pNormalFile.get(), filePath);
138 SysTryReturn(NID_IO, !IsFailed(r), r, r, "[%s] Failed to delete block replica of file.", GetErrorMessage(r));
140 r = _SecureIoUtil::SetFlag(pNormalFile.get(), FLAG_STATE_CVF);
141 SysTryReturn(NID_IO, !IsFailed(r), r, r, "[%s] Failed to set flags in file header.", GetErrorMessage(r));
143 else if (flag == FLAG_STATE_CVF)
151 r = pNormalFile->Seek(FILESEEKPOSITION_BEGIN, SECURE_FILE_HEADER_STRING_SIZE + SECURE_IO_10_BYTES);
152 SysTryReturn(NID_IO, !IsFailed(r), r, r, "[%s] Failed to seek file (%ls) in openMode (%s).",
153 GetErrorMessage(r), filePath.GetPointer(), pOpenMode);
155 readItems = pNormalFile->Read(&dataLen, SECURE_IO_LOF_SIZE); // read LoF
156 if (readItems < SECURE_IO_LOF_SIZE)
158 if (_SecureIoUtil::IsEndOfFile(pNormalFile.get()) && readItems == 0)
164 r = __ConvertNativeErrorToResult(errno);
167 SysLog(NID_IO, "[%s] Failed to fread file (%ls) in openMode (%s), (errno: %d).",
168 GetErrorMessage(r), filePath.GetPointer(), pOpenMode, errno);
172 if (dataLen > SECURE_FILE_HEADER_SIZE_V1)
174 r = pNormalFile->Truncate(dataLen);
175 SysTryReturn(NID_IO, !IsFailed(r), r, r, "[%s] Failed to truncate file (%ls) in openMode (%ls).", GetErrorMessage(r));
177 r = pNormalFile->Flush();
178 SysTryReturn(NID_IO, !IsFailed(r), r, r, "[%s] Failed to flush data to file", GetErrorMessage(r));
180 r = _SecureIoUtil::SetFlag(pNormalFile.get(), FLAG_STATE_CVF);
181 SysTryReturn(NID_IO, !IsFailed(r), r, r, "[%s] Failed to set flags in file header.", GetErrorMessage(r));
185 r = pNormalFile->Truncate(0);
186 SysTryReturn(NID_IO, !IsFailed(r), r, r, "[%s] Failed to truncate file (%ls) in openMode (%s).",
187 GetErrorMessage(r), filePath.GetPointer(), pOpenMode);
189 r = pNormalFile->Flush();
190 SysTryReturn(NID_IO, !IsFailed(r), r, r, "[%s] Failed to flush data to file", GetErrorMessage(r));
196 __filePath = filePath;
197 __pNormalFile = pNormalFile.release();
198 __pKey = pKey.release();
204 _SecureFile::Read(ByteBuffer& buffer)
206 result r = E_SUCCESS;
208 int length = buffer.GetRemaining();
209 int curPos = buffer.GetPosition();
211 const byte* pTempBuffer = null;
214 SysAssertf(__pNormalFile != null, "Not yet constructed. Construct() should be called before use.\n");
216 SysTryReturnResult(NID_IO, length > 0, E_INVALID_ARG, "Invalid argument passed.");
217 SysAssert(curPos >= 0);
219 r = _SecureIoUtil::SelectCipherBlock(__pNormalFile, __virtualFilePointer, &dataPos);
222 if (r == E_STORAGE_FULL)
228 pTempBuffer = buffer.GetPointer();
229 r = _SecureIoUtil::ReadDataFromCipherBlock(__pNormalFile, dataPos, length, (const_cast< byte* >(pTempBuffer) + curPos), DATA_FORMAT_BYTE, &readBytes, *__pKey);
232 SysTryReturnResult(NID_IO, !(r == E_INVALID_OPERATION), E_ILLEGAL_ACCESS, "File is not opened for reading!");
233 SysLog(NID_IO, "[%s] Failed to read data from file", GetErrorMessage(r));
237 SysTryReturnResult(NID_IO, readBytes >= 0, E_IO, "Read bytes value is invalid");
239 r = buffer.SetPosition(curPos + readBytes);
240 SysAssert(!IsFailed(r));
241 __virtualFilePointer = __virtualFilePointer + readBytes;
247 _SecureFile::Read(void* pBuffer, int length)
249 SysAssertf(__pNormalFile != null, "Not yet constructed. Construct() should be called before use.\n");
250 SysTryReturn(NID_IO, !(pBuffer == null || length <= 0), 0, E_INVALID_ARG, "[E_INVALID_ARG] Invalid argument passed.");
254 result r = E_SUCCESS;
256 r = _SecureIoUtil::SelectCipherBlock(__pNormalFile, __virtualFilePointer, &dataPos);
259 if (r == E_STORAGE_FULL)
261 r = E_IO; //for security error
263 SysPropagate(NID_IO, r);
267 r = _SecureIoUtil::ReadDataFromCipherBlock(__pNormalFile, dataPos, length, reinterpret_cast< byte* >(pBuffer), DATA_FORMAT_BYTE, &readBytes, *__pKey);
270 SysTryReturn(NID_IO, !(r == E_INVALID_OPERATION), 0, E_ILLEGAL_ACCESS, "[E_ILLEGAL_ACCESS]File is not opended for reading!");
271 SysLog(NID_IO, "[%s] Failed to read data from file", GetErrorMessage(r));
272 SysPropagate(NID_IO, r);
276 SysTryReturn(NID_IO, readBytes >= 0, 0, E_IO, "[E_IO] Failed to read specified bytes from file.");
278 __virtualFilePointer = __virtualFilePointer + readBytes;
285 _SecureFile::Read(String& buffer)
287 result r = E_SUCCESS;
290 char bstrBuf[FIO_LEN_4K] = {0, };
293 SysAssertf(__pNormalFile != null, "Not yet constructed. Construct() should be called before use.\n");
297 r = _SecureIoUtil::SelectCipherBlock(__pNormalFile, __virtualFilePointer, &dataPos);
300 if (r == E_STORAGE_FULL)
302 r = E_IO; //for security error
307 r = _SecureIoUtil::ReadDataFromCipherBlock(__pNormalFile, dataPos, sizeof(bstrBuf), reinterpret_cast< byte* >(bstrBuf), DATA_FORMAT_STRING, &readItems, *__pKey);
310 SysTryReturnResult(NID_IO, !(r == E_INVALID_OPERATION), E_ILLEGAL_ACCESS, "File is not opened for reading!");
311 SysLog(NID_IO, "[%s] Failed to read data from file", GetErrorMessage(r));
314 SysAssert(readItems > 0);
315 __virtualFilePointer = __virtualFilePointer + readItems;
326 _SecureFile::Write(const ByteBuffer& buffer)
328 return Write(buffer.GetPointer(), buffer.GetLimit());
332 _SecureFile::Write(const void* pBuffer, int length)
334 result r = E_SUCCESS;
337 bool replica = false;
340 SysAssertf(__pNormalFile != null, "Not yet constructed. Construct() should be called before use.\n");
342 SysTryReturnResult(NID_IO, !(!pBuffer || length <= 0), E_INVALID_ARG, "Invalid argument passed.");
344 r = _SecureIoUtil::InsertSecureFileHeader(__pNormalFile);
345 SysTryReturn(NID_IO, !IsFailed(r), r, r, "[%s] Failed to write file headers.", GetErrorMessage(r));
347 r = _SecureIoUtil::SaveLengthOfFile(__pNormalFile);
348 SysTryReturn(NID_IO, !IsFailed(r), r, r, "[%s] Failed to set length in file header.", GetErrorMessage(r));
350 r = _SecureIoUtil::SelectCipherBlock(__pNormalFile, __virtualFilePointer, &dataPos);
353 if (r == E_END_OF_FILE)
355 r = E_IO; //for security error
362 eofSet = _SecureIoUtil::IsEndOfFile(__pNormalFile);
366 r = _SecureIoUtil::SetFlag(__pNormalFile, FLAG_STATE_NONE);
367 SysTryCatch(NID_IO, !IsFailed(r), , r, "[%s] Failed to set flags in file header.", GetErrorMessage(r));
373 r = _SecureIoUtil::MakeCipherBlockReplica(__pNormalFile, __filePath, dataPos, length);
374 SysTryCatch(NID_IO, !IsFailed(r), , r, "[%s] Failed to make cipher block replica of file.", GetErrorMessage(r));
376 r = _SecureIoUtil::SetFlag(__pNormalFile, FLAG_STATE_CTF);
377 SysTryCatch(NID_IO, !IsFailed(r), , r, "[%s] Failed to set flags in file header.", GetErrorMessage(r));
385 r = _SecureIoUtil::MakeCipherBlockReplica(__pNormalFile, __filePath, dataPos, length);
386 SysTryCatch(NID_IO, !IsFailed(r), , r, "[%s] Failed to make cipher block replica of file.", GetErrorMessage(r));
388 r = _SecureIoUtil::SetFlag(__pNormalFile, FLAG_STATE_CTF);
389 SysTryCatch(NID_IO, !IsFailed(r), , r, "[%s] Failed to set flags in file header.", GetErrorMessage(r));
394 r = _SecureIoUtil::WriteDataInCipherBlock(__pNormalFile, dataPos, eofSet, length, const_cast< byte* >(static_cast< const byte* >(pBuffer)), *__pKey);
397 if (r == E_END_OF_FILE)
399 r = E_IO; //for security error
406 r = _SecureIoUtil::SetFlag(__pNormalFile, FLAG_STATE_CVF_CTF);
407 SysTryCatch(NID_IO, !IsFailed(r), , r, "[%s] Failed to set flags in file header.", GetErrorMessage(r));
408 r = _SecureIoUtil::DeleteBlockReplica(__pNormalFile, __filePath);
409 SysTryCatch(NID_IO, !IsFailed(r), , r, "[%s] Failedt to delete block replica of file.", GetErrorMessage(r));
412 r = _SecureIoUtil::SetFlag(__pNormalFile, FLAG_STATE_CVF);
413 SysTryCatch(NID_IO, !IsFailed(r), , r, "[%s] Failed to set flags in file header.", GetErrorMessage(r));
415 __virtualFilePointer = __virtualFilePointer + length;
419 SysTryReturnResult(NID_IO, !(r == E_INVALID_OPERATION), E_ILLEGAL_ACCESS, "File is not opened for writing!");
425 _SecureFile::Write(const String& buffer)
427 unique_ptr< char[] > pData(_StringConverter::CopyToCharArrayN(buffer));
429 SysTryReturn(NID_IO, pData != null, GetLastResult(), GetLastResult(), "[%s] Propagated.", GetErrorMessage(GetLastResult()));
431 return Write(pData.get(), buffer.GetLength());
435 _SecureFile::Flush(void)
437 result r = E_SUCCESS;
440 SysAssertf(__pNormalFile != null, "Not yet constructed. Construct() should be called before use.\n");
441 r = __pNormalFile->Flush();
446 _SecureFile::Tell(void) const
448 SysAssertf(__pNormalFile != null, "Not yet constructed. Construct() should be called before use.\n");
451 result r = E_SUCCESS;
454 r = _SecureIoUtil::GetDataLengh(__pNormalFile, &dataLen);
457 if (r == E_ILLEGAL_ACCESS || r == E_STORAGE_FULL || r == E_END_OF_FILE)
459 r = E_IO; //for security error
464 SysTryCatch(NID_IO, (dataLen >= __virtualFilePointer), r = E_IO, E_IO, "[E_IO] Failed to tell in file.");
466 ret = __virtualFilePointer;
474 _SecureFile::Seek(FileSeekPosition position, long offset)
476 result r = E_SUCCESS;
478 long tempFilePointer = 0;
481 SysAssertf(__pNormalFile != null, "Not yet constructed. Construct() should be called before use.\n");
483 r = _SecureIoUtil::GetDataLengh(__pNormalFile, &fileEndPos);
486 if (r == E_ILLEGAL_ACCESS || r == E_END_OF_FILE)
488 r = E_IO; //for security error
495 case FILESEEKPOSITION_BEGIN:
499 case FILESEEKPOSITION_CURRENT:
500 tempFilePointer = __virtualFilePointer;
503 case FILESEEKPOSITION_END:
504 tempFilePointer = fileEndPos;
512 if (tempFilePointer + offset > fileEndPos)
514 //In Linux , Seek () will set file position beyond end of file also even if file is opened in READONLY.
517 return E_ILLEGAL_ACCESS;
521 unique_ptr< byte[] > pTempBuffer(new (std::nothrow) byte[tempFilePointer + offset - fileEndPos]);
522 SysTryReturnResult(NID_IO, pTempBuffer != null, E_OUT_OF_MEMORY, "The memory is insufficient.");
524 memset(pTempBuffer.get(), 0, tempFilePointer + offset - fileEndPos);
525 __virtualFilePointer = fileEndPos;
527 r = this->Write(pTempBuffer.get(), tempFilePointer + offset - fileEndPos);
529 SysTryReturn(NID_IO, !IsFailed(r), r, r, "[%s] Failed to write data in to the file.", GetErrorMessage(r));
533 else if (tempFilePointer + offset == fileEndPos)
535 __virtualFilePointer = fileEndPos;
537 else if (tempFilePointer + offset < 0)
539 return E_INVALID_ARG;
541 else if (tempFilePointer + offset == 0)
543 __virtualFilePointer = 0;
547 __virtualFilePointer = tempFilePointer + offset;
554 _SecureFile::Truncate(int length)
556 result r = E_SUCCESS;
562 SysAssertf(__pNormalFile != null, "Not yet constructed. Construct() should be called before use.\n");
563 SysTryReturnResult(NID_IO, length >= 0, E_INVALID_ARG, "Invalid argument is passed (length < 0)");
567 r = __pNormalFile->Truncate(length);
570 SysLog(NID_IO, "[%s] Failed to truncate data to file", GetErrorMessage(r));
572 __virtualFilePointer = 0;
577 r = _SecureIoUtil::GetDataLengh(__pNormalFile, &fileEndPos);
580 if (r == E_END_OF_FILE)
582 r = E_IO; //for security error
587 if (length >= fileEndPos)
589 if (length == fileEndPos)
591 this->Seek(FILESEEKPOSITION_END, 0);
596 unique_ptr< byte[] > pTempBuffer(new (std::nothrow) byte[length - fileEndPos]);
597 SysTryCatch(NID_IO, pTempBuffer != null, r = E_OUT_OF_MEMORY, E_OUT_OF_MEMORY, "[E_OUT_OF_MEMORY] The memory is insufficient.");
600 memset(pTempBuffer.get(), 0, length - fileEndPos);
601 r = this->Seek(FILESEEKPOSITION_END, 0);
602 SysTryCatch(NID_IO, !IsFailed(r), , r, "[%s] Failed to seek in file.", GetErrorMessage(r));
604 r = this->Write(pTempBuffer.get(), length - fileEndPos);
605 SysTryCatch(NID_IO, !IsFailed(r), , r, "[%s] Failed to write data in file.", GetErrorMessage(r));
610 unique_ptr< byte[] > pTempBuffer(null);
612 __virtualFilePointer = length;
613 r = _SecureIoUtil::SelectCipherBlock(__pNormalFile, __virtualFilePointer, &dataPos);
616 if (r == E_END_OF_FILE)
618 r = E_IO; //for security error
625 pTempBuffer = unique_ptr< byte[] >(new (std::nothrow) byte[dataPos]);
626 SysTryCatch(NID_IO, pTempBuffer, r = E_OUT_OF_MEMORY, E_OUT_OF_MEMORY, "[E_OUT_OF_MEMORY] The memory is insufficient.");
628 r = _SecureIoUtil::ReadDataFromCipherBlock(__pNormalFile, 0, dataPos, pTempBuffer.get(), DATA_FORMAT_BYTE, &readItems, *__pKey);
631 if (r == E_END_OF_FILE)
633 r = E_IO; //for security error
638 SysAssert(readItems == dataPos);
639 r = _SecureIoUtil::SelectCipherBlock(__pNormalFile, __virtualFilePointer, &dataPos);
642 if (r == E_END_OF_FILE)
644 r = E_IO; //for security error
650 length = __pNormalFile->Tell();
651 SysTryCatch(NID_IO, length != -1, r = __ConvertNativeErrorToResult(errno), r, "[%s] Failed to tell in file", GetErrorMessage(r));
653 r = __pNormalFile->Truncate(length);
654 SysTryCatch(NID_IO, !IsFailed(r), , r, "[%s] Failed to truncate data to file", GetErrorMessage(r));
657 r = __pNormalFile->Flush();
658 SysTryCatch(NID_IO, !IsFailed(r), , r, "[%s] Failed to flush data to file", GetErrorMessage(r));
661 r = _SecureIoUtil::GetDataLengh(__pNormalFile, &__virtualFilePointer);
664 if (r == E_END_OF_FILE)
666 r = E_IO; //for security error
671 if (pTempBuffer != null)
673 r = this->Write(static_cast< void* >(pTempBuffer.get()), dataPos);
674 SysTryCatch(NID_IO, !IsFailed(r), , r, "[%s] Failed to write data in file.", GetErrorMessage(r));
677 r = _SecureIoUtil::GetDataLengh(__pNormalFile, &__virtualFilePointer);
680 if (r == E_END_OF_FILE)
682 r = E_IO; //for security error
689 __pNormalFile->Flush();
694 _SecureFile::GetName(void)
696 SysAssertf(__pNormalFile != null, "Not yet constructed. Construct() should be called before use.\n");
698 SetLastResult(E_SUCCESS); // for OSP 2.0 compatibility