====== std.fs.part — MBR und GPT lesen ====== ''import std.fs.part;'' Diese Unit liest **kein** Dateisystem. Sie beantwortet die Frage, die vor jedem Dateisystem steht: **wo auf dem Datenträger fängt es an?** Ihr Ergebnis — ein Byte-Versatz — ist genau das, was ''FatMount'', ''ExfatMount'', ''Ext4Mount'', ''NtfsMount'' und ''SquashMount'' als zweites Argument erwarten. → [[lyx_-_programmiersprache:units:fs:dateisysteme|Die Dateisystem-Sammlung]] · [[lyx_-_programmiersprache:units:fs|std.fs]] · [[lyx_-_programmiersprache:guides:dateisysteme-lesen|Guide: Fremde Dateisysteme lesen]] ---- ===== 1. Konstanten ===== ^ Konstante ^ Wert ^ Bedeutung ^ | ''PART_ERR'' | −1 | Lesefehler oder ungültige Struktur | | ''PART_SCHEMA_KEINS'' · ''PART_SCHEMA_MBR'' · ''PART_SCHEMA_GPT'' | 0 · 1 · 2 | erkanntes Schema in ''PartTable.schema'' | | ''PART_MAX'' | 128 | Höchstzahl der Einträge | | ''PART_TYP_ERW_CHS'' · ''PART_TYP_ERW_LBA'' · ''PART_TYP_ERW_LINUX'' | 0x05 · 0x0F · 0x85 | MBR-Typbytes einer **erweiterten** Partition | | ''PART_TYP_GPT_SCHUTZ'' | 0xEE | der Schutz-MBR einer GPT-Platte | ''PART_MAX'' ist keine Willkür: mehr trägt kein übliches Medium, und die Grenze verhindert, dass ein beschädigtes Eintragsfeld in eine unbegrenzte Belegung läuft. **Alle drei Typbytes für „erweitert" bedeuten dasselbe.** Wer nur ''0x05'' kennt, übersieht die Platten, die mit LBA-Adressierung (''0x0F'') angelegt wurden — und das sind fast alle. Dafür gibt es ''PartIstErweitert''. ---- ===== 2. Typen ===== pub type PartTable = struct { fd: int64; sectorSize: int64; schema: int64; // PART_SCHEMA_* count: int64; eintraege: int64; // count × 48 Byte kopfCrcOk: bool; // nur GPT feldCrcOk: bool; // nur GPT gueltig: bool; } pub type PartEntry = struct { nummer: int64; // 1-basiert, wie in den Werkzeugen startLba: int64; sectors: int64; typ: int64; // MBR: Typbyte; GPT: 0 istErweitert: bool; // MBR-Behälter, trägt selbst kein Dateisystem istLogisch: bool; // MBR: aus der EBR-Kette istGpt: bool; } Bei GPT werden **beide Prüfsummen gerechnet, nicht geglaubt**: ''kopfCrcOk'' für den Kopf, ''feldCrcOk'' für das Eintragsfeld. ---- ===== 3. Einlesen ===== ^ Signatur ^ Zweck ^ | ''PartScan(fd: int64, sectorSize: int64): PartTable'' | Liest die Tabelle vom Deskriptor | | ''PartFree(ref t: PartTable): void'' | Gibt die eingelesenen Einträge frei | | ''PartValid(t: PartTable): bool'' | Wurde etwas Gültiges gefunden? | | ''PartSchema(t: PartTable): int64'' | ''PART_SCHEMA_MBR'' oder ''PART_SCHEMA_GPT'' | | ''PartCount(t: PartTable): int64'' | Zahl der Einträge | **GPT wird zuerst geprüft** — und das ist der Kern der Sache: eine GPT-Platte trägt bei Sektor 0 einen **Schutz-MBR** mit einem einzigen Eintrag vom Typ ''0xEE'' über die ganze Platte. Wer zuerst den MBR liest, findet genau diesen einen Eintrag und hält eine Platte mit fünf Partitionen für eine einzige riesige. ---- ===== 4. Einträge auswerten ===== ^ Signatur ^ Zweck ^ | ''PartGet(t: PartTable, idx: int64, ref e: PartEntry): int64'' | Eintrag ''idx'' in ''e'' | | ''PartByteOffset(t: PartTable, idx: int64): int64'' | **Byte-Versatz** — das Bindeglied zu den Dateisystem-Units | | ''PartByteSize(t: PartTable, idx: int64): int64'' | Größe in Byte | | ''PartName(t: PartTable, idx: int64, buf: int64, max: int64): int64'' | Name einer GPT-Partition (36 Zeichen UTF-16) | | ''PartTypeGuid(t: PartTable, idx: int64, buf: int64): int64'' | die ersten vier Byte des Typ-GUID | | ''PartIstErweitert(typ: int64): bool'' | Ist dieses MBR-Typbyte ein Behälter? | | ''PartCrc32(daten: int64, len: int64): int64'' | CRC32 (IEEE 802.3) — dieselbe Rechnung wie in ''std.fs.fat'' und im Compiler | **Bei MBR gibt es keinen Namen** — das Format kennt kein Namensfeld. ''PartName'' liefert dann 0 Zeichen, und das ist die Wahrheit, kein Fehler. Die vier Byte aus ''PartTypeGuid'' genügen, um die gängigen Arten auseinanderzuhalten: EFI-System, Linux-Dateisystem, Microsoft-Daten. ---- ===== 5. Beispiel ===== unit main; import std.fs.part; import std.io; import std.string; fn main(): int64 { var fd: int64 := open("/tmp/platte.img"c, 0, 0); if (fd < 0) { PrintLn("Abbild fehlt"); return 1; } var t: PartTable := PartScan(fd, 512); if (!PartValid(t)) { PrintLn("keine Partitionstabelle"); close(fd); return 1; } PrintLn(StrConcat("Schema: ", IntToStr(PartSchema(t)))); var i: int64 := 0; while (i < PartCount(t)) { var e: PartEntry; PartGet(t, i, e); PrintLn(StrConcat(StrConcat(" #", IntToStr(i)), StrConcat(" Versatz ", IntToStr(PartByteOffset(t, i))))); i := i + 1; } PartFree(t); close(fd); return 0; } **Erweiterte Einträge überspringen**, wenn man Dateisysteme sucht: ''istErweitert'' kennzeichnet einen Behälter, der selbst keines trägt. Die darin liegenden logischen Partitionen stehen als eigene Einträge mit ''istLogisch = true'' in der Tabelle. ---- ===== 6. Grenzen ===== * **Nur MBR und GPT** — kein Apple Partition Map, keine BSD-Disklabels. * **Höchstens 128 Einträge** (''PART_MAX''). * Die Unit liest, sie schreibt nicht. Partitionieren macht unter Lyx OS der Kernel (→ [[lyxos:syscalls|''sys_mkpart'', ''sys_gpt_create'']]). Prüfstand: ''tests/part_test.sh'' — **47 Prüfungen, 0 FAIL** (2026-09-05, lyxc 1.2.2A), gegen erzeugte MBR- und GPT-Abbilder. Letzte Aktualisierung: 2026-09-05 — Seite neu angelegt; erhoben aus ''std/fs/part.lyx'' ([[https://github.com/SEOLizer/LyX-Compiler/issues/1928|#1928]]), Beispiel übersetzt. 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.