EHS/src/io/FileMonitor_UNX.cpp
karutoh 1a4a1ecd9c
Some checks failed
Build & Release / Linux-x86_64-Build (push) Successful in 40s
Build & Release / Linux-AARCH64-Build (push) Has been cancelled
First commit.
2024-01-31 22:28:19 -08:00

174 lines
3.0 KiB
C++

#include "ehs/io/FileMonitor_UNX.h"
#include "ehs/Log.h"
#include <sys/inotify.h>
#include <cerrno>
#include <unistd.h>
#include <fcntl.h>
#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;
}
}