удалены комментарии
This commit is contained in:
parent
582ae5a294
commit
ed0d2780c3
2 changed files with 72 additions and 144 deletions
59
source/app.d
59
source/app.d
|
@ -1,28 +1,15 @@
|
||||||
// Модуль app.d
|
import dfanotify;
|
||||||
// Это основное приложение, демонстрирующее использование обёртки fanotify_wrapper.
|
|
||||||
// Инициализирует fanotify, маркирует директорию /tmp/scripts для мониторинга событий (открытие, модификация и т.д.),
|
|
||||||
// затем в бесконечном цикле читает события и выводит информацию о них в консоль.
|
|
||||||
// Импорты: fanotify_wrapper - обёртка, std.stdio для вывода, std.file для readLink (хотя здесь не используется из-за режима),
|
|
||||||
// std.format для форматирования строк, core.sys.posix для констант.
|
|
||||||
|
|
||||||
import dfanotify; // Импорт обёртки для fanotify.
|
import std.stdio;
|
||||||
|
import std.file : readLink;
|
||||||
import std.stdio; // Импорт для writeln, writefln (вывод в консоль).
|
import std.format : format;
|
||||||
import std.file : readLink; // Импорт readLink для чтения симлинков (не используется здесь, но оставлено для возможного расширения).
|
import core.sys.posix.fcntl : AT_FDCWD;
|
||||||
import std.format : format; // Импорт format для форматирования строк (хотя здесь используется writefln напрямую).
|
import core.sys.posix.unistd : close;
|
||||||
import core.sys.posix.fcntl : AT_FDCWD; // Импорт AT_FDCWD для текущей директории.
|
|
||||||
import core.sys.posix.unistd : close; // Импорт close (не используется здесь, но для возможного расширения с fd).
|
|
||||||
import core.stdc.stdlib : exit;
|
import core.stdc.stdlib : exit;
|
||||||
|
|
||||||
// Функция main: точка входа приложения.
|
|
||||||
void main()
|
void main()
|
||||||
{
|
{
|
||||||
Fanotify fan;
|
Fanotify fan;
|
||||||
// Инициализация объекта Fanotify с флагами:
|
|
||||||
// FAN_CLASS_NOTIF - режим уведомлений (без контроля доступа),
|
|
||||||
// FAN_CLOEXEC - закрытие дескриптора при exec,
|
|
||||||
// FAN_REPORT_FID | FAN_REPORT_DIR_FID | FAN_REPORT_NAME - отчёт с FID (идентификатор файла) вместо fd, плюс имя файла.
|
|
||||||
// Это позволяет получать имя без реального fd (fd будет FAN_NOFD).
|
|
||||||
try {
|
try {
|
||||||
fan = new Fanotify(
|
fan = new Fanotify(
|
||||||
FAN_CLASS_NOTIF | FAN_CLOEXEC | FAN_REPORT_FID | FAN_REPORT_DIR_FID | FAN_REPORT_NAME);
|
FAN_CLASS_NOTIF | FAN_CLOEXEC | FAN_REPORT_FID | FAN_REPORT_DIR_FID | FAN_REPORT_NAME);
|
||||||
|
@ -31,14 +18,8 @@ void main()
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Определение маски событий: битовая OR флагов для мониторинга.
|
|
||||||
// FAN_OPEN - открытие, FAN_MODIFY - модификация, FAN_CLOSE - закрытие (включает WRITE и NOWRITE),
|
|
||||||
// FAN_CREATE - создание, FAN_DELETE - удаление, FAN_EVENT_ON_CHILD - события в поддиректориях.
|
|
||||||
auto eventMask = FAN_OPEN | FAN_MODIFY | FAN_CLOSE | FAN_CREATE | FAN_DELETE | FAN_EVENT_ON_CHILD;
|
auto eventMask = FAN_OPEN | FAN_MODIFY | FAN_CLOSE | FAN_CREATE | FAN_DELETE | FAN_EVENT_ON_CHILD;
|
||||||
|
|
||||||
// Маркировка директории /tmp/scripts:
|
|
||||||
// FAN_MARK_ADD - добавить марку, FAN_MARK_ONLYDIR - только для директории (ошибка, если не директория).
|
|
||||||
// AT_FDCWD - базовая директория текущая, путь "/tmp/scripts".
|
|
||||||
try {
|
try {
|
||||||
fan.mark(FAN_MARK_ADD | FAN_MARK_ONLYDIR, eventMask, AT_FDCWD, "/tmp/scripts");
|
fan.mark(FAN_MARK_ADD | FAN_MARK_ONLYDIR, eventMask, AT_FDCWD, "/tmp/scripts");
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
|
@ -46,37 +27,29 @@ void main()
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
writeln("Мониторинг запущен для /tmp/scripts..."); // Вывод сообщения о старте мониторинга.
|
writeln("Мониторинг запущен для /tmp/scripts...");
|
||||||
|
|
||||||
// Бесконечный цикл: постоянно читает события и обрабатывает их.
|
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
auto events = fan.readEvents(); // Чтение событий (блокирующее, ждёт до появления событий).
|
auto events = fan.readEvents();
|
||||||
|
|
||||||
foreach (ref e; events) // Цикл по каждому событию в массиве.
|
foreach (ref e; events)
|
||||||
{
|
{
|
||||||
// Определение пути: если name извлечено (из FAN_REPORT_NAME), использовать его; иначе "unknown".
|
string path = e.name.length ? e.name : "unknown";
|
||||||
// name - относительное имя файла/директории относительно маркированной.
|
|
||||||
string path = e.name.length ? e.name : "unknown"; // Используем извлечённое имя (относительное)
|
|
||||||
|
|
||||||
// Комментарий: в режиме с FAN_REPORT_FID fd = FAN_NOFD, так что нельзя использовать readLink("/proc/self/fd/" ~ to!string(e.eventFd)) для полного пути.
|
|
||||||
// fd теперь FAN_NOFD, так что пропускаем readLink/close
|
|
||||||
|
|
||||||
// Вывод общей информации о событии: маска в hex, PID, путь/имя.
|
|
||||||
writefln("Событие: mask=0x%x, pid=%d, name/path=%s", e.mask, e.pid, path);
|
writefln("Событие: mask=0x%x, pid=%d, name/path=%s", e.mask, e.pid, path);
|
||||||
|
|
||||||
// Проверки и вывод конкретных типов событий с использованием методов структуры.
|
if (e.isOpen)
|
||||||
if (e.isOpen) // Если открытие.
|
|
||||||
writeln(" - Открытие файла");
|
writeln(" - Открытие файла");
|
||||||
if (e.isModify) // Если модификация.
|
if (e.isModify)
|
||||||
writeln(" - Модификация файла");
|
writeln(" - Модификация файла");
|
||||||
if (e.isCloseWrite) // Если закрытие после записи.
|
if (e.isCloseWrite)
|
||||||
writeln(" - Закрытие после записи");
|
writeln(" - Закрытие после записи");
|
||||||
if (e.isCloseNoWrite) // Если закрытие без записи.
|
if (e.isCloseNoWrite)
|
||||||
writeln(" - Закрытие без записи");
|
writeln(" - Закрытие без записи");
|
||||||
if (e.isCreate) // Если создание.
|
if (e.isCreate)
|
||||||
writeln(" - Создание файла/директории");
|
writeln(" - Создание файла/директории");
|
||||||
if (e.isDelete) // Если удаление.
|
if (e.isDelete)
|
||||||
writeln(" - Удаление файла/директории");
|
writeln(" - Удаление файла/директории");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,199 +1,154 @@
|
||||||
// Модуль fanotify_wrapper.d
|
|
||||||
// Этот модуль предоставляет обёртку вокруг API fanotify для упрощения мониторинга событий файловой системы в Linux.
|
|
||||||
// Fanotify позволяет получать уведомления о действиях с файлами, такими как открытие, модификация, создание и удаление.
|
|
||||||
// Обёртка включает структуру для событий, класс для управления дескриптором и методы для инициализации, маркировки и чтения событий.
|
|
||||||
// Импорты: public import fanotify - предполагается, что это низкоуровневый модуль с определениями из <linux/fanotify.h>.
|
|
||||||
// Другие импорты из core.sys.posix для системных вызовов (read, close и т.д.), std.exception для обработки ошибок,
|
|
||||||
// std.string и std.conv для работы со строками, core.stdc.errno для errno и strerror для детальных сообщений об ошибках,
|
|
||||||
// core.stdc.stdint для типов вроде uint64_t.
|
|
||||||
|
|
||||||
module dfanotify;
|
module dfanotify;
|
||||||
|
|
||||||
public import fanotify; // Импорт низкоуровневых определений fanotify (структуры, константы, функции вроде fanotify_init, fanotify_mark).
|
public import fanotify;
|
||||||
|
|
||||||
import core.sys.posix.unistd : read, close, ssize_t; // Импорт функций для чтения (read), закрытия (close) дескрипторов и типа ssize_t для возвращаемых значений.
|
import core.sys.posix.unistd : read, close, ssize_t;
|
||||||
import core.sys.posix.fcntl : O_RDONLY, O_RDWR, O_LARGEFILE, AT_FDCWD; // Импорт флагов для open (O_RDONLY - только чтение, O_LARGEFILE - поддержка больших файлов) и AT_FDCWD для текущей директории.
|
import core.sys.posix.fcntl : O_RDONLY, O_RDWR, O_LARGEFILE, AT_FDCWD;
|
||||||
import std.exception : enforce; // Импорт enforce для проверки условий и бросания исключений при ошибках.
|
import std.exception : enforce;
|
||||||
import std.string : toStringz, fromStringz; // Импорт функций для конвертации строк D в C-строки (toStringz) и обратно (fromStringz).
|
import std.string : toStringz, fromStringz;
|
||||||
import std.conv : to; // Импорт to для конвертации типов (например, int в string).
|
import std.conv : to;
|
||||||
import core.stdc.errno : errno; // Импорт errno для получения кода последней ошибки.
|
import core.stdc.errno : errno;
|
||||||
import core.stdc.string : strerror; // Импорт strerror для получения строкового описания ошибки по errno.
|
import core.stdc.string : strerror;
|
||||||
import core.stdc.stdint; // Импорт стандартных целочисленных типов (uint64_t и т.п.).
|
import core.stdc.stdint;
|
||||||
|
|
||||||
// Структура FanotifyEvent: представляет одно событие fanotify.
|
|
||||||
// Расширена по сравнению с базовой fanotify_event_metadata: добавлено поле name для извлечённого имени файла (если используются флаги FAN_REPORT_NAME).
|
|
||||||
// Также добавлены свойства для доступа к ключевым полям и методы для проверки конкретных типов событий.
|
|
||||||
// Это упрощает работу с событиями, делая код более читаемым (вместо прямого доступа к meta.mask и т.д.).
|
|
||||||
struct FanotifyEvent
|
struct FanotifyEvent
|
||||||
{
|
{
|
||||||
fanotify_event_metadata meta; // Базовая структура метаданных события из fanotify (содержит mask, fd, pid, event_len и т.д.).
|
fanotify_event_metadata meta;
|
||||||
string name; // Извлечённое имя файла или директории (относительное имя, если FAN_REPORT_NAME включено; парсится из дополнительной информации в буфере).
|
string name;
|
||||||
|
|
||||||
// Свойство mask: возвращает маску событий (битовая маска, где каждый бит соответствует типу события, например FAN_OPEN).
|
|
||||||
@property uint64_t mask() const
|
@property uint64_t mask() const
|
||||||
{
|
{
|
||||||
return meta.mask; // Просто возвращает значение из meta; const гарантирует, что структура не модифицируется.
|
return meta.mask;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Свойство eventFd: возвращает дескриптор файла события (fd). В режиме FAN_REPORT_FID это FAN_NOFD (-1), иначе реальный fd.
|
|
||||||
@property int eventFd() const
|
@property int eventFd() const
|
||||||
{
|
{
|
||||||
return meta.fd; // Доступ к fd из meta; полезно, если нужно работать с файлом напрямую (но в этом коде используется режим без fd).
|
return meta.fd;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Свойство pid: возвращает PID процесса, который вызвал событие.
|
|
||||||
@property int pid() const
|
@property int pid() const
|
||||||
{
|
{
|
||||||
return meta.pid; // Доступ к pid из meta; помогает идентифицировать, какой процесс взаимодействовал с файлом.
|
return meta.pid;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Метод isOpen: проверяет, включает ли маска событие открытия файла (FAN_OPEN).
|
|
||||||
// Использует битовую операцию & для проверки наличия бита FAN_OPEN в mask.
|
|
||||||
bool isOpen() const
|
bool isOpen() const
|
||||||
{
|
{
|
||||||
return (mask & FAN_OPEN) != 0; // Если бит установлен, возвращает true; это стандартный способ работы с битoвыми масками.
|
return (mask & FAN_OPEN) != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Метод isModify: проверяет событие модификации файла (FAN_MODIFY, например, запись в файл).
|
|
||||||
bool isModify() const
|
bool isModify() const
|
||||||
{
|
{
|
||||||
return (mask & FAN_MODIFY) != 0; // Аналогично, проверка бита FAN_MODIFY.
|
return (mask & FAN_MODIFY) != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Метод isCloseWrite: проверяет закрытие файла после записи (FAN_CLOSE_WRITE).
|
|
||||||
bool isCloseWrite() const
|
bool isCloseWrite() const
|
||||||
{
|
{
|
||||||
return (mask & FAN_CLOSE_WRITE) != 0; // Проверка бита для закрытия с модификацией.
|
return (mask & FAN_CLOSE_WRITE) != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Метод isCloseNoWrite: проверяет закрытие файла без записи (FAN_CLOSE_NOWRITE, например, после чтения).
|
|
||||||
bool isCloseNoWrite() const
|
bool isCloseNoWrite() const
|
||||||
{
|
{
|
||||||
return (mask & FAN_CLOSE_NOWRITE) != 0; // Проверка бита для закрытия без модификации.
|
return (mask & FAN_CLOSE_NOWRITE) != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Метод isAccess: проверяет событие доступа (FAN_ACCESS, например, чтение).
|
|
||||||
bool isAccess() const
|
bool isAccess() const
|
||||||
{
|
{
|
||||||
return (mask & FAN_ACCESS) != 0; // Проверка бита FAN_ACCESS.
|
return (mask & FAN_ACCESS) != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Метод isCreate: проверяет создание файла или директории (FAN_CREATE).
|
|
||||||
bool isCreate() const
|
bool isCreate() const
|
||||||
{
|
{
|
||||||
return (mask & FAN_CREATE) != 0; // Проверка бита для создания.
|
return (mask & FAN_CREATE) != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Метод isDelete: проверяет удаление файла или директории (FAN_DELETE).
|
|
||||||
bool isDelete() const
|
bool isDelete() const
|
||||||
{
|
{
|
||||||
return (mask & FAN_DELETE) != 0; // Проверка бита для удаления.
|
return (mask & FAN_DELETE) != 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Класс Fanotify: основной класс для работы с fanotify.
|
|
||||||
// Управляет дескриптором (fd), инициализирует его, маркирует пути для мониторинга, читает события и закрывает дескриптор.
|
|
||||||
// Расширен для парсинга дополнительной информации (FID, NAME) в методе readEvents.
|
|
||||||
// Использует RAII: дескриптор закрывается в деструкторе автоматически.
|
|
||||||
class Fanotify
|
class Fanotify
|
||||||
{
|
{
|
||||||
private int fd = -1; // Приватный дескриптор fanotify; инициализирован -1 (недействительный), чтобы избежать использования до инициализации.
|
private int fd = -1;
|
||||||
|
|
||||||
// Конструктор: инициализирует fanotify с заданными флагами.
|
|
||||||
// initFlags: флаги для fanotify_init (например, FAN_CLASS_NOTIF для уведомлений без контроля доступа).
|
|
||||||
// eventFFlags: флаги для событий (по умолчанию O_RDONLY | O_LARGEFILE для чтения больших файлов).
|
|
||||||
this(uint initFlags, uint eventFFlags = O_RDONLY | O_LARGEFILE)
|
this(uint initFlags, uint eventFFlags = O_RDONLY | O_LARGEFILE)
|
||||||
{
|
{
|
||||||
fd = fanotify_init(initFlags, eventFFlags); // Вызов системной функции fanotify_init для создания дескриптора.
|
fd = fanotify_init(initFlags, eventFFlags);
|
||||||
enforce(fd >= 0, "Ошибка инициализации fanotify: " ~ to!string(fd)); // Проверка: если fd < 0, бросить исключение с сообщением; enforce упрощает обработку ошибок.
|
enforce(fd >= 0, "Ошибка инициализации fanotify: " ~ to!string(fd));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Деструктор: автоматически вызывается при уничтожении объекта.
|
|
||||||
~this()
|
~this()
|
||||||
{
|
{
|
||||||
if (fd >= 0) // Проверка, валиден ли fd (чтобы избежать закрытия -1).
|
if (fd >= 0)
|
||||||
{
|
{
|
||||||
close(fd); // Закрытие дескриптора через системный вызов close; освобождает ресурсы.
|
close(fd);
|
||||||
fd = -1; // Установка в -1 для безопасности (хотя объект уничтожается).
|
fd = -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Метод mark: маркирует путь (файл или директорию) для мониторинга.
|
|
||||||
// markFlags: флаги маркировки (например, FAN_MARK_ADD для добавления, FAN_MARK_ONLYDIR для только директорий).
|
|
||||||
// eventMask: маска событий, которые нужно мониторить (битовая маска, например FAN_OPEN | FAN_MODIFY).
|
|
||||||
// dirFd: дескриптор директории (по умолчанию AT_FDCWD - текущая).
|
|
||||||
// path: путь к маркируемому объекту (null для текущей директории).
|
|
||||||
void mark(uint markFlags, uint64_t eventMask, int dirFd = AT_FDCWD, string path = null)
|
void mark(uint markFlags, uint64_t eventMask, int dirFd = AT_FDCWD, string path = null)
|
||||||
{
|
{
|
||||||
const(char)* cPath = path ? path.toStringz() : null; // Конвертация пути в C-строку (toStringz добавляет null-терминатор); если path null, то null.
|
const(char)* cPath = path ? path.toStringz() : null;
|
||||||
int res = fanotify_mark(fd, markFlags, eventMask, dirFd, cPath); // Вызов системной функции fanotify_mark для добавления марки.
|
int res = fanotify_mark(fd, markFlags, eventMask, dirFd, cPath);
|
||||||
if (res == -1) // Проверка на ошибку (-1 означает неудачу).
|
if (res == -1)
|
||||||
{
|
{
|
||||||
// Сборка детального сообщения об ошибке: включает res, errno и описание от strerror.
|
|
||||||
string errMsg = "Ошибка маркировки fanotify: " ~ to!string(
|
string errMsg = "Ошибка маркировки fanotify: " ~ to!string(
|
||||||
res) ~ " (errno: " ~ to!string(errno) ~ ", " ~ strerror(errno)
|
res) ~ " (errno: " ~ to!string(errno) ~ ", " ~ strerror(errno)
|
||||||
.fromStringz.to!string ~ ")";
|
.fromStringz.to!string ~ ")";
|
||||||
throw new Exception(errMsg); // Бросить исключение для прерывания выполнения при ошибке.
|
throw new Exception(errMsg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Метод readEvents: читает события из дескриптора fanotify.
|
|
||||||
// bufferSize: размер буфера для чтения (по умолчанию 4096 байт - размер страницы памяти, достаточно для нескольких событий).
|
|
||||||
// Возвращает массив FanotifyEvent; расширен для парсинга дополнительной информации (FID, DFID, NAME).
|
|
||||||
FanotifyEvent[] readEvents(size_t bufferSize = 4096)
|
FanotifyEvent[] readEvents(size_t bufferSize = 4096)
|
||||||
{
|
{
|
||||||
ubyte[] buffer = new ubyte[bufferSize]; // Выделение буфера unsigned byte[] для сырых данных (fanotify возвращает байты).
|
ubyte[] buffer = new ubyte[bufferSize];
|
||||||
ssize_t len = read(fd, buffer.ptr, buffer.length); // Чтение данных из fd через системный вызов read; len - количество прочитанных байт (блокирующий вызов, ждёт событий).
|
ssize_t len = read(fd, buffer.ptr, buffer.length);
|
||||||
if (len <= 0) // Если ничего не прочитано или ошибка, вернуть пустой массив.
|
if (len <= 0)
|
||||||
{
|
{
|
||||||
return []; // Нет событий или ошибка (не бросаем исключение, чтобы цикл мог продолжаться).
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
FanotifyEvent[] events; // Массив для собранных событий.
|
FanotifyEvent[] events;
|
||||||
size_t offset = 0; // Смещение в буфере для парсинга (события идут подряд).
|
size_t offset = 0;
|
||||||
while (offset + FAN_EVENT_METADATA_LEN <= len) // Цикл по буферу: пока хватает места для минимальной структуры metadata.
|
while (offset + FAN_EVENT_METADATA_LEN <= len)
|
||||||
{
|
{
|
||||||
auto meta = cast(fanotify_event_metadata*)(buffer.ptr + offset); // Кастинг байтов в структуру metadata (unsafe, но стандартно для C-API).
|
auto meta = cast(fanotify_event_metadata*)(buffer.ptr + offset);
|
||||||
if (meta.event_len < FAN_EVENT_METADATA_LEN || offset + meta.event_len > len) // Проверка валидности: длина события должна быть >= минимальной и не выходить за буфер.
|
if (meta.event_len < FAN_EVENT_METADATA_LEN || offset + meta.event_len > len)
|
||||||
{
|
{
|
||||||
break; // Если некорректно, прервать цикл (защита от повреждённых данных).
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
FanotifyEvent ev = FanotifyEvent(*meta); // Создание структуры события на основе meta (копирует данные).
|
FanotifyEvent ev = FanotifyEvent(*meta);
|
||||||
|
|
||||||
// Парсинг дополнительной информации (info blocks): если флаги включают FAN_REPORT_FID/NAME, в буфере после meta идут блоки с FID, NAME и т.д.
|
size_t infoOffset = offset + fanotify_event_metadata.sizeof;
|
||||||
size_t infoOffset = offset + fanotify_event_metadata.sizeof; // Смещение после meta.
|
while (infoOffset < offset + meta.event_len)
|
||||||
while (infoOffset < offset + meta.event_len) // Цикл по блокам info внутри события.
|
|
||||||
{
|
{
|
||||||
auto hdr = cast(fanotify_event_info_header*)(buffer.ptr + infoOffset); // Кастинг в заголовок info (содержит type и len).
|
auto hdr = cast(fanotify_event_info_header*)(buffer.ptr + infoOffset);
|
||||||
if (hdr.len == 0 || infoOffset + hdr.len > offset + meta.event_len) // Проверка валидности блока.
|
if (hdr.len == 0 || infoOffset + hdr.len > offset + meta.event_len)
|
||||||
{
|
{
|
||||||
break; // Если некорректно, прервать.
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hdr.info_type == FAN_EVENT_INFO_TYPE_DFID_NAME) // Если тип - DFID + NAME (директория FID + имя).
|
if (hdr.info_type == FAN_EVENT_INFO_TYPE_DFID_NAME)
|
||||||
{
|
{
|
||||||
// Расчёт смещения: пропускаем hdr, fsid (filesystem ID), затем file_handle.
|
|
||||||
size_t fidOffset = infoOffset + fanotify_event_info_header.sizeof + __kernel_fsid_t.sizeof;
|
size_t fidOffset = infoOffset + fanotify_event_info_header.sizeof + __kernel_fsid_t.sizeof;
|
||||||
auto handle = cast(file_handle*)(buffer.ptr + fidOffset); // Кастинг в структуру file_handle (содержит handle_bytes - размер handle).
|
auto handle = cast(file_handle*)(buffer.ptr + fidOffset);
|
||||||
size_t handleEnd = fidOffset + file_handle.sizeof + handle.handle_bytes; // Конец handle в буфере.
|
size_t handleEnd = fidOffset + file_handle.sizeof + handle.handle_bytes;
|
||||||
if (handleEnd < offset + meta.event_len) // Проверка, что за handle есть место для имени.
|
if (handleEnd < offset + meta.event_len)
|
||||||
{
|
{
|
||||||
// Извлечение имени: null-terminated C-строка после handle; конвертируем в string D.
|
|
||||||
ev.name = (cast(char*)(buffer.ptr + handleEnd)).fromStringz.to!string;
|
ev.name = (cast(char*)(buffer.ptr + handleEnd)).fromStringz.to!string;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
infoOffset += hdr.len; // Переход к следующему блоку info.
|
infoOffset += hdr.len;
|
||||||
}
|
}
|
||||||
events ~= ev; // Добавление parsed события в массив.
|
events ~= ev;
|
||||||
offset += meta.event_len; // Переход к следующему событию в буфере.
|
offset += meta.event_len;
|
||||||
}
|
}
|
||||||
return events; // Возврат массива событий.
|
return events;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Свойство handle: возвращает дескриптор fd для низкоуровневого доступа (если нужно, например, для select или других вызовов).
|
|
||||||
@property int handle() const
|
@property int handle() const
|
||||||
{
|
{
|
||||||
return fd; // Просто геттер.
|
return fd;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue