Backout 128 limits in DataControl
[platform/framework/native/appfw.git] / src / io / FIo_FileEventManagerImpl.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_FileEventManager.cpp
20  * @brief       This is the implementation file for FileEventManager class.
21  */
22
23 #include <unistd.h>
24 #include <sys/inotify.h>
25 #include <errno.h>
26 #include <new>
27 #include <unique_ptr.h>
28
29 #include <FBaseInteger.h>
30 #include <FBaseString.h>
31 #include <FBaseSysLog.h>
32 #include <FBaseColAllElementsDeleter.h>
33 #include <FIoFile.h>
34 #include <FIoIFileEventListener.h>
35 #include <FIoFileEventManager.h>
36
37 #include <FBase_StringConverter.h>
38 #include <FBase_NativeError.h>
39 #include <FIo_FileEventManagerImpl.h>
40
41 #define INOTIFY_BUFFER_LEN      (1024*(sizeof(struct inotify_event) + 16))
42
43 using namespace std;
44 using namespace Tizen::Base;
45 using namespace Tizen::Base::Collection;
46
47 namespace Tizen { namespace Io
48 {
49
50 _FileEventManagerImpl::_FileEventManagerImpl(void)
51         : __pMonitorFileList(null)
52         , __pFileEventListener(null)
53         , __inotifyFd(-1)
54         , __pGSource(null)
55         , __pGIOChannel(null)
56 {
57 }
58
59 _FileEventManagerImpl::~_FileEventManagerImpl(void)
60 {
61         if (__inotifyFd != -1)
62         {
63                 close(__inotifyFd);
64         }
65
66         if (__pGIOChannel != null)
67         {
68                 g_io_channel_unref(__pGIOChannel);
69         }
70
71         if (__pGSource != null)
72         {
73                 g_source_destroy(__pGSource);
74                 g_source_unref(__pGSource);
75         }
76
77         if (__pMonitorFileList != null)
78         {
79                 __pMonitorFileList->RemoveAll(true);
80                 delete __pMonitorFileList;
81         }
82 }
83
84 gboolean
85 _FileEventManagerImpl::OnFileEventOccured(GIOChannel* source, GIOCondition condition, gpointer data)
86 {
87         _FileEventManagerImpl* pFileEventManagerImpl = (_FileEventManagerImpl*)data;
88
89         pFileEventManagerImpl->SendEvent();
90
91         return true;
92 }
93
94 result
95 _FileEventManagerImpl::SendEvent(void)
96 {
97         unsigned long iter = 0;
98         ssize_t length = 0;
99         char buffer[INOTIFY_BUFFER_LEN] = {0,};
100
101         unsigned long event = 0;
102         String path;
103         unsigned int eventId = 0;
104         result r = E_IO;
105
106         SysTryReturnResult(NID_IO, __inotifyFd != -1, E_IO, "Failed to inotify.");
107
108         length = read(__inotifyFd, buffer, INOTIFY_BUFFER_LEN -1);
109         SysTryReturnResult(NID_IO, length < (long)INOTIFY_BUFFER_LEN, E_IO, "Read buffer has failed.");
110
111         while (iter < static_cast<unsigned long> (length))
112         {
113                 struct inotify_event* pEvent = (struct inotify_event*)&buffer[iter];
114                 SysTryReturnResult(NID_IO, pEvent != null, E_IO, "Event info not found.");
115                 event = (unsigned long)pEvent->mask;
116                 eventId = pEvent->cookie;
117
118                 if (pEvent->len)
119                 {
120                         path = pEvent->name;
121                 }
122                 else
123                 {
124                         path = GetRegisteredPath(pEvent->wd);
125                 }
126
127                 if (__pFileEventListener != null)
128                 {
129                         __pFileEventListener->OnFileEventOccured(event, path, eventId);
130                         r = E_SUCCESS;
131                 }
132
133                 iter += sizeof(struct inotify_event) + pEvent->len;
134         }
135
136         return r;
137 }
138
139 result
140 _FileEventManagerImpl::Construct(IFileEventListener& listener)
141 {
142         GMainContext* pGContext = null;
143         result r = E_SUCCESS;
144         __inotifyFd = inotify_init();
145
146         if (__inotifyFd == -1 && errno == EMFILE)
147         {
148                 SysLogException(NID_IO, E_MAX_EXCEEDED, "The number of opened files has exceeded the maximum limit.");
149                 return E_MAX_EXCEEDED;
150         }
151         SysTryReturnResult(NID_IO, __inotifyFd != -1, E_IO, "Failed to init inotify.");
152
153         unique_ptr<HashMap, AllElementsDeleter> pMonitorFileList(new (std::nothrow) HashMap());
154         SysTryCatch(NID_IO, pMonitorFileList != null, r = E_OUT_OF_MEMORY, E_OUT_OF_MEMORY, "[E_OUT_OF_MEMORY] Failed to create monitored file list.");
155
156         r = pMonitorFileList->Construct();
157         SysTryCatch(NID_IO, r == E_SUCCESS, , r, "[%s] Propagated.", GetErrorMessage(r));
158
159         pGContext = g_main_context_get_thread_default(); //get own gmain context except default thread
160
161         if (pGContext == null)
162         {
163                 pGContext = g_main_context_default(); //get gmain context from me (default)
164                 SysTryCatch(NID_IO, pGContext != null, r = E_IO, E_IO, "[E_IO] Failed to get glib context.");
165         }
166
167         SysLog(NID_IO, "GContext:%x", pGContext);
168
169         __pFileEventListener = &listener;
170
171         __pGIOChannel = g_io_channel_unix_new(__inotifyFd); //fd wrapping
172         SysTryCatch(NID_IO, __pGIOChannel != null, r = E_IO, E_IO, "[E_IO] Failed to create glib channel.");
173         SysLog(NID_IO, "__pGIOChannel:%x", __pGIOChannel);
174
175         __pGSource = g_io_create_watch(__pGIOChannel, (GIOCondition)(G_IO_IN | G_IO_ERR | G_IO_NVAL | G_IO_HUP));
176         SysTryCatch(NID_IO, __pGSource != null, r = E_IO, E_IO, "[E_IO] Failed to create glib watch.");
177         SysLog(NID_IO, "__pGSource:%x", __pGSource);
178
179         g_source_set_callback(__pGSource, (GSourceFunc)OnFileEventOccured, this, NULL);
180         g_source_attach(__pGSource, pGContext);
181         SysLog(NID_IO, "Attached fd on g_source");
182
183         __pMonitorFileList = pMonitorFileList.release();
184
185         // fall thru
186 CATCH:
187         if (r != E_SUCCESS)
188         {
189                 if (__inotifyFd != -1)
190                 {
191                         close(__inotifyFd);
192                 }
193
194                 if (__pGIOChannel != null)
195                 {
196                         g_io_channel_unref(__pGIOChannel);
197                         __pGIOChannel = null;
198                 }
199
200                 if (__pGSource != null)
201                 {
202                         g_source_destroy(__pGSource);
203                         g_source_unref(__pGSource);
204                         __pGSource = null;
205                 }
206         }
207
208         return r;
209 }
210
211 result
212 _FileEventManagerImpl::AddPath(const String& path, unsigned long eventsToMonitor)
213 {
214         int monitoredFd = 0;
215         result r = E_SUCCESS;
216
217         SysTryReturnResult(NID_IO, File::IsFileExist(path) == true, E_FILE_NOT_FOUND,
218                         "path[%ls] dose not exist.", path.GetPointer());
219
220         SysLog(NID_IO, "path:%ls", path.GetPointer());
221
222         unique_ptr<char[]> pPath(_StringConverter::CopyToCharArrayN(path));
223         SysTryReturnResult(NID_IO, pPath != null, E_IO, "String covert is failed.");
224
225         monitoredFd = inotify_add_watch(__inotifyFd, pPath.get(), eventsToMonitor);
226
227         if (monitoredFd == -1)
228         {
229                 r = E_IO;
230                 switch (errno)
231                 {
232                 case EACCES:
233                         SysLogException(NID_IO, E_IO, "Read access to the given file[%s] is not permitted.", pPath.get());
234                         r = E_ILLEGAL_ACCESS;
235                         break;
236                 case EFAULT:
237                         SysLogException(NID_IO, E_IO, "The path[%s] points outside of the process's accessible address space.", pPath.get());
238                         r = E_ILLEGAL_ACCESS;
239                         break;
240                 case EBADF:
241                         SysLogException(NID_IO, E_IO, "The given file descriptor is not valid.");
242                         break;
243                 case EINVAL:
244                         SysLogException(NID_IO, E_INVALID_ARG, "The given event mask contains no valid events; or fd is not an inotify file descriptor.");
245                         r = E_INVALID_ARG;
246                         break;
247                 case ENOMEM:
248                         SysLogException(NID_IO, E_IO, "Insufficient kernel memory was available.");
249                         break;
250                 case ENOSPC:
251                         SysLogException(NID_IO, E_IO, "The user limit on the total number of inotify watches was reached or the kernel failed to allocate a needed resource");
252                         break;
253                 default:
254                         break;
255                 }
256
257                 return r;
258         }
259
260         unique_ptr<String> pMonitoredPath(new (std::nothrow) String(path));
261         unique_ptr<Integer> pMonitoredFd(new (std::nothrow) Integer(monitoredFd));
262         SysTryReturnResult(NID_IO, pMonitoredPath != null && pMonitoredFd != null, E_IO, "Failed to allocate memory");
263
264         SysTryReturnResult(NID_IO, __pMonitorFileList != null, E_IO, "Monitored file list is null");
265
266         r = __pMonitorFileList->Add(*pMonitoredPath.release(), *pMonitoredFd.release());
267         SysTryReturnResult(NID_IO, r == E_SUCCESS || r == E_OBJ_ALREADY_EXIST, E_IO, "Failed to add on monitored list.");
268
269         return r;
270 }
271
272 result
273 _FileEventManagerImpl::RemovePath(const String& path)
274 {
275         Integer* pMonitoredFd = null;
276
277         SysTryReturnResult(NID_IO, __pMonitorFileList != null, E_IO, "Monitored file list is null");
278
279         pMonitoredFd = (Integer*)__pMonitorFileList->GetValue(path);
280
281         SysTryReturnResult(NID_IO, pMonitoredFd != null, E_IO, "path[%ls] is not registered.", path.GetPointer());
282
283         SysTryReturnResult(NID_IO, inotify_rm_watch(__inotifyFd, pMonitoredFd->ToInt()) == 0,
284                                 E_IO, "path[%ls] is not registered.", path.GetPointer());
285
286         SysTryReturnResult(NID_IO, __pMonitorFileList->Remove(path, true) == E_SUCCESS,
287                                 E_IO, "path[%ls] is not registered.", path.GetPointer());
288         return E_SUCCESS;
289 }
290
291 String
292 _FileEventManagerImpl::GetRegisteredPath(int fd)
293 {
294         String* pRegisteredPath = null;
295         Integer* pRegisteredFD = null;
296
297         if (__pMonitorFileList == null)
298         {
299                 SysLog(NID_IO, "There is no path for fd:%d", fd);
300                 return "";
301         }
302
303         unique_ptr<IMapEnumerator> pEnumerator(__pMonitorFileList->GetMapEnumeratorN());
304         SysTryReturn(NID_IO, pEnumerator != null, L"", GetLastResult(), "[%s] Monitored file list is empty", GetErrorMessage(GetLastResult()));
305
306         while (pEnumerator && pEnumerator->MoveNext() == E_SUCCESS)
307         {
308                 pRegisteredPath = static_cast<String*> (pEnumerator->GetKey());
309                 pRegisteredFD = static_cast<Integer*> (pEnumerator->GetValue());
310
311                 if (fd == pRegisteredFD->ToInt())
312                 {
313                         SysLog(NID_IO, "Path is %ls", pRegisteredPath->GetPointer());
314                         return *pRegisteredPath;
315                 }
316
317         }
318
319         SysLog(NID_IO, "There is no path for fd:%d", fd);
320         return "";
321 }
322
323 _FileEventManagerImpl*
324 _FileEventManagerImpl::GetInstance(FileEventManager& fileEventManager)
325 {
326         return fileEventManager.__pFileEventManagerImpl;
327 }
328
329 const _FileEventManagerImpl*
330 _FileEventManagerImpl::GetInstance(const FileEventManager& fileEventManager)
331 {
332         return fileEventManager.__pFileEventManagerImpl;
333 }
334
335 }} // Tizen::Io
336