2.9 KiB
2.9 KiB
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