Merge "Implemented client-server model and changed code for thread safety" into tizen_2.1
[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         result r = E_SUCCESS;
110
111         int ret = fseek(__pFile, 0, SEEK_END);
112         SysTryReturnResult(NID_IO, ret >= 0, E_SYSTEM, "The system I/O error occurred.");
113
114         long fileSize = ftell(__pFile);
115         SysTryReturnResult(NID_IO, fileSize >= 0, E_SYSTEM, "The system I/O error occurred.");
116
117         SysLog(NID_IO, "The length of registry file (%ls) is %ld.", __filePath.GetPointer(), fileSize);
118         if (fileSize == 0)
119         {
120                 return E_SUCCESS;
121         }
122
123         ret = fseek(__pFile, 0, SEEK_SET); // moves file offset to zero because of a+ open mode.
124         SysTryReturnResult(NID_IO, ret >= 0, E_SYSTEM, "The system I/O error occurred.");
125
126         unique_ptr<char[]> pBuffer(new (std::nothrow) char[fileSize + 1]);
127         SysTryReturnResult(NID_IO, pBuffer != null, E_OUT_OF_MEMORY, "The memory is insufficient.");
128         memset(pBuffer.get(), 0x00, fileSize + 1);
129
130         int readBytes = fread((void*)pBuffer.get(), 1, (size_t)fileSize, __pFile);
131         SysTryCatch(NID_IO, readBytes > 0, r = E_SYSTEM, E_SYSTEM, "[E_SYSTEM] Failed to read registry file (%d, %s).",
132                         errno, strerror(errno));
133
134         length = readBytes + 1;
135         *buffer = pBuffer.release();
136
137         // fall through
138 CATCH:
139         if (IsFailed(r))
140         {
141                 *buffer = null;
142                 length = 0;
143         }
144
145         return r;
146 }
147
148 result
149 _NormalFile::Read(ByteBuffer& buffer)
150 {
151         SysAssertf(__pFile != NULL, "Not yet constructed. Construct() should be called before use.\n");
152
153         result r = E_SUCCESS;
154
155         int length = buffer.GetRemaining();
156         if (length == 0)
157         {
158                 return E_INVALID_ARG;
159         }
160
161         int curPos = buffer.GetPosition();
162         int bytesRead = fread((void*) (buffer.GetPointer() + curPos), 1, length, __pFile);
163         if (bytesRead < length)
164         {
165                 SysTryReturnResult(NID_IO, !(bytesRead == 0 && feof(__pFile)), E_END_OF_FILE, "end of file");
166
167                 if (ferror(__pFile))
168                 {
169                         r = __ConvertNativeErrorToResult(errno);
170                         SysTryReturnResult(NID_IO, !(r == E_INVALID_OPERATION), E_ILLEGAL_ACCESS, "File was not opened for reading!");
171                         SysLogException(NID_IO, r, "[%s] Failed to read data from file, (errno: %d)", GetErrorMessage(r), errno);
172                         return r;
173                 }
174         }
175
176         buffer.SetPosition(curPos + bytesRead);
177
178         return E_SUCCESS;
179 }
180
181 int
182 _NormalFile::Read(void* buffer, int length)
183 {
184         SysAssertf(__pFile != NULL, "Not yet constructed. Construct() should be called before use.\n");
185
186         result r = E_SUCCESS;
187
188         int readBytes = fread(buffer, 1, length, __pFile);
189         if (readBytes < length)
190         {
191                 //SysTryReturn(NID_IO, !(readBytes == 0 && feof(__pFile)), 0, E_END_OF_FILE, "[E_END_OF_FILE] end of file");
192                 if (readBytes == 0 && feof(__pFile))
193                 {
194                         SysLog(NID_IO, "[E_END_OF_FILE] end of file");
195                         SetLastResult(E_END_OF_FILE);
196                         return 0;
197                 }
198
199                 if (ferror(__pFile))
200                 {
201                         r = __ConvertNativeErrorToResult(errno);
202                         SysTryReturn(NID_IO, !(r == E_INVALID_OPERATION), 0, E_ILLEGAL_ACCESS,
203                                         "[E_ILLEGAL_ACCESS] File was not opened for reading!");
204                         SysLogException(NID_IO, r, "[%s] Failed to read data from file", GetErrorMessage(r));
205                         return 0;
206                 }
207         }
208
209         SetLastResult(E_SUCCESS);
210         return readBytes;
211 }
212
213 result
214 _NormalFile::Read(String& buffer)
215 {
216         SysAssertf(__pFile != NULL, "Not yet constructed. Construct() should be called before use.\n");
217
218         char line[_MAX_LINE_LENGTH] = {0, };
219         result r = E_SUCCESS;
220
221         buffer.Clear();
222         if (fgets(line, _MAX_LINE_LENGTH - 1, __pFile) == null)
223         {
224                 SysTryReturnResult(NID_IO, !feof(__pFile), E_END_OF_FILE, "end of file");
225
226                 if (ferror(__pFile))
227                 {
228                         r = __ConvertNativeErrorToResult(errno);
229                         SysTryReturnResult(NID_IO, !(r == E_INVALID_OPERATION), E_ILLEGAL_ACCESS, " File was not opened for reading!");
230                         SysLogException(NID_IO, r, "[%s] Failed to read data from file", GetErrorMessage(r));
231                 }
232         }
233         else
234         {
235                 buffer = String(line);
236         }
237
238         return r;
239 }
240
241 result
242 _NormalFile::Write(const ByteBuffer& buffer)
243 {
244         SysAssertf(__pFile != NULL, "Not yet constructed. Construct() should be called before use.\n");
245
246         result r = E_SUCCESS;
247
248         int length = buffer.GetLimit();
249         if (length == 0)
250         {
251                 return E_INVALID_ARG;
252         }
253
254         int bytesWritten = fwrite(buffer.GetPointer(), 1, length, __pFile);
255         if (bytesWritten < length)
256         {
257                 if (ferror(__pFile))
258                 {
259                         r = __ConvertNativeErrorToResult(errno);
260                         SysTryReturnResult(NID_IO, !(r == E_INVALID_OPERATION), E_ILLEGAL_ACCESS, "File was not opened for writing!");
261                         SysLogException(NID_IO, r, "[%s] Failed to write data to file, (errno: %d).", GetErrorMessage(r), errno);
262                 }
263         }
264
265         return r;
266 }
267
268 result
269 _NormalFile::Write(const void* buffer, int length)
270 {
271         SysAssertf(__pFile != NULL, "Not yet constructed. Construct() should be called before use.\n");
272         SysTryReturnResult(NID_IO, length > 0, E_INVALID_ARG, "length cannot be 0!");
273
274         result r = E_SUCCESS;
275
276         if ((size_t) length > fwrite(buffer, 1, length, __pFile))
277         {
278                 if (ferror(__pFile))
279                 {
280                         r = __ConvertNativeErrorToResult(errno);
281                         SysTryReturnResult(NID_IO, !(r == E_INVALID_OPERATION), E_ILLEGAL_ACCESS, "File was not opened for writing!");
282                         SysLogException(NID_IO, r, "[%s] Failed to write data to file, (errno: %d).", GetErrorMessage(r), errno);
283                 }
284         }
285
286         return r;
287 }
288
289 result
290 _NormalFile::Write(const String& buffer)
291 {
292         result r = E_SUCCESS;
293
294         SysAssertf(__pFile != NULL, "Not yet constructed. Construct() should be called before use.\n");
295         SysTryReturnResult(NID_IO, buffer.GetLength() > 0, E_INVALID_ARG, "Buffer length cannot be 0!");
296
297         unique_ptr<char[]> pData(_StringConverter::CopyToCharArrayN(buffer));
298         SysTryReturn(NID_IO, (pData != null), GetLastResult(), GetLastResult(), ("[%s] Invalid file path."),
299                                 GetErrorMessage(GetLastResult()));
300
301         if (fputs(pData.get(), __pFile) <= 0)
302         {
303                 if (ferror(__pFile))
304                 {
305                         r = __ConvertNativeErrorToResult(errno);
306                         SysTryReturnResult(NID_IO, !(r == E_INVALID_OPERATION), E_ILLEGAL_ACCESS, "File was not opened for writing!");
307                         SysLogException(NID_IO, r, "[%s] Failed to write data to file, (errno: %d).", GetErrorMessage(r), errno);
308                 }
309         }
310
311         return r;
312 }
313
314 result
315 _NormalFile::Flush(void)
316 {
317         result r = E_SUCCESS;
318
319         SysAssertf(__pFile != NULL, "Not yet constructed. Construct() should be called before use.\n");
320
321         // fflush() returns '0' even if file was opened in read only mode!
322         if (fflush(__pFile) != 0)
323         {
324                 r = __ConvertNativeErrorToResult(errno);
325                 SysLogException(NID_IO, r, "[%s] Failed to flush data to file. errno(%d)", GetErrorMessage(r), errno);
326         }
327
328         return r;
329 }
330
331 int
332 _NormalFile::Tell(void) const
333 {
334         SysAssertf(__pFile != NULL, "Not yet constructed. Construct() should be called before use.\n");
335         result r = E_SUCCESS;
336
337         int ret = ftell(__pFile);
338         if (ret == -1)
339         {
340                 r = __ConvertNativeErrorToResult(errno);
341                 SysLogException(NID_IO, r, "[%s] Failed to flush data to file", GetErrorMessage(r));
342         }
343
344         SetLastResult(r);
345         return ret;
346 }
347
348 result
349 _NormalFile::Seek(FileSeekPosition position, long offset)
350 {
351         SysAssertf(__pFile != NULL, "Not yet constructed. Construct() should be called before use.\n");
352
353         result r = E_SUCCESS;
354
355         int whence = FILESEEKPOSITION_CURRENT;
356         switch (position)
357         {
358         case FILESEEKPOSITION_BEGIN:
359                 whence = SEEK_SET;
360                 break;
361
362         case FILESEEKPOSITION_CURRENT:
363                 whence = SEEK_CUR;
364                 break;
365
366         case FILESEEKPOSITION_END:
367                 whence = SEEK_END;
368                 break;
369         default:
370                 SysTryReturnResult(NID_IO, false, E_INVALID_ARG, "Seek position is invalid.");
371         }
372
373         int ret = fseek(__pFile, offset, whence);
374         if (ret != 0)
375         {
376                 r = __ConvertNativeErrorToResult(errno);
377                 SysLogException(NID_IO, r, "[%s] Failed to seek in file", GetErrorMessage(r));
378         }
379
380         return r;
381 }
382
383 result
384 _NormalFile::Truncate(int length)
385 {
386         SysAssertf(__pFile != NULL, "Not yet constructed. Construct() should be called before use.\n");
387         result r = E_SUCCESS;
388
389         int ret = ftruncate(fileno(__pFile), (off_t)length);
390         if (ret != 0)
391         {
392                 r = __ConvertNativeErrorToResult(errno);
393                 SysLogException(NID_IO, r, "[%s] Failed to truncate file. errno(%d)", GetErrorMessage(r), errno);
394         }
395
396         return r;
397 }
398
399 String
400 _NormalFile::GetName(void)
401 {
402         SysAssertf(__pFile != NULL, "Not yet constructed. Construct() should be called before use.\n");
403
404         SetLastResult(E_SUCCESS); // for OSP 2.0 compatibility
405         return __filePath;
406 }
407
408 }} // Tizen::Io
409