std.xattr — Erweiterte Dateiattribute & Dateisystem-Statistik

import std.xattr;

Drei Themenblöcke:

  • xattr: Erweiterte Dateiattribute — beliebige Name-Wert-Paare an Dateien/Verzeichnissen speichern
  • statfs: Dateisystem-Statistiken (Gesamtgröße, freier Speicher, Blockgröße)
  • fallocate: Speicherplatz-Vorabzuweisung und Hole-Punching

Syscalls: setxattr(188), getxattr(191), listxattr(194), removexattr(197), fsetxattr(190), fgetxattr(193), flistxattr(196), fremovexattr(199), fallocate(285), statfs(137).

std.fs · std.sysadmin


xattr-Konstanten

Konstante Wert Bedeutung
XATTR_CREATE 1 Fehler wenn Attribut schon existiert
XATTR_REPLACE 2 Fehler wenn Attribut nicht existiert

Namespace-Konvention für Attributnamen:

Namespace Zugriffsrecht Beispiel
user. Normale Anwendungen user.comment
security. Kernel-intern (SELinux) security.selinux
trusted. Nur root trusted.md5sum
system. ACLs system.posix_acl_access

xattr-Funktionen

Pfad-basiert

Funktion Signatur Beschreibung
XattrSet (path: pchar, name: pchar, val: int64, size: int64, flags: int64): int64 Setzt Attribut; flags=0 = anlegen oder ersetzen
XattrGet (path: pchar, name: pchar, buf: int64, size: int64): int64 Liest Attribut; buf=0, size=0 liefert benötigte Größe
XattrList (path: pchar, buf: int64, size: int64): int64 Listet alle Attributnamen (null-separiert)
XattrRemove (path: pchar, name: pchar): int64 Löscht Attribut

fd-basiert

Funktion Signatur Beschreibung
FXattrSet (fd: int64, name: pchar, val: int64, size: int64, flags: int64): int64 Wie XattrSet, via Dateideskriptor
FXattrGet (fd: int64, name: pchar, buf: int64, size: int64): int64 Wie XattrGet, via Dateideskriptor
FXattrList (fd: int64, buf: int64, size: int64): int64 Wie XattrList, via Dateideskriptor
FXattrRemove (fd: int64, name: pchar): int64 Wie XattrRemove, via Dateideskriptor

statfs-Konstanten

STATFS_SIZE: 120 Bytes (struct statfs auf x86-64).

Konstante Offset Beschreibung
STATFS_BSIZE 8 Optimale Blockgröße in Bytes
STATFS_BLOCKS 16 Gesamtanzahl Datenblöcke
STATFS_BFREE 24 Freie Blöcke (nur root sichtbar)
STATFS_BAVAIL 32 Freie Blöcke für nicht-root
STATFS_FILES 40 Gesamtanzahl Inodes
STATFS_FFREE 48 Freie Inodes
STATFS_NAMELEN 64 Maximale Dateinamenslänge

statfs-Funktionen

Funktion Signatur Beschreibung
StatFs (path: pchar, buf: int64): int64 Füllt statfs-Puffer (STATFS_SIZE Bytes)
StatFsBlockSize (buf: int64): int64 Blockgröße in Bytes
StatFsTotalBlocks (buf: int64): int64 Gesamtanzahl Datenblöcke
StatFsFreeBlocks (buf: int64): int64 Verfügbare freie Blöcke (für nicht-root)
StatFsTotalBytes (buf: int64): int64 Gesamtkapazität in Bytes
StatFsFreeBytes (buf: int64): int64 Verfügbarer Speicher in Bytes

fallocate-Konstanten

Konstante Wert Bedeutung
FALLOC_FL_KEEP_SIZE 1 Dateigröße nicht ändern
FALLOC_FL_PUNCH_HOLE 2 Hole stanzen (benötigt KEEP_SIZE)
FALLOC_FL_COLLAPSE_RANGE 8 Bereich entfernen und zusammenführen
FALLOC_FL_INSERT_RANGE 32 Bereich einfügen (Lücke öffnen)

fallocate-Funktionen

Funktion Signatur Beschreibung
FileAllocate (fd: int64, offset: int64, size: int64): int64 Reserviert Speicherplatz ohne zu schreiben (keine Nullen)
FileAllocateMode (fd: int64, mode: int64, offset: int64, size: int64): int64 Wie FileAllocate mit explizitem Modus-Flag

Verwendung

Attribut setzen und lesen

import std.xattr;
import std.alloc;

fn main(): int64 {
    var val: pchar := "Wichtige Datei";
    var r: int64 := XattrSet("/tmp/test.txt", "user.comment",
                              val as int64, 14, 0);
    if (r < 0) { return r; }

    // Größe abfragen
    var sz: int64 := XattrGet("/tmp/test.txt", "user.comment", 0, 0);
    if (sz < 0) { return sz; }

    // Wert lesen
    var buf: int64 := alloc(sz + 1);
    XattrGet("/tmp/test.txt", "user.comment", buf, sz);
    poke8(buf + sz, 0);  // NUL-terminieren

    free(buf, sz + 1);
    return 0;
}

Alle Attribute auflisten

import std.xattr;
import std.alloc;

fn ListAttrs(path: pchar): void {
    // Benötigte Größe abfragen
    var sz: int64 := XattrList(path, 0, 0);
    if (sz <= 0) { return; }

    var buf: int64 := alloc(sz);
    XattrList(path, buf, sz);

    // Null-separierte Namen ausgeben
    var pos: int64 := 0;
    while (pos < sz) {
        var name: pchar := (buf + pos) as pchar;
        // name ist ein \0-terminierter String
        pos := pos + StrLen(name) + 1;
    }

    free(buf, sz);
}

Freien Speicher prüfen

import std.xattr;
import std.alloc;

fn GetFreeBytes(path: pchar): int64 {
    var buf: int64 := alloc(STATFS_SIZE);
    var r: int64 := StatFs(path, buf);
    if (r < 0) { free(buf, STATFS_SIZE); return r; }

    var freeBytes: int64 := StatFsFreeBytes(buf);
    free(buf, STATFS_SIZE);
    return freeBytes;
}

Speicherplatz vorab reservieren

import std.xattr;
import std.fs;

fn PreallocFile(path: pchar, size: int64): int64 {
    var fd: int64 := OpenFile(path, 1);  // O_WRONLY
    if (fd < 0) { return fd; }

    // Speicher reservieren — Kernel muss keine Blöcke on-demand allokieren
    var r: int64 := FileAllocate(fd, 0, size);
    CloseFile(fd);
    return r;
}

Hole in Datei stanzen

import std.xattr;

fn PunchHole(fd: int64, offset: int64, len: int64): int64 {
    // Gibt Blöcke im Bereich frei, Dateigröße bleibt gleich
    return FileAllocateMode(fd, FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE,
                             offset, len);
}


Hinweise

  • xattr-Namespace: Der user.-Namespace ist für normale Anwendungen auf normalen Dateisystemen (ext4, xfs, btrfs) zugänglich. tmpfs und FAT unterstützen xattr nicht.
  • Größe abfragen: XattrGet mit buf=0, size=0 gibt die benötigte Puffergröße zurück — immer zuerst aufrufen bevor Speicher alloziert wird.
  • StatFsFreeBytes vs. StatFsFreeBlocks: StatFsFreeBytes verwendet BAVAIL (für nicht-root verfügbar), nicht BFREE (root-reservierter Anteil zusätzlich). Das ist der relevante Wert für Anwendungen.
  • FileAllocate vs. Schreiben: FileAllocate reserviert Blöcke, schreibt aber keine Daten — schneller als Nullen zu schreiben. Die reservierten Blöcke enthalten zufällige Daten bis überschrieben.
  • Hole-Punching: Nicht alle Dateisysteme unterstützen FALLOC_FL_PUNCH_HOLE — ext4/xfs/btrfs ja, FAT/tmpfs nein. Bei Fehler -EOPNOTSUPP.

Letzte Aktualisierung: 2026-06-06