osaf/libs/core/cplusplus/base/Makefile.am    |    2 +
 osaf/libs/core/cplusplus/base/file_notify.cc |  163 +++++++++++++++++++++++++++
 osaf/libs/core/cplusplus/base/file_notify.h  |   84 +++++++++++++
 3 files changed, 249 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,163 @@
+/*      -*- 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 <unistd.h>
+#include <sys/stat.h>
+#include <cstring>
+#include "osaf_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() {
+  if (inotify_fd_ != -1) {
+    if (inotify_rm_watch(inotify_fd_, inotify_wd_) == -1) {
+      LOG_NO("inotify_rm_watch: %s", strerror(errno));
+    }
+  }
+}
+
+//
+
+inline bool FileNotify::FileExists(const std::string& file_name) {
+  struct stat buffer;
+  return (stat(file_name.c_str(), &buffer) == 0);
+}
+
+//
+
+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);
+}
+
+//
+
+int FileNotify::WaitForFileCreation(const std::string &file_name, int timeout) 
{
+  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 kError;
+  }
+
+  if (FileExists(file_name)) {
+    TRACE("File already created: %s", file_name.c_str());
+    return kOK;
+  }
+
+  return ProcessEvents(timeout);
+}
+
+//
+
+int FileNotify::WaitForFileDeletion(const std::string &file_name, int timeout) 
{
+  //
+  SplitFileName(file_name);
+
+  //
+  if ((inotify_wd_ =
+       inotify_add_watch(inotify_fd_, file_path_.c_str(), IN_DELETE)) == -1) {
+    LOG_NO("inotify_add_watch failed: %s", strerror(errno));
+    return kError;
+  }
+
+  if (!FileExists(file_name)) {
+    TRACE("File already deleted: %s", file_name.c_str());
+    return kOK;
+  }
+  return ProcessEvents(timeout);
+}
+
+int FileNotify::ProcessEvents(int timeout) {
+  //
+  timespec start_time;
+  timespec time_left_ts;
+  timespec timeout_ts;
+
+  osaf_millis_to_timespec(timeout, &timeout_ts);
+  osaf_clock_gettime(CLOCK_MONOTONIC, &start_time);
+
+  while (true) {
+    struct timespec current_time;
+    struct timespec elapsed_time = {.tv_sec = 0, .tv_nsec = 0};
+
+    TRACE("remaining timeout: %d", timeout);
+    int rc = osaf_poll_one_fd(inotify_fd_, timeout);
+
+    if (rc > 0) {
+      ssize_t num_read = read(inotify_fd_, buf_, kBufferSize);
+
+      if (num_read == 0) {
+        LOG_WA("read returned zero");
+        return kError;
+      } else if (num_read == -1) {
+        LOG_WA("read returned -1");
+        return kError;
+      } else {
+        for (char *p = buf_; p < buf_ + num_read;) {
+          inotify_event *event = reinterpret_cast<inotify_event*> (p);
+          if (file_name_ == event->name) {
+            TRACE("file name: %s created", file_name_.c_str());
+            return kOK;
+          }
+          p += sizeof (inotify_event) + event->len;
+        }
+        // calculate remaining timeout
+        osaf_clock_gettime(CLOCK_MONOTONIC, &current_time);
+
+        if (osaf_timespec_compare(&current_time, &start_time) >= 0) {
+          osaf_timespec_subtract(&current_time, &start_time,
+                                 &elapsed_time);
+        }
+        if (osaf_timespec_compare(&elapsed_time, &timeout_ts) >= 0) {
+          return kTimeOut;
+        }
+        osaf_timespec_subtract(&timeout_ts, &elapsed_time, &time_left_ts);
+
+        timeout = osaf_timespec_to_millis(&time_left_ts);
+      }
+    } else if (rc == 0) {
+      TRACE("timeout");
+      return kTimeOut;
+    } else {
+      LOG_WA("poll error %s", strerror(errno));
+      return 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,84 @@
+/*      -*- 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 <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 {
+  DELETE_COPY_AND_MOVE_OPERATORS(FileNotify);
+
+ public:
+  enum FileNotifyErrors {
+    kOK = 0,
+    kTimeOut,
+    kError,
+  };
+
+  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.
+   *
+   */
+  int WaitForFileCreation(const std::string &file_name, int timeout);
+
+  /**
+   * @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.
+   *
+   */
+  int WaitForFileDeletion(const std::string &file_name, int timeout);
+
+ private:
+  enum {
+    kBufferSize = 10 * (sizeof (inotify_event) + NAME_MAX + 1)
+  };
+
+  char buf_[kBufferSize] __attribute__((aligned(8))) = {};
+
+  int ProcessEvents(int timeout);
+  inline bool FileExists(const std::string& file_name);
+  void SplitFileName(const std::string &file_name);
+
+  std::string file_path_;
+  std::string file_name_;
+
+  int inotify_fd_{-1};
+  int inotify_wd_{-1};
+};
+
+}  // 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
Opensaf-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/opensaf-devel

Reply via email to