====== ISO 9660 Guide — Images lesen und erstellen ======
Dieser Guide zeigt den praktischen Einsatz von ''std.iso'' für typische Aufgaben: ISO-Images auslesen, eigene Images für Software-Distribution oder Embedded-Systeme bauen und das Format sinnvoll mit anderen Archiv-Units kombinieren.
→ [[lyx_-_programmiersprache:units:iso|std.iso (Unit-Referenz)]] · [[lyx_-_programmiersprache:units:archiv|Archiv-Übersicht]] · [[lyx_-_programmiersprache:guides:welche-unit|Welche Unit?]]
----
===== Wann ISO 9660 einsetzen? =====
ISO 9660 ist kein allgemeines Archivformat — es hat einen spezifischen Anwendungsbereich:
^ Szenario ^ ISO 9660? ^ Alternative ^
| Bootfähiges CD/DVD/USB-Image bauen | **ja** | — |
| Firmware-Update als selbstlesendes Image ausliefern | **ja** | — |
| Read-only Dateisystem für Embedded-Geräte | **ja** | — |
| Vorhandene ISO-Images (Linux-ISOs, Software-DVDs) auslesen | **ja** | — |
| Allgemeines Archiv mit Kompression | nein | ''std.zip'' / ''std.tar'' |
| Archiv mit Unterverzeichnissen (schreiben) | nein | ''std.zip'' / ''std.tar'' |
| Austauschformat zwischen Systemen | nein | ''std.zip'' (universell) |
ISO 9660 ist die richtige Wahl wenn das Ziel ein bootfähiges Medium ist, ein Read-only-Dateisystem gebraucht wird oder das Image von einem BIOS/UEFI, einem DVD-Laufwerk oder einem virtuellen Laufwerk gemountet werden soll.
----
===== ISO-Image lesen =====
==== Inhalt auflisten ====
''IsoOpen'' liest das gesamte Image in den Speicher und traversiert den Verzeichnisbaum per BFS. Das Ergebnis ist eine flache Liste aller Dateien mit vollständigen Pfaden.
import std.iso;
import std.alloc;
import std.io;
fn IsoAuflisten(pfad: pchar): void {
var img: int64 := IsoOpen(pfad as int64);
if img == 0 then {
PrintLn("Kein gültiges ISO 9660-Image"c);
return;
}
var n: int64 := IsoCount(img);
Print("Dateien: "c); PrintLn(IntToStr(n)c);
var i: int64 := 0;
while i < n do {
Print(IsoName(img, i) as pchar);
Print(" ("c);
Print(IntToStr(IsoSize(img, i))c);
PrintLn(" Bytes)"c);
i := i + 1;
}
IsoClose(img);
}
''IsoName'' gibt vollständige Pfade zurück inklusive Verzeichnisanteil:
BOOT/GRUB/GRUB.CFG
BOOT/GRUB/GRUB.EFI
EFI/BOOT/BOOTX64.EFI
README.TXT
AUTORUN.INF
Die Dateinamen enthalten das ISO 9660 Version-Suffix '';1'' nicht — ''isoStripVersion'' entfernt es beim Einlesen automatisch.
==== Einzelne Datei extrahieren ====
fn IsoDateiLesen(pfad: pchar, name: pchar): void {
var img: int64 := IsoOpen(pfad as int64);
if img == 0 then { return; }
var idx: int64 := IsoFind(img, name as int64);
if idx < 0 then {
Print("Nicht gefunden: "c); PrintLn(name);
IsoClose(img);
return;
}
var sz: int64 := IsoSize(img, idx);
var buf: int64 := alloc(sz + 1);
var n: int64 := IsoRead(img, idx, buf, sz);
if n >= 0 then {
poke8(buf + n, 0);
PrintLn(buf as pchar);
}
free(buf, sz + 1);
IsoClose(img);
}
==== Alle Dateien in Verzeichnis extrahieren ====
Da ''IsoName'' vollständige Pfade liefert, lassen sich alle Dateien eines bestimmten Unterverzeichnisses filtern:
import std.iso;
import std.alloc;
import std.string;
import std.fs;
fn IsoPfadExtrahieren(imgPfad: pchar, prefix: pchar, zielOrdner: pchar): void {
var img: int64 := IsoOpen(imgPfad as int64);
if img == 0 then { return; }
var plen: int64 := StrLen(prefix as int64);
var n: int64 := IsoCount(img);
var i: int64 := 0;
while i < n do {
var name: pchar := IsoName(img, i) as pchar;
// Prüfen ob Name mit prefix beginnt
if StrStartsWith(name as int64, prefix as int64) == 1 then {
var sz: int64 := IsoSize(img, i);
var buf: int64 := alloc(sz);
IsoRead(img, idx, buf, sz);
// Zieldatei: zielOrdner + "/" + name
var outPfad: int64 := StrConcat(zielOrdner as int64, "/"c as int64);
outPfad := StrConcat(outPfad, name as int64);
WriteFile(outPfad, buf, sz);
free(buf, sz);
free(outPfad, StrLen(outPfad) + 1);
}
i := i + 1;
}
IsoClose(img);
}
----
===== ISO-Image erstellen =====
==== Einfaches Image ====
Der Writer legt alle Dateien im Root-Verzeichnis ab. Namen werden automatisch auf ISO 9660 Level 1 normalisiert: Kleinbuchstaben → Großbuchstaben, Sonderzeichen → ''_''.
import std.iso;
import std.alloc;
fn EinfachesIso(): void {
var w: int64 := IsoWriterNew();
var readme: pchar := "Mein Lyx-Projekt v1.0\n"c;
IsoWriterAdd(w, "README.TXT"c as int64, readme as int64, 22);
var cfg: pchar := "version=1\ndebug=0\n"c;
IsoWriterAdd(w, "config.ini"c as int64, cfg as int64, 18);
// → wird im Image zu CONFIG.INI
var rc: int64 := IsoWriterSave(w, "release.iso"c as int64);
if rc != ISO_ERR_OK then {
PrintLn("Fehler beim Erzeugen des ISO-Images"c);
}
IsoWriterFree(w);
}
==== Datei aus Dateisystem einlesen und ins Image packen ====
''IsoWriterAdd'' kopiert den Datenpuffer **nicht** — der Zeiger muss bis zum ''IsoWriterSave''-Aufruf gültig bleiben. Bei mehreren Dateien aus dem Dateisystem alle zuerst laden, dann erst speichern:
import std.iso;
import std.alloc;
import std.fs;
fn IsoAusDateien(outPfad: pchar): int64 {
var w: int64 := IsoWriterNew();
// Alle Puffer halten bis IsoWriterSave
var sz1: int64 := FileSize("build/firmware.bin"c as int64);
var buf1: int64 := alloc(sz1);
ReadFile("build/firmware.bin"c as int64, buf1, sz1);
IsoWriterAdd(w, "FIRMWARE.BIN"c as int64, buf1, sz1);
var sz2: int64 := FileSize("docs/manual.pdf"c as int64);
var buf2: int64 := alloc(sz2);
ReadFile("docs/manual.pdf"c as int64, buf2, sz2);
IsoWriterAdd(w, "MANUAL.PDF"c as int64, buf2, sz2);
var rc: int64 := IsoWriterSave(w, outPfad as int64);
// Erst nach Save freigeben
free(buf1, sz1);
free(buf2, sz2);
IsoWriterFree(w);
return rc;
}
----
===== Dateinamen-Normalisierung =====
ISO 9660 Level 1 erlaubt nur Großbuchstaben, Ziffern, Unterstrich und Punkt. ''IsoWriterAdd'' normalisiert automatisch:
^ Eingabe-Name ^ Im Image ^
| ''README.txt'' | ''README.TXT'' |
| ''boot-loader.bin'' | ''BOOT_LOADER.BIN'' |
| ''mein datei.cfg'' | ''MEIN_DATEI.CFG'' |
| ''v1.0-release_notes.txt'' | ''V1.0_RELEASE_NOTES.TXT'' |
| ''name-länger-als-36-zeichen-geht-nicht.txt'' | ''ISO_ERR_NAMETOOLONG'' (Fehler) |
**Eindeutigkeit:** Wenn zwei Eingabe-Namen nach Normalisierung identisch werden (z.B. ''boot.bin'' und ''BOOT.BIN''), überschreibt der zweite Eintrag im Root-Verzeichnis den ersten nicht — beide landen als separate Einträge mit identischem normalisierten Namen. Das Image ist dann technisch gültig, aber der zweite Eintrag kann vom Reader nur über den Index, nicht über ''IsoFind'' erreicht werden.
----
===== ISO + TAR: Unterverzeichnisse simulieren =====
Da der Writer nur ein flaches Root-Verzeichnis unterstützt, lässt sich ein TAR-Archiv als Träger für eine vollständige Verzeichnisstruktur ins ISO packen:
import std.iso;
import std.tar;
import std.alloc;
import std.fs;
fn IsoMitTar(outIso: pchar): void {
// 1. TAR mit Unterverzeichnisstruktur bauen
var t: int64 := TarWriterNew();
TarWriterAdd(t, "etc/config.txt"c as int64, "debug=0\n"c as int64, 8);
TarWriterAdd(t, "bin/app"c as int64, "..."c as int64, 3);
TarWriterAdd(t, "lib/runtime.so"c as int64, "..."c as int64, 3);
TarWriterSave(t, "/tmp/payload.tar"c as int64);
TarWriterFree(t);
// 2. TAR-Datei ins ISO packen
var tsz: int64 := FileSize("/tmp/payload.tar"c as int64);
var tbuf: int64 := alloc(tsz);
ReadFile("/tmp/payload.tar"c as int64, tbuf, tsz);
var w: int64 := IsoWriterNew();
IsoWriterAdd(w, "PAYLOAD.TAR"c as int64, tbuf, tsz);
var readme: pchar := "Inhalt: payload.tar entpacken\n"c;
IsoWriterAdd(w, "README.TXT"c as int64, readme as int64, 30);
IsoWriterSave(w, outIso as int64);
free(tbuf, tsz);
IsoWriterFree(w);
}
Das ISO enthält dann ''PAYLOAD.TAR'' und ''README.TXT'' im Root. Das TAR innerhalb des ISO bringt die vollständige Verzeichnisstruktur.
----
===== Fehlerbehandlung =====
fn IsoMitFehlerbehandlung(pfad: pchar): void {
var w: int64 := IsoWriterNew();
var rc: int64 := IsoWriterAdd(w,
"dieser-dateiname-ist-definitiv-zu-lang-fuer-iso9660.txt"c as int64,
"Inhalt"c as int64, 6);
if rc == ISO_ERR_NAMETOOLONG then {
PrintLn("Name > 36 Zeichen — kürzen oder umbenennen"c);
IsoWriterFree(w);
return;
}
if rc == ISO_ERR_FULL then {
PrintLn("Maximale Eintragsanzahl (4096) erreicht"c);
IsoWriterFree(w);
return;
}
rc := IsoWriterSave(w, pfad as int64);
if rc == ISO_ERR_IO then {
PrintLn("I/O-Fehler — Schreibrechte oder Speicherplatz prüfen"c);
}
IsoWriterFree(w);
}
^ Fehlercode ^ Bedeutung ^ Lösung ^
| ''ISO_ERR_NOTISO'' | Datei ist kein ISO 9660-Image | PVD-Signatur ''CD001'' fehlt |
| ''ISO_ERR_IO'' | Lese- oder Schreibfehler | Pfad, Rechte, Speicherplatz prüfen |
| ''ISO_ERR_CORRUPT'' | Image beschädigt | Andere Quelle verwenden |
| ''ISO_ERR_FULL'' | 4096 Einträge erreicht | Image aufteilen |
| ''ISO_ERR_NAMETOOLONG'' | Name > 36 Zeichen oder leer | Namen kürzen |
----
===== Einschränkungen im Überblick =====
^ Einschränkung ^ Details ^
| Unterverzeichnisse (Writer) | Nicht unterstützt — nur Flat-Root. Workaround: TAR im ISO |
| Dateiname (Writer) | Max. 36 Zeichen, nur ''A–Z 0–9 _ .'' |
| Einträge | Max. 4096 Dateien, max. 256 Verzeichnisse (Reader) |
| Dateigröße | Durch verfügbaren RAM beim Lesen begrenzt (Image wird vollständig geladen) |
| Kompression | Keine — ISO 9660 komprimiert nicht |
| Joliet / Rock Ridge | Nicht unterstützt — lange Dateinamen und Unix-Permissions fehlen |
| ZIP64 / große Images | Kein inhärentes Limit, aber Einzeldateien müssen in den RAM passen |
| Bootfähigkeit | Image ist strukturell korrekt; El Torito Boot-Record wird nicht geschrieben |
----
===== Weiterführend =====
* [[lyx_-_programmiersprache:units:iso|std.iso — Unit-Referenz]]
* [[lyx_-_programmiersprache:units:archiv|Archiv-Übersicht — ZIP, TAR, RAR, ISO]]
* [[lyx_-_programmiersprache:units:tar|std.tar]] — für Unterverzeichnisstrukturen im ISO
* [[lyx_-_programmiersprache:units:zip|std.zip]] — wenn Kompression oder universelle Kompatibilität gefragt ist
Letzte Aktualisierung: 2026-06-13