//
-// Open Service Platform
// Copyright (c) 2012 Samsung Electronics Co., Ltd.
//
// Licensed under the Apache License, Version 2.0 (the License);
/**
* @file FIo_FileEventManager.cpp
- * @brief This is the implementation file for FileEventManager class.
+ * @brief This is the implementation file for _FileEventManager class.
*/
+#include <unique_ptr.h>
#include <unistd.h>
#include <sys/inotify.h>
#include <errno.h>
-#include <new>
-#include <unique_ptr.h>
#include <FBaseInteger.h>
#include <FBaseString.h>
-#include <FBaseSysLog.h>
#include <FBaseColAllElementsDeleter.h>
-#include <FBaseRtIEventArg.h>
+#include <FBaseColIMapEnumerator.h>
+#include <FBaseSysLog.h>
#include <FIoFile.h>
-#include <FIoIFileEventListener.h>
#include <FIoFileEventManager.h>
+#include <FIoIFileEventListener.h>
#include <FBase_StringConverter.h>
#include <FBase_NativeError.h>
-#include <FIo_FileEventManagerImpl.h>
-
-#define INOTIFY_BUFFER_LEN (1024*(sizeof(struct inotify_event) + 16))
+#include "FIo_FileEventManagerImpl.h"
+#include "FIo_FileEventDispatcher.h"
+#include "FIo_FileEvent.h"
using namespace std;
using namespace Tizen::Base;
namespace Tizen { namespace Io
{
-class _FileEventArg
- : public IEventArg
-{
-public:
- _FileEventArg(unsigned long event, String path, unsigned int eventId)
- : __event(event)
- , __path(path)
- , __eventId(eventId)
- {
- }
- unsigned long __event;
- String __path;
- unsigned int __eventId;
-};
-
-class _FileEvent
- : public Event
-{
-protected:
- virtual void FireImpl(IEventListener& listener, const IEventArg& arg)
- {
- IFileEventListener* pListener = dynamic_cast<IFileEventListener*> (&listener);
- if (pListener != null)
- {
- const _FileEventArg* pArg = dynamic_cast<const _FileEventArg*>(&arg);
- if (pArg != null)
- {
- pListener->OnFileEventOccured(pArg->__event, pArg->__path, pArg->__eventId);
- }
- }
- }
-};
-
_FileEventManagerImpl::_FileEventManagerImpl(void)
- : __pMonitorFileList(null)
+ : __pWatchList(null)
, __pEvent(null)
, __inotifyFd(-1)
- , __pGSource(null)
- , __pGIOChannel(null)
{
}
_FileEventManagerImpl::~_FileEventManagerImpl(void)
{
- if (__inotifyFd != -1)
- {
- close(__inotifyFd);
- }
+ SysLog(NID_IO, "_FileEventManagerImpl: 0x%x", this);
- if (__pGIOChannel != null)
+ if (__pWatchList != null)
{
- g_io_channel_unref(__pGIOChannel);
- }
-
- if (__pGSource != null)
- {
- g_source_destroy(__pGSource);
- g_source_unref(__pGSource);
- }
-
- if (__pMonitorFileList != null)
- {
- __pMonitorFileList->RemoveAll(true);
- delete __pMonitorFileList;
- }
-
- delete __pEvent;
-}
-
-gboolean
-_FileEventManagerImpl::OnFileEventOccured(GIOChannel* source, GIOCondition condition, gpointer data)
-{
- _FileEventManagerImpl* pFileEventManagerImpl = (_FileEventManagerImpl*)data;
-
- pFileEventManagerImpl->SendEvent();
-
- return true;
-}
-
-result
-_FileEventManagerImpl::SendEvent(void)
-{
- unsigned long iter = 0;
- ssize_t length = 0;
- char buffer[INOTIFY_BUFFER_LEN + 1] = {0,};
-
- unsigned long event = 0;
- String path;
- unsigned int eventId = 0;
- result r = E_IO;
-
- SysTryReturnResult(NID_IO, __inotifyFd != -1, E_IO, "Failed to inotify.");
-
- length = read(__inotifyFd, buffer, INOTIFY_BUFFER_LEN);
- SysTryReturnResult(NID_IO, length < (long)INOTIFY_BUFFER_LEN, E_IO, "Read buffer has failed.");
-
- while (iter < static_cast<unsigned long> (length))
- {
- struct inotify_event* pEvent = (struct inotify_event*)&buffer[iter];
- SysTryReturnResult(NID_IO, pEvent != null, E_IO, "Event info not found.");
- event = (unsigned long)pEvent->mask;
- eventId = pEvent->cookie;
-
- if (pEvent->len)
+ _FileEventDispatcher* pDispatcher = _FileEventDispatcher::GetInstance();
+ IMapEnumerator* pMapEnum = __pWatchList->GetMapEnumeratorN();
+ while (pMapEnum->MoveNext() == E_SUCCESS)
{
- path = pEvent->name;
+ Integer* pWd = dynamic_cast< Integer* >(pMapEnum->GetValue());
+ if (pWd != null)
+ {
+ SysLog(NID_IO, "inotify fd: %d, watch description: %d", __inotifyFd, pWd->ToInt());
+ int res = inotify_rm_watch(__inotifyFd, pWd->ToInt());
+ SysTryLog(NID_IO, res == 0, "inotify_rm_watch() failed, errno: %d (%s)", errno, strerror(errno));
+ pDispatcher->RemoveFileEventInfo(*pWd);
+ }
}
- else
- {
- path = GetRegisteredPath(pEvent->wd);
- }
-
- _FileEventArg* pEventArg= new (std::nothrow) _FileEventArg(event, path, eventId);
- if(pEventArg != null)
- {
- SysLog(NID_IO, "_FileEventManagerImpl::SendEvent Event Fire");
- __pEvent->Fire(*pEventArg);
- r = E_SUCCESS;
- }
-
- iter += sizeof(struct inotify_event) + pEvent->len;
}
- return r;
+ delete __pWatchList;
+ delete __pEvent;
}
result
_FileEventManagerImpl::Construct(IFileEventListener& listener)
{
- GMainContext* pGContext = null;
- result r = E_SUCCESS;
- _FileEvent* pEvent = null;
- __inotifyFd = inotify_init();
-
- if (__inotifyFd == -1 && errno == EMFILE)
- {
- SysLogException(NID_IO, E_MAX_EXCEEDED, "The number of opened files has exceeded the maximum limit.");
- return E_MAX_EXCEEDED;
- }
- SysTryReturnResult(NID_IO, __inotifyFd != -1, E_IO, "Failed to init inotify.");
-
- unique_ptr<HashMap, AllElementsDeleter> pMonitorFileList(new (std::nothrow) HashMap());
- SysTryCatch(NID_IO, pMonitorFileList != null, r = E_OUT_OF_MEMORY, E_OUT_OF_MEMORY, "[E_OUT_OF_MEMORY] Failed to create monitored file list.");
+ unique_ptr< HashMap > pWatchList(new (std::nothrow) HashMap(SingleObjectDeleter));
+ SysTryReturnResult(NID_IO, pWatchList != null, E_OUT_OF_MEMORY, "The memory is insufficient.");
+ pWatchList->Construct();
- r = pMonitorFileList->Construct();
- SysTryCatch(NID_IO, r == E_SUCCESS, , r, "[%s] Propagated.", GetErrorMessage(r));
+ _FileEventDispatcher* pDispatcher = _FileEventDispatcher::GetInstance();
- pGContext = g_main_context_get_thread_default(); //get own gmain context except default thread
+ unique_ptr< _FileEvent > pEvent(new (std::nothrow) _FileEvent());
+ SysTryReturnResult(NID_IO, pEvent != null, E_OUT_OF_MEMORY, "The memory is insufficient.");
+ result r = pEvent->Construct();
+ SysTryReturn(NID_IO, !IsFailed(r), E_IO, r, "[%s] The caller is a worker thread.", GetErrorMessage(r));
- if (pGContext == null)
- {
- pGContext = g_main_context_default(); //get gmain context from me (default)
- SysTryCatch(NID_IO, pGContext != null, r = E_IO, E_IO, "[E_IO] Failed to get glib context.");
- }
-
- __pEvent = new (std::nothrow) _FileEvent();
- SysTryReturnResult(NID_IO, __pEvent != null, E_OUT_OF_MEMORY, "The memory is insufficient.");
-
- __pEvent->AddListener(listener);
-
- __pGIOChannel = g_io_channel_unix_new(__inotifyFd); //fd wrapping
- SysTryCatch(NID_IO, __pGIOChannel != null, r = E_IO, E_IO, "[E_IO] Failed to create glib channel.");
-
- __pGSource = g_io_create_watch(__pGIOChannel, (GIOCondition)(G_IO_IN | G_IO_ERR | G_IO_NVAL | G_IO_HUP));
- SysTryCatch(NID_IO, __pGSource != null, r = E_IO, E_IO, "[E_IO] Failed to create glib watch.");
-
- g_source_set_callback(__pGSource, (GSourceFunc)OnFileEventOccured, this, NULL);
- g_source_attach(__pGSource, pGContext);
-
- __pMonitorFileList = pMonitorFileList.release();
-
- // fall thru
-CATCH:
- if (r != E_SUCCESS)
- {
- if (__inotifyFd != -1)
- {
- close(__inotifyFd);
- }
-
- if (__pGIOChannel != null)
- {
- g_io_channel_unref(__pGIOChannel);
- __pGIOChannel = null;
- }
+ r = pEvent->AddListener(listener, true);
+ SysTryReturn(NID_IO, r == E_SUCCESS || r == E_OBJ_ALREADY_EXIST, E_IO, r,
+ "[%s] The caller is a worker thread.", GetErrorMessage(r));
- if (__pGSource != null)
- {
- g_source_destroy(__pGSource);
- g_source_unref(__pGSource);
- __pGSource = null;
- }
- }
+ __inotifyFd = pDispatcher->GetInotifyFd();
+ __pWatchList = pWatchList.release();
+ __pEvent = pEvent.release();
- return r;
+ SysLog(NID_IO, "_FileEventManagerImpl: 0x%x, _Event: 0x%x", this, __pEvent);
+ return E_SUCCESS;
}
result
_FileEventManagerImpl::AddPath(const String& path, unsigned long eventsToMonitor)
{
- int monitoredFd = 0;
+ SysSecureLog(NID_IO, "Add watch path: %ls, _FileEventManagerImpl: 0x%x", path.GetPointer(), this);
result r = E_SUCCESS;
SysTryReturnResult(NID_IO, File::IsFileExist(path) == true, E_FILE_NOT_FOUND,
- "path[%ls] dose not exist.", path.GetPointer());
+ "The path (%ls) dose not exist.", path.GetPointer());
- SysLog(NID_IO, "path:%ls", path.GetPointer());
+ unique_ptr< char[] > pPath(_StringConverter::CopyToCharArrayN(path));
+ SysTryReturnResult(NID_IO, pPath != null, GetLastResult(), "Propagating to caller...");
- unique_ptr<char[]> pPath(_StringConverter::CopyToCharArrayN(path));
- SysTryReturnResult(NID_IO, pPath != null, E_IO, "String covert is failed.");
-
- monitoredFd = inotify_add_watch(__inotifyFd, pPath.get(), eventsToMonitor);
-
- if (monitoredFd == -1)
+ int watchDescription = inotify_add_watch(__inotifyFd, pPath.get(), eventsToMonitor & ~IN_IGNORED);
+ if (watchDescription == -1)
{
r = E_IO;
switch (errno)
{
case EACCES:
- SysLogException(NID_IO, E_IO, "Read access to the given file[%s] is not permitted.", pPath.get());
+ SysLogException(NID_IO, E_IO, "Read access to the given file (%s) is not permitted.", pPath.get());
r = E_ILLEGAL_ACCESS;
break;
case EFAULT:
- SysLogException(NID_IO, E_IO, "The path[%s] points outside of the process's accessible address space.", pPath.get());
+ SysLogException(NID_IO, E_IO, "The path (%s) points outside of the process's accessible address space.", pPath.get());
r = E_ILLEGAL_ACCESS;
break;
case EBADF:
return r;
}
- unique_ptr<String> pMonitoredPath(new (std::nothrow) String(path));
- unique_ptr<Integer> pMonitoredFd(new (std::nothrow) Integer(monitoredFd));
- SysTryReturnResult(NID_IO, pMonitoredPath != null && pMonitoredFd != null, E_IO, "Failed to allocate memory");
+ Integer* pWatchDescription = new (std::nothrow) Integer(watchDescription);
+ _FileEventInfo* pFileEventInfo = new (std::nothrow) _FileEventInfo();
+ String* pWatchPath = new (std::nothrow) String(path);
+ Integer* pWd = new (std::nothrow) Integer(watchDescription);
+ SysTryCatch(NID_IO, pWatchDescription != null && pFileEventInfo != null && pWatchPath != null && pWd != null,
+ r = E_OUT_OF_MEMORY, E_OUT_OF_MEMORY, "The memory is insufficient.");
- SysTryReturnResult(NID_IO, __pMonitorFileList != null, E_IO, "Monitored file list is null");
+ pFileEventInfo->pFileEventManagerImpl = this;
+ pFileEventInfo->path = path;
- r = __pMonitorFileList->Add(*pMonitoredPath.release(), *pMonitoredFd.release());
- SysTryReturnResult(NID_IO, r == E_SUCCESS || r == E_OBJ_ALREADY_EXIST, E_IO, "Failed to add on monitored list.");
+ r = _FileEventDispatcher::GetInstance()->AddFileEventInfo(pWatchDescription, pFileEventInfo);
+ SysTryCatch(NID_IO, r == E_SUCCESS || r == E_OBJ_ALREADY_EXIST, r = E_IO, r,
+ "[%s] Failed to add file event info.", GetErrorMessage(r));
+ if (r == E_OBJ_ALREADY_EXIST)
+ {
+ SysLog(NID_IO, "FileEventInfo already exists.");
+ delete pWatchDescription;
+ delete pFileEventInfo;
+ delete pWatchPath;
+ delete pWd;
+ }
+ else
+ {
+ SysLog(NID_IO, "Add to watch list");
+ __pWatchList->Add(pWatchPath, pWd);
+ }
+
+ return E_SUCCESS;
+
+CATCH:
+ delete pWatchDescription;
+ delete pFileEventInfo;
+ delete pWatchPath;
+ delete pWd;
return r;
}
result
_FileEventManagerImpl::RemovePath(const String& path)
{
- Integer* pMonitoredFd = null;
-
- SysTryReturnResult(NID_IO, __pMonitorFileList != null, E_IO, "Monitored file list is null");
+ SysSecureLog(NID_IO, "Remove watch path (%ls), _FileEventManagerImpl: 0x%x", path.GetPointer(), this);
- pMonitoredFd = (Integer*)__pMonitorFileList->GetValue(path);
+ Integer* pWd = dynamic_cast< Integer* >(__pWatchList->GetValue(path));
+ SysTryReturnResult(NID_IO, pWd != null, E_IO, "The path (%ls) is not registered.", path.GetPointer());
- SysTryReturnResult(NID_IO, pMonitoredFd != null, E_IO, "path[%ls] is not registered.", path.GetPointer());
+ SysTryReturnResult(NID_IO, inotify_rm_watch(__inotifyFd, pWd->ToInt()) == 0,
+ E_IO, "The path (%ls) is not registered.", path.GetPointer());
- SysTryReturnResult(NID_IO, inotify_rm_watch(__inotifyFd, pMonitoredFd->ToInt()) == 0,
- E_IO, "path[%ls] is not registered.", path.GetPointer());
+ _FileEventDispatcher::GetInstance()->RemoveFileEventInfo(*pWd);
+ __pWatchList->Remove(path);
- SysTryReturnResult(NID_IO, __pMonitorFileList->Remove(path, true) == E_SUCCESS,
- E_IO, "path[%ls] is not registered.", path.GetPointer());
return E_SUCCESS;
}
-String
-_FileEventManagerImpl::GetRegisteredPath(int fd)
-{
- String* pRegisteredPath = null;
- Integer* pRegisteredFD = null;
-
- if (__pMonitorFileList == null)
- {
- SysLog(NID_IO, "There is no path for fd:%d", fd);
- return "";
- }
-
- unique_ptr<IMapEnumerator> pEnumerator(__pMonitorFileList->GetMapEnumeratorN());
- SysTryReturn(NID_IO, pEnumerator != null, L"", GetLastResult(), "[%s] Monitored file list is empty", GetErrorMessage(GetLastResult()));
-
- while (pEnumerator && pEnumerator->MoveNext() == E_SUCCESS)
- {
- pRegisteredPath = static_cast<String*> (pEnumerator->GetKey());
- pRegisteredFD = static_cast<Integer*> (pEnumerator->GetValue());
-
- if (fd == pRegisteredFD->ToInt())
- {
- SysLog(NID_IO, "Path is %ls", pRegisteredPath->GetPointer());
- return *pRegisteredPath;
- }
-
- }
-
- SysLog(NID_IO, "There is no path for fd:%d", fd);
- return "";
-}
-
_FileEventManagerImpl*
_FileEventManagerImpl::GetInstance(FileEventManager& fileEventManager)
{