From c0cdb2ad99a1e2a6ade5ce76c91177a79258e669 Mon Sep 17 00:00:00 2001 From: Daniel Wilhelm Date: Fri, 18 Apr 2014 17:10:11 +0200 Subject: 3.14 --- shared/inotify/inotify-cxx.cpp | 1020 +++++++++++++++-------------- shared/inotify/inotify-cxx.h | 1375 ++++++++++++++++++++-------------------- 2 files changed, 1233 insertions(+), 1162 deletions(-) (limited to 'shared/inotify') diff --git a/shared/inotify/inotify-cxx.cpp b/shared/inotify/inotify-cxx.cpp index 689612ac..5a460ec7 100644 --- a/shared/inotify/inotify-cxx.cpp +++ b/shared/inotify/inotify-cxx.cpp @@ -2,11 +2,11 @@ /// inotify C++ interface implementation /** * \file inotify-cxx.cpp - * + * * inotify C++ interface - * + * * Copyright (C) 2006, 2007, 2009 Lukas Jelinek - * + * * This program is free software; you can redistribute it and/or * modify it under the terms of one of the following licenses: * @@ -19,9 +19,9 @@ * * Credits: * Mike Frysinger (cleanup of includes) - * + * */ - + #include #include @@ -52,590 +52,658 @@ int32_t InotifyEvent::GetDescriptor() const { - return m_pWatch != NULL // if watch exists - ? m_pWatch->GetDescriptor() // return its descriptor - : -1; // else return -1 + return m_pWatch != NULL // if watch exists + ? m_pWatch->GetDescriptor() // return its descriptor + : -1; // else return -1 } uint32_t InotifyEvent::GetMaskByName(const std::string& rName) { - if (rName == "IN_ACCESS") - return IN_ACCESS; - else if (rName == "IN_MODIFY") - return IN_MODIFY; - else if (rName == "IN_ATTRIB") - return IN_ATTRIB; - else if (rName == "IN_CLOSE_WRITE") - return IN_CLOSE_WRITE; - else if (rName == "IN_CLOSE_NOWRITE") - return IN_CLOSE_NOWRITE; - else if (rName == "IN_OPEN") - return IN_OPEN; - else if (rName == "IN_MOVED_FROM") - return IN_MOVED_FROM; - else if (rName == "IN_MOVED_TO") - return IN_MOVED_TO; - else if (rName == "IN_CREATE") - return IN_CREATE; - else if (rName == "IN_DELETE") - return IN_DELETE; - else if (rName == "IN_DELETE_SELF") - return IN_DELETE_SELF; - else if (rName == "IN_UNMOUNT") - return IN_UNMOUNT; - else if (rName == "IN_Q_OVERFLOW") - return IN_Q_OVERFLOW; - else if (rName == "IN_IGNORED") - return IN_IGNORED; - else if (rName == "IN_CLOSE") - return IN_CLOSE; - else if (rName == "IN_MOVE") - return IN_MOVE; - else if (rName == "IN_ISDIR") - return IN_ISDIR; - else if (rName == "IN_ONESHOT") - return IN_ONESHOT; - else if (rName == "IN_ALL_EVENTS") - return IN_ALL_EVENTS; - + if (rName == "IN_ACCESS") + return IN_ACCESS; + else if (rName == "IN_MODIFY") + return IN_MODIFY; + else if (rName == "IN_ATTRIB") + return IN_ATTRIB; + else if (rName == "IN_CLOSE_WRITE") + return IN_CLOSE_WRITE; + else if (rName == "IN_CLOSE_NOWRITE") + return IN_CLOSE_NOWRITE; + else if (rName == "IN_OPEN") + return IN_OPEN; + else if (rName == "IN_MOVED_FROM") + return IN_MOVED_FROM; + else if (rName == "IN_MOVED_TO") + return IN_MOVED_TO; + else if (rName == "IN_CREATE") + return IN_CREATE; + else if (rName == "IN_DELETE") + return IN_DELETE; + else if (rName == "IN_DELETE_SELF") + return IN_DELETE_SELF; + else if (rName == "IN_UNMOUNT") + return IN_UNMOUNT; + else if (rName == "IN_Q_OVERFLOW") + return IN_Q_OVERFLOW; + else if (rName == "IN_IGNORED") + return IN_IGNORED; + else if (rName == "IN_CLOSE") + return IN_CLOSE; + else if (rName == "IN_MOVE") + return IN_MOVE; + else if (rName == "IN_ISDIR") + return IN_ISDIR; + else if (rName == "IN_ONESHOT") + return IN_ONESHOT; + else if (rName == "IN_ALL_EVENTS") + return IN_ALL_EVENTS; + #ifdef IN_DONT_FOLLOW - else if (rName == "IN_DONT_FOLLOW") - return IN_DONT_FOLLOW; + else if (rName == "IN_DONT_FOLLOW") + return IN_DONT_FOLLOW; #endif // IN_DONT_FOLLOW #ifdef IN_ONLYDIR - else if (rName == "IN_ONLYDIR") - return IN_ONLYDIR; + else if (rName == "IN_ONLYDIR") + return IN_ONLYDIR; #endif // IN_ONLYDIR #ifdef IN_MOVE_SELF - else if (rName == "IN_MOVE_SELF") - return IN_MOVE_SELF; + else if (rName == "IN_MOVE_SELF") + return IN_MOVE_SELF; #endif // IN_MOVE_SELF - - return (uint32_t) 0; + + return (uint32_t) 0; } void InotifyEvent::DumpTypes(uint32_t uValue, std::string& rStr) { - rStr = ""; - - if (IsType(uValue, IN_ALL_EVENTS)) { - rStr.append("IN_ALL_EVENTS"); - } - else { - if (IsType(uValue, IN_ACCESS)) { - DUMP_SEP; - rStr.append("IN_ACCESS"); - } - if (IsType(uValue, IN_MODIFY)) { - DUMP_SEP; - rStr.append("IN_MODIFY"); - } - if (IsType(uValue, IN_ATTRIB)) { - DUMP_SEP; - rStr.append("IN_ATTRIB"); - } - if (IsType(uValue, IN_CREATE)) { - DUMP_SEP; - rStr.append("IN_CREATE"); - } - if (IsType(uValue, IN_DELETE)) { - DUMP_SEP; - rStr.append("IN_DELETE"); - } - if (IsType(uValue, IN_DELETE_SELF)) { - DUMP_SEP; - rStr.append("IN_DELETE_SELF"); - } - if (IsType(uValue, IN_OPEN)) { - DUMP_SEP; - rStr.append("IN_OPEN"); - } - if (IsType(uValue, IN_CLOSE)) { - DUMP_SEP; - rStr.append("IN_CLOSE"); + rStr = ""; + + if (IsType(uValue, IN_ALL_EVENTS)) + { + rStr.append("IN_ALL_EVENTS"); } + else + { + if (IsType(uValue, IN_ACCESS)) + { + DUMP_SEP; + rStr.append("IN_ACCESS"); + } + if (IsType(uValue, IN_MODIFY)) + { + DUMP_SEP; + rStr.append("IN_MODIFY"); + } + if (IsType(uValue, IN_ATTRIB)) + { + DUMP_SEP; + rStr.append("IN_ATTRIB"); + } + if (IsType(uValue, IN_CREATE)) + { + DUMP_SEP; + rStr.append("IN_CREATE"); + } + if (IsType(uValue, IN_DELETE)) + { + DUMP_SEP; + rStr.append("IN_DELETE"); + } + if (IsType(uValue, IN_DELETE_SELF)) + { + DUMP_SEP; + rStr.append("IN_DELETE_SELF"); + } + if (IsType(uValue, IN_OPEN)) + { + DUMP_SEP; + rStr.append("IN_OPEN"); + } + if (IsType(uValue, IN_CLOSE)) + { + DUMP_SEP; + rStr.append("IN_CLOSE"); + } #ifdef IN_MOVE_SELF - if (IsType(uValue, IN_MOVE_SELF)) { - DUMP_SEP; - rStr.append("IN_MOVE_SELF"); - } + if (IsType(uValue, IN_MOVE_SELF)) + { + DUMP_SEP; + rStr.append("IN_MOVE_SELF"); + } #endif // IN_MOVE_SELF - - else { - if (IsType(uValue, IN_CLOSE_WRITE)) { + + else + { + if (IsType(uValue, IN_CLOSE_WRITE)) + { + DUMP_SEP; + rStr.append("IN_CLOSE_WRITE"); + } + if (IsType(uValue, IN_CLOSE_NOWRITE)) + { + DUMP_SEP; + rStr.append("IN_CLOSE_NOWRITE"); + } + } + if (IsType(uValue, IN_MOVE)) + { + DUMP_SEP; + rStr.append("IN_MOVE"); + } + else + { + if (IsType(uValue, IN_MOVED_FROM)) + { + DUMP_SEP; + rStr.append("IN_MOVED_FROM"); + } + if (IsType(uValue, IN_MOVED_TO)) + { + DUMP_SEP; + rStr.append("IN_MOVED_TO"); + } + } + } + if (IsType(uValue, IN_UNMOUNT)) + { DUMP_SEP; - rStr.append("IN_CLOSE_WRITE"); - } - if (IsType(uValue, IN_CLOSE_NOWRITE)) { + rStr.append("IN_UNMOUNT"); + } + if (IsType(uValue, IN_Q_OVERFLOW)) + { DUMP_SEP; - rStr.append("IN_CLOSE_NOWRITE"); - } + rStr.append("IN_Q_OVERFLOW"); } - if (IsType(uValue, IN_MOVE)) { - DUMP_SEP; - rStr.append("IN_MOVE"); + if (IsType(uValue, IN_IGNORED)) + { + DUMP_SEP; + rStr.append("IN_IGNORED"); } - else { - if (IsType(uValue, IN_MOVED_FROM)) { + if (IsType(uValue, IN_ISDIR)) + { DUMP_SEP; - rStr.append("IN_MOVED_FROM"); - } - if (IsType(uValue, IN_MOVED_TO)) { + rStr.append("IN_ISDIR"); + } + if (IsType(uValue, IN_ONESHOT)) + { DUMP_SEP; - rStr.append("IN_MOVED_TO"); - } - } - } - if (IsType(uValue, IN_UNMOUNT)) { - DUMP_SEP; - rStr.append("IN_UNMOUNT"); - } - if (IsType(uValue, IN_Q_OVERFLOW)) { - DUMP_SEP; - rStr.append("IN_Q_OVERFLOW"); - } - if (IsType(uValue, IN_IGNORED)) { - DUMP_SEP; - rStr.append("IN_IGNORED"); - } - if (IsType(uValue, IN_ISDIR)) { - DUMP_SEP; - rStr.append("IN_ISDIR"); - } - if (IsType(uValue, IN_ONESHOT)) { - DUMP_SEP; - rStr.append("IN_ONESHOT"); - } - + rStr.append("IN_ONESHOT"); + } + #ifdef IN_DONT_FOLLOW - if (IsType(uValue, IN_DONT_FOLLOW)) { - DUMP_SEP; - rStr.append("IN_DONT_FOLLOW"); - } + if (IsType(uValue, IN_DONT_FOLLOW)) + { + DUMP_SEP; + rStr.append("IN_DONT_FOLLOW"); + } #endif // IN_DONT_FOLLOW - + #ifdef IN_ONLYDIR - if (IsType(uValue, IN_ONLYDIR)) { - DUMP_SEP; - rStr.append("IN_ONLYDIR"); - } + if (IsType(uValue, IN_ONLYDIR)) + { + DUMP_SEP; + rStr.append("IN_ONLYDIR"); + } #endif // IN_ONLYDIR } void InotifyEvent::DumpTypes(std::string& rStr) const { - DumpTypes(m_uMask, rStr); + DumpTypes(m_uMask, rStr); } void InotifyWatch::SetMask(uint32_t uMask) throw (InotifyException) { - IN_WRITE_BEGIN - - if (m_wd != -1) { - int wd = inotify_add_watch(m_pInotify->GetDescriptor(), m_path.c_str(), uMask); - if (wd != m_wd) { - IN_WRITE_END_NOTHROW - throw InotifyException(IN_EXC_MSG("changing mask failed"), wd == -1 ? errno : EINVAL, this); - } - } - - m_uMask = uMask; - - IN_WRITE_END + IN_WRITE_BEGIN + + if (m_wd != -1) + { + int wd = inotify_add_watch(m_pInotify->GetDescriptor(), m_path.c_str(), uMask); + if (wd != m_wd) + { + IN_WRITE_END_NOTHROW + throw InotifyException(IN_EXC_MSG("changing mask failed"), wd == -1 ? errno : EINVAL, this); + } + } + + m_uMask = uMask; + + IN_WRITE_END } void InotifyWatch::SetEnabled(bool fEnabled) throw (InotifyException) { - IN_WRITE_BEGIN - - if (fEnabled == m_fEnabled) { - IN_WRITE_END_NOTHROW - return; - } - - if (m_pInotify != NULL) { - if (fEnabled) { - m_wd = inotify_add_watch(m_pInotify->GetDescriptor(), m_path.c_str(), m_uMask); - if (m_wd == -1) { + IN_WRITE_BEGIN + + if (fEnabled == m_fEnabled) + { IN_WRITE_END_NOTHROW - throw InotifyException(IN_EXC_MSG("enabling watch failed"), errno, this); - } - m_pInotify->m_watches.insert(IN_WATCH_MAP::value_type(m_wd, this)); + return; } - else { - if (inotify_rm_watch(m_pInotify->GetDescriptor(), m_wd) != 0) { - IN_WRITE_END_NOTHROW - throw InotifyException(IN_EXC_MSG("disabling watch failed"), errno, this); - } - m_pInotify->m_watches.erase(m_wd); - m_wd = -1; - } - } - - m_fEnabled = fEnabled; - - IN_WRITE_END + + if (m_pInotify != NULL) + { + if (fEnabled) + { + m_wd = inotify_add_watch(m_pInotify->GetDescriptor(), m_path.c_str(), m_uMask); + if (m_wd == -1) + { + IN_WRITE_END_NOTHROW + throw InotifyException(IN_EXC_MSG("enabling watch failed"), errno, this); + } + m_pInotify->m_watches.insert(IN_WATCH_MAP::value_type(m_wd, this)); + } + else + { + if (inotify_rm_watch(m_pInotify->GetDescriptor(), m_wd) != 0) + { + IN_WRITE_END_NOTHROW + throw InotifyException(IN_EXC_MSG("disabling watch failed"), errno, this); + } + m_pInotify->m_watches.erase(m_wd); + m_wd = -1; + } + } + + m_fEnabled = fEnabled; + + IN_WRITE_END } void InotifyWatch::__Disable() { - IN_WRITE_BEGIN - - if (!m_fEnabled) { - IN_WRITE_END_NOTHROW - throw InotifyException(IN_EXC_MSG("event cannot occur on disabled watch"), EINVAL, this); - } - - if (m_pInotify != NULL) { - m_pInotify->m_watches.erase(m_wd); - m_wd = -1; - } - - m_fEnabled = false; - - IN_WRITE_END + IN_WRITE_BEGIN + + if (!m_fEnabled) + { + IN_WRITE_END_NOTHROW + throw InotifyException(IN_EXC_MSG("event cannot occur on disabled watch"), EINVAL, this); + } + + if (m_pInotify != NULL) + { + m_pInotify->m_watches.erase(m_wd); + m_wd = -1; + } + + m_fEnabled = false; + + IN_WRITE_END } Inotify::Inotify() throw (InotifyException) { - IN_LOCK_INIT - - m_fd = inotify_init(); - if (m_fd == -1) { - IN_LOCK_DONE - throw InotifyException(IN_EXC_MSG("inotify init failed"), errno, NULL); - } + IN_LOCK_INIT + + m_fd = inotify_init(); + if (m_fd == -1) + { + IN_LOCK_DONE + throw InotifyException(IN_EXC_MSG("inotify init failed"), errno, NULL); + } } - + Inotify::~Inotify() { - Close(); - - IN_LOCK_DONE + Close(); + + IN_LOCK_DONE } void Inotify::Close() { - IN_WRITE_BEGIN - - if (m_fd != -1) { - RemoveAll(); - close(m_fd); - m_fd = -1; - } - - IN_WRITE_END + IN_WRITE_BEGIN + + if (m_fd != -1) + { + RemoveAll(); + close(m_fd); + m_fd = -1; + } + + IN_WRITE_END } void Inotify::Add(InotifyWatch* pWatch) throw (InotifyException) { - IN_WRITE_BEGIN - - // invalid descriptor - this case shouldn't occur - go away - if (m_fd == -1) { - IN_WRITE_END_NOTHROW - throw InotifyException(IN_EXC_MSG("invalid file descriptor"), EBUSY, this); - } - - // this path already watched - go away - if (FindWatch(pWatch->GetPath()) != NULL) { - IN_WRITE_END_NOTHROW - throw InotifyException(IN_EXC_MSG("path already watched"), EBUSY, this); - } - - // for enabled watch - if (pWatch->IsEnabled()) { - - // try to add watch to kernel - int wd = inotify_add_watch(m_fd, pWatch->GetPath().c_str(), pWatch->GetMask()); - - // adding failed - go away - if (wd == -1) { - IN_WRITE_END_NOTHROW - throw InotifyException(IN_EXC_MSG("adding watch failed"), errno, this); - } - - // this path already watched (but defined another way) - InotifyWatch* pW = FindWatch(wd); - if (pW != NULL) { - - // try to recover old watch because it may be modified - then go away - if (inotify_add_watch(m_fd, pW->GetPath().c_str(), pW->GetMask()) < 0) { + IN_WRITE_BEGIN + + // invalid descriptor - this case shouldn't occur - go away + if (m_fd == -1) + { IN_WRITE_END_NOTHROW - throw InotifyException(IN_EXC_MSG("watch collision detected and recovery failed"), errno, this); - } - else { - // recovery failed - go away + throw InotifyException(IN_EXC_MSG("invalid file descriptor"), EBUSY, this); + } + + // this path already watched - go away + if (FindWatch(pWatch->GetPath()) != NULL) + { IN_WRITE_END_NOTHROW - throw InotifyException(IN_EXC_MSG("path already watched (but defined another way)"), EBUSY, this); - } - } - - pWatch->m_wd = wd; - m_watches.insert(IN_WATCH_MAP::value_type(pWatch->m_wd, pWatch)); - } - - m_paths.insert(IN_WP_MAP::value_type(pWatch->m_path, pWatch)); - pWatch->m_pInotify = this; - - IN_WRITE_END + throw InotifyException(IN_EXC_MSG("path already watched"), EBUSY, this); + } + + // for enabled watch + if (pWatch->IsEnabled()) + { + + // try to add watch to kernel + int wd = inotify_add_watch(m_fd, pWatch->GetPath().c_str(), pWatch->GetMask()); + + // adding failed - go away + if (wd == -1) + { + IN_WRITE_END_NOTHROW + throw InotifyException(IN_EXC_MSG("adding watch failed"), errno, this); + } + + // this path already watched (but defined another way) + InotifyWatch* pW = FindWatch(wd); + if (pW != NULL) + { + + // try to recover old watch because it may be modified - then go away + if (inotify_add_watch(m_fd, pW->GetPath().c_str(), pW->GetMask()) < 0) + { + IN_WRITE_END_NOTHROW + throw InotifyException(IN_EXC_MSG("watch collision detected and recovery failed"), errno, this); + } + else + { + // recovery failed - go away + IN_WRITE_END_NOTHROW + throw InotifyException(IN_EXC_MSG("path already watched (but defined another way)"), EBUSY, this); + } + } + + pWatch->m_wd = wd; + m_watches.insert(IN_WATCH_MAP::value_type(pWatch->m_wd, pWatch)); + } + + m_paths.insert(IN_WP_MAP::value_type(pWatch->m_path, pWatch)); + pWatch->m_pInotify = this; + + IN_WRITE_END } void Inotify::Remove(InotifyWatch* pWatch) throw (InotifyException) { - IN_WRITE_BEGIN - - // invalid descriptor - this case shouldn't occur - go away - if (m_fd == -1) { - IN_WRITE_END_NOTHROW - throw InotifyException(IN_EXC_MSG("invalid file descriptor"), EBUSY, this); - } - - // for enabled watch - if (pWatch->m_wd != -1) { - - // removing watch failed - go away - if (inotify_rm_watch(m_fd, pWatch->m_wd) == -1) { - IN_WRITE_END_NOTHROW - throw InotifyException(IN_EXC_MSG("removing watch failed"), errno, this); - } - m_watches.erase(pWatch->m_wd); - pWatch->m_wd = -1; - } - - m_paths.erase(pWatch->m_path); - pWatch->m_pInotify = NULL; - - IN_WRITE_END + IN_WRITE_BEGIN + + // invalid descriptor - this case shouldn't occur - go away + if (m_fd == -1) + { + IN_WRITE_END_NOTHROW + throw InotifyException(IN_EXC_MSG("invalid file descriptor"), EBUSY, this); + } + + // for enabled watch + if (pWatch->m_wd != -1) + { + + // removing watch failed - go away + if (inotify_rm_watch(m_fd, pWatch->m_wd) == -1) + { + IN_WRITE_END_NOTHROW + throw InotifyException(IN_EXC_MSG("removing watch failed"), errno, this); + } + m_watches.erase(pWatch->m_wd); + pWatch->m_wd = -1; + } + + m_paths.erase(pWatch->m_path); + pWatch->m_pInotify = NULL; + + IN_WRITE_END } void Inotify::RemoveAll() { - IN_WRITE_BEGIN - - IN_WP_MAP::iterator it = m_paths.begin(); - while (it != m_paths.end()) { - InotifyWatch* pW = (*it).second; - if (pW->m_wd != -1) { - inotify_rm_watch(m_fd, pW->m_wd); - pW->m_wd = -1; - } - pW->m_pInotify = NULL; - it++; - } - - m_watches.clear(); - m_paths.clear(); - - IN_WRITE_END + IN_WRITE_BEGIN + + IN_WP_MAP::iterator it = m_paths.begin(); + while (it != m_paths.end()) + { + InotifyWatch* pW = (*it).second; + if (pW->m_wd != -1) + { + inotify_rm_watch(m_fd, pW->m_wd); + pW->m_wd = -1; + } + pW->m_pInotify = NULL; + it++; + } + + m_watches.clear(); + m_paths.clear(); + + IN_WRITE_END } void Inotify::WaitForEvents(bool fNoIntr) throw (InotifyException) { - ssize_t len = 0; - - do { - len = read(m_fd, m_buf, INOTIFY_BUFLEN); - } while (fNoIntr && len == -1 && errno == EINTR); - - if (len == -1 && !(errno == EWOULDBLOCK || errno == EINTR)) - throw InotifyException(IN_EXC_MSG("reading events failed"), errno, this); - - if (len == -1) - return; - - IN_WRITE_BEGIN - - ssize_t i = 0; - while (i < len) { - struct inotify_event* pEvt = (struct inotify_event*) &m_buf[i]; - InotifyWatch* pW = FindWatch(pEvt->wd); - if (pW != NULL) { - InotifyEvent evt(pEvt, pW); - if ( InotifyEvent::IsType(pW->GetMask(), IN_ONESHOT) - || InotifyEvent::IsType(evt.GetMask(), IN_IGNORED)) - pW->__Disable(); - m_events.push_back(evt); - } - i += INOTIFY_EVENT_SIZE + (ssize_t) pEvt->len; - } - - IN_WRITE_END + ssize_t len = 0; + + do + { + len = read(m_fd, m_buf, INOTIFY_BUFLEN); + } + while (fNoIntr && len == -1 && errno == EINTR); + + if (len == -1 && !(errno == EWOULDBLOCK || errno == EINTR)) + throw InotifyException(IN_EXC_MSG("reading events failed"), errno, this); + + if (len == -1) + return; + + IN_WRITE_BEGIN + + ssize_t i = 0; + while (i < len) + { + struct inotify_event* pEvt = (struct inotify_event*) &m_buf[i]; + InotifyWatch* pW = FindWatch(pEvt->wd); + if (pW != NULL) + { + InotifyEvent evt(pEvt, pW); + if ( InotifyEvent::IsType(pW->GetMask(), IN_ONESHOT) + || InotifyEvent::IsType(evt.GetMask(), IN_IGNORED)) + pW->__Disable(); + m_events.push_back(evt); + } + i += INOTIFY_EVENT_SIZE + (ssize_t) pEvt->len; + } + + IN_WRITE_END } - + bool Inotify::GetEvent(InotifyEvent* pEvt) throw (InotifyException) { - if (pEvt == NULL) - throw InotifyException(IN_EXC_MSG("null pointer to event"), EINVAL, this); - - IN_WRITE_BEGIN - - bool b = !m_events.empty(); - if (b) { - *pEvt = m_events.front(); - m_events.pop_front(); - } - - IN_WRITE_END - - return b; + if (pEvt == NULL) + throw InotifyException(IN_EXC_MSG("null pointer to event"), EINVAL, this); + + IN_WRITE_BEGIN + + bool b = !m_events.empty(); + if (b) + { + *pEvt = m_events.front(); + m_events.pop_front(); + } + + IN_WRITE_END + + return b; } - + bool Inotify::PeekEvent(InotifyEvent* pEvt) throw (InotifyException) { - if (pEvt == NULL) - throw InotifyException(IN_EXC_MSG("null pointer to event"), EINVAL, this); - - IN_READ_BEGIN - - bool b = !m_events.empty(); - if (b) { - *pEvt = m_events.front(); - } - - IN_READ_END - - return b; + if (pEvt == NULL) + throw InotifyException(IN_EXC_MSG("null pointer to event"), EINVAL, this); + + IN_READ_BEGIN + + bool b = !m_events.empty(); + if (b) + { + *pEvt = m_events.front(); + } + + IN_READ_END + + return b; } InotifyWatch* Inotify::FindWatch(int iDescriptor) { - IN_READ_BEGIN - - IN_WATCH_MAP::iterator it = m_watches.find(iDescriptor); - InotifyWatch* pW = it == m_watches.end() ? NULL : (*it).second; - - IN_READ_END - - return pW; + IN_READ_BEGIN + + IN_WATCH_MAP::iterator it = m_watches.find(iDescriptor); + InotifyWatch* pW = it == m_watches.end() ? NULL : (*it).second; + + IN_READ_END + + return pW; } InotifyWatch* Inotify::FindWatch(const std::string& rPath) { - IN_READ_BEGIN - - IN_WP_MAP::iterator it = m_paths.find(rPath); - InotifyWatch* pW = it == m_paths.end() ? NULL : (*it).second; - - IN_READ_END - - return pW; + IN_READ_BEGIN + + IN_WP_MAP::iterator it = m_paths.find(rPath); + InotifyWatch* pW = it == m_paths.end() ? NULL : (*it).second; + + IN_READ_END + + return pW; } - + void Inotify::SetNonBlock(bool fNonBlock) throw (InotifyException) { - IN_WRITE_BEGIN - - if (m_fd == -1) { - IN_WRITE_END_NOTHROW - throw InotifyException(IN_EXC_MSG("invalid file descriptor"), EBUSY, this); - } - - int res = fcntl(m_fd, F_GETFL); - if (res == -1) { - IN_WRITE_END_NOTHROW - throw InotifyException(IN_EXC_MSG("cannot get inotify flags"), errno, this); - } - - if (fNonBlock) { - res |= O_NONBLOCK; - } - else { - res &= ~O_NONBLOCK; - } - - if (fcntl(m_fd, F_SETFL, res) == -1) { - IN_WRITE_END_NOTHROW - throw InotifyException(IN_EXC_MSG("cannot set inotify flags"), errno, this); - } - - IN_WRITE_END + IN_WRITE_BEGIN + + if (m_fd == -1) + { + IN_WRITE_END_NOTHROW + throw InotifyException(IN_EXC_MSG("invalid file descriptor"), EBUSY, this); + } + + int res = fcntl(m_fd, F_GETFL); + if (res == -1) + { + IN_WRITE_END_NOTHROW + throw InotifyException(IN_EXC_MSG("cannot get inotify flags"), errno, this); + } + + if (fNonBlock) + { + res |= O_NONBLOCK; + } + else + { + res &= ~O_NONBLOCK; + } + + if (fcntl(m_fd, F_SETFL, res) == -1) + { + IN_WRITE_END_NOTHROW + throw InotifyException(IN_EXC_MSG("cannot set inotify flags"), errno, this); + } + + IN_WRITE_END } void Inotify::SetCloseOnExec(bool fClOnEx) throw (InotifyException) { - IN_WRITE_BEGIN - - if (m_fd == -1) { - IN_WRITE_END_NOTHROW - throw InotifyException(IN_EXC_MSG("invalid file descriptor"), EBUSY, this); - } - - int res = fcntl(m_fd, F_GETFD); - if (res == -1) { - IN_WRITE_END_NOTHROW - throw InotifyException(IN_EXC_MSG("cannot get inotify flags"), errno, this); - } - - if (fClOnEx) { - res |= FD_CLOEXEC; - } - else { - res &= ~FD_CLOEXEC; - } - - if (fcntl(m_fd, F_SETFD, res) == -1) { - IN_WRITE_END_NOTHROW - throw InotifyException(IN_EXC_MSG("cannot set inotify flags"), errno, this); - } - - IN_WRITE_END + IN_WRITE_BEGIN + + if (m_fd == -1) + { + IN_WRITE_END_NOTHROW + throw InotifyException(IN_EXC_MSG("invalid file descriptor"), EBUSY, this); + } + + int res = fcntl(m_fd, F_GETFD); + if (res == -1) + { + IN_WRITE_END_NOTHROW + throw InotifyException(IN_EXC_MSG("cannot get inotify flags"), errno, this); + } + + if (fClOnEx) + { + res |= FD_CLOEXEC; + } + else + { + res &= ~FD_CLOEXEC; + } + + if (fcntl(m_fd, F_SETFD, res) == -1) + { + IN_WRITE_END_NOTHROW + throw InotifyException(IN_EXC_MSG("cannot set inotify flags"), errno, this); + } + + IN_WRITE_END } uint32_t Inotify::GetCapability(InotifyCapability_t cap) throw (InotifyException) { - FILE* f = fopen(GetCapabilityPath(cap).c_str(), "r"); - if (f == NULL) - throw InotifyException(IN_EXC_MSG("cannot get capability"), errno, NULL); - - unsigned int val = 0; - if (fscanf(f, "%u", &val) != 1) { + FILE* f = fopen(GetCapabilityPath(cap).c_str(), "r"); + if (f == NULL) + throw InotifyException(IN_EXC_MSG("cannot get capability"), errno, NULL); + + unsigned int val = 0; + if (fscanf(f, "%u", &val) != 1) + { + fclose(f); + throw InotifyException(IN_EXC_MSG("cannot get capability"), EIO, NULL); + } + fclose(f); - throw InotifyException(IN_EXC_MSG("cannot get capability"), EIO, NULL); - } - - fclose(f); - - return (uint32_t) val; + + return (uint32_t) val; } void Inotify::SetCapability(InotifyCapability_t cap, uint32_t val) throw (InotifyException) { - FILE* f = fopen(GetCapabilityPath(cap).c_str(), "w"); - if (f == NULL) - throw InotifyException(IN_EXC_MSG("cannot set capability"), errno, NULL); - - if (fprintf(f, "%u", (unsigned int) val) <= 0) { + FILE* f = fopen(GetCapabilityPath(cap).c_str(), "w"); + if (f == NULL) + throw InotifyException(IN_EXC_MSG("cannot set capability"), errno, NULL); + + if (fprintf(f, "%u", (unsigned int) val) <= 0) + { + fclose(f); + throw InotifyException(IN_EXC_MSG("cannot set capability"), EIO, NULL); + } + fclose(f); - throw InotifyException(IN_EXC_MSG("cannot set capability"), EIO, NULL); - } - - fclose(f); } std::string Inotify::GetCapabilityPath(InotifyCapability_t cap) throw (InotifyException) { - std::string path(PROCFS_INOTIFY_BASE); - - switch (cap) { - case IN_MAX_EVENTS: - path.append("max_queued_events"); - break; - case IN_MAX_INSTANCES: - path.append("max_user_instances"); - break; - case IN_MAX_WATCHES: - path.append("max_user_watches"); - break; - default: - throw InotifyException(IN_EXC_MSG("unknown capability type"), EINVAL, NULL); - } - - return path; + std::string path(PROCFS_INOTIFY_BASE); + + switch (cap) + { + case IN_MAX_EVENTS: + path.append("max_queued_events"); + break; + case IN_MAX_INSTANCES: + path.append("max_user_instances"); + break; + case IN_MAX_WATCHES: + path.append("max_user_watches"); + break; + default: + throw InotifyException(IN_EXC_MSG("unknown capability type"), EINVAL, NULL); + } + + return path; } diff --git a/shared/inotify/inotify-cxx.h b/shared/inotify/inotify-cxx.h index 34ae2212..2fb00fc8 100644 --- a/shared/inotify/inotify-cxx.h +++ b/shared/inotify/inotify-cxx.h @@ -2,11 +2,11 @@ /// inotify C++ interface header /** * \file inotify-cxx.h - * + * * inotify C++ interface - * + * * Copyright (C) 2006, 2007, 2009 Lukas Jelinek, - * + * * This program is free software; you can redistribute it and/or * modify it under the terms of one of the following licenses: * @@ -50,12 +50,12 @@ */ #define IN_EXC_MSG(msg) (std::string(__PRETTY_FUNCTION__) + ": " + msg) -/// inotify capability/limit identifiers +/// inotify capability/limit identifiers typedef enum { - IN_MAX_EVENTS = 0, ///< max. events in the kernel queue - IN_MAX_INSTANCES = 1, ///< max. inotify file descriptors per process - IN_MAX_WATCHES = 2 ///< max. watches per file descriptor + IN_MAX_EVENTS = 0, ///< max. events in the kernel queue + IN_MAX_INSTANCES = 1, ///< max. inotify file descriptors per process + IN_MAX_WATCHES = 2 ///< max. watches per file descriptor } InotifyCapability_t; /// inotify-cxx thread safety @@ -63,16 +63,16 @@ typedef enum * If this symbol is defined you can use this interface safely * threaded applications. Remember that it slightly degrades * performance. - * + * * Even if INOTIFY_THREAD_SAFE is defined some classes stay * unsafe. If you must use them (must you?) in more than one * thread concurrently you need to implement explicite locking. - * + * * You need not to define INOTIFY_THREAD_SAFE in that cases * where the application is multithreaded but all the inotify * infrastructure will be managed only in one thread. This is * the recommended way. - * + * * Locking may fail (it is very rare but not impossible). In this * case an exception is thrown. But if unlocking fails in case * of an error it does nothing (this failure is ignored). @@ -95,7 +95,7 @@ typedef enum throw InotifyException(IN_EXC_MSG("cannot initialize lock"), res, this); \ pthread_rwlockattr_destroy(&attr); \ } - + #define IN_LOCK_DONE pthread_rwlock_destroy(&__m_lock); #define IN_READ_BEGIN \ @@ -104,23 +104,23 @@ typedef enum if (res != 0) \ throw InotifyException(IN_EXC_MSG("locking for reading failed"), res, (void*) this); \ } - + #define IN_READ_END \ { \ int res = pthread_rwlock_unlock(&__m_lock); \ if (res != 0) \ throw InotifyException(IN_EXC_MSG("unlocking failed"), res, (void*) this); \ } - + #define IN_READ_END_NOTHROW pthread_rwlock_unlock(&__m_lock); - + #define IN_WRITE_BEGIN \ { \ int res = pthread_rwlock_wrlock(&__m_lock); \ if (res != 0) \ throw InotifyException(IN_EXC_MSG("locking for writing failed"), res, (void*) this); \ } - + #define IN_WRITE_END IN_READ_END #define IN_WRITE_END_NOTHROW IN_READ_END_NOTHROW @@ -151,59 +151,59 @@ class Inotify; * This class allows to acquire information about exceptional * events. It makes easier to log or display error messages * and to identify problematic code locations. - * + * * Although this class is basically thread-safe it is not intended * to be shared between threads. */ class InotifyException { public: - /// Constructor - /** - * \param[in] rMsg message - * \param[in] iErr error number (see errno.h) - * \param[in] pSrc source - */ - InotifyException(const std::string& rMsg = "", int iErr = 0, void* pSrc = NULL) - : m_msg(rMsg), - m_err(iErr) - { - m_pSrc = pSrc; - } - - /// Returns the exception message. - /** - * \return message - */ - inline const std::string& GetMessage() const - { - return m_msg; - } - - /// Returns the exception error number. - /** - * If not applicable this value is 0 (zero). - * - * \return error number (standardized; see errno.h) - */ - inline int GetErrorNumber() const - { - return m_err; - } - - /// Returns the exception source. - /** - * \return source - */ - inline void* GetSource() const - { - return m_pSrc; - } + /// Constructor + /** + * \param[in] rMsg message + * \param[in] iErr error number (see errno.h) + * \param[in] pSrc source + */ + InotifyException(const std::string& rMsg = "", int iErr = 0, void* pSrc = NULL) + : m_msg(rMsg), + m_err(iErr) + { + m_pSrc = pSrc; + } + + /// Returns the exception message. + /** + * \return message + */ + inline const std::string& GetMessage() const + { + return m_msg; + } + + /// Returns the exception error number. + /** + * If not applicable this value is 0 (zero). + * + * \return error number (standardized; see errno.h) + */ + inline int GetErrorNumber() const + { + return m_err; + } + + /// Returns the exception source. + /** + * \return source + */ + inline void* GetSource() const + { + return m_pSrc; + } protected: - std::string m_msg; ///< message - int m_err; ///< error number - mutable void* m_pSrc; ///< source + std::string m_msg; ///< message + int m_err; ///< error number + mutable void* m_pSrc; ///< source }; @@ -211,7 +211,7 @@ protected: /** * It holds all information about inotify event and provides * access to its particular values. - * + * * This class is not (and is not intended to be) thread-safe * and therefore it must not be used concurrently in multiple * threads. @@ -219,157 +219,160 @@ protected: class InotifyEvent { public: - /// Constructor. - /** - * Creates a plain event. - */ - InotifyEvent() - : m_uMask(0), - m_uCookie(0) - { - m_pWatch = NULL; - } - - /// Constructor. - /** - * Creates an event based on inotify event data. - * For NULL pointers it works the same way as InotifyEvent(). - * - * \param[in] pEvt event data - * \param[in] pWatch inotify watch - */ - InotifyEvent(const struct inotify_event* pEvt, InotifyWatch* pWatch) - : m_uMask(0), - m_uCookie(0) - { - if (pEvt != NULL) { - m_uMask = (uint32_t) pEvt->mask; - m_uCookie = (uint32_t) pEvt->cookie; - if (pEvt->name != NULL) { - m_name = pEvt->len > 0 - ? pEvt->name - : ""; - } - m_pWatch = pWatch; - } - else { - m_pWatch = NULL; + /// Constructor. + /** + * Creates a plain event. + */ + InotifyEvent() + : m_uMask(0), + m_uCookie(0) + { + m_pWatch = NULL; } - } - - /// Destructor. - ~InotifyEvent() {} - - /// Returns the event watch descriptor. - /** - * \return watch descriptor - * - * \sa InotifyWatch::GetDescriptor() - */ - int32_t GetDescriptor() const; - - /// Returns the event mask. - /** - * \return event mask - * - * \sa InotifyWatch::GetMask() - */ - inline uint32_t GetMask() const - { - return m_uMask; - } - - /// Checks a value for the event type. - /** - * \param[in] uValue checked value - * \param[in] uType type which is checked for - * \return true = the value contains the given type, false = otherwise - */ - inline static bool IsType(uint32_t uValue, uint32_t uType) - { - return ((uValue & uType) != 0) && ((~uValue & uType) == 0); - } - - /// Checks for the event type. - /** - * \param[in] uType type which is checked for - * \return true = event mask contains the given type, false = otherwise - */ - inline bool IsType(uint32_t uType) const - { - return IsType(m_uMask, uType); - } - - /// Returns the event cookie. - /** - * \return event cookie - */ - inline uint32_t GetCookie() const - { - return m_uCookie; - } - - /// Returns the event name length. - /** - * \return event name length - */ - inline uint32_t GetLength() const - { - return (uint32_t) m_name.length(); - } - - /// Returns the event name. - /** - * \return event name - */ - inline const std::string& GetName() const - { - return m_name; - } - - /// Extracts the event name. - /** - * \param[out] rName event name - */ - inline void GetName(std::string& rName) const - { - rName = GetName(); - } - - /// Returns the source watch. - /** - * \return source watch - */ - inline InotifyWatch* GetWatch() - { - return m_pWatch; - } - - /// Finds the appropriate mask for a name. - /** - * \param[in] rName mask name - * \return mask for name; 0 on failure - */ - static uint32_t GetMaskByName(const std::string& rName); - - /// Fills the string with all types contained in an event mask value. - /** - * \param[in] uValue event mask value - * \param[out] rStr dumped event types - */ - static void DumpTypes(uint32_t uValue, std::string& rStr); - - /// Fills the string with all types contained in the event mask. - /** - * \param[out] rStr dumped event types - */ - void DumpTypes(std::string& rStr) const; - + + /// Constructor. + /** + * Creates an event based on inotify event data. + * For NULL pointers it works the same way as InotifyEvent(). + * + * \param[in] pEvt event data + * \param[in] pWatch inotify watch + */ + InotifyEvent(const struct inotify_event* pEvt, InotifyWatch* pWatch) + : m_uMask(0), + m_uCookie(0) + { + if (pEvt != NULL) + { + m_uMask = (uint32_t) pEvt->mask; + m_uCookie = (uint32_t) pEvt->cookie; + if (pEvt->name != NULL) + { + m_name = pEvt->len > 0 + ? pEvt->name + : ""; + } + m_pWatch = pWatch; + } + else + { + m_pWatch = NULL; + } + } + + /// Destructor. + ~InotifyEvent() {} + + /// Returns the event watch descriptor. + /** + * \return watch descriptor + * + * \sa InotifyWatch::GetDescriptor() + */ + int32_t GetDescriptor() const; + + /// Returns the event mask. + /** + * \return event mask + * + * \sa InotifyWatch::GetMask() + */ + inline uint32_t GetMask() const + { + return m_uMask; + } + + /// Checks a value for the event type. + /** + * \param[in] uValue checked value + * \param[in] uType type which is checked for + * \return true = the value contains the given type, false = otherwise + */ + inline static bool IsType(uint32_t uValue, uint32_t uType) + { + return ((uValue & uType) != 0) && ((~uValue & uType) == 0); + } + + /// Checks for the event type. + /** + * \param[in] uType type which is checked for + * \return true = event mask contains the given type, false = otherwise + */ + inline bool IsType(uint32_t uType) const + { + return IsType(m_uMask, uType); + } + + /// Returns the event cookie. + /** + * \return event cookie + */ + inline uint32_t GetCookie() const + { + return m_uCookie; + } + + /// Returns the event name length. + /** + * \return event name length + */ + inline uint32_t GetLength() const + { + return (uint32_t) m_name.length(); + } + + /// Returns the event name. + /** + * \return event name + */ + inline const std::string& GetName() const + { + return m_name; + } + + /// Extracts the event name. + /** + * \param[out] rName event name + */ + inline void GetName(std::string& rName) const + { + rName = GetName(); + } + + /// Returns the source watch. + /** + * \return source watch + */ + inline InotifyWatch* GetWatch() + { + return m_pWatch; + } + + /// Finds the appropriate mask for a name. + /** + * \param[in] rName mask name + * \return mask for name; 0 on failure + */ + static uint32_t GetMaskByName(const std::string& rName); + + /// Fills the string with all types contained in an event mask value. + /** + * \param[in] uValue event mask value + * \param[out] rStr dumped event types + */ + static void DumpTypes(uint32_t uValue, std::string& rStr); + + /// Fills the string with all types contained in the event mask. + /** + * \param[out] rStr dumped event types + */ + void DumpTypes(std::string& rStr) const; + private: - uint32_t m_uMask; ///< mask - uint32_t m_uCookie; ///< cookie - std::string m_name; ///< name - InotifyWatch* m_pWatch; ///< source watch + uint32_t m_uMask; ///< mask + uint32_t m_uCookie; ///< cookie + std::string m_name; ///< name + InotifyWatch* m_pWatch; ///< source watch }; @@ -378,140 +381,140 @@ private: /** * It holds information about the inotify watch on a particular * inode. - * + * * If the INOTIFY_THREAD_SAFE is defined this class is thread-safe. */ class InotifyWatch { public: - /// Constructor. - /** - * Creates an inotify watch. Because this watch is - * inactive it has an invalid descriptor (-1). - * - * \param[in] rPath watched file path - * \param[in] uMask mask for events - * \param[in] fEnabled events enabled yes/no - */ - InotifyWatch(const std::string& rPath, int32_t uMask, bool fEnabled = true) - : m_path(rPath), - m_uMask(uMask), - m_wd((int32_t) -1), - m_fEnabled(fEnabled) - { - IN_LOCK_INIT - } - - /// Destructor. - ~InotifyWatch() - { - IN_LOCK_DONE - } - - /// Returns the watch descriptor. - /** - * \return watch descriptor; -1 for inactive watch - */ - inline int32_t GetDescriptor() const - { - return m_wd; - } - - /// Returns the watched file path. - /** - * \return file path - */ - inline const std::string& GetPath() const - { - return m_path; - } - - /// Returns the watch event mask. - /** - * \return event mask - */ - inline uint32_t GetMask() const - { - return (uint32_t) m_uMask; - } - - /// Sets the watch event mask. - /** - * If the watch is active (added to an instance of Inotify) - * this method may fail due to unsuccessful re-setting - * the watch in the kernel. - * - * \param[in] uMask event mask - * - * \throw InotifyException thrown if changing fails - */ - void SetMask(uint32_t uMask) throw (InotifyException); - - /// Returns the appropriate inotify class instance. - /** - * \return inotify instance - */ - inline Inotify* GetInotify() - { - return m_pInotify; - } - - /// Enables/disables the watch. - /** - * If the watch is active (added to an instance of Inotify) - * this method may fail due to unsuccessful re-setting - * the watch in the kernel. - * - * Re-setting the current state has no effect. - * - * \param[in] fEnabled set enabled yes/no - * - * \throw InotifyException thrown if enabling/disabling fails - */ - void SetEnabled(bool fEnabled) throw (InotifyException); - - /// Checks whether the watch is enabled. - /** - * \return true = enables, false = disabled - */ - inline bool IsEnabled() const - { - return m_fEnabled; - } - - /// Checks whether the watch is recursive. - /** - * A recursive watch monitors a directory itself and all - * its subdirectories. This watch is a logical object - * which may have many underlying kernel watches. - * - * \return currently always false (recursive watches not yet supported) - * \attention Recursive watches are currently NOT supported. - * They are planned for future versions. - */ - inline bool IsRecursive() const - { - return false; - } - + /// Constructor. + /** + * Creates an inotify watch. Because this watch is + * inactive it has an invalid descriptor (-1). + * + * \param[in] rPath watched file path + * \param[in] uMask mask for events + * \param[in] fEnabled events enabled yes/no + */ + InotifyWatch(const std::string& rPath, int32_t uMask, bool fEnabled = true) + : m_path(rPath), + m_uMask(uMask), + m_wd((int32_t) -1), + m_fEnabled(fEnabled) + { + IN_LOCK_INIT + } + + /// Destructor. + ~InotifyWatch() + { + IN_LOCK_DONE + } + + /// Returns the watch descriptor. + /** + * \return watch descriptor; -1 for inactive watch + */ + inline int32_t GetDescriptor() const + { + return m_wd; + } + + /// Returns the watched file path. + /** + * \return file path + */ + inline const std::string& GetPath() const + { + return m_path; + } + + /// Returns the watch event mask. + /** + * \return event mask + */ + inline uint32_t GetMask() const + { + return (uint32_t) m_uMask; + } + + /// Sets the watch event mask. + /** + * If the watch is active (added to an instance of Inotify) + * this method may fail due to unsuccessful re-setting + * the watch in the kernel. + * + * \param[in] uMask event mask + * + * \throw InotifyException thrown if changing fails + */ + void SetMask(uint32_t uMask) throw (InotifyException); + + /// Returns the appropriate inotify class instance. + /** + * \return inotify instance + */ + inline Inotify* GetInotify() + { + return m_pInotify; + } + + /// Enables/disables the watch. + /** + * If the watch is active (added to an instance of Inotify) + * this method may fail due to unsuccessful re-setting + * the watch in the kernel. + * + * Re-setting the current state has no effect. + * + * \param[in] fEnabled set enabled yes/no + * + * \throw InotifyException thrown if enabling/disabling fails + */ + void SetEnabled(bool fEnabled) throw (InotifyException); + + /// Checks whether the watch is enabled. + /** + * \return true = enables, false = disabled + */ + inline bool IsEnabled() const + { + return m_fEnabled; + } + + /// Checks whether the watch is recursive. + /** + * A recursive watch monitors a directory itself and all + * its subdirectories. This watch is a logical object + * which may have many underlying kernel watches. + * + * \return currently always false (recursive watches not yet supported) + * \attention Recursive watches are currently NOT supported. + * They are planned for future versions. + */ + inline bool IsRecursive() const + { + return false; + } + private: - friend class Inotify; - - std::string m_path; ///< watched file path - uint32_t m_uMask; ///< event mask - int32_t m_wd; ///< watch descriptor - Inotify* m_pInotify; ///< inotify object - bool m_fEnabled; ///< events enabled yes/no - - IN_LOCK_DECL - - /// Disables the watch (due to removing by the kernel). - /** - * This method must be called after receiving an event. - * It ensures the watch object is consistent with the kernel - * data. - */ - void __Disable(); + friend class Inotify; + + std::string m_path; ///< watched file path + uint32_t m_uMask; ///< event mask + int32_t m_wd; ///< watch descriptor + Inotify* m_pInotify; ///< inotify object + bool m_fEnabled; ///< events enabled yes/no + + IN_LOCK_DECL + + /// Disables the watch (due to removing by the kernel). + /** + * This method must be called after receiving an event. + * It ensures the watch object is consistent with the kernel + * data. + */ + void __Disable(); }; @@ -526,360 +529,360 @@ typedef std::map IN_WP_MAP; /** * It holds information about the inotify device descriptor * and manages the event queue. - * + * * If the INOTIFY_THREAD_SAFE is defined this class is thread-safe. */ class Inotify { public: - /// Constructor. - /** - * Creates and initializes an instance of inotify communication - * object (opens the inotify device). - * - * \throw InotifyException thrown if inotify isn't available - */ - Inotify() throw (InotifyException); - - /// Destructor. - /** - * Calls Close() due to clean-up. - */ - ~Inotify(); - - /// Removes all watches and closes the inotify device. - void Close(); - - /// Adds a new watch. - /** - * \param[in] pWatch inotify watch - * - * \throw InotifyException thrown if adding failed - */ - void Add(InotifyWatch* pWatch) throw (InotifyException); - - /// Adds a new watch. - /** - * \param[in] rWatch inotify watch - * - * \throw InotifyException thrown if adding failed - */ - inline void Add(InotifyWatch& rWatch) throw (InotifyException) - { - Add(&rWatch); - } - - /// Removes a watch. - /** - * If the given watch is not present it does nothing. - * - * \param[in] pWatch inotify watch - * - * \throw InotifyException thrown if removing failed - */ - void Remove(InotifyWatch* pWatch) throw (InotifyException); - - /// Removes a watch. - /** - * If the given watch is not present it does nothing. - * - * \param[in] rWatch inotify watch - * - * \throw InotifyException thrown if removing failed - */ - inline void Remove(InotifyWatch& rWatch) throw (InotifyException) - { - Remove(&rWatch); - } - - /// Removes all watches. - void RemoveAll(); - - /// Returns the count of watches. - /** - * This is the total count of all watches (regardless whether - * enabled or not). - * - * \return count of watches - * - * \sa GetEnabledCount() - */ - inline size_t GetWatchCount() const - { - IN_READ_BEGIN - size_t n = (size_t) m_paths.size(); - IN_READ_END - return n; - } - - /// Returns the count of enabled watches. - /** - * \return count of enabled watches - * - * \sa GetWatchCount() - */ - inline size_t GetEnabledCount() const - { - IN_READ_BEGIN - size_t n = (size_t) m_watches.size(); - IN_READ_END - return n; - } - - /// Waits for inotify events. - /** - * It waits until one or more events occur. When called - * in nonblocking mode it only retrieves occurred events - * to the internal queue and exits. - * - * \param[in] fNoIntr if true it re-calls the system call after a handled signal - * - * \throw InotifyException thrown if reading events failed - * - * \sa SetNonBlock() - */ - void WaitForEvents(bool fNoIntr = false) throw (InotifyException); - - /// Returns the count of received and queued events. - /** - * This number is related to the events in the queue inside - * this object, not to the events pending in the kernel. - * - * \return count of events - */ - inline size_t GetEventCount() - { - IN_READ_BEGIN - size_t n = (size_t) m_events.size(); - IN_READ_END - return n; - } - - /// Extracts a queued inotify event. - /** - * The extracted event is removed from the queue. - * If the pointer is NULL it does nothing. - * - * \param[in,out] pEvt event object - * - * \throw InotifyException thrown if the provided pointer is NULL - */ - bool GetEvent(InotifyEvent* pEvt) throw (InotifyException); - - /// Extracts a queued inotify event. - /** - * The extracted event is removed from the queue. - * - * \param[in,out] rEvt event object - * - * \throw InotifyException thrown only in very anomalous cases - */ - bool GetEvent(InotifyEvent& rEvt) throw (InotifyException) - { - return GetEvent(&rEvt); - } - - /// Extracts a queued inotify event (without removing). - /** - * The extracted event stays in the queue. - * If the pointer is NULL it does nothing. - * - * \param[in,out] pEvt event object - * - * \throw InotifyException thrown if the provided pointer is NULL - */ - bool PeekEvent(InotifyEvent* pEvt) throw (InotifyException); - - /// Extracts a queued inotify event (without removing). - /** - * The extracted event stays in the queue. - * - * \param[in,out] rEvt event object - * - * \throw InotifyException thrown only in very anomalous cases - */ - bool PeekEvent(InotifyEvent& rEvt) throw (InotifyException) - { - return PeekEvent(&rEvt); - } - - /// Searches for a watch by a watch descriptor. - /** - * It tries to find a watch by the given descriptor. - * - * \param[in] iDescriptor watch descriptor - * \return pointer to a watch; NULL if no such watch exists - */ - InotifyWatch* FindWatch(int iDescriptor); - - /// Searches for a watch by a filesystem path. - /** - * It tries to find a watch by the given filesystem path. - * - * \param[in] rPath filesystem path - * \return pointer to a watch; NULL if no such watch exists - * - * \attention The path must be exactly identical to the one - * used for the searched watch. Be careful about - * absolute/relative and case-insensitive paths. - */ - InotifyWatch* FindWatch(const std::string& rPath); - - /// Returns the file descriptor. - /** - * The descriptor can be used in standard low-level file - * functions (poll(), select(), fcntl() etc.). - * - * \return valid file descriptor or -1 for inactive object - * - * \sa SetNonBlock() - */ - inline int GetDescriptor() const - { - return m_fd; - } - - /// Enables/disables non-blocking mode. - /** - * Use this mode if you want to monitor the descriptor - * (acquired thru GetDescriptor()) in functions such as - * poll(), select() etc. - * - * Non-blocking mode is disabled by default. - * - * \param[in] fNonBlock enable/disable non-blocking mode - * - * \throw InotifyException thrown if setting mode failed - * - * \sa GetDescriptor(), SetCloseOnExec() - */ - void SetNonBlock(bool fNonBlock) throw (InotifyException); - - /// Enables/disables closing on exec. - /** - * Enable this if you want to close the descriptor when - * executing another program. Otherwise, the descriptor - * will be inherited. - * - * Closing on exec is disabled by default. - * - * \param[in] fClOnEx enable/disable closing on exec - * - * \throw InotifyException thrown if setting failed - * - * \sa GetDescriptor(), SetNonBlock() - */ - void SetCloseOnExec(bool fClOnEx) throw (InotifyException); - - /// Acquires a particular inotify capability/limit. - /** - * \param[in] cap capability/limit identifier - * \return capability/limit value - * \throw InotifyException thrown if the given value cannot be acquired - */ - static uint32_t GetCapability(InotifyCapability_t cap) throw (InotifyException); - - /// Modifies a particular inotify capability/limit. - /** - * \param[in] cap capability/limit identifier - * \param[in] val new capability/limit value - * \throw InotifyException thrown if the given value cannot be set - * \attention Using this function requires root privileges. - * Beware of setting extensive values - it may seriously - * affect system performance and/or stability. - */ - static void SetCapability(InotifyCapability_t cap, uint32_t val) throw (InotifyException); - - /// Returns the maximum number of events in the kernel queue. - /** - * \return maximum number of events in the kernel queue - * \throw InotifyException thrown if the given value cannot be acquired - */ - inline static uint32_t GetMaxEvents() throw (InotifyException) - { - return GetCapability(IN_MAX_EVENTS); - } - - /// Sets the maximum number of events in the kernel queue. - /** - * \param[in] val new value - * \throw InotifyException thrown if the given value cannot be set - * \attention Using this function requires root privileges. - * Beware of setting extensive values - the greater value - * is set here the more physical memory may be used for the inotify - * infrastructure. - */ - inline static void SetMaxEvents(uint32_t val) throw (InotifyException) - { - SetCapability(IN_MAX_EVENTS, val); - } - - /// Returns the maximum number of inotify instances per process. - /** - * It means the maximum number of open inotify file descriptors - * per running process. - * - * \return maximum number of inotify instances - * \throw InotifyException thrown if the given value cannot be acquired - */ - inline static uint32_t GetMaxInstances() throw (InotifyException) - { - return GetCapability(IN_MAX_INSTANCES); - } - - /// Sets the maximum number of inotify instances per process. - /** - * \param[in] val new value - * \throw InotifyException thrown if the given value cannot be set - * \attention Using this function requires root privileges. - * Beware of setting extensive values - the greater value - * is set here the more physical memory may be used for the inotify - * infrastructure. - */ - inline static void SetMaxInstances(uint32_t val) throw (InotifyException) - { - SetCapability(IN_MAX_INSTANCES, val); - } - - /// Returns the maximum number of inotify watches per instance. - /** - * It means the maximum number of inotify watches per inotify - * file descriptor. - * - * \return maximum number of inotify watches - * \throw InotifyException thrown if the given value cannot be acquired - */ - inline static uint32_t GetMaxWatches() throw (InotifyException) - { - return GetCapability(IN_MAX_WATCHES); - } - - /// Sets the maximum number of inotify watches per instance. - /** - * \param[in] val new value - * \throw InotifyException thrown if the given value cannot be set - * \attention Using this function requires root privileges. - * Beware of setting extensive values - the greater value - * is set here the more physical memory may be used for the inotify - * infrastructure. - */ - inline static void SetMaxWatches(uint32_t val) throw (InotifyException) - { - SetCapability(IN_MAX_WATCHES, val); - } + /// Constructor. + /** + * Creates and initializes an instance of inotify communication + * object (opens the inotify device). + * + * \throw InotifyException thrown if inotify isn't available + */ + Inotify() throw (InotifyException); + + /// Destructor. + /** + * Calls Close() due to clean-up. + */ + ~Inotify(); + + /// Removes all watches and closes the inotify device. + void Close(); + + /// Adds a new watch. + /** + * \param[in] pWatch inotify watch + * + * \throw InotifyException thrown if adding failed + */ + void Add(InotifyWatch* pWatch) throw (InotifyException); + + /// Adds a new watch. + /** + * \param[in] rWatch inotify watch + * + * \throw InotifyException thrown if adding failed + */ + inline void Add(InotifyWatch& rWatch) throw (InotifyException) + { + Add(&rWatch); + } + + /// Removes a watch. + /** + * If the given watch is not present it does nothing. + * + * \param[in] pWatch inotify watch + * + * \throw InotifyException thrown if removing failed + */ + void Remove(InotifyWatch* pWatch) throw (InotifyException); + + /// Removes a watch. + /** + * If the given watch is not present it does nothing. + * + * \param[in] rWatch inotify watch + * + * \throw InotifyException thrown if removing failed + */ + inline void Remove(InotifyWatch& rWatch) throw (InotifyException) + { + Remove(&rWatch); + } + + /// Removes all watches. + void RemoveAll(); + + /// Returns the count of watches. + /** + * This is the total count of all watches (regardless whether + * enabled or not). + * + * \return count of watches + * + * \sa GetEnabledCount() + */ + inline size_t GetWatchCount() const + { + IN_READ_BEGIN + size_t n = (size_t) m_paths.size(); + IN_READ_END + return n; + } + + /// Returns the count of enabled watches. + /** + * \return count of enabled watches + * + * \sa GetWatchCount() + */ + inline size_t GetEnabledCount() const + { + IN_READ_BEGIN + size_t n = (size_t) m_watches.size(); + IN_READ_END + return n; + } + + /// Waits for inotify events. + /** + * It waits until one or more events occur. When called + * in nonblocking mode it only retrieves occurred events + * to the internal queue and exits. + * + * \param[in] fNoIntr if true it re-calls the system call after a handled signal + * + * \throw InotifyException thrown if reading events failed + * + * \sa SetNonBlock() + */ + void WaitForEvents(bool fNoIntr = false) throw (InotifyException); + + /// Returns the count of received and queued events. + /** + * This number is related to the events in the queue inside + * this object, not to the events pending in the kernel. + * + * \return count of events + */ + inline size_t GetEventCount() + { + IN_READ_BEGIN + size_t n = (size_t) m_events.size(); + IN_READ_END + return n; + } + + /// Extracts a queued inotify event. + /** + * The extracted event is removed from the queue. + * If the pointer is NULL it does nothing. + * + * \param[in,out] pEvt event object + * + * \throw InotifyException thrown if the provided pointer is NULL + */ + bool GetEvent(InotifyEvent* pEvt) throw (InotifyException); + + /// Extracts a queued inotify event. + /** + * The extracted event is removed from the queue. + * + * \param[in,out] rEvt event object + * + * \throw InotifyException thrown only in very anomalous cases + */ + bool GetEvent(InotifyEvent& rEvt) throw (InotifyException) + { + return GetEvent(&rEvt); + } + + /// Extracts a queued inotify event (without removing). + /** + * The extracted event stays in the queue. + * If the pointer is NULL it does nothing. + * + * \param[in,out] pEvt event object + * + * \throw InotifyException thrown if the provided pointer is NULL + */ + bool PeekEvent(InotifyEvent* pEvt) throw (InotifyException); + + /// Extracts a queued inotify event (without removing). + /** + * The extracted event stays in the queue. + * + * \param[in,out] rEvt event object + * + * \throw InotifyException thrown only in very anomalous cases + */ + bool PeekEvent(InotifyEvent& rEvt) throw (InotifyException) + { + return PeekEvent(&rEvt); + } + + /// Searches for a watch by a watch descriptor. + /** + * It tries to find a watch by the given descriptor. + * + * \param[in] iDescriptor watch descriptor + * \return pointer to a watch; NULL if no such watch exists + */ + InotifyWatch* FindWatch(int iDescriptor); + + /// Searches for a watch by a filesystem path. + /** + * It tries to find a watch by the given filesystem path. + * + * \param[in] rPath filesystem path + * \return pointer to a watch; NULL if no such watch exists + * + * \attention The path must be exactly identical to the one + * used for the searched watch. Be careful about + * absolute/relative and case-insensitive paths. + */ + InotifyWatch* FindWatch(const std::string& rPath); + + /// Returns the file descriptor. + /** + * The descriptor can be used in standard low-level file + * functions (poll(), select(), fcntl() etc.). + * + * \return valid file descriptor or -1 for inactive object + * + * \sa SetNonBlock() + */ + inline int GetDescriptor() const + { + return m_fd; + } + + /// Enables/disables non-blocking mode. + /** + * Use this mode if you want to monitor the descriptor + * (acquired thru GetDescriptor()) in functions such as + * poll(), select() etc. + * + * Non-blocking mode is disabled by default. + * + * \param[in] fNonBlock enable/disable non-blocking mode + * + * \throw InotifyException thrown if setting mode failed + * + * \sa GetDescriptor(), SetCloseOnExec() + */ + void SetNonBlock(bool fNonBlock) throw (InotifyException); + + /// Enables/disables closing on exec. + /** + * Enable this if you want to close the descriptor when + * executing another program. Otherwise, the descriptor + * will be inherited. + * + * Closing on exec is disabled by default. + * + * \param[in] fClOnEx enable/disable closing on exec + * + * \throw InotifyException thrown if setting failed + * + * \sa GetDescriptor(), SetNonBlock() + */ + void SetCloseOnExec(bool fClOnEx) throw (InotifyException); + + /// Acquires a particular inotify capability/limit. + /** + * \param[in] cap capability/limit identifier + * \return capability/limit value + * \throw InotifyException thrown if the given value cannot be acquired + */ + static uint32_t GetCapability(InotifyCapability_t cap) throw (InotifyException); + + /// Modifies a particular inotify capability/limit. + /** + * \param[in] cap capability/limit identifier + * \param[in] val new capability/limit value + * \throw InotifyException thrown if the given value cannot be set + * \attention Using this function requires root privileges. + * Beware of setting extensive values - it may seriously + * affect system performance and/or stability. + */ + static void SetCapability(InotifyCapability_t cap, uint32_t val) throw (InotifyException); + + /// Returns the maximum number of events in the kernel queue. + /** + * \return maximum number of events in the kernel queue + * \throw InotifyException thrown if the given value cannot be acquired + */ + inline static uint32_t GetMaxEvents() throw (InotifyException) + { + return GetCapability(IN_MAX_EVENTS); + } + + /// Sets the maximum number of events in the kernel queue. + /** + * \param[in] val new value + * \throw InotifyException thrown if the given value cannot be set + * \attention Using this function requires root privileges. + * Beware of setting extensive values - the greater value + * is set here the more physical memory may be used for the inotify + * infrastructure. + */ + inline static void SetMaxEvents(uint32_t val) throw (InotifyException) + { + SetCapability(IN_MAX_EVENTS, val); + } + + /// Returns the maximum number of inotify instances per process. + /** + * It means the maximum number of open inotify file descriptors + * per running process. + * + * \return maximum number of inotify instances + * \throw InotifyException thrown if the given value cannot be acquired + */ + inline static uint32_t GetMaxInstances() throw (InotifyException) + { + return GetCapability(IN_MAX_INSTANCES); + } + + /// Sets the maximum number of inotify instances per process. + /** + * \param[in] val new value + * \throw InotifyException thrown if the given value cannot be set + * \attention Using this function requires root privileges. + * Beware of setting extensive values - the greater value + * is set here the more physical memory may be used for the inotify + * infrastructure. + */ + inline static void SetMaxInstances(uint32_t val) throw (InotifyException) + { + SetCapability(IN_MAX_INSTANCES, val); + } + + /// Returns the maximum number of inotify watches per instance. + /** + * It means the maximum number of inotify watches per inotify + * file descriptor. + * + * \return maximum number of inotify watches + * \throw InotifyException thrown if the given value cannot be acquired + */ + inline static uint32_t GetMaxWatches() throw (InotifyException) + { + return GetCapability(IN_MAX_WATCHES); + } + + /// Sets the maximum number of inotify watches per instance. + /** + * \param[in] val new value + * \throw InotifyException thrown if the given value cannot be set + * \attention Using this function requires root privileges. + * Beware of setting extensive values - the greater value + * is set here the more physical memory may be used for the inotify + * infrastructure. + */ + inline static void SetMaxWatches(uint32_t val) throw (InotifyException) + { + SetCapability(IN_MAX_WATCHES, val); + } + +private: + int m_fd; ///< file descriptor + IN_WATCH_MAP m_watches; ///< watches (by descriptors) + IN_WP_MAP m_paths; ///< watches (by paths) + unsigned char m_buf[INOTIFY_BUFLEN]; ///< buffer for events + std::deque m_events; ///< event queue + + IN_LOCK_DECL + + friend class InotifyWatch; -private: - int m_fd; ///< file descriptor - IN_WATCH_MAP m_watches; ///< watches (by descriptors) - IN_WP_MAP m_paths; ///< watches (by paths) - unsigned char m_buf[INOTIFY_BUFLEN]; ///< buffer for events - std::deque m_events; ///< event queue - - IN_LOCK_DECL - - friend class InotifyWatch; - - static std::string GetCapabilityPath(InotifyCapability_t cap) throw (InotifyException); + static std::string GetCapabilityPath(InotifyCapability_t cap) throw (InotifyException); }; -- cgit