Ack with minor comments, see inline marked [AndersW]. regards,
Anders Widell On 10/17/2016 06:25 PM, Hans Nordeback wrote: > 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> [AndersW] Missing header <cerrno> [AndersW] Missing header <cstdlib> (for free()) > +#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); [AndersW] Can use base::MillisToTimespec(), and intialize timeout_ts at the declaration above. > + start_time = base::ReadMonotonicClock(); > + > + while (true) { > + timespec current_time {0}; [AndersW] [osaf/libs/core/cplusplus/base/file_notify.cc:111]: (style) The scope of the variable 'current_time' can be reduced. > + timespec elapsed_time {0}; [AndersW] [osaf/libs/core/cplusplus/base/file_notify.cc:112]: (style) The scope of the variable 'elapsed_time' can be reduced. > + > + TRACE("remaining timeout: %d", timeout); > + int rc = osaf_poll(&fds[0], NUM_FDS, timeout); [AndersW] The type of the return value from osaf_poll() is unsigned, not int. > + > + 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 { [AndersW] This else clause is dead code, remove. > + 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 Opensaf-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/opensaf-devel