std.fs.squashfs — SquashFS 4.0 lesen

import std.fs.squashfs;

Liest SquashFS-Abbilder: Superblock auswerten, Inodes und Verzeichnisse aus komprimierten Metadatenblöcken holen, Dateien entpacken. Das erste Dateisystem der Sammlung, das mit Kompression umgeht — und damit grundlegend anders aufgebaut als FAT, exFAT, ext4 und NTFS.

Die Dateisystem-Sammlung · std.decomp · Guide: Fremde Dateisysteme lesen


1. Was hier anders ist

  • Keine Cluster, keine Zuordnungstabelle. Alles liegt in Metadatenblöcken zu höchstens 8 KiB (SQFS_META_SIZE), jeder für sich komprimiert.
  • Eine Inode-Referenz ist keine Nummer, sondern ein Paar: obere 32 Bit = Adresse des Metadatenblocks, untere 16 Bit = Versatz im entpackten Block. Dafür gibt es SquashRefBlock und SquashRefOffset.
  • Blockgrößen in der Liste sind die Größe auf der Platte, nicht die entpackte. Wer sie als entpackte Länge liest, bekommt zu wenig Daten.
  • Kleine Dateireste liegen nicht in eigenen Blöcken, sondern zusammen mit anderen in einem Fragment. Eine Datei kann also aus ganzen Blöcken plus einem Fragmentstück bestehen.

2. Konstanten

Konstante Wert Bedeutung
SQFS_ERR −1 Lesefehler oder ungültige Struktur
SQFS_MAGIC 0x73717368 Kennung hsqs
SQFS_META_SIZE 8192 Größe eines entpackten Metadatenblocks
SQFS_COMP_GZIPSQFS_COMP_ZSTD 1…6 GZIP, LZMA, LZO, XZ, LZ4, ZSTD
SQFS_INODE_DIR · SQFS_INODE_FILE · SQFS_INODE_SYMLINK 1 · 2 · 3 Grundarten
SQFS_INODE_BLKDEVSQFS_INODE_SOCKET 4…7 Gerätedateien, FIFO, Socket
SQFS_INODE_XDIR · SQFS_INODE_XFILE · SQFS_INODE_XSYMLINK 8 · 9 · 10 die erweiterten Formen
 
Welches Kompressionsverfahren im Abbild steht, heißt nicht, dass es gelesen werden kann. SquashCompressionUnterstuetzt sagt, ob das Verfahren zur Verfügung steht; SquashCompressionName liefert den Klartextnamen für Meldungen.

3. Typen

pub type SquashVolume = struct {
  fd:          int64;
  partOffset:  int64;   // Byte-Versatz des Abbilds im Deskriptor
  inodeCount:  int64;
  blockSize:   int64;
  fragCount:   int64;
  compression: int64;   // SQFS_COMP_*
  flags:       int64;
  idCount:     int64;
  rootRef:     int64;   // Inode-Referenz der Wurzel
  bytesUsed:   int64;
  idTable:     int64;
  inodeTable:  int64;
  dirTable:    int64;
  fragTable:   int64;
  gueltig:     bool;
}

pub type SquashEntry = struct {
  art:         int64;   // SQFS_INODE_*
  mode:        int64;
  uid:         int64;
  gid:         int64;
  inodeNr:     int64;
  groesse:     int64;   // Datei: Bytes; Verzeichnis: Bytes der Eintragsliste
  istDir:      bool;
  istDatei:    bool;
  istSymlink:  bool;
  dirStart:    int64;   // Verzeichnis: Versatz des Metadatenblocks
  dirOffset:   int64;   // Verzeichnis: Versatz im entpackten Block
  blocksStart: int64;   // Datei: Beginn der Datenblöcke im Abbild
  fragIndex:   int64;   // Datei: Fragmentnummer, 0xFFFFFFFF = keins
  fragOffset:  int64;   // Datei: Versatz im entpackten Fragment
  blockListe:  int64;   // Datei: Adresse der Blockgrößenliste
  blockAnzahl: int64;
  symlinkRef:  int64;   // Symlink: Adresse des Ziels
  symlinkLen:  int64;
}

pub type SquashDirEntry = struct {
  kindRef: int64;   // Inode-Referenz des Kindes
  art:     int64;
  inodeNr: int64;
}

SquashDirEntry gibt es, weil die Rückgabe mehrerer Werte in Lyx über ein Struct läuft: ref wirkt nur bei Struct-Parametern, skalare Ausgabeparameter kennt die Sprache nicht.


4. Volume

Signatur Zweck
SquashMount(fd: int64, versatz: int64, ref vol: SquashVolume): bool Superblock lesen und Volume aufbauen
SquashValid(vol: SquashVolume): bool Wurde ein gültiges Abbild gefunden?
SquashBlockSize(vol: SquashVolume): int64 Blockgröße des Abbilds
SquashInodeCount(vol: SquashVolume): int64 Zahl der Inodes
SquashCompression(vol: SquashVolume): int64 Verfahren als SQFS_COMP_*
SquashCompressionName(vol: SquashVolume): pchar Klartextname des Verfahrens
SquashCompressionUnterstuetzt(vol: SquashVolume): bool Kann es gelesen werden?
SquashRootRef(vol: SquashVolume): int64 Inode-Referenz der Wurzel

5. Inode-Referenzen

Signatur Zweck
SquashRefBlock(ref_: int64): int64 Obere 32 Bit — Adresse des Metadatenblocks
SquashRefOffset(ref_: int64): int64 Untere 16 Bit — Versatz im entpackten Block
SquashInode(vol: SquashVolume, ref_: int64, ref e: SquashEntry): bool Inode zu einer Referenz holen
SquashEntryFreigeben(ref e: SquashEntry): void Puffer des Eintrags freigeben

6. Verzeichnisse und Dateien

Signatur Zweck
SquashDirOpen(vol, e: SquashEntry, ref d: SquashDir): bool Verzeichnis öffnen (entpackt den Bereich)
SquashDirNext(ref d: SquashDir, ref de: SquashDirEntry, name: int64): bool Nächster Eintrag; Name nach name
SquashDirClose(ref d: SquashDir): void Puffer freigeben
SquashFindInDir(vol, e: SquashEntry, name: int64): int64 Kind-Referenz zu einem Namen
SquashFindPath(vol: SquashVolume, pfad: int64): int64 Pfad ab der Wurzel auflösen → Inode-Referenz
SquashReadFile(vol, e: SquashEntry, ziel: int64, zielMax: int64): int64 Datei entpacken — ganze Blöcke und Fragmentrest
SquashReadLink(e: SquashEntry, ziel: int64, zielMax: int64): int64 Ziel eines symbolischen Verweises
SquashSymlinkLen(e: SquashEntry): int64 Länge des Verweisziels

7. Beispiel

unit main;
import std.fs.squashfs;
import std.alloc;
import std.io;
import std.string;

fn main(): int64 {
    var fd: int64 := open("/tmp/abbild.squashfs"c, 0, 0);
    if (fd < 0) { return 1; }

    var vol: SquashVolume;
    if (!SquashMount(fd, 0, vol)) { PrintLn("kein SquashFS"); close(fd); return 1; }

    PrintLn(StrConcat("Kompression: ", SquashCompressionName(vol)));
    if (!SquashCompressionUnterstuetzt(vol)) {
        PrintLn("Verfahren wird nicht unterstuetzt");
        close(fd);
        return 1;
    }

    var wurzel: SquashEntry;
    SquashInode(vol, SquashRootRef(vol), wurzel);

    var d: SquashDir;
    var de: SquashDirEntry;
    var name: int64 := alloc(300);

    if (SquashDirOpen(vol, wurzel, d)) {
        while (SquashDirNext(d, de, name)) {
            PrintLn(name as pchar);
        }
        SquashDirClose(d);
    }

    free(name, 300);
    SquashEntryFreigeben(wurzel);
    close(fd);
    return 0;
}


8. Grenzen

  • Nicht enthalten: erweiterte Attribute (xattr), Gerätedateien, Sockets.
  • Nur lesen — und das ist hier keine Einschränkung der Unit, sondern des Formats: SquashFS ist ein Nur-Lese-Dateisystem. Ein Abbild zu ändern hieße, es neu zu bauen; dafür gibt es mksquashfs.

Prüfstand: tests/squashfs_test.sh37 Prüfungen gegen ein erzeugtes Abbild.

Letzte Aktualisierung: 2026-09-05 — Seite neu angelegt; erhoben aus std/fs/squashfs.lyx.

Prüflauf 2026-09-05 mit doku-pruefer.py (Repo-Compiler lyxc 1.2.2A): 7 Vollprogramme der Sammlung, 7 übersetzen, 0 echte Fehler; 53 Aufrufe gegen die pub fn-Signaturen gehalten, 0 Abweichungen.