Inhaltsverzeichnis

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


Verwandte Units

Letzte Aktualisierung: 2026-06-05