```mermaid sequenceDiagram %%{init: { 'theme': 'default', 'themeVariables': { 'primaryColor': '#ff0000', 'nodeTextColor': '#ffffff', 'edgeLabelBackground': '#f0f0f0' }}}%% autonumber participant Watcher as Демон-наблюдатель participant Kernel as Ядро (fanotify) participant Editor as Процесс-редактор (PID X) participant FS as Файловая система (целевой каталог/файл) participant Ep as epoll participant Pfd as pidfd(PID X) participant Map as Карта соответствий (в памяти) participant ChLog as Журнал изменений Note over Watcher: Инициализация Watcher->>Kernel: fanotify_init(PRE_CONTENT|NONBLOCK|CLOEXEC, O_RDONLY|O_CLOEXEC|O_LARGEFILE) Watcher->>Kernel: fanotify_mark(ADD|ONLYDIR, EVENT_ON_CHILD|(OPEN[_EXEC]_PERM)|OPEN|CLOSE_WRITE, watchDir) Watcher->>Ep: add(fanotify_fd, tag=FAN) Note over Editor: Запрос доступа к файлу Editor->>FS: open(target, O_RDONLY/O_RDWR/EXEC) FS-->>Kernel: системный вызов доступа Kernel-->>Watcher: PERM-событие (+fd, mask, pid) Note over Watcher: Сбор контекста Watcher->>FS: fstat(fd) → (inode, dev) FS-->>Watcher: inode, dev Watcher->>Watcher: readlink(/proc/self/fd/FD) → file_path_open Watcher->>Watcher: read /proc/PID/{comm,status} → proc_name, RUID, UID(EUID) %% КЛАДЁМ СВЯЗКУ Watcher->>Map: PUT key=(PID,inode,dev), val={proc_name,RUID,UID,file_path_open,changed=false} Note over Map: Добавлена связка key=(PID,inode,dev) %% pidfd и epoll Watcher->>Pfd: pidfd_open(PID, flags=0) Pfd-->>Watcher: pidfd Watcher->>Ep: add(pidfd, tag=PID, events=IN|HUP|RDHUP|ERR) %% Разрешаем доступ Watcher->>Kernel: fanotify_response{fd, FAN_ALLOW} Watcher->>FS: close(fd) Note over Editor: Работа с файлом Editor->>FS: write(...) Editor->>FS: close() Kernel-->>Watcher: CLOSE_WRITE (+fd) Note over Watcher: Фиксация факта изменения Watcher->>FS: fstat(fd) → (inode, dev) FS-->>Watcher: inode, dev Watcher->>Map: GET key=(PID,inode,dev) Map-->>Watcher: {…} Watcher->>Map: SET changed=true Watcher->>FS: close(fd) Note over Editor: Завершение процесса Editor->>Editor: exit() Pfd-->>Ep: EPOLLIN/HUP (pid завершён) Ep-->>Watcher: событие(tag=PID) %% ПИШЕМ ЖУРНАЛ И ЧИСТИМ Watcher->>Map: GET_ALL where pid=PID Map-->>Watcher: список записей Watcher->>ChLog: APPEND для всех changed=true → {proc=proc_name, file=file_path_open, uid=UID, ruid=RUID} Watcher->>Ep: remove(pidfd) Watcher->>Pfd: close(pidfd) Watcher->>Map: DELETE_ALL where pid=PID Note over Map: Удалены все связки для PID ```