154 lines
3.2 KiB
D
154 lines
3.2 KiB
D
module dfanotify;
|
|
|
|
public import fanotify;
|
|
|
|
import core.sys.posix.unistd : read, close, ssize_t;
|
|
import core.sys.posix.fcntl : O_RDONLY, O_RDWR, O_LARGEFILE, AT_FDCWD;
|
|
import std.exception : enforce;
|
|
import std.string : toStringz, fromStringz;
|
|
import std.conv : to;
|
|
import core.stdc.errno : errno;
|
|
import core.stdc.string : strerror;
|
|
import core.stdc.stdint;
|
|
|
|
struct FanotifyEvent
|
|
{
|
|
fanotify_event_metadata meta;
|
|
string name;
|
|
|
|
@property uint64_t mask() const
|
|
{
|
|
return meta.mask;
|
|
}
|
|
|
|
@property int eventFd() const
|
|
{
|
|
return meta.fd;
|
|
}
|
|
|
|
@property int pid() const
|
|
{
|
|
return meta.pid;
|
|
}
|
|
|
|
bool isOpen() const
|
|
{
|
|
return (mask & FAN_OPEN) != 0;
|
|
}
|
|
|
|
bool isModify() const
|
|
{
|
|
return (mask & FAN_MODIFY) != 0;
|
|
}
|
|
|
|
bool isCloseWrite() const
|
|
{
|
|
return (mask & FAN_CLOSE_WRITE) != 0;
|
|
}
|
|
|
|
bool isCloseNoWrite() const
|
|
{
|
|
return (mask & FAN_CLOSE_NOWRITE) != 0;
|
|
}
|
|
|
|
bool isAccess() const
|
|
{
|
|
return (mask & FAN_ACCESS) != 0;
|
|
}
|
|
|
|
bool isCreate() const
|
|
{
|
|
return (mask & FAN_CREATE) != 0;
|
|
}
|
|
|
|
bool isDelete() const
|
|
{
|
|
return (mask & FAN_DELETE) != 0;
|
|
}
|
|
}
|
|
|
|
class Fanotify
|
|
{
|
|
private int fd = -1;
|
|
|
|
this(uint initFlags, uint eventFFlags = O_RDONLY | O_LARGEFILE)
|
|
{
|
|
fd = fanotify_init(initFlags, eventFFlags);
|
|
enforce(fd >= 0, "Ошибка инициализации fanotify: " ~ to!string(fd));
|
|
}
|
|
|
|
~this()
|
|
{
|
|
if (fd >= 0)
|
|
{
|
|
close(fd);
|
|
fd = -1;
|
|
}
|
|
}
|
|
|
|
void mark(uint markFlags, uint64_t eventMask, int dirFd = AT_FDCWD, string path = null)
|
|
{
|
|
const(char)* cPath = path ? path.toStringz() : null;
|
|
int res = fanotify_mark(fd, markFlags, eventMask, dirFd, cPath);
|
|
if (res == -1)
|
|
{
|
|
string errMsg = "Ошибка маркировки fanotify: " ~ to!string(
|
|
res) ~ " (errno: " ~ to!string(errno) ~ ", " ~ strerror(errno)
|
|
.fromStringz.to!string ~ ")";
|
|
throw new Exception(errMsg);
|
|
}
|
|
}
|
|
|
|
FanotifyEvent[] readEvents(size_t bufferSize = 4096)
|
|
{
|
|
ubyte[] buffer = new ubyte[bufferSize];
|
|
ssize_t len = read(fd, buffer.ptr, buffer.length);
|
|
if (len <= 0)
|
|
{
|
|
return [];
|
|
}
|
|
|
|
FanotifyEvent[] events;
|
|
size_t offset = 0;
|
|
while (offset + FAN_EVENT_METADATA_LEN <= len)
|
|
{
|
|
auto meta = cast(fanotify_event_metadata*)(buffer.ptr + offset);
|
|
if (meta.event_len < FAN_EVENT_METADATA_LEN || offset + meta.event_len > len)
|
|
{
|
|
break;
|
|
}
|
|
|
|
FanotifyEvent ev = FanotifyEvent(*meta);
|
|
|
|
size_t infoOffset = offset + fanotify_event_metadata.sizeof;
|
|
while (infoOffset < offset + meta.event_len)
|
|
{
|
|
auto hdr = cast(fanotify_event_info_header*)(buffer.ptr + infoOffset);
|
|
if (hdr.len == 0 || infoOffset + hdr.len > offset + meta.event_len)
|
|
{
|
|
break;
|
|
}
|
|
|
|
if (hdr.info_type == FAN_EVENT_INFO_TYPE_DFID_NAME)
|
|
{
|
|
size_t fidOffset = infoOffset + fanotify_event_info_header.sizeof + __kernel_fsid_t.sizeof;
|
|
auto handle = cast(file_handle*)(buffer.ptr + fidOffset);
|
|
size_t handleEnd = fidOffset + file_handle.sizeof + handle.handle_bytes;
|
|
if (handleEnd < offset + meta.event_len)
|
|
{
|
|
ev.name = (cast(char*)(buffer.ptr + handleEnd)).fromStringz.to!string;
|
|
}
|
|
}
|
|
infoOffset += hdr.len;
|
|
}
|
|
events ~= ev;
|
|
offset += meta.event_len;
|
|
}
|
|
return events;
|
|
}
|
|
|
|
@property int handle() const
|
|
{
|
|
return fd;
|
|
}
|
|
}
|