Apply secure logs
[platform/framework/native/appfw.git] / src / io / FIo_NormalFile.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_NormalFile.cpp
19  * @brief       This is the implementation file for _NormalFile 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 <FIo_FileAttributesImpl.h>
43 #include <FIo_NormalFile.h>
44
45 using namespace std;
46 using namespace Tizen::Base;
47
48 namespace Tizen { namespace Io
49 {
50
51 static const int _MAX_LINE_LENGTH = 4096;
52
53 #define _MAX_OPENMODE_LENGTH 3
54
55 _NormalFile::_NormalFile(void)
56         : __pFile(NULL)
57 {
58 }
59
60 _NormalFile::~_NormalFile(void)
61 {
62         result r = E_SUCCESS;
63
64         if (__pFile)
65         {
66                 if (fclose(__pFile) != 0)
67                 {
68                         r = __ConvertNativeErrorToResult(errno);
69                         SysLog(NID_IO, "[%s] Failed to close the file.", GetErrorMessage(r));
70                 }
71                 __pFile = NULL;
72         }
73 }
74
75 result
76 _NormalFile::Construct(const String& filePath, const char* pOpenMode)
77 {
78         SysAssertf(__pFile == NULL, "Already constructed. Calling Construct() twice or more on a same instance is not allowed for this class\n");
79
80         int fd = -1;
81         result r = E_SUCCESS;
82
83         unique_ptr<char[]> pFilePath(_StringConverter::CopyToCharArrayN(filePath));
84         SysTryReturn(NID_IO, (pFilePath != null), GetLastResult(), GetLastResult(), ("[%s] Invalid file path."),
85                                 GetErrorMessage(GetLastResult()));
86
87         FILE* pFile = fopen(pFilePath.get(), pOpenMode);
88         if (pFile == null)
89         {
90                 r = __ConvertNativeErrorToResult(errno);
91                 SysSecureLogException(NID_IO, r, "[%s] Failed to open file (%s) in openMode (%s), errno: %d (%s).",
92                                 GetErrorMessage(r), pFilePath.get(), pOpenMode, errno, strerror(errno));
93                 return r;
94         }
95
96         fd = fileno(pFile);
97
98         __pFile = pFile;
99         __filePath = filePath;
100
101         return E_SUCCESS;
102 }
103
104 result
105 _NormalFile::ReadN(char** buffer, int& length)
106 {
107         SysAssertf(__pFile != NULL, "Not yet constructed. Construct() should be called before use.\n");
108         result r = E_SUCCESS;
109
110         int ret = fseek(__pFile, 0, SEEK_END);
111         SysTryReturnResult(NID_IO, ret >= 0, E_SYSTEM, "The system I/O error occurred.");
112
113         long fileSize = ftell(__pFile);
114         SysTryReturnResult(NID_IO, fileSize >= 0, E_SYSTEM, "The system I/O error occurred.");
115
116         SysSecureLog(NID_IO, "The length of registry file (%ls) is %ld.", __filePath.GetPointer(), fileSize);
117         if (fileSize == 0)
118         {
119                 return E_SUCCESS;
120         }
121
122         ret = fseek(__pFile, 0, SEEK_SET); // moves file offset to zero because of a+ open mode.
123         SysTryReturnResult(NID_IO, ret >= 0, E_SYSTEM, "The system I/O error occurred.");
124
125         unique_ptr<char[]> pBuffer(new (std::nothrow) char[fileSize + 1]);
126         SysTryReturnResult(NID_IO, pBuffer != null, E_OUT_OF_MEMORY, "The memory is insufficient.");
127         memset(pBuffer.get(), 0x00, fileSize + 1);
128
129         int readBytes = fread((void*)pBuffer.get(), 1, (size_t)fileSize, __pFile);
130         SysTryCatch(NID_IO, readBytes > 0, r = E_SYSTEM, E_SYSTEM, "[E_SYSTEM] Failed to read registry file (%d, %s).",
131                         errno, strerror(errno));
132
133         length = readBytes + 1;
134         *buffer = pBuffer.release();
135
136         // fall through
137 CATCH:
138         if (IsFailed(r))
139         {
140                 *buffer = null;
141                 length = 0;
142         }
143
144         return r;
145 }
146
147 result
148 _NormalFile::Read(ByteBuffer& buffer)
149 {
150         SysAssertf(__pFile != NULL, "Not yet constructed. Construct() should be called before use.\n");
151
152         result r = E_SUCCESS;
153
154         int length = buffer.GetRemaining();
155         if (length == 0)
156         {
157                 return E_INVALID_ARG;
158         }
159
160         int curPos = buffer.GetPosition();
161         int bytesRead = fread((void*) (buffer.GetPointer() + curPos), 1, length, __pFile);
162         if (bytesRead < length)
163         {
164                 SysTryReturnResult(NID_IO, !(bytesRead == 0 && feof(__pFile)), E_END_OF_FILE, "end of file");
165
166                 if (ferror(__pFile))
167                 {
168                         r = __ConvertNativeErrorToResult(errno);
169                         SysTryReturnResult(NID_IO, !(r == E_INVALID_OPERATION), E_ILLEGAL_ACCESS, "File was not opened for reading!");
170                         SysLogException(NID_IO, r, "[%s] Failed to read data from file, (errno: %d)", GetErrorMessage(r), errno);
171                         return r;
172                 }
173         }
174
175         buffer.SetPosition(curPos + bytesRead);
176
177         return E_SUCCESS;
178 }
179
180 int
181 _NormalFile::Read(void* buffer, int length)
182 {
183         SysAssertf(__pFile != NULL, "Not yet constructed. Construct() should be called before use.\n");
184
185         result r = E_SUCCESS;
186
187         int readBytes = fread(buffer, 1, length, __pFile);
188         if (readBytes < length)
189         {
190                 //SysTryReturn(NID_IO, !(readBytes == 0 && feof(__pFile)), 0, E_END_OF_FILE, "[E_END_OF_FILE] end of file");
191                 if (readBytes == 0 && feof(__pFile))
192                 {
193                         SysLog(NID_IO, "[E_END_OF_FILE] end of file");
194                         SetLastResult(E_END_OF_FILE);
195                         return 0;
196                 }
197
198                 if (ferror(__pFile))
199                 {
200                         r = __ConvertNativeErrorToResult(errno);
201                         SysTryReturn(NID_IO, !(r == E_INVALID_OPERATION), 0, E_ILLEGAL_ACCESS,
202                                         "[E_ILLEGAL_ACCESS] File was not opened for reading!");
203                         SysLogException(NID_IO, r, "[%s] Failed to read data from file", GetErrorMessage(r));
204                         return 0;
205                 }
206         }
207
208         SetLastResult(E_SUCCESS);
209         return readBytes;
210 }
211
212 result
213 _NormalFile::Read(String& buffer)
214 {
215         SysAssertf(__pFile != NULL, "Not yet constructed. Construct() should be called before use.\n");
216
217         char line[_MAX_LINE_LENGTH] = {0, };
218         result r = E_SUCCESS;
219
220         buffer.Clear();
221         if (fgets(line, _MAX_LINE_LENGTH - 1, __pFile) == null)
222         {
223                 SysTryReturnResult(NID_IO, !feof(__pFile), E_END_OF_FILE, "end of file");
224
225                 if (ferror(__pFile))
226                 {
227                         r = __ConvertNativeErrorToResult(errno);
228                         SysTryReturnResult(NID_IO, !(r == E_INVALID_OPERATION), E_ILLEGAL_ACCESS, " File was not opened for reading!");
229                         SysLogException(NID_IO, r, "[%s] Failed to read data from file", GetErrorMessage(r));
230                 }
231         }
232         else
233         {
234                 buffer = String(line);
235         }
236
237         return r;
238 }
239
240 result
241 _NormalFile::Write(const ByteBuffer& buffer)
242 {
243         SysAssertf(__pFile != NULL, "Not yet constructed. Construct() should be called before use.\n");
244
245         result r = E_SUCCESS;
246
247         int length = buffer.GetLimit();
248         if (length == 0)
249         {
250                 return E_INVALID_ARG;
251         }
252
253         int bytesWritten = fwrite(buffer.GetPointer(), 1, length, __pFile);
254         if (bytesWritten < length)
255         {
256                 if (ferror(__pFile))
257                 {
258                         r = __ConvertNativeErrorToResult(errno);
259                         SysTryReturnResult(NID_IO, !(r == E_INVALID_OPERATION), E_ILLEGAL_ACCESS, "File was not opened for writing!");
260                         SysLogException(NID_IO, r, "[%s] Failed to write data to file, (errno: %d).", GetErrorMessage(r), errno);
261                 }
262         }
263
264         return r;
265 }
266
267 result
268 _NormalFile::Write(const void* buffer, int length)
269 {
270         SysAssertf(__pFile != NULL, "Not yet constructed. Construct() should be called before use.\n");
271         SysTryReturnResult(NID_IO, length > 0, E_INVALID_ARG, "length cannot be 0!");
272
273         result r = E_SUCCESS;
274
275         if ((size_t) length > fwrite(buffer, 1, length, __pFile))
276         {
277                 if (ferror(__pFile))
278                 {
279                         r = __ConvertNativeErrorToResult(errno);
280                         SysTryReturnResult(NID_IO, !(r == E_INVALID_OPERATION), E_ILLEGAL_ACCESS, "File was not opened for writing!");
281                         SysLogException(NID_IO, r, "[%s] Failed to write data to file, (errno: %d).", GetErrorMessage(r), errno);
282                 }
283         }
284
285         return r;
286 }
287
288 result
289 _NormalFile::Write(const String& buffer)
290 {
291         result r = E_SUCCESS;
292
293         SysAssertf(__pFile != NULL, "Not yet constructed. Construct() should be called before use.\n");
294         SysTryReturnResult(NID_IO, buffer.GetLength() > 0, E_INVALID_ARG, "Buffer length cannot be 0!");
295
296         unique_ptr<char[]> pData(_StringConverter::CopyToCharArrayN(buffer));
297         SysTryReturn(NID_IO, (pData != null), GetLastResult(), GetLastResult(), ("[%s] Invalid file path."),
298                                 GetErrorMessage(GetLastResult()));
299
300         if (fputs(pData.get(), __pFile) <= 0)
301         {
302                 if (ferror(__pFile))
303                 {
304                         r = __ConvertNativeErrorToResult(errno);
305                         SysTryReturnResult(NID_IO, !(r == E_INVALID_OPERATION), E_ILLEGAL_ACCESS, "File was not opened for writing!");
306                         SysLogException(NID_IO, r, "[%s] Failed to write data to file, (errno: %d).", GetErrorMessage(r), errno);
307                 }
308         }
309
310         return r;
311 }
312
313 result
314 _NormalFile::Flush(void)
315 {
316         result r = E_SUCCESS;
317
318         SysAssertf(__pFile != NULL, "Not yet constructed. Construct() should be called before use.\n");
319
320         // fflush() returns '0' even if file was opened in read only mode!
321         if (fflush(__pFile) != 0)
322         {
323                 r = __ConvertNativeErrorToResult(errno);
324                 SysLogException(NID_IO, r, "[%s] Failed to flush data to file. errno(%d)", GetErrorMessage(r), errno);
325         }
326
327         return r;
328 }
329
330 int
331 _NormalFile::Tell(void) const
332 {
333         SysAssertf(__pFile != NULL, "Not yet constructed. Construct() should be called before use.\n");
334         result r = E_SUCCESS;
335
336         int ret = ftell(__pFile);
337         if (ret == -1)
338         {
339                 r = __ConvertNativeErrorToResult(errno);
340                 SysLogException(NID_IO, r, "[%s] Failed to flush data to file", GetErrorMessage(r));
341         }
342
343         SetLastResult(r);
344         return ret;
345 }
346
347 result
348 _NormalFile::Seek(FileSeekPosition position, long offset)
349 {
350         SysAssertf(__pFile != NULL, "Not yet constructed. Construct() should be called before use.\n");
351
352         result r = E_SUCCESS;
353
354         int whence = FILESEEKPOSITION_CURRENT;
355         switch (position)
356         {
357         case FILESEEKPOSITION_BEGIN:
358                 whence = SEEK_SET;
359                 break;
360
361         case FILESEEKPOSITION_CURRENT:
362                 whence = SEEK_CUR;
363                 break;
364
365         case FILESEEKPOSITION_END:
366                 whence = SEEK_END;
367                 break;
368         default:
369                 SysTryReturnResult(NID_IO, false, E_INVALID_ARG, "Seek position is invalid.");
370         }
371
372         int ret = fseek(__pFile, offset, whence);
373         if (ret != 0)
374         {
375                 r = __ConvertNativeErrorToResult(errno);
376                 SysLogException(NID_IO, r, "[%s] Failed to seek in file", GetErrorMessage(r));
377         }
378
379         return r;
380 }
381
382 result
383 _NormalFile::Truncate(int length)
384 {
385         SysAssertf(__pFile != NULL, "Not yet constructed. Construct() should be called before use.\n");
386         result r = E_SUCCESS;
387
388         int ret = ftruncate(fileno(__pFile), (off_t)length);
389         if (ret != 0)
390         {
391                 r = __ConvertNativeErrorToResult(errno);
392                 SysLogException(NID_IO, r, "[%s] Failed to truncate file. errno(%d)", GetErrorMessage(r), errno);
393         }
394
395         return r;
396 }
397
398 String
399 _NormalFile::GetName(void)
400 {
401         SysAssertf(__pFile != NULL, "Not yet constructed. Construct() should be called before use.\n");
402
403         SetLastResult(E_SUCCESS); // for OSP 2.0 compatibility
404         return __filePath;
405 }
406
407 }} // Tizen::Io
408