#include "ehs/io/FileMonitor_UNX.h" #include "ehs/Log.h" #include #include #include #include #define BUF_LEN (1024 * (sizeof(inotify_event) + 16)) namespace ehs { FileMonitor::~FileMonitor() { inotify_rm_watch( hdl, wd); close(hdl); } FileMonitor::FileMonitor() : hdl(-1), wd(-1) { } FileMonitor::FileMonitor(Str_8 filePath) : BaseFileMonitor((Str_8&&)filePath), hdl(-1), wd(-1) { FileMonitor::Initialize(); } FileMonitor::FileMonitor(FileMonitor&& fm) noexcept : BaseFileMonitor((BaseFileMonitor&&)fm), hdl(fm.hdl), wd(fm.wd) { fm.hdl = -1; fm.wd = -1; } FileMonitor::FileMonitor(const FileMonitor& fm) : BaseFileMonitor(fm), hdl(-1), wd(-1) { FileMonitor::Initialize(); } FileMonitor& FileMonitor::operator=(FileMonitor&& fm) noexcept { if (this == &fm) return *this; Release(); BaseFileMonitor::operator=((BaseFileMonitor&&)fm); hdl = fm.hdl; wd = fm.wd; fm.hdl = -1; fm.wd = -1; return *this; } FileMonitor& FileMonitor::operator=(const FileMonitor& fm) { if (this == &fm) return *this; Release(); BaseFileMonitor::operator=(fm); hdl = -1; wd = -1; Initialize(); return *this; } void FileMonitor::Initialize() { if (!IsValid() || IsInitialized()) return; hdl = inotify_init(); if (hdl < 0) { EHS_LOG_INT("Error", 0, "Failed to initialize inotify."); return; } int flags = fcntl(hdl, F_GETFL, 0); if (flags == -1) { EHS_LOG_INT("Error", 1, "Failed to retrieve flags with error #" + Str_8::FromNum(errno) + "."); return; } flags |= O_NONBLOCK; if (fcntl(hdl, F_SETFL, flags) == -1) { EHS_LOG_INT("Error", 2, "Failed to set flags with error #" + Str_8::FromNum(errno) + "."); return; } wd = inotify_add_watch( hdl, filePath, IN_MODIFY | IN_DELETE_SELF | IN_MOVE_SELF | IN_ACCESS); if (wd < 0) { EHS_LOG_INT("Error", 3, "Failed to add watch."); close(hdl); hdl = -1; return; } } void FileMonitor::Release() { if (!IsValid() || !IsInitialized()) return; inotify_rm_watch( hdl, wd); wd = -1; close(hdl); hdl = -1; } UInt_8 FileMonitor::Poll() { UInt_8 mask = EHS_FE_NONE; if (!IsValid() || !IsInitialized()) return mask; Byte buffer[BUF_LEN]; SInt_64 length = read(hdl, buffer, BUF_LEN); if (length < 0) { UInt_8 code = errno; if (code != EWOULDBLOCK) EHS_LOG_INT("Error", 0, "Failed to read with error #" + Str_8::FromNum(code) + "."); return mask; } UInt_64 i = 0; while (i < length) { inotify_event *event = (inotify_event*)&buffer[i]; if (event->mask & IN_MODIFY) mask |= EHS_FE_MODIFIED; if (event->mask & IN_DELETE_SELF) mask |= EHS_FE_DELETED; if (event->mask & IN_MOVE_SELF) mask |= EHS_FE_MOVED; if (event->mask & IN_ACCESS) mask |= EHS_FE_OPENED; i += sizeof(inotify_event) + event->len; } if (mask & EHS_FE_DELETED || mask & EHS_FE_MOVED) Release(); return mask; } bool FileMonitor::IsInitialized() const { return hdl >= 0 && wd >= 0; } }