Inhaltsverzeichnis

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.

Die Dateisystem-Sammlung · std.fs · 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

Prüfstand: tests/part_test.sh47 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 (#1928), Beispiel übersetzt.