osaf/libs/core/cplusplus/base/Makefile.am | 2 +
osaf/libs/core/cplusplus/base/file_notify.cc | 175 +++++++++++++++++++++++++++
osaf/libs/core/cplusplus/base/file_notify.h | 87 +++++++++++++
3 files changed, 264 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
@@ -23,6 +23,7 @@ DEFAULT_INCLUDES =
SUBDIRS = tests
noinst_HEADERS = \
+ file_notify.h \
getenv.h \
macros.h \
process.h \
@@ -38,5 +39,6 @@ libbase_la_CPPFLAGS = \
libbase_la_LDFLAGS = -static
libbase_la_SOURCES = \
+ file_notify.cc \
getenv.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,175 @@
+/* -*- 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 <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, int user_fd) {
+ 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_fd);
+ inotify_rm_watch(inotify_fd_, inotify_wd_);
+ return rc;
+}
+
+FileNotify::FileNotifyErrors
+FileNotify::WaitForFileDeletion(
+ const std::string &file_name, int timeout, int user_fd) {
+ 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_fd);
+ inotify_rm_watch(inotify_fd_, inotify_wd_);
+ return rc;
+}
+
+FileNotify::FileNotifyErrors
+FileNotify::ProcessEvents(int timeout, int user_fd) {
+ enum {
+ FD_INOTIFY = 0,
+ FD_USER,
+ NUM_FDS
+ };
+
+ timespec start_time;
+ timespec time_left_ts;
+ timespec timeout_ts;
+ pollfd fds[NUM_FDS] {};
+ fds[FD_INOTIFY].fd = inotify_fd_;
+ fds[FD_INOTIFY].events = POLLIN;
+ fds[FD_USER].fd = user_fd;
+ fds[FD_USER].events = POLLIN;
+
+ osaf_millis_to_timespec(timeout, &timeout_ts);
+ start_time = base::ReadMonotonicClock();
+
+ while (true) {
+ timespec current_time {0};
+ timespec elapsed_time {0};
+
+ TRACE("remaining timeout: %d", timeout);
+ int rc = osaf_poll(&fds[0], NUM_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");
+ return FileNotifyErrors::kError;
+ } else if (num_read == -1) {
+ if (errno == EINTR) {
+ continue;
+ } else {
+ LOG_WA("read error: %s", strerror(errno));
+ return FileNotifyErrors::kError;
+ }
+ } else {
+ 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());
+ return FileNotifyErrors::kOK;
+ }
+ if (event->mask & IN_CREATE) {
+ if (file_name_ == event->name) {
+ TRACE("file name: %s created", file_name_.c_str());
+ 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);
+ }
+ }
+ if (fds[FD_USER].revents & POLLIN) {
+ return FileNotifyErrors::kUserFD;
+ }
+ } else if (rc == 0) {
+ TRACE("timeout");
+ return FileNotifyErrors::kTimeOut;
+ } else {
+ LOG_WA("poll error %s", strerror(errno));
+ return FileNotifyErrors::kError;
+ }
+ }
+}
+} // 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,87 @@
+/* -*- 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 "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, int user_fd = -1);
+
+ /**
+ * @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, int user_fd = -1);
+
+ private:
+ static const int kBufferSize = 10 * (sizeof (inotify_event) + NAME_MAX + 1);
+
+ FileNotifyErrors ProcessEvents(int timeout, int user_fd);
+
+ 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