osaf/libs/core/cplusplus/base/Makefile.am | 2 +
osaf/libs/core/cplusplus/base/file_notify.cc | 188 +++++++++++++++++++++++++++
osaf/libs/core/cplusplus/base/file_notify.h | 103 ++++++++++++++
3 files changed, 293 insertions(+), 0 deletions(-)
diff --git a/osaf/libs/core/cplusplus/base/Makefile.am
b/osaf/libs/core/cplusplus/base/Makefile.am
--- a/osaf/libs/core/cplusplus/base/Makefile.am
+++ b/osaf/libs/core/cplusplus/base/Makefile.am
@@ -24,6 +24,7 @@ SUBDIRS = tests
noinst_HEADERS = \
buffer.h \
+ file_notify.h \
getenv.h \
log_message.h \
macros.h \
@@ -43,6 +44,7 @@ libbase_la_CPPFLAGS = \
libbase_la_LDFLAGS = -static
libbase_la_SOURCES = \
+ file_notify.cc \
getenv.cc \
log_message.cc \
process.cc \
diff --git a/osaf/libs/core/cplusplus/base/file_notify.cc
b/osaf/libs/core/cplusplus/base/file_notify.cc
new file mode 100644
--- /dev/null
+++ b/osaf/libs/core/cplusplus/base/file_notify.cc
@@ -0,0 +1,188 @@
+/* -*- OpenSAF -*-
+ *
+ * (C) Copyright 2016 The OpenSAF Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. This file and program are licensed
+ * under the GNU Lesser General Public License Version 2.1, February 1999.
+ * The complete license can be accessed from the following location:
+ * http://opensource.org/licenses/lgpl-license.php
+ * See the Copying file included with the OpenSAF distribution for full
+ * licensing terms.
+ *
+ * Author(s): Ericsson AB
+ *
+ */
+
+#include "base/file_notify.h"
+#include <libgen.h>
+#include <cerrno>
+#include <cstdlib>
+#include <cstring>
+#include "time.h"
+#include "osaf_poll.h"
+#include "logtrace.h"
+
+namespace base {
+
+FileNotify::FileNotify() {
+ if ((inotify_fd_ = inotify_init()) == -1) {
+ LOG_NO("inotify_init failed: %s", strerror(errno));
+ }
+}
+
+FileNotify::~FileNotify() {
+ close(inotify_fd_);
+}
+
+void FileNotify::SplitFileName(const std::string &file_name) {
+ char *tmp1 = strdup(file_name.c_str());
+ char *tmp2 = strdup(file_name.c_str());
+ file_path_ = dirname(tmp1);
+ file_name_ = basename(tmp2);
+ free(tmp1);
+ free(tmp2);
+}
+
+FileNotify::FileNotifyErrors
+FileNotify::WaitForFileCreation(const std::string &file_name,
+ int timeout, const std::vector<int>& user_fds)
{
+ FileNotify::FileNotifyErrors rc {FileNotifyErrors::kOK};
+ SplitFileName(file_name);
+
+ if ((inotify_wd_ =
+ inotify_add_watch(inotify_fd_, file_path_.c_str(), IN_CREATE)) == -1) {
+ LOG_NO("inotify_add_watch failed: %s", strerror(errno));
+ return FileNotifyErrors::kError;
+ }
+
+ if (FileExists(file_name)) {
+ TRACE("File already created: %s", file_name.c_str());
+ inotify_rm_watch(inotify_fd_, inotify_wd_);
+ return FileNotifyErrors::kOK;
+ }
+
+ rc = ProcessEvents(timeout, user_fds);
+ inotify_rm_watch(inotify_fd_, inotify_wd_);
+ return rc;
+}
+
+FileNotify::FileNotifyErrors
+FileNotify::WaitForFileDeletion(const std::string &file_name,
+ int timeout,
+ const std::vector<int>& user_fds) {
+ FileNotify::FileNotifyErrors rc { FileNotifyErrors::kOK };
+
+ if ((inotify_wd_ = inotify_add_watch(inotify_fd_, file_name.c_str(),
+ IN_DELETE_SELF)) == -1) {
+ if (errno == ENOENT) {
+ TRACE("File already deleted: %s", file_name.c_str());
+ return FileNotifyErrors::kOK;
+ } else {
+ LOG_NO("inotify_add_watch failed: %s", strerror(errno));
+ return FileNotifyErrors::kError;
+ }
+ }
+
+ rc = ProcessEvents(timeout, user_fds);
+ inotify_rm_watch(inotify_fd_, inotify_wd_);
+ return rc;
+}
+
+FileNotify::FileNotifyErrors
+FileNotify::ProcessEvents(int timeout, const std::vector<int>& user_fds) {
+ enum {
+ FD_INOTIFY = 0,
+ };
+
+ timespec start_time {0};
+ timespec time_left_ts {0};
+ timespec timeout_ts {0};
+
+ int num_of_fds = user_fds.size() + 1;
+ pollfd* fds = new pollfd[num_of_fds];
+
+ fds[FD_INOTIFY].fd = inotify_fd_;
+ fds[FD_INOTIFY].events = POLLIN;
+ for (int i = 1; i < num_of_fds; ++i) {
+ fds[i].fd = user_fds[i-1];
+ fds[i].events = POLLIN;
+ }
+
+ timeout_ts = base::MillisToTimespec(timeout);
+ start_time = base::ReadMonotonicClock();
+
+ while (true) {
+ TRACE("remaining timeout: %d", timeout);
+ unsigned rc = osaf_poll(fds, num_of_fds, timeout);
+
+ if (rc > 0) {
+ if (fds[FD_INOTIFY].revents & POLLIN) {
+ ssize_t num_read = read(inotify_fd_, buf_, kBufferSize);
+
+ if (num_read == 0) {
+ LOG_WA("read returned zero");
+ delete [] fds;
+ return FileNotifyErrors::kError;
+ } else if (num_read == -1) {
+ if (errno == EINTR) {
+ continue;
+ } else {
+ LOG_WA("read error: %s", strerror(errno));
+ delete [] fds;
+ return FileNotifyErrors::kError;
+ }
+ } else {
+ timespec current_time {0};
+ timespec elapsed_time {0};
+ for (char *p = buf_; p < buf_ + num_read;) {
+ inotify_event *event = reinterpret_cast<inotify_event*> (p);
+ if (event->mask & IN_DELETE_SELF) {
+ TRACE("file name: %s deleted", file_name_.c_str());
+ delete [] fds;
+ return FileNotifyErrors::kOK;
+ }
+ if (event->mask & IN_CREATE) {
+ if (file_name_ == event->name) {
+ TRACE("file name: %s created", file_name_.c_str());
+ delete [] fds;
+ return FileNotifyErrors::kOK;
+ }
+ }
+ if (event->mask & IN_IGNORED) {
+ TRACE("IN_IGNORE received, (ignored)");
+ }
+ p += sizeof(inotify_event) + event->len;
+ }
+ // calculate remaining timeout
+ current_time = base::ReadMonotonicClock();
+
+ if (current_time >= start_time) {
+ elapsed_time = current_time - start_time;
+ }
+ if (elapsed_time >= timeout_ts) {
+ return FileNotifyErrors::kTimeOut;
+ }
+ time_left_ts = timeout_ts - elapsed_time;
+
+ timeout = base::TimespecToMillis(time_left_ts);
+ }
+ }
+ // Check user file descriptors
+ for (int i = 1; i < num_of_fds; i++) {
+ if ((fds[i].revents & POLLIN) ||
+ (fds[i].revents & POLLHUP) ||
+ (fds[i].revents & POLLERR)) {
+ delete [] fds;
+ return FileNotifyErrors::kUserFD;
+ }
+ }
+ } else if (rc == 0) {
+ TRACE("timeout");
+ delete [] fds;
+ return FileNotifyErrors::kTimeOut;
+ }
+ }
+}
+} // namespace base
diff --git a/osaf/libs/core/cplusplus/base/file_notify.h
b/osaf/libs/core/cplusplus/base/file_notify.h
new file mode 100644
--- /dev/null
+++ b/osaf/libs/core/cplusplus/base/file_notify.h
@@ -0,0 +1,103 @@
+/* -*- OpenSAF -*-
+ *
+ * (C) Copyright 2016 The OpenSAF Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. This file and program are licensed
+ * under the GNU Lesser General Public License Version 2.1, February 1999.
+ * The complete license can be accessed from the following location:
+ * http://opensource.org/licenses/lgpl-license.php
+ * See the Copying file included with the OpenSAF distribution for full
+ * licensing terms.
+ *
+ * Author(s): Ericsson AB
+ *
+ */
+
+#include <unistd.h>
+#include <sys/stat.h>
+#include <limits.h>
+#include <sys/inotify.h>
+#include <string>
+#include <vector>
+#include "base/macros.h"
+
+#ifndef OSAF_LIBS_CORE_CPLUSPLUS_BASE_FILE_NOTIFY_H_
+#define OSAF_LIBS_CORE_CPLUSPLUS_BASE_FILE_NOTIFY_H_
+
+namespace base {
+
+class FileNotify {
+ public:
+ enum class FileNotifyErrors {
+ kOK = 0,
+ kTimeOut,
+ kError,
+ kUserFD
+ };
+
+ FileNotify();
+ virtual ~FileNotify();
+
+ /**
+ * @brief Wait for a file to be created with a timeout.
+ *
+ * @a file name in format /path/file.
+ * This function blocks until the file has been created or until the @a
timeout expires,
+ * whichever happens first.
+ *
+ */
+ FileNotifyErrors
+ WaitForFileCreation(const std::string &file_name,
+ int timeout, const std::vector<int>& user_fds);
+
+ FileNotifyErrors
+ WaitForFileCreation(const std::string &file_name, int timeout) {
+ std::vector<int> empty_user_fds;
+ return WaitForFileCreation(file_name, timeout, empty_user_fds);
+ }
+
+ /**
+ * @brief Wait for a file to be deleted.
+ *
+ * @a file name in format /path/file.
+ * This function blocks until the file has been deleted or until the @a
timeout expires,
+ * whichever happens first.
+ *
+ */
+ FileNotifyErrors
+ WaitForFileDeletion(const std::string &file_name,
+ int timeout, const std::vector<int>& user_fds);
+
+ FileNotifyErrors
+ WaitForFileDeletion(const std::string &file_name, int timeout) {
+ std::vector<int> empty_user_fds;
+ return WaitForFileDeletion(file_name, timeout, empty_user_fds);
+ }
+
+
+ private:
+ static const int kBufferSize = 10 * (sizeof (inotify_event) + NAME_MAX + 1);
+
+ FileNotifyErrors ProcessEvents(int timeout, const std::vector<int>&
user_fds);
+
+ bool FileExists(const std::string& file_name) const {
+ struct stat buffer;
+ return stat(file_name.c_str(), &buffer) == 0;
+ }
+
+ void SplitFileName(const std::string &file_name);
+
+ char buf_[kBufferSize] __attribute__((aligned(8))) = {};
+ std::string file_path_;
+ std::string file_name_;
+
+ int inotify_fd_{-1};
+ int inotify_wd_{-1};
+ DELETE_COPY_AND_MOVE_OPERATORS(FileNotify);
+};
+
+} // namespace base
+
+#endif // OSAF_LIBS_CORE_CPLUSPLUS_BASE_FILE_NOTIFY_H_
------------------------------------------------------------------------------
Check out the vibrant tech community on one of the world's most
engaging tech sites, SlashDot.org! http://sdm.link/slashdot
_______________________________________________
Opensaf-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/opensaf-devel