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_FileEventManager.cpp
20 * @brief This is the implementation file for FileEventManager class.
24 #include <sys/inotify.h>
27 #include <unique_ptr.h>
29 #include <FBaseInteger.h>
30 #include <FBaseString.h>
31 #include <FBaseSysLog.h>
32 #include <FBaseColAllElementsDeleter.h>
33 #include <FBaseRtIEventArg.h>
35 #include <FIoIFileEventListener.h>
36 #include <FIoFileEventManager.h>
38 #include <FBase_StringConverter.h>
39 #include <FBase_NativeError.h>
40 #include <FIo_FileEventManagerImpl.h>
42 #define INOTIFY_BUFFER_LEN (1024*(sizeof(struct inotify_event) + 16))
45 using namespace Tizen::Base;
46 using namespace Tizen::Base::Runtime;
47 using namespace Tizen::Base::Collection;
49 namespace Tizen { namespace Io
56 _FileEventArg(unsigned long event, String path, unsigned int eventId)
62 unsigned long __event;
64 unsigned int __eventId;
71 virtual void FireImpl(IEventListener& listener, const IEventArg& arg)
73 IFileEventListener* pListener = dynamic_cast<IFileEventListener*> (&listener);
74 if (pListener != null)
76 const _FileEventArg* pArg = dynamic_cast<const _FileEventArg*>(&arg);
79 pListener->OnFileEventOccured(pArg->__event, pArg->__path, pArg->__eventId);
85 _FileEventManagerImpl::_FileEventManagerImpl(void)
86 : __pMonitorFileList(null)
94 _FileEventManagerImpl::~_FileEventManagerImpl(void)
96 if (__inotifyFd != -1)
101 if (__pGIOChannel != null)
103 g_io_channel_unref(__pGIOChannel);
106 if (__pGSource != null)
108 g_source_destroy(__pGSource);
109 g_source_unref(__pGSource);
112 if (__pMonitorFileList != null)
114 __pMonitorFileList->RemoveAll(true);
115 delete __pMonitorFileList;
122 _FileEventManagerImpl::OnFileEventOccured(GIOChannel* source, GIOCondition condition, gpointer data)
124 _FileEventManagerImpl* pFileEventManagerImpl = (_FileEventManagerImpl*)data;
126 pFileEventManagerImpl->SendEvent();
132 _FileEventManagerImpl::SendEvent(void)
134 unsigned long iter = 0;
136 char buffer[INOTIFY_BUFFER_LEN] = {0,};
138 unsigned long event = 0;
140 unsigned int eventId = 0;
143 SysTryReturnResult(NID_IO, __inotifyFd != -1, E_IO, "Failed to inotify.");
145 length = read(__inotifyFd, buffer, INOTIFY_BUFFER_LEN -1);
146 SysTryReturnResult(NID_IO, length < (long)INOTIFY_BUFFER_LEN, E_IO, "Read buffer has failed.");
148 while (iter < static_cast<unsigned long> (length))
150 struct inotify_event* pEvent = (struct inotify_event*)&buffer[iter];
151 SysTryReturnResult(NID_IO, pEvent != null, E_IO, "Event info not found.");
152 event = (unsigned long)pEvent->mask;
153 eventId = pEvent->cookie;
161 path = GetRegisteredPath(pEvent->wd);
164 _FileEventArg* pEventArg= new (std::nothrow) _FileEventArg(event, path, eventId);
165 if(pEventArg != null)
167 SysLog(NID_IO, "_FileEventManagerImpl::SendEvent Event Fire");
168 __pEvent->Fire(*pEventArg);
172 iter += sizeof(struct inotify_event) + pEvent->len;
179 _FileEventManagerImpl::Construct(IFileEventListener& listener)
181 GMainContext* pGContext = null;
182 result r = E_SUCCESS;
183 _FileEvent* pEvent = null;
184 __inotifyFd = inotify_init();
186 if (__inotifyFd == -1 && errno == EMFILE)
188 SysLogException(NID_IO, E_MAX_EXCEEDED, "The number of opened files has exceeded the maximum limit.");
189 return E_MAX_EXCEEDED;
191 SysTryReturnResult(NID_IO, __inotifyFd != -1, E_IO, "Failed to init inotify.");
193 unique_ptr<HashMap, AllElementsDeleter> pMonitorFileList(new (std::nothrow) HashMap());
194 SysTryCatch(NID_IO, pMonitorFileList != null, r = E_OUT_OF_MEMORY, E_OUT_OF_MEMORY, "[E_OUT_OF_MEMORY] Failed to create monitored file list.");
196 r = pMonitorFileList->Construct();
197 SysTryCatch(NID_IO, r == E_SUCCESS, , r, "[%s] Propagated.", GetErrorMessage(r));
199 pGContext = g_main_context_get_thread_default(); //get own gmain context except default thread
201 if (pGContext == null)
203 pGContext = g_main_context_default(); //get gmain context from me (default)
204 SysTryCatch(NID_IO, pGContext != null, r = E_IO, E_IO, "[E_IO] Failed to get glib context.");
207 __pEvent = new (std::nothrow) _FileEvent();
208 SysTryReturnResult(NID_IO, __pEvent != null, E_OUT_OF_MEMORY, "The memory is insufficient.");
210 __pEvent->AddListener(listener);
212 __pGIOChannel = g_io_channel_unix_new(__inotifyFd); //fd wrapping
213 SysTryCatch(NID_IO, __pGIOChannel != null, r = E_IO, E_IO, "[E_IO] Failed to create glib channel.");
215 __pGSource = g_io_create_watch(__pGIOChannel, (GIOCondition)(G_IO_IN | G_IO_ERR | G_IO_NVAL | G_IO_HUP));
216 SysTryCatch(NID_IO, __pGSource != null, r = E_IO, E_IO, "[E_IO] Failed to create glib watch.");
218 g_source_set_callback(__pGSource, (GSourceFunc)OnFileEventOccured, this, NULL);
219 g_source_attach(__pGSource, pGContext);
221 __pMonitorFileList = pMonitorFileList.release();
227 if (__inotifyFd != -1)
232 if (__pGIOChannel != null)
234 g_io_channel_unref(__pGIOChannel);
235 __pGIOChannel = null;
238 if (__pGSource != null)
240 g_source_destroy(__pGSource);
241 g_source_unref(__pGSource);
250 _FileEventManagerImpl::AddPath(const String& path, unsigned long eventsToMonitor)
253 result r = E_SUCCESS;
255 SysTryReturnResult(NID_IO, File::IsFileExist(path) == true, E_FILE_NOT_FOUND,
256 "path[%ls] dose not exist.", path.GetPointer());
258 SysLog(NID_IO, "path:%ls", path.GetPointer());
260 unique_ptr<char[]> pPath(_StringConverter::CopyToCharArrayN(path));
261 SysTryReturnResult(NID_IO, pPath != null, E_IO, "String covert is failed.");
263 monitoredFd = inotify_add_watch(__inotifyFd, pPath.get(), eventsToMonitor);
265 if (monitoredFd == -1)
271 SysLogException(NID_IO, E_IO, "Read access to the given file[%s] is not permitted.", pPath.get());
272 r = E_ILLEGAL_ACCESS;
275 SysLogException(NID_IO, E_IO, "The path[%s] points outside of the process's accessible address space.", pPath.get());
276 r = E_ILLEGAL_ACCESS;
279 SysLogException(NID_IO, E_IO, "The given file descriptor is not valid.");
282 SysLogException(NID_IO, E_INVALID_ARG, "The given event mask contains no valid events; or fd is not an inotify file descriptor.");
286 SysLogException(NID_IO, E_IO, "Insufficient kernel memory was available.");
289 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");
298 unique_ptr<String> pMonitoredPath(new (std::nothrow) String(path));
299 unique_ptr<Integer> pMonitoredFd(new (std::nothrow) Integer(monitoredFd));
300 SysTryReturnResult(NID_IO, pMonitoredPath != null && pMonitoredFd != null, E_IO, "Failed to allocate memory");
302 SysTryReturnResult(NID_IO, __pMonitorFileList != null, E_IO, "Monitored file list is null");
304 r = __pMonitorFileList->Add(*pMonitoredPath.release(), *pMonitoredFd.release());
305 SysTryReturnResult(NID_IO, r == E_SUCCESS || r == E_OBJ_ALREADY_EXIST, E_IO, "Failed to add on monitored list.");
311 _FileEventManagerImpl::RemovePath(const String& path)
313 Integer* pMonitoredFd = null;
315 SysTryReturnResult(NID_IO, __pMonitorFileList != null, E_IO, "Monitored file list is null");
317 pMonitoredFd = (Integer*)__pMonitorFileList->GetValue(path);
319 SysTryReturnResult(NID_IO, pMonitoredFd != null, E_IO, "path[%ls] is not registered.", path.GetPointer());
321 SysTryReturnResult(NID_IO, inotify_rm_watch(__inotifyFd, pMonitoredFd->ToInt()) == 0,
322 E_IO, "path[%ls] is not registered.", path.GetPointer());
324 SysTryReturnResult(NID_IO, __pMonitorFileList->Remove(path, true) == E_SUCCESS,
325 E_IO, "path[%ls] is not registered.", path.GetPointer());
330 _FileEventManagerImpl::GetRegisteredPath(int fd)
332 String* pRegisteredPath = null;
333 Integer* pRegisteredFD = null;
335 if (__pMonitorFileList == null)
337 SysLog(NID_IO, "There is no path for fd:%d", fd);
341 unique_ptr<IMapEnumerator> pEnumerator(__pMonitorFileList->GetMapEnumeratorN());
342 SysTryReturn(NID_IO, pEnumerator != null, L"", GetLastResult(), "[%s] Monitored file list is empty", GetErrorMessage(GetLastResult()));
344 while (pEnumerator && pEnumerator->MoveNext() == E_SUCCESS)
346 pRegisteredPath = static_cast<String*> (pEnumerator->GetKey());
347 pRegisteredFD = static_cast<Integer*> (pEnumerator->GetValue());
349 if (fd == pRegisteredFD->ToInt())
351 SysLog(NID_IO, "Path is %ls", pRegisteredPath->GetPointer());
352 return *pRegisteredPath;
357 SysLog(NID_IO, "There is no path for fd:%d", fd);
361 _FileEventManagerImpl*
362 _FileEventManagerImpl::GetInstance(FileEventManager& fileEventManager)
364 return fileEventManager.__pFileEventManagerImpl;
367 const _FileEventManagerImpl*
368 _FileEventManagerImpl::GetInstance(const FileEventManager& fileEventManager)
370 return fileEventManager.__pFileEventManagerImpl;