std.tar — TAR-Archive lesen und schreiben

std.tar liest und schreibt TAR-Archive im POSIX ustar Format (IEEE Std 1003.1-1988). TAR komprimiert nicht — es ist ein reines Archivformat. Für komprimierte Archive (.tar.gz) wird TAR mit std.gzip kombiniert.

Archiv-Übersicht · std.zip · std.rar · std.gzip · Standard Library

Alle Beispiele dieser Seite sind mit lyxc 1.0.21A übersetzt und ausgeführt; die gezeigten Ausgaben sind echte Programmausgaben.

Einschränkungen: Max. 4096 Einträge, Dateinamen max. 100 Bytes (kein GNU LongLink / split-header). Beim Lesen werden nur reguläre Dateien (typeflag 0) erfasst — Verzeichnisse werden übersprungen.


Konstanten

Konstante Wert Bedeutung
TAR_BLOCK_SIZE 512 Header- und Datei-Blöcke sind je 512 Bytes
TAR_MAX_ENTRIES 4096 Maximale Einträge pro Archiv
TAR_ERR_OK 0 Kein Fehler
TAR_ERR_NOTTAR 1 Keine gültige TAR-Datei
TAR_ERR_IO 2 I/O-Fehler beim Lesen oder Schreiben
TAR_ERR_CORRUPT 3 Archiv beschädigt
TAR_ERR_FULL 4 TAR_MAX_ENTRIES erreicht

Lesen (TarReader)

Funktion Rückgabe Beschreibung
TarOpen(path) int64 Handle oder 0 Öffnet TAR-Archiv aus Datei
TarClose(handle) void Gibt Handle und alle Ressourcen frei
TarCount(handle) int64 Anzahl der regulären Datei-Einträge
TarName(handle, idx) int64 pchar Name des idx-ten Eintrags (interner Puffer — nicht free'n)
TarSize(handle, idx) int64 Größe in Bytes
TarRead(handle, idx, outBuf, maxLen) int64 Bytes oder -1 Liest Eintrag in outBuf
TarFind(handle, name) int64 Index oder -1 Sucht Eintrag nach exaktem Namen

import std.tar;
import std.alloc;
import std.string;

fn main(): int64 {
    var w: int64 := TarWriterNew();
    TarWriterAdd(w, "daten/log.txt"c, "Zeile 1\nZeile 2\n"c as int64, 16);
    TarWriterAdd(w, "README"c, "TAR aus Lyx"c as int64, 11);
    var rc: int64 := TarWriterSave(w, "/tmp/lyx_test.tar"c);
    TarWriterFree(w);
    PrintLn(StrConcat("Save rc (0 = ok): ", IntToStr(rc)));

    var h: int64 := TarOpen("/tmp/lyx_test.tar"c);
    if (h == 0) { PrintLn("TarOpen fehlgeschlagen"); return 1; }
    PrintLn(StrConcat("Eintraege: ", IntToStr(TarCount(h))));
    var i: int64 := 0;
    while (i < TarCount(h)) {
        PrintLn(StrConcat(StrConcat("  ", TarName(h, i) as pchar),
                StrConcat("  ", IntToStr(TarSize(h, i)))));
        i := i + 1;
    }
    var idx: int64 := TarFind(h, "README"c);
    var buf: int64 := alloc(256);
    var n: int64 := TarRead(h, idx, buf, 256);
    poke8(buf + n, 0);
    PrintLn(StrConcat("Inhalt: ", buf as pchar));
    TarClose(h);
    return 0;
}

Save rc (0 = ok): 0
Eintraege: 2
  daten/log.txt  16
  README  11
Inhalt: TAR aus Lyx

GNU tar liest das Ergebnis unverändert:

$ tar -tvf /tmp/lyx_test.tar
-rw-r--r-- 0/0              16 1970-01-01 01:00 daten/log.txt
-rw-r--r-- 0/0              11 1970-01-01 01:00 README


Schreiben (TarWriter)

Funktion Rückgabe Beschreibung
TarWriterNew() int64 Writer-Handle Erstellt neuen leeren Writer
TarWriterAdd(writer, name, data, dataLen) int64 Fehlercode Fügt Eintrag hinzu (kopiert Name + Daten)
TarWriterSave(writer, path) int64 Fehlercode Schreibt Archiv in Datei (POSIX ustar)
TarWriterFree(writer) void Gibt Writer und alle Einträge frei

Geschriebene Archive: mode 0644, uid/gid 0, mtime 0. Datenblöcke werden auf 512-Byte-Grenzen aufgerundet. Das Archiv endet mit zwei Null-Blöcken (POSIX-Anforderung).


TAR + Kompression (.tar.gz)

TAR selbst komprimiert nicht. Um ein .tar.gz zu erzeugen, das Archiv in einen Puffer schreiben und anschließend mit std.gzip komprimieren:

import std.tar;
import std.gzip;
import std.fs;
import std.alloc;
import std.string;

fn main(): int64 {
    // 1. TAR schreiben
    var w: int64 := TarWriterNew();
    TarWriterAdd(w, "datei.txt"c, "Inhalt aus Lyx\n"c as int64, 15);
    TarWriterSave(w, "/tmp/demo2.tar"c);
    TarWriterFree(w);

    // 2. TAR-Datei einlesen
    var sz: int64 := FileSize("/tmp/demo2.tar"c);
    var buf: int64 := alloc(sz);
    ReadFile("/tmp/demo2.tar"c, buf as pchar, sz);
    PrintLn(StrConcat("TAR-Groesse:  ", IntToStr(sz)));

    // 3. Mit gzip komprimieren
    var bound: int64 := GzipCompressBound(sz);
    var cbuf: int64 := alloc(bound);
    var clen: int64 := GzipCompress(buf, sz, cbuf, bound);
    PrintLn(StrConcat("gzip-Groesse: ", IntToStr(clen)));
    WriteFile("/tmp/demo2.tar.gz"c, cbuf as pchar, clen);

    free(buf, sz); free(cbuf, bound);
    return 0;
}

TAR-Groesse:  2048
gzip-Groesse: 105

$ tar -tzf /tmp/demo2.tar.gz
datei.txt

Die 2048 Byte sind kein Fehler: TAR rundet jeden Eintrag auf 512-Byte-Blöcke auf und hängt zwei Nullblöcke als Endmarke an. Genau diese Nullen komprimiert gzip auf 105 Byte.


Fallstricke

 
Zu lange Pfade werden stillschweigend gekürzt. Das ustar-Namensfeld fasst 100 Byte; TarWriterAdd nimmt auch längere Pfade an und meldet 0 (Erfolg), TarWriterSave schreibt dann den auf 100 Zeichen abgeschnittenen Namen. Nachgemessen mit einem 110 Zeichen langen Pfad — sowohl TarName als auch GNU tar zeigen anschließend den gekürzten Namen. Die ustar-Erweiterung mit prefix-Feld und GNU LongLink sind nicht umgesetzt; Pfade selbst auf ≤ 100 Byte prüfen.
  • Zeitstempel sind 0 (1. Januar 1970), Eigentümer und Gruppe ebenfalls — std.tar schreibt keine echten Metadaten.
  • Nur reguläre Dateien. Beim Lesen werden Verzeichniseinträge (typeflag 5), Symlinks und Gerätedateien übersprungen; beim Schreiben entstehen Ordner allein durch Schrägstriche im Namen.
  • TarWriterSave liefert 0 bei Erfolg, TarOpen dagegen 0 im Fehlerfall.
  • TarRead terminiert nicht — Nullbyte selbst setzen, wenn der Puffer als Text ausgegeben wird.
  • Pfade als pchar: TarOpen(„/tmp/a.tar“c) — ohne as int64. std.zip macht es umgekehrt.

Speicherverwaltung

Handle Freigabe
TarOpen → Reader-Handle TarClose(handle)
TarWriterNew → Writer-Handle TarWriterFree(writer)
TarName → interner Puffer nicht free'n — gehört dem Handle
outBuf in TarRead Aufrufer allokiert, Aufrufer gibt frei

Letzte Aktualisierung: 2026-08-13 — Beispiele lauffähig gemacht, ausgeführt und mit GNU tar gegengelesen (lyxc 1.0.17K); belegt und dokumentiert: Pfade über 100 Byte werden stillschweigend gekürzt. .tar.gz-Beispiel neu geschrieben.

Codebeispiele geprüft: gegen lyxc 1.2.5C übersetzt (Prüflauf 2026-09-08 über die gesamte Doku: 574 Vollprogramme, 0 echte Fehler; zusätzlich 5159 Aufrufe gegen die pub fn-Signaturen in aurum/std gehalten, 0 Abweichungen).