Добавлен вывод через библиотеку sdiff
This commit is contained in:
parent
aa214dcf96
commit
7f54a56ef5
2 changed files with 66 additions and 5 deletions
9
dub.json
9
dub.json
|
@ -8,7 +8,14 @@
|
||||||
"name": "dwatch",
|
"name": "dwatch",
|
||||||
"targetPath": "bin",
|
"targetPath": "bin",
|
||||||
"targetType": "executable",
|
"targetType": "executable",
|
||||||
|
"libs": [
|
||||||
|
"xdiff"
|
||||||
|
],
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"fanotify": "~>0.1.0"
|
"fanotify": "~>0.1.0",
|
||||||
|
"sdiff": {
|
||||||
|
"repository": "git+git+https://git.zhirov.kz/dlang/sdiff.git",
|
||||||
|
"version": "8c388b112360a9f5bf89b9aa12b1977b8967b219"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
62
source/app.d
62
source/app.d
|
@ -10,7 +10,7 @@ import core.sys.posix.sys.stat : fstat, stat_t;
|
||||||
import core.stdc.errno : errno, EINTR;
|
import core.stdc.errno : errno, EINTR;
|
||||||
import core.stdc.string : strerror;
|
import core.stdc.string : strerror;
|
||||||
import std.stdio : writeln, writefln, stderr;
|
import std.stdio : writeln, writefln, stderr;
|
||||||
import std.file : isDir, readText, exists;
|
import std.file : isDir, readText, exists, read;
|
||||||
import std.string : strip, splitLines, startsWith, toStringz, fromStringz, split;
|
import std.string : strip, splitLines, startsWith, toStringz, fromStringz, split;
|
||||||
import std.conv : to;
|
import std.conv : to;
|
||||||
import std.exception : enforce;
|
import std.exception : enforce;
|
||||||
|
@ -147,6 +147,8 @@ struct Session
|
||||||
uint uid; // LOGINUID из /proc/PID/loginuid
|
uint uid; // LOGINUID из /proc/PID/loginuid
|
||||||
string filePathOpen; // путь, снятый на PERM
|
string filePathOpen; // путь, снятый на PERM
|
||||||
bool changed; // был CLOSE_WRITE
|
bool changed; // был CLOSE_WRITE
|
||||||
|
const(ubyte)[] fileBytesSource;
|
||||||
|
const(ubyte)[] fileBytesDiff;
|
||||||
}
|
}
|
||||||
|
|
||||||
__gshared Session[DevIno] gMap; // (pid,dev,ino) -> Session
|
__gshared Session[DevIno] gMap; // (pid,dev,ino) -> Session
|
||||||
|
@ -184,12 +186,28 @@ ulong dirMask()
|
||||||
FAN_OPEN | FAN_CLOSE_WRITE;
|
FAN_OPEN | FAN_CLOSE_WRITE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ubyte[] readAllFromFd(int fd)
|
||||||
|
{
|
||||||
|
import std.array : appender;
|
||||||
|
|
||||||
|
ubyte[16_384] buf; // 16 KiB буфер
|
||||||
|
auto output = appender!(ubyte[]);
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
auto n = read(fd, buf.ptr, buf.length);
|
||||||
|
if (n <= 0)
|
||||||
|
break;
|
||||||
|
output.put(buf[0 .. n]);
|
||||||
|
}
|
||||||
|
return output.data;
|
||||||
|
}
|
||||||
|
|
||||||
/// ---- обработчики ----
|
/// ---- обработчики ----
|
||||||
void onOpenPerm(FanotifyEvent ev, Epoll ep)
|
void onOpenPerm(FanotifyEvent ev, Epoll ep)
|
||||||
{
|
{
|
||||||
const pid = ev.pid;
|
const pid = ev.pid;
|
||||||
auto procName = readProcComm(pid);
|
auto procName = readProcComm(pid);
|
||||||
auto ids = readProcIds(pid); // <-- ruid + loginuid
|
auto ids = readProcIds(pid);
|
||||||
|
|
||||||
DevIno key;
|
DevIno key;
|
||||||
if (!getDevIno(ev.eventFd, key, pid))
|
if (!getDevIno(ev.eventFd, key, pid))
|
||||||
|
@ -200,13 +218,26 @@ void onOpenPerm(FanotifyEvent ev, Epoll ep)
|
||||||
|
|
||||||
auto path = readlinkFdPath(ev.eventFd);
|
auto path = readlinkFdPath(ev.eventFd);
|
||||||
|
|
||||||
|
const(ubyte)[] content;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (path.length)
|
||||||
|
{
|
||||||
|
content = readAllFromFd(ev.eventFd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
content = [];
|
||||||
|
}
|
||||||
|
|
||||||
if (auto ps = key in gMap)
|
if (auto ps = key in gMap)
|
||||||
{
|
{
|
||||||
// уже есть
|
// уже есть
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
gMap[key] = Session(procName, ids.ruid, ids.uid, path, false);
|
gMap[key] = Session(procName, ids.ruid, ids.uid, path, false, content);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(pid in gPidfdByPid))
|
if (!(pid in gPidfdByPid))
|
||||||
|
@ -214,7 +245,7 @@ void onOpenPerm(FanotifyEvent ev, Epoll ep)
|
||||||
int pfd = -1;
|
int pfd = -1;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
pfd = pidfd_open(pid, 0); // на твоей системе так ок
|
pfd = pidfd_open(pid, 0);
|
||||||
if (pfd < 0)
|
if (pfd < 0)
|
||||||
writeln("pidfd_open failed: ", strerror(errno).fromStringz);
|
writeln("pidfd_open failed: ", strerror(errno).fromStringz);
|
||||||
}
|
}
|
||||||
|
@ -244,7 +275,27 @@ void onCloseWrite(FanotifyEvent ev)
|
||||||
if (!getDevIno(ev.eventFd, key, ev.pid))
|
if (!getDevIno(ev.eventFd, key, ev.pid))
|
||||||
return;
|
return;
|
||||||
if (auto ps = key in gMap)
|
if (auto ps = key in gMap)
|
||||||
|
{
|
||||||
ps.changed = true;
|
ps.changed = true;
|
||||||
|
|
||||||
|
import sdiff;
|
||||||
|
|
||||||
|
const(ubyte)[] content;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (ps.filePathOpen.length)
|
||||||
|
content = readAllFromFd(ev.eventFd);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
content = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
auto dataSource = new MMFile(ps.fileBytesSource);
|
||||||
|
auto dataChange = new MMFile(content);
|
||||||
|
|
||||||
|
ps.fileBytesDiff = dataSource.diff(dataChange).slice();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void flushAndClearForPid(int pid, Epoll ep)
|
void flushAndClearForPid(int pid, Epoll ep)
|
||||||
|
@ -256,7 +307,10 @@ void flushAndClearForPid(int pid, Epoll ep)
|
||||||
continue;
|
continue;
|
||||||
auto s = gMap[k];
|
auto s = gMap[k];
|
||||||
if (s.changed)
|
if (s.changed)
|
||||||
|
{
|
||||||
logChange(s.procName, s.filePathOpen, s.uid, s.ruid);
|
logChange(s.procName, s.filePathOpen, s.uid, s.ruid);
|
||||||
|
writeln(cast(string)s.fileBytesDiff);
|
||||||
|
}
|
||||||
gMap.remove(k);
|
gMap.remove(k);
|
||||||
}
|
}
|
||||||
if (auto p = pid in gPidfdByPid)
|
if (auto p = pid in gPidfdByPid)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue