std.inotify
Dateisystem-Ereignisüberwachung via Linux inotify (WP-10). Meldet Datei- und Verzeichnisänderungen ohne Polling: Ein inotify-fd liefert via InotifyRead eine Folge von inotify_event-Einträgen. Mehrere Pfade können über separate Watch-Deskriptoren (wd) an einen einzigen fd gehängt werden.
→ Standard Library · std.fs · std.fs_ext
Event-Masken
| Konstante | Wert | Beschreibung |
|---|---|---|
IN_ACCESS | 1 | Datei wurde gelesen |
IN_MODIFY | 2 | Dateiinhalt wurde geändert |
IN_ATTRIB | 4 | Metadaten geändert (Rechte, Timestamps, …) |
IN_CLOSE_WRITE | 8 | Zum Schreiben geöffnete Datei wurde geschlossen |
IN_CLOSE_NOWRITE | 16 | Zum Lesen geöffnete Datei wurde geschlossen |
IN_OPEN | 32 | Datei oder Verzeichnis wurde geöffnet |
IN_MOVED_FROM | 64 | Datei aus überwachtem Verzeichnis verschoben |
IN_MOVED_TO | 128 | Datei in überwachtes Verzeichnis verschoben |
IN_CREATE | 256 | Datei oder Verzeichnis erstellt |
IN_DELETE | 512 | Datei oder Verzeichnis gelöscht |
IN_DELETE_SELF | 1024 | Überwachtes Objekt selbst wurde gelöscht |
IN_MOVE_SELF | 2048 | Überwachtes Objekt selbst wurde verschoben |
IN_ALL_EVENTS | 4095 | Alle obigen Ereignisse (0xFFF) |
IN_UNMOUNT | 8192 | Dateisystem wurde ausgehängt |
IN_Q_OVERFLOW | 16384 | Kernel-Event-Queue übergelaufen |
IN_IGNORED | 32768 | Watch wurde automatisch entfernt |
IN_ISDIR | 1073741824 | Ereignis betrifft ein Verzeichnis |
IN_ONESHOT | −2147483648 | Nur ein Event, danach Watch automatisch entfernen |
Init-Flags
| Konstante | Wert | Beschreibung |
|---|---|---|
IN_NONBLOCK | 2048 | Nicht-blockierendes InotifyRead (O_NONBLOCK) |
IN_CLOEXEC | 524288 | fd bei exec() schließen (O_CLOEXEC) |
inotify_event-Struktur
Jedes von InotifyRead gelieferte Ereignis hat folgenden Aufbau im Puffer:
| Offset | Typ | Feld | Beschreibung |
|---|---|---|---|
| +0 | int32 | wd | Watch-Deskriptor |
| +4 | uint32 | mask | Ereignistyp (IN_*-Konstante) |
| +8 | uint32 | cookie | Bewegungs-Cookie (IN_MOVED_FROM/TO-Korrelation) |
| +12 | uint32 | len | Länge von name[] inkl. Null-Byte und Padding |
| +16 | char[] | name | Dateiname, null-terminiert, auf 4 Bytes aufgefüllt |
INOTIFY_EVENT_HDR_SIZE (16) ist die feste Header-Größe ohne name.
Funktionen
fd erstellen und verwalten
| Signatur | Beschreibung |
|---|---|
InotifyCreate(): int64 | Erstellt eine neue inotify-Instanz mit IN_CLOEXEC; gibt fd zurück, < 0 bei Fehler |
InotifyWatch(fd: int64, path: pchar, mask: int64): int64 | Überwacht path mit den angegebenen Masken; gibt Watch-Deskriptor wd (> 0) zurück |
InotifyUnwatch(fd: int64, wd: int64): int64 | Entfernt einen Watch-Deskriptor; gibt 0 bei Erfolg |
Events lesen
| Signatur | Beschreibung |
|---|---|
InotifyRead(fd: int64, buf: int64, bufSize: int64): int64 | Liest Events in buf; gibt gelesene Bytes zurück. buf muss mindestens INOTIFY_EVENT_HDR_SIZE + max_name_len Bytes groß sein |
inotify_event-Felder auslesen
| Signatur | Beschreibung |
|---|---|
InotifyEventWd(buf: int64): int64 | Watch-Deskriptor des Events (int32 an Offset 0) |
InotifyEventMask(buf: int64): int64 | Ereignismaske des Events (uint32 an Offset 4) |
InotifyEventCookie(buf: int64): int64 | Bewegungs-Cookie (uint32 an Offset 8); korreliert IN_MOVED_FROM mit IN_MOVED_TO |
InotifyEventLen(buf: int64): int64 | Länge des name-Felds inkl. Padding (uint32 an Offset 12) |
InotifyEventName(buf: int64): int64 | Zeiger auf das name-Feld (Offset 16); null-terminierter Dateiname |
InotifyEventNext(buf: int64): int64 | Zeiger auf das nächste Event im Puffer (buf + HDR_SIZE + len) |
Verwendung
Einzelnes Verzeichnis überwachen
import std.inotify;
import std.alloc;
import std.io;
fn WatchDir(path: pchar): void {
var fd := InotifyCreate();
var wd := InotifyWatch(fd, path, IN_CREATE | IN_DELETE | IN_MODIFY);
var buf: int64 := alloc(4096);
var running: bool := true;
while (running) {
var n := InotifyRead(fd, buf, 4096);
if (n < 0) { running := false; }
var ptr := buf;
while (ptr < buf + n) {
var mask := InotifyEventMask(ptr);
var name := InotifyEventName(ptr);
if ((mask & IN_CREATE) != 0) {
PrintLn("Erstellt: " + name);
}
if ((mask & IN_DELETE) != 0) {
PrintLn("Gelöscht: " + name);
}
if ((mask & IN_MODIFY) != 0) {
PrintLn("Geändert: " + name);
}
if ((mask & IN_ISDIR) != 0) {
PrintLn(" (Verzeichnis)");
}
ptr := InotifyEventNext(ptr);
}
}
free(buf, 4096);
InotifyUnwatch(fd, wd);
close(fd);
}
Mehrere Pfade mit einem fd überwachen
import std.inotify;
import std.alloc;
import std.io;
fn WatchMultiple(): void {
var fd := InotifyCreate();
// Verschiedene Verzeichnisse mit unterschiedlichen Masken
var wd1 := InotifyWatch(fd, "/etc", IN_MODIFY | IN_CREATE);
var wd2 := InotifyWatch(fd, "/var/log", IN_MODIFY);
var wd3 := InotifyWatch(fd, "/tmp", IN_ALL_EVENTS);
var buf: int64 := alloc(8192);
var n := InotifyRead(fd, buf, 8192);
var ptr := buf;
while (ptr < buf + n) {
var wd := InotifyEventWd(ptr);
var mask := InotifyEventMask(ptr);
var name := InotifyEventName(ptr);
PrintLn("wd=" + IntToStr(wd) + " mask=" + IntToStr(mask) + " name=" + name);
ptr := InotifyEventNext(ptr);
}
free(buf, 8192);
close(fd);
}
IN_ONESHOT: Einmaliges Event
import std.inotify;
import std.alloc;
// Wartet auf die erste Änderung einer Datei, dann Schluss.
fn WaitForChange(path: pchar): void {
var fd := InotifyCreate();
InotifyWatch(fd, path, IN_MODIFY | IN_ONESHOT);
var buf: int64 := alloc(128);
InotifyRead(fd, buf, 128); // blockiert bis zum ersten Event
free(buf, 128);
close(fd);
}
Bewegungs-Cookie: verschobene Dateien korrelieren
IN_MOVED_FROM und IN_MOVED_TO haben denselben cookie-Wert und können so als zusammengehörendes Rename/Move-Paar erkannt werden.
import std.inotify;
import std.alloc;
import std.io;
fn TrackMoves(dir: pchar): void {
var fd := InotifyCreate();
InotifyWatch(fd, dir, IN_MOVED_FROM | IN_MOVED_TO);
var buf: int64 := alloc(4096);
var n := InotifyRead(fd, buf, 4096);
var ptr := buf;
while (ptr < buf + n) {
var mask := InotifyEventMask(ptr);
var cookie := InotifyEventCookie(ptr);
var name := InotifyEventName(ptr);
if ((mask & IN_MOVED_FROM) != 0) {
PrintLn("Quelle (cookie=" + IntToStr(cookie) + "): " + name);
}
if ((mask & IN_MOVED_TO) != 0) {
PrintLn("Ziel (cookie=" + IntToStr(cookie) + "): " + name);
}
ptr := InotifyEventNext(ptr);
}
free(buf, 4096);
close(fd);
}
Hinweise
- Der inotify-fd kann zusammen mit
std.net.epollin eine epoll-Instanz eingehängt werden, um Dateisystemereignisse und Netzwerkereignisse in derselben Event-Loop zu verarbeiten. - Bei rekursiver Verzeichnisüberwachung muss jedes Unterverzeichnis einzeln per
InotifyWatchregistriert werden — inotify ist nicht rekursiv. IN_Q_OVERFLOWsignalisiert, dass Events verloren gingen. Puffergröße erhöhen oder Lese-Rate steigern.InotifyEventLenkann 0 sein, wenn das Ereignis keinname-Feld hat (z. B.IN_DELETE_SELF).
Verwandte Units
std.fs— Datei-I/Ostd.fs_ext— Erweitertes Datei-I/O (pread, sendfile …)std.net.epoll— Event-Loop-Integrationstd.signals— UNIX-Signalbehandlung
Letzte Aktualisierung: 2026-06-05
