Простой пример

This commit is contained in:
Alexander Zhirov 2025-08-22 22:10:39 +03:00
parent d14c1d37ba
commit e259f5901b
Signed by: alexander
GPG key ID: C8D8BE544A27C511
2 changed files with 81 additions and 180 deletions

View file

@ -1,71 +1,54 @@
// Модуль app.d
// Это основное приложение, демонстрирующее использование обёртки fanotify_wrapper.
// Инициализирует fanotify, маркирует директорию /tmp/scripts для мониторинга событий (открытие, модификация и т.д.),
// затем в бесконечном цикле читает события и выводит информацию о них в консоль.
// Импорты: fanotify_wrapper - обёртка, std.stdio для вывода, std.file для readLink (хотя здесь не используется из-за режима),
// std.format для форматирования строк, core.sys.posix для констант.
import fanotify_wrapper;
import fanotify_wrapper; // Импорт обёртки для fanotify.
import std.stdio;
import std.file : readLink;
import std.format : format;
import core.sys.posix.fcntl : AT_FDCWD;
import core.sys.posix.unistd : close;
import std.stdio; // Импорт для writeln, writefln (вывод в консоль).
import std.file : readLink; // Импорт readLink для чтения симлинков (не используется здесь, но оставлено для возможного расширения).
import std.format : format; // Импорт format для форматирования строк (хотя здесь используется writefln напрямую).
import core.sys.posix.fcntl : AT_FDCWD; // Импорт AT_FDCWD для текущей директории.
import core.sys.posix.unistd : close; // Импорт close (не используется здесь, но для возможного расширения с fd).
// Функция main: точка входа приложения.
void main()
{
// Инициализация объекта Fanotify с флагами:
// FAN_CLASS_NOTIF - режим уведомлений (без контроля доступа),
// FAN_CLOEXEC - закрытие дескриптора при exec,
// FAN_REPORT_FID | FAN_REPORT_DIR_FID | FAN_REPORT_NAME - отчёт с FID (идентификатор файла) вместо fd, плюс имя файла.
// Это позволяет получать имя без реального fd (fd будет FAN_NOFD).
auto fan = new Fanotify(
FAN_CLASS_NOTIF | FAN_CLOEXEC | FAN_REPORT_FID | FAN_REPORT_DIR_FID | FAN_REPORT_NAME);
// Инициализация fanotify в режиме уведомлений (без разрешений), с CLOEXEC
auto fan = new Fanotify(FAN_CLASS_NOTIF | FAN_CLOEXEC);
// Определение маски событий: битовая 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_EVENT_ON_CHILD;
// Маркировка директории /tmp/scripts:
// FAN_MARK_ADD - добавить марку, FAN_MARK_ONLYDIR - только для директории (ошибка, если не директория).
// AT_FDCWD - базовая директория текущая, путь "/tmp/scripts".
fan.mark(FAN_MARK_ADD | FAN_MARK_ONLYDIR, eventMask, AT_FDCWD, "/tmp/scripts");
// Маркировка директории /tmp/scripts
fan.mark(FAN_MARK_ADD, eventMask, AT_FDCWD, "/tmp/scripts");
writeln("Мониторинг запущен для /tmp/scripts..."); // Вывод сообщения о старте мониторинга.
writeln("Мониторинг запущен для /tmp/scripts...");
// Бесконечный цикл: постоянно читает события и обрабатывает их.
// Бесконечный цикл чтения событий
while (true)
{
auto events = fan.readEvents(); // Чтение событий (блокирующее, ждёт до появления событий).
foreach (ref e; events) // Цикл по каждому событию в массиве.
auto events = fan.readEvents();
foreach (ref e; events)
{
// Определение пути: если name извлечено (из FAN_REPORT_NAME), использовать его; иначе "unknown".
// name - относительное имя файла/директории относительно маркированной.
string path = e.name.length ? e.name : "unknown"; // Используем извлечённое имя (относительное)
string path = "unknown";
if (e.eventFd != FAN_NOFD)
{
try
{
path = readLink(format("/proc/self/fd/%d", e.eventFd));
}
catch (Exception ex)
{
// Игнорируем ошибки (например, если файл удалён)
}
close(e.eventFd); // Обязательно закрываем fd после обработки
}
// Комментарий: в режиме с 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);
// Проверки и вывод конкретных типов событий с использованием методов структуры.
if (e.isOpen) // Если открытие.
// Вывод информации о событии
writefln("Событие: mask=0x%x, pid=%d, path=%s", e.mask, e.pid, path);
if (e.isOpen)
writeln(" - Открытие файла");
if (e.isModify) // Если модификация.
if (e.isModify)
writeln(" - Модификация файла");
if (e.isCloseWrite) // Если закрытие после записи.
if (e.isCloseWrite)
writeln(" - Закрытие после записи");
if (e.isCloseNoWrite) // Если закрытие без записи.
if (e.isCloseNoWrite)
writeln(" - Закрытие без записи");
if (e.isCreate) // Если создание.
writeln(" - Создание файла/директории");
if (e.isDelete) // Если удаление.
writeln(" - Удаление файла/директории");
}
}
}