dwatch/source/dfanotify.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;
}
}