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, ¤t_time); + + if (osaf_timespec_compare(¤t_time, &start_time) >= 0) { + osaf_timespec_subtract(¤t_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