174 lines
3.0 KiB
C++
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;
|
|
}
|
|
} |