Промежуток 1
This commit is contained in:
parent
ed0d2780c3
commit
cb3f40deee
2 changed files with 171 additions and 57 deletions
|
@ -2,7 +2,7 @@ module dfanotify;
|
|||
|
||||
public import fanotify;
|
||||
|
||||
import core.sys.posix.unistd : read, close, ssize_t;
|
||||
import core.sys.posix.unistd : read, write, close, ssize_t;
|
||||
import core.sys.posix.fcntl : O_RDONLY, O_RDWR, O_LARGEFILE, AT_FDCWD;
|
||||
import std.exception : enforce;
|
||||
import std.string : toStringz, fromStringz;
|
||||
|
@ -11,26 +11,53 @@ import core.stdc.errno : errno;
|
|||
import core.stdc.string : strerror;
|
||||
import core.stdc.stdint;
|
||||
|
||||
struct FanotifyEvent
|
||||
// Класс для представления события fanotify (ООП-стиль, с методами для проверки и обработки)
|
||||
class FanotifyEvent
|
||||
{
|
||||
fanotify_event_metadata meta;
|
||||
string name;
|
||||
private fanotify_event_metadata meta_;
|
||||
private string name_;
|
||||
private int fanFd_; // Ссылка на fanotify fd для отправки response (копируется при создании)
|
||||
|
||||
// Конструктор (value semantics, копирует данные)
|
||||
this(fanotify_event_metadata meta, string name, int fanFd)
|
||||
{
|
||||
meta_ = meta;
|
||||
name_ = name;
|
||||
fanFd_ = fanFd;
|
||||
}
|
||||
|
||||
// Деструктор: автоматически закрывает fd события, если он валиден (RAII)
|
||||
~this()
|
||||
{
|
||||
if (meta_.fd >= 0 && meta_.fd != FAN_NOFD)
|
||||
{
|
||||
close(meta_.fd);
|
||||
meta_.fd = -1; // Избегаем повторного закрытия
|
||||
}
|
||||
}
|
||||
|
||||
// Геттеры (value types)
|
||||
@property uint64_t mask() const
|
||||
{
|
||||
return meta.mask;
|
||||
return meta_.mask;
|
||||
}
|
||||
|
||||
@property int eventFd() const
|
||||
{
|
||||
return meta.fd;
|
||||
return meta_.fd;
|
||||
}
|
||||
|
||||
@property int pid() const
|
||||
{
|
||||
return meta.pid;
|
||||
return meta_.pid;
|
||||
}
|
||||
|
||||
@property string name() const
|
||||
{
|
||||
return name_;
|
||||
}
|
||||
|
||||
// Методы проверки событий (без ref)
|
||||
bool isOpen() const
|
||||
{
|
||||
return (mask & FAN_OPEN) != 0;
|
||||
|
@ -65,44 +92,97 @@ struct FanotifyEvent
|
|||
{
|
||||
return (mask & FAN_DELETE) != 0;
|
||||
}
|
||||
}
|
||||
|
||||
class Fanotify
|
||||
{
|
||||
private int fd = -1;
|
||||
|
||||
this(uint initFlags, uint eventFFlags = O_RDONLY | O_LARGEFILE)
|
||||
bool isOpenPerm() const
|
||||
{
|
||||
fd = fanotify_init(initFlags, eventFFlags);
|
||||
enforce(fd >= 0, "Ошибка инициализации fanotify: " ~ to!string(fd));
|
||||
return (mask & FAN_OPEN_PERM) != 0;
|
||||
}
|
||||
|
||||
bool isAccessPerm() const
|
||||
{
|
||||
return (mask & FAN_ACCESS_PERM) != 0;
|
||||
}
|
||||
|
||||
bool isOpenExecPerm() const
|
||||
{
|
||||
return (mask & FAN_OPEN_EXEC_PERM) != 0;
|
||||
}
|
||||
|
||||
bool isOverflow() const
|
||||
{
|
||||
return (mask & FAN_Q_OVERFLOW) != 0;
|
||||
}
|
||||
|
||||
bool isFsError() const
|
||||
{
|
||||
return (mask & FAN_FS_ERROR) != 0;
|
||||
}
|
||||
|
||||
// Метод для постобработки события (виртуальный, можно override для кастомной логики)
|
||||
void postProcess()
|
||||
{
|
||||
// По умолчанию ничего, но можно добавить логику, например, логирование
|
||||
}
|
||||
|
||||
// Метод для отправки response (для permission-событий), закрывает fd автоматически после
|
||||
void respond(uint response)
|
||||
{
|
||||
if (eventFd < 0 || eventFd == FAN_NOFD)
|
||||
{
|
||||
return; // Нет fd для response
|
||||
}
|
||||
|
||||
fanotify_response resp;
|
||||
resp.fd = eventFd;
|
||||
resp.response = response;
|
||||
|
||||
ssize_t res = write(fanFd_, &resp, fanotify_response.sizeof);
|
||||
enforce(res == fanotify_response.sizeof, "Ошибка записи response: " ~ strerror(errno)
|
||||
.fromStringz.to!string);
|
||||
|
||||
// Закрываем fd сразу после response (не ждем деструктора, но деструктор на всякий случай)
|
||||
close(meta_.fd);
|
||||
meta_.fd = -1;
|
||||
}
|
||||
}
|
||||
|
||||
// Основной ООП-класс для управления fanotify
|
||||
class Fanotify
|
||||
{
|
||||
private int fd_ = -1;
|
||||
|
||||
// Конструктор: инициализация с флагами
|
||||
this(uint initFlags, uint eventFFlags = O_RDONLY | O_LARGEFILE)
|
||||
{
|
||||
fd_ = fanotify_init(initFlags, eventFFlags);
|
||||
enforce(fd_ >= 0, "Ошибка инициализации fanotify: " ~ strerror(errno)
|
||||
.fromStringz.to!string);
|
||||
}
|
||||
|
||||
// Деструктор: автоматически закрывает fanotify fd
|
||||
~this()
|
||||
{
|
||||
if (fd >= 0)
|
||||
if (fd_ >= 0)
|
||||
{
|
||||
close(fd);
|
||||
fd = -1;
|
||||
close(fd_);
|
||||
fd_ = -1;
|
||||
}
|
||||
}
|
||||
|
||||
// Метод для добавления/удаления/модификации меток (управление событиями)
|
||||
void mark(uint markFlags, uint64_t eventMask, int dirFd = AT_FDCWD, string path = null)
|
||||
{
|
||||
const(char)* cPath = path ? path.toStringz() : null;
|
||||
int res = fanotify_mark(fd, markFlags, eventMask, dirFd, cPath);
|
||||
if (res == -1)
|
||||
{
|
||||
string errMsg = "Ошибка маркировки fanotify: " ~ to!string(
|
||||
res) ~ " (errno: " ~ to!string(errno) ~ ", " ~ strerror(errno)
|
||||
.fromStringz.to!string ~ ")";
|
||||
throw new Exception(errMsg);
|
||||
}
|
||||
int res = fanotify_mark(fd_, markFlags, eventMask, dirFd, cPath);
|
||||
enforce(res == 0, "Ошибка маркировки fanotify: " ~ strerror(errno)
|
||||
.fromStringz.to!string);
|
||||
}
|
||||
|
||||
// Метод для чтения событий (возвращает массив объектов событий)
|
||||
FanotifyEvent[] readEvents(size_t bufferSize = 4096)
|
||||
{
|
||||
ubyte[] buffer = new ubyte[bufferSize];
|
||||
ssize_t len = read(fd, buffer.ptr, buffer.length);
|
||||
ssize_t len = read(fd_, buffer.ptr, buffer.length);
|
||||
if (len <= 0)
|
||||
{
|
||||
return [];
|
||||
|
@ -112,43 +192,56 @@ class Fanotify
|
|||
size_t offset = 0;
|
||||
while (offset + FAN_EVENT_METADATA_LEN <= len)
|
||||
{
|
||||
auto meta = cast(fanotify_event_metadata*)(buffer.ptr + offset);
|
||||
auto meta = *(cast(fanotify_event_metadata*)(buffer.ptr + offset));
|
||||
if (meta.event_len < FAN_EVENT_METADATA_LEN || offset + meta.event_len > len)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
FanotifyEvent ev = FanotifyEvent(*meta);
|
||||
|
||||
string name;
|
||||
size_t infoOffset = offset + fanotify_event_metadata.sizeof;
|
||||
while (infoOffset < offset + meta.event_len)
|
||||
{
|
||||
auto hdr = cast(fanotify_event_info_header*)(buffer.ptr + infoOffset);
|
||||
auto hdr = *(cast(fanotify_event_info_header*)(buffer.ptr + infoOffset));
|
||||
if (hdr.len == 0 || infoOffset + hdr.len > offset + meta.event_len)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if (hdr.info_type == FAN_EVENT_INFO_TYPE_DFID_NAME)
|
||||
if (hdr.info_type == FAN_EVENT_INFO_TYPE_DFID_NAME ||
|
||||
hdr.info_type == FAN_EVENT_INFO_TYPE_OLD_DFID_NAME ||
|
||||
hdr.info_type == FAN_EVENT_INFO_TYPE_NEW_DFID_NAME)
|
||||
{
|
||||
size_t fidOffset = infoOffset + fanotify_event_info_header.sizeof + __kernel_fsid_t.sizeof;
|
||||
auto handle = cast(file_handle*)(buffer.ptr + fidOffset);
|
||||
auto handle = *(cast(file_handle*)(buffer.ptr + fidOffset));
|
||||
size_t handleEnd = fidOffset + file_handle.sizeof + handle.handle_bytes;
|
||||
if (handleEnd < offset + meta.event_len)
|
||||
{
|
||||
ev.name = (cast(char*)(buffer.ptr + handleEnd)).fromStringz.to!string;
|
||||
name = (cast(char*)(buffer.ptr + handleEnd)).fromStringz.to!string;
|
||||
}
|
||||
}
|
||||
infoOffset += hdr.len;
|
||||
}
|
||||
|
||||
auto ev = new FanotifyEvent(meta, name, fd_);
|
||||
events ~= ev;
|
||||
offset += meta.event_len;
|
||||
}
|
||||
return events;
|
||||
}
|
||||
|
||||
// Метод для постобработки всех событий (вызывает postProcess на каждом)
|
||||
void postProcessEvents(FanotifyEvent[] events)
|
||||
{
|
||||
foreach (ev; events)
|
||||
{
|
||||
ev.postProcess();
|
||||
}
|
||||
}
|
||||
|
||||
// Геттер для fd (если нужно внешне, но лучше использовать методы)
|
||||
@property int handle() const
|
||||
{
|
||||
return fd;
|
||||
return fd_;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue