#include "Notify.h" #include #include #include #include #include #include using namespace std; #ifdef _WIN32 constexpr const char FOLDER_DELIM = '\\'; #else constexpr const char FOLDER_DELIM = '/'; #endif Notify::Notify(std::ostream& log_stream) : m_log_stream(log_stream), m_notify_fd(-1) { m_notify_fd = inotify_init(); if (m_notify_fd < 0) { m_log_stream << __FILE__ << ":" << __LINE__ << endl; m_log_stream << "Could not create notify FD - "; m_log_stream << errno << " - " << strerror(errno) << endl; } } Notify::~Notify() { if (m_notify_fd >= 0) { close(m_notify_fd); m_notify_fd = -1; } } vector> Notify::get_watch_events() const { vector> result; int error; unsigned int buffer_size; void* buffer = nullptr; int bytes; inotify_event* event; notify_event tmp; if (m_notify_fd < 0) { m_log_stream << __FILE__ << ":" << __LINE__ << endl; m_log_stream << "Negative notify FD - " << m_notify_fd << endl; return result; } error = ioctl(m_notify_fd, FIONREAD, &buffer_size); if (0 != error) { m_log_stream << __FILE__ << ":" << __LINE__ << endl; m_log_stream << "IOCTL for buffer size failed - "; m_log_stream << errno << " - " << strerror(errno) << endl; return result; } buffer = calloc(buffer_size, 1); if (nullptr == buffer) { m_log_stream << __FILE__ << ":" << __LINE__ << endl; m_log_stream << "Buffer allocation failed"; return result; } bytes = 0; while (bytes < buffer_size) { error = read(m_notify_fd, buffer + bytes, buffer_size - bytes); if (error < 1) { m_log_stream << __FILE__ << ":" << __LINE__ << endl; m_log_stream << "Reading notify fd failed - "; m_log_stream << errno << " - " << strerror(errno) << endl; free(buffer); return result; } bytes += error; } bytes = 0; while (bytes < buffer_size) { event = static_cast(buffer + bytes); tmp.file = event->name; tmp.mask = event->mask; result.push_back(make_pair(event->wd, tmp)); bytes += sizeof(inotify_event) + event->len; } free(buffer); buffer = nullptr; return result; } void Notify::add_file(const string& filename, uint32_t mask) { int error; if (m_watch_fds.count(filename) != 0) { // Append mask mask |= IN_MASK_ADD; } // Add watch error = inotify_add_watch(m_notify_fd, filename.c_str(), mask); if (error < 0) { m_log_stream << __FILE__ << ":" << __LINE__ << endl; m_log_stream << "Could not add watch FD - "; m_log_stream << errno << " - " << strerror(errno) << endl; } else { m_watch_fds[filename] = error; } } void Notify::add_list(const vector& files, uint32_t mask) { for (auto file : files) { add_file(file, mask); } } void Notify::add_list(const vector>& files) { for (auto file : files) { add_file(file.first, file.second); } } void Notify::remove_file(const string& filename) { int error; if (m_watch_fds.count(filename) != 0) { // Remove watch error = inotify_rm_watch(m_notify_fd, m_watch_fds[filename]); if (0 != error) { m_log_stream << __FILE__ << ":" << __LINE__ << endl; m_log_stream << "Could not remove watch - "; m_log_stream << errno << " - " << strerror(errno) << endl; } } m_watch_fds.erase(filename); } void Notify::remove_list(const vector& files) { for (auto file : files) { remove_file(file); } } void Notify::clear() { int error; for (auto fd : m_watch_fds) { // Remove watch error = inotify_rm_watch(m_notify_fd, fd.second); if (0 != error) { m_log_stream << __FILE__ << ":" << __LINE__ << endl; m_log_stream << "Could not remove watch - "; m_log_stream << errno << " - " << strerror(errno) << endl; } fd.second = -1; } m_watch_fds.clear(); } size_t Notify::size() const { return m_watch_fds.size(); } vector Notify::get_list() const { vector result; for (auto fd : m_watch_fds) { result.push_back(fd.first); } return result; } void Notify::set_list(vector>& files) { map existing; for (auto fd : m_watch_fds) { existing[fd.first] = 0; } for (auto file : files) { add_file(file.first, file.second); existing[file.first] = 1; } for (auto item : existing) { if (0 == item.second) { remove_file(item.first); } } // Or do a clear + add } vector Notify::get_events() const { vector result; vector> events = get_watch_events(); string filepath; map r_watch_fds; // Do a reverse map for (auto fd : m_watch_fds) { if (0 != r_watch_fds.count(fd.second)) { m_log_stream << __FILE__ << ":" << __LINE__ << endl; m_log_stream << "Watch FD is duplicated - " << fd.second; m_log_stream << " -> \"" << r_watch_fds[fd.second]; m_log_stream << "\" -> \"" << fd.first << "\"" << endl; } r_watch_fds[fd.second] = fd.first; } // Translate for (auto event : events) { if (event.second.file.size() != 0) { // Concat watched folder and filename filepath = r_watch_fds[event.first]; filepath += FOLDER_DELIM; filepath += event.second.file; event.second.file = filepath; } else { // Watched file/folder is the target event.second.file = r_watch_fds[event.first]; } result.push_back(event.second); } return result; }