====== 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.
→ [[lyx_-_programmiersprache:units:fs:dateisysteme|Die Dateisystem-Sammlung]] · [[lyx_-_programmiersprache:units:decomp|std.decomp]] · [[lyx_-_programmiersprache:guides:dateisysteme-lesen|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_GZIP'' … ''SQFS_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_BLKDEV'' … ''SQFS_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.sh'' — **37 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.