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