====== 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.