2 // Open Service Platform
3 // Copyright (c) 2012 Samsung Electronics Co., Ltd.
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
9 // http://www.apache.org/licenses/LICENSE-2.0
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.
19 * @file FIo_SecureFile.cpp
20 * @brief This is the implementation file for _SecureFile class.
27 #include <sys/types.h>
34 #include <unique_ptr.h>
35 #include <FBaseResult.h>
37 #include <FBase_StringConverter.h>
38 #include <FBase_NativeError.h>
39 #include <FBaseSysLog.h>
40 #include <FIo_FileImpl.h>
41 #include <FIo_NormalFile.h>
42 #include <FIo_SecureFile.h>
43 #include <FIo_SecureIoUtil.h>
46 using namespace Tizen::Base;
48 namespace Tizen { namespace Io
51 _SecureFile::_SecureFile(void)
53 , __virtualFilePointer(0)
58 _SecureFile::_SecureFile(bool read, bool write, bool truncate, bool append)
60 , __virtualFilePointer(0)
69 _SecureFile::~_SecureFile(void)
76 _SecureFile::Construct(const String& filePath, const char* pOpenMode, const ByteBuffer* pKeyBuffer)
78 SysAssertf(__pNormalFile == null, "Already constructed. Calling Construct() twice or more on a same instance is not allowed for this class\n");
82 SysTryReturnResult(NID_IO, !(pKeyBuffer && pKeyBuffer->GetRemaining() <= 0), E_INVALID_ARG,
83 "Invalid Key parameter");
85 unique_ptr< Tizen::Base::ByteBuffer > pKey(_SecureIoUtil::GetSecureKeyN(pKeyBuffer));
86 SysTryReturnResult(NID_IO, !(pKey == null || (pKey != null && pKey->GetRemaining() < ONE_BLOCK_SIZE)), E_INVALID_ARG, "Unable to generate key!");
88 unique_ptr< _NormalFile > pNormalFile(new (std::nothrow) _NormalFile());
89 SysTryReturnResult(NID_IO, pNormalFile != null, E_OUT_OF_MEMORY, "The memory is insufficient.");
93 unique_ptr< char[] > pMode(new char[strlen(pOpenMode) + 2]);
94 strcpy(pMode.get(), pOpenMode);
95 strcat(pMode.get(), "+\0");
96 r = pNormalFile->Construct(filePath, pMode.get());
100 r = pNormalFile->Construct(filePath, pOpenMode);
102 SysTryReturn(NID_IO, !IsFailed(r), r, r, "[%s] Failed to open file (%ls) in openmode (%s).",
103 GetErrorMessage(r), filePath.GetPointer(), pOpenMode);
107 r = _SecureIoUtil::GetDataLengh(pNormalFile.get(), &__virtualFilePointer);
110 if (r == E_END_OF_FILE)
112 r = E_IO; //for security error
118 if (!(_SecureIoUtil::IsEmpty(filePath)))
120 Tizen::Io::_FlagState flag;
122 r = _SecureIoUtil::CheckFlag(pNormalFile.get(), &flag);
123 SysTryReturn(NID_IO, !IsFailed(r), r, r, "[%s] Failed to check flags in file header.", GetErrorMessage(r));
125 if (flag == FLAG_STATE_CVF_CTF)
127 r = _SecureIoUtil::DeleteBlockReplica(pNormalFile.get(), filePath);
128 SysTryReturn(NID_IO, !IsFailed(r), r, r, "[%s] Failed to delete block replica of file.", GetErrorMessage(r));
130 r = _SecureIoUtil::SetFlag(pNormalFile.get(), FLAG_STATE_CVF);
131 SysTryReturn(NID_IO, !IsFailed(r), r, r, "[%s] Failed to set flags in file header.", GetErrorMessage(r));
133 else if (flag == FLAG_STATE_CTF)
135 r = _SecureIoUtil::RestoreCorruptBlock(pNormalFile.get(), filePath);
136 SysTryReturnResult(NID_IO, !IsFailed(r), E_IO, "Failed to set flags in file header.");
138 r = _SecureIoUtil::DeleteBlockReplica(pNormalFile.get(), filePath);
139 SysTryReturn(NID_IO, !IsFailed(r), r, r, "[%s] Failed to delete block replica of file.", GetErrorMessage(r));
141 r = _SecureIoUtil::SetFlag(pNormalFile.get(), FLAG_STATE_CVF);
142 SysTryReturn(NID_IO, !IsFailed(r), r, r, "[%s] Failed to set flags in file header.", GetErrorMessage(r));
144 else if (flag == FLAG_STATE_CVF)
152 r = pNormalFile->Seek(FILESEEKPOSITION_BEGIN, SECURE_FILE_HEADER_STRING_SIZE + SECURE_IO_10_BYTES);
153 SysTryReturn(NID_IO, !IsFailed(r), r, r, "[%s] Failed to seek file (%ls) in openMode (%s).",
154 GetErrorMessage(r), filePath.GetPointer(), pOpenMode);
156 readItems = pNormalFile->Read(&dataLen, SECURE_IO_LOF_SIZE); // read LoF
157 if (readItems < SECURE_IO_LOF_SIZE)
159 if (_SecureIoUtil::IsEndOfFile(pNormalFile.get()) && readItems == 0)
165 r = __ConvertNativeErrorToResult(errno);
168 SysLog(NID_IO, "[%s] Failed to fread file (%ls) in openMode (%s), (errno: %d).",
169 GetErrorMessage(r), filePath.GetPointer(), pOpenMode, errno);
173 if (dataLen > SECURE_FILE_HEADER_SIZE_V1)
175 r = pNormalFile->Truncate(dataLen);
176 SysTryReturn(NID_IO, !IsFailed(r), r, r, "[%s] Failed to truncate file (%ls) in openMode (%ls).", GetErrorMessage(r));
178 r = pNormalFile->Flush();
179 SysTryReturn(NID_IO, !IsFailed(r), r, r, "[%s] Failed to flush data to file", GetErrorMessage(r));
181 r = _SecureIoUtil::SetFlag(pNormalFile.get(), FLAG_STATE_CVF);
182 SysTryReturn(NID_IO, !IsFailed(r), r, r, "[%s] Failed to set flags in file header.", GetErrorMessage(r));
186 r = pNormalFile->Truncate(0);
187 SysTryReturn(NID_IO, !IsFailed(r), r, r, "[%s] Failed to truncate file (%ls) in openMode (%s).",
188 GetErrorMessage(r), filePath.GetPointer(), pOpenMode);
190 r = pNormalFile->Flush();
191 SysTryReturn(NID_IO, !IsFailed(r), r, r, "[%s] Failed to flush data to file", GetErrorMessage(r));
197 __filePath = filePath;
198 __pNormalFile = pNormalFile.release();
199 __pKey = pKey.release();
205 _SecureFile::Read(ByteBuffer& buffer)
207 result r = E_SUCCESS;
209 int length = buffer.GetRemaining();
210 int curPos = buffer.GetPosition();
212 const byte* pTempBuffer = null;
215 SysAssertf(__pNormalFile != null, "Not yet constructed. Construct() should be called before use.\n");
217 SysTryReturnResult(NID_IO, length > 0, E_INVALID_ARG, "Invalid argument passed.");
218 SysAssert(curPos >= 0);
220 r = _SecureIoUtil::SelectCipherBlock(__pNormalFile, __virtualFilePointer, &dataPos);
223 if (r == E_STORAGE_FULL)
229 pTempBuffer = buffer.GetPointer();
230 r = _SecureIoUtil::ReadDataFromCipherBlock(__pNormalFile, dataPos, length, (const_cast< byte* >(pTempBuffer) + curPos), DATA_FORMAT_BYTE, &readBytes, *__pKey);
233 SysTryReturnResult(NID_IO, !(r == E_INVALID_OPERATION), E_ILLEGAL_ACCESS, "File is not opened for reading!");
234 SysLog(NID_IO, "[%s] Failed to read data from file", GetErrorMessage(r));
238 SysTryReturnResult(NID_IO, readBytes >= 0, E_IO, "Read bytes value is invalid");
240 r = buffer.SetPosition(curPos + readBytes);
241 SysAssert(!IsFailed(r));
242 __virtualFilePointer = __virtualFilePointer + readBytes;
248 _SecureFile::Read(void* pBuffer, int length)
250 SysAssertf(__pNormalFile != null, "Not yet constructed. Construct() should be called before use.\n");
251 SysTryReturn(NID_IO, !(pBuffer == null || length <= 0), 0, E_INVALID_ARG, "[E_INVALID_ARG] Invalid argument passed.");
255 result r = E_SUCCESS;
257 r = _SecureIoUtil::SelectCipherBlock(__pNormalFile, __virtualFilePointer, &dataPos);
260 if (r == E_STORAGE_FULL)
262 r = E_IO; //for security error
264 SysPropagate(NID_IO, r);
268 r = _SecureIoUtil::ReadDataFromCipherBlock(__pNormalFile, dataPos, length, reinterpret_cast< byte* >(pBuffer), DATA_FORMAT_BYTE, &readBytes, *__pKey);
271 SysTryReturn(NID_IO, !(r == E_INVALID_OPERATION), 0, E_ILLEGAL_ACCESS, "[E_ILLEGAL_ACCESS]File is not opended for reading!");
272 SysLog(NID_IO, "[%s] Failed to read data from file", GetErrorMessage(r));
273 SysPropagate(NID_IO, r);
277 SysTryReturn(NID_IO, readBytes >= 0, 0, E_IO, "[E_IO] Failed to read specified bytes from file.");
279 __virtualFilePointer = __virtualFilePointer + readBytes;
286 _SecureFile::Read(String& buffer)
288 result r = E_SUCCESS;
291 char bstrBuf[FIO_LEN_4K] = {0, };
294 SysAssertf(__pNormalFile != null, "Not yet constructed. Construct() should be called before use.\n");
298 r = _SecureIoUtil::SelectCipherBlock(__pNormalFile, __virtualFilePointer, &dataPos);
301 if (r == E_STORAGE_FULL)
303 r = E_IO; //for security error
308 r = _SecureIoUtil::ReadDataFromCipherBlock(__pNormalFile, dataPos, sizeof(bstrBuf), reinterpret_cast< byte* >(bstrBuf), DATA_FORMAT_STRING, &readItems, *__pKey);
311 SysTryReturnResult(NID_IO, !(r == E_INVALID_OPERATION), E_ILLEGAL_ACCESS, "File is not opened for reading!");
312 SysLog(NID_IO, "[%s] Failed to read data from file", GetErrorMessage(r));
315 SysAssert(readItems > 0);
316 __virtualFilePointer = __virtualFilePointer + readItems;
327 _SecureFile::Write(const ByteBuffer& buffer)
329 return Write(buffer.GetPointer(), buffer.GetLimit());
333 _SecureFile::Write(const void* pBuffer, int length)
335 result r = E_SUCCESS;
338 bool replica = false;
341 SysAssertf(__pNormalFile != null, "Not yet constructed. Construct() should be called before use.\n");
343 SysTryReturnResult(NID_IO, !(!pBuffer || length <= 0), E_INVALID_ARG, "Invalid argument passed.");
345 r = _SecureIoUtil::InsertSecureFileHeader(__pNormalFile);
346 SysTryReturn(NID_IO, !IsFailed(r), r, r, "[%s] Failed to write file headers.", GetErrorMessage(r));
348 r = _SecureIoUtil::SaveLengthOfFile(__pNormalFile);
349 SysTryReturn(NID_IO, !IsFailed(r), r, r, "[%s] Failed to set length in file header.", GetErrorMessage(r));
351 r = _SecureIoUtil::SelectCipherBlock(__pNormalFile, __virtualFilePointer, &dataPos);
354 if (r == E_END_OF_FILE)
356 r = E_IO; //for security error
363 eofSet = _SecureIoUtil::IsEndOfFile(__pNormalFile);
367 r = _SecureIoUtil::SetFlag(__pNormalFile, FLAG_STATE_NONE);
368 SysTryCatch(NID_IO, !IsFailed(r), , r, "[%s] Failed to set flags in file header.", GetErrorMessage(r));
374 r = _SecureIoUtil::MakeCipherBlockReplica(__pNormalFile, __filePath, dataPos, length);
375 SysTryCatch(NID_IO, !IsFailed(r), , r, "[%s] Failed to make cipher block replica of file.", GetErrorMessage(r));
377 r = _SecureIoUtil::SetFlag(__pNormalFile, FLAG_STATE_CTF);
378 SysTryCatch(NID_IO, !IsFailed(r), , r, "[%s] Failed to set flags in file header.", GetErrorMessage(r));
386 r = _SecureIoUtil::MakeCipherBlockReplica(__pNormalFile, __filePath, dataPos, length);
387 SysTryCatch(NID_IO, !IsFailed(r), , r, "[%s] Failed to make cipher block replica of file.", GetErrorMessage(r));
389 r = _SecureIoUtil::SetFlag(__pNormalFile, FLAG_STATE_CTF);
390 SysTryCatch(NID_IO, !IsFailed(r), , r, "[%s] Failed to set flags in file header.", GetErrorMessage(r));
395 r = _SecureIoUtil::WriteDataInCipherBlock(__pNormalFile, dataPos, eofSet, length, const_cast< byte* >(static_cast< const byte* >(pBuffer)), *__pKey);
398 if (r == E_END_OF_FILE)
400 r = E_IO; //for security error
407 r = _SecureIoUtil::SetFlag(__pNormalFile, FLAG_STATE_CVF_CTF);
408 SysTryCatch(NID_IO, !IsFailed(r), , r, "[%s] Failed to set flags in file header.", GetErrorMessage(r));
409 r = _SecureIoUtil::DeleteBlockReplica(__pNormalFile, __filePath);
410 SysTryCatch(NID_IO, !IsFailed(r), , r, "[%s] Failedt to delete block replica of file.", GetErrorMessage(r));
413 r = _SecureIoUtil::SetFlag(__pNormalFile, FLAG_STATE_CVF);
414 SysTryCatch(NID_IO, !IsFailed(r), , r, "[%s] Failed to set flags in file header.", GetErrorMessage(r));
416 __virtualFilePointer = __virtualFilePointer + length;
420 SysTryReturnResult(NID_IO, !(r == E_INVALID_OPERATION), E_ILLEGAL_ACCESS, "File is not opened for writing!");
426 _SecureFile::Write(const String& buffer)
428 unique_ptr< char[] > pData(_StringConverter::CopyToCharArrayN(buffer));
430 SysTryReturn(NID_IO, pData != null, GetLastResult(), GetLastResult(), "[%s] Propagated.", GetErrorMessage(GetLastResult()));
432 return Write(pData.get(), buffer.GetLength());
436 _SecureFile::Flush(void)
438 result r = E_SUCCESS;
441 SysAssertf(__pNormalFile != null, "Not yet constructed. Construct() should be called before use.\n");
442 r = __pNormalFile->Flush();
447 _SecureFile::Tell(void) const
449 SysAssertf(__pNormalFile != null, "Not yet constructed. Construct() should be called before use.\n");
452 result r = E_SUCCESS;
455 r = _SecureIoUtil::GetDataLengh(__pNormalFile, &dataLen);
458 if (r == E_ILLEGAL_ACCESS || r == E_STORAGE_FULL || r == E_END_OF_FILE)
460 r = E_IO; //for security error
465 SysTryCatch(NID_IO, (dataLen >= __virtualFilePointer), r = E_IO, E_IO, "[E_IO] Failed to tell in file.");
467 ret = __virtualFilePointer;
475 _SecureFile::Seek(FileSeekPosition position, long offset)
477 result r = E_SUCCESS;
479 long tempFilePointer = 0;
482 SysAssertf(__pNormalFile != null, "Not yet constructed. Construct() should be called before use.\n");
484 r = _SecureIoUtil::GetDataLengh(__pNormalFile, &fileEndPos);
487 if (r == E_ILLEGAL_ACCESS || r == E_END_OF_FILE)
489 r = E_IO; //for security error
496 case FILESEEKPOSITION_BEGIN:
500 case FILESEEKPOSITION_CURRENT:
501 tempFilePointer = __virtualFilePointer;
504 case FILESEEKPOSITION_END:
505 tempFilePointer = fileEndPos;
513 if (tempFilePointer + offset > fileEndPos)
515 //In Linux , Seek () will set file position beyond end of file also even if file is opened in READONLY.
518 return E_ILLEGAL_ACCESS;
522 unique_ptr< byte[] > pTempBuffer(new (std::nothrow) byte[tempFilePointer + offset - fileEndPos]);
523 SysTryReturnResult(NID_IO, pTempBuffer != null, E_OUT_OF_MEMORY, "The memory is insufficient.");
525 memset(pTempBuffer.get(), 0, tempFilePointer + offset - fileEndPos);
526 __virtualFilePointer = fileEndPos;
528 r = this->Write(pTempBuffer.get(), tempFilePointer + offset - fileEndPos);
530 SysTryReturn(NID_IO, !IsFailed(r), r, r, "[%s] Failed to write data in to the file.", GetErrorMessage(r));
534 else if (tempFilePointer + offset == fileEndPos)
536 __virtualFilePointer = fileEndPos;
538 else if (tempFilePointer + offset < 0)
540 return E_INVALID_ARG;
542 else if (tempFilePointer + offset == 0)
544 __virtualFilePointer = 0;
548 __virtualFilePointer = tempFilePointer + offset;
555 _SecureFile::Truncate(int length)
557 result r = E_SUCCESS;
563 SysAssertf(__pNormalFile != null, "Not yet constructed. Construct() should be called before use.\n");
564 SysTryReturnResult(NID_IO, length >= 0, E_INVALID_ARG, "Invalid argument is passed (length < 0)");
568 r = __pNormalFile->Truncate(length);
571 SysLog(NID_IO, "[%s] Failed to truncate data to file", GetErrorMessage(r));
573 __virtualFilePointer = 0;
578 r = _SecureIoUtil::GetDataLengh(__pNormalFile, &fileEndPos);
581 if (r == E_END_OF_FILE)
583 r = E_IO; //for security error
588 if (length >= fileEndPos)
590 if (length == fileEndPos)
592 this->Seek(FILESEEKPOSITION_END, 0);
597 unique_ptr< byte[] > pTempBuffer(new (std::nothrow) byte[length - fileEndPos]);
598 SysTryCatch(NID_IO, pTempBuffer != null, r = E_OUT_OF_MEMORY, E_OUT_OF_MEMORY, "[E_OUT_OF_MEMORY] The memory is insufficient.");
601 memset(pTempBuffer.get(), 0, length - fileEndPos);
602 r = this->Seek(FILESEEKPOSITION_END, 0);
603 SysTryCatch(NID_IO, !IsFailed(r), , r, "[%s] Failed to seek in file.", GetErrorMessage(r));
605 r = this->Write(pTempBuffer.get(), length - fileEndPos);
606 SysTryCatch(NID_IO, !IsFailed(r), , r, "[%s] Failed to write data in file.", GetErrorMessage(r));
611 unique_ptr< byte[] > pTempBuffer(null);
613 __virtualFilePointer = length;
614 r = _SecureIoUtil::SelectCipherBlock(__pNormalFile, __virtualFilePointer, &dataPos);
617 if (r == E_END_OF_FILE)
619 r = E_IO; //for security error
626 pTempBuffer = unique_ptr< byte[] >(new (std::nothrow) byte[dataPos]);
627 SysTryCatch(NID_IO, pTempBuffer, r = E_OUT_OF_MEMORY, E_OUT_OF_MEMORY, "[E_OUT_OF_MEMORY] The memory is insufficient.");
629 r = _SecureIoUtil::ReadDataFromCipherBlock(__pNormalFile, 0, dataPos, pTempBuffer.get(), DATA_FORMAT_BYTE, &readItems, *__pKey);
632 if (r == E_END_OF_FILE)
634 r = E_IO; //for security error
639 SysAssert(readItems == dataPos);
640 r = _SecureIoUtil::SelectCipherBlock(__pNormalFile, __virtualFilePointer, &dataPos);
643 if (r == E_END_OF_FILE)
645 r = E_IO; //for security error
651 length = __pNormalFile->Tell();
652 SysTryCatch(NID_IO, length != -1, r = __ConvertNativeErrorToResult(errno), r, "[%s] Failed to tell in file", GetErrorMessage(r));
654 r = __pNormalFile->Truncate(length);
655 SysTryCatch(NID_IO, !IsFailed(r), , r, "[%s] Failed to truncate data to file", GetErrorMessage(r));
658 r = __pNormalFile->Flush();
659 SysTryCatch(NID_IO, !IsFailed(r), , r, "[%s] Failed to flush data to file", GetErrorMessage(r));
662 r = _SecureIoUtil::GetDataLengh(__pNormalFile, &__virtualFilePointer);
665 if (r == E_END_OF_FILE)
667 r = E_IO; //for security error
672 if (pTempBuffer != null)
674 r = this->Write(static_cast< void* >(pTempBuffer.get()), dataPos);
675 SysTryCatch(NID_IO, !IsFailed(r), , r, "[%s] Failed to write data in file.", GetErrorMessage(r));
678 r = _SecureIoUtil::GetDataLengh(__pNormalFile, &__virtualFilePointer);
681 if (r == E_END_OF_FILE)
683 r = E_IO; //for security error
690 __pNormalFile->Flush();
695 _SecureFile::GetName(void)
697 SysAssertf(__pNormalFile != null, "Not yet constructed. Construct() should be called before use.\n");
699 SetLastResult(E_SUCCESS); // for OSP 2.0 compatibility