disklayout

package
v0.2.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 6, 2026 License: Apache-2.0 Imports: 11 Imported by: 0

Documentation

Overview

Package disklayout parses and models GPT disk layouts for bare-metal backup/recovery (issue #67, docs/BARE_METAL_RECOVERY.md). It is pure parsing over an io.ReaderAt — device, image file, or byte slice — with no platform dependencies, so the whole package is testable on any OS against synthetic images.

Index

Constants

View Source
const (
	TypeESP           = "C12A7328-F81F-11D2-BA4B-00A0C93EC93B" // EFI System Partition
	TypeMSR           = "E3C9E316-0B5C-4DB8-817D-F92DF00215AE" // Microsoft Reserved
	TypeMSBasicData   = "EBD0A0A2-B9E5-4433-87C0-68B6B72699C7" // Windows basic data (NTFS/exFAT)
	TypeWinRE         = "DE94BBA4-06D1-4D40-A16A-BFD50179D6AC" // Windows Recovery Environment
	TypeLinuxFS       = "0FC63DAF-8483-4772-8E79-3D69D8477DE4" // Linux filesystem
	TypeLinuxSwap     = "0657FD6D-A4AB-43C4-84E5-0933C84B4F4F" // Linux swap
	TypeBIOSBoot      = "21686148-6449-6E6F-744E-656564454649" // GRUB BIOS boot
	TypeLinuxLVM      = "E6D6D379-F507-44C2-A23C-238F2A3DF928" // Linux LVM PV
	TypeLinuxHome     = "933AC7E1-2EB4-4F13-B844-0E14E2AEF915" // Linux /home
	TypeMSLDMMetadata = "5808C8AA-7E8F-42E0-85D2-E1E90434CFB3" // Windows LDM metadata
)

Well-known partition type GUIDs (canonical string form).

Variables

This section is empty.

Functions

func ApplyFit added in v0.2.0

func ApplyFit(l *DiskLayout, plan *FitPlan, capturedPrimary, capturedBackup []byte) (primary []byte, backupOffset int64, backup []byte, err error)

ApplyFit rewrites the captured boot structures for a plan: entries carry their new extents, the GPT headers their new last-usable and alternate LBAs, every CRC is recomputed, and every GUID is untouched. It returns the primary region for LBA0 onward and, for GPT, the backup structures and where they go. A plan with refusals is refused.

func ListMachineManifests

func ListMachineManifests(repoPath string) ([]string, error)

ListMachineManifests returns the snapshot IDs of all machine manifests in a repo (for the recovery flow's listing).

func MachineManifestPath

func MachineManifestPath(repoPath, snapshotID string) string

MachineManifestPath is the repo location of a machine snapshot manifest.

func MarshalMachineManifest

func MarshalMachineManifest(m *MachineManifest) ([]byte, error)

MarshalMachineManifest validates and encodes a manifest in the CRC envelope used both for the local repo file and the S3 object (#70).

func RelocateGPT

func RelocateGPT(l *DiskLayout, capturedPrimary, capturedBackup []byte, newDiskSize int64) (primary []byte, backupOffset int64, backup []byte, err error)

RelocateGPT adapts a captured disk's verbatim GPT regions to a LARGER target disk (#76): real drive replacements are rarely the same size, and a backup GPT header that is not at the last LBA is flagged as corruption by firmware and partitioning tools.

It returns:

  • primary: the captured primary region with ONLY the header's AlternateLBA patched to the new last LBA (and the header CRC recomputed) — everything else, including the protective MBR, disk GUID, partition entries and their GUIDs, stays byte-identical, which is what keeps BCD/fstab references valid.
  • backupOffset/backup: the rebuilt backup structures (entry-array copy + backup header) positioned at the true end of the new disk.

The extra space beyond the captured LastUsableLBA is left unallocated (partition growth is a deliberate non-goal here; growpart/ntfsresize on the recovery key cover it). Same-size targets pass through unchanged (verbatim backup at its captured offset). Smaller targets are refused.

func SaveMachineManifest

func SaveMachineManifest(repoPath, snapshotID string, m *MachineManifest) error

SaveMachineManifest atomically writes the manifest (temp + fsync + rename + dir sync — the repo-wide durability pattern).

func TypeName

func TypeName(g GUID) string

TypeName returns a short human-readable name for a partition type GUID, or the GUID string itself when unknown.

Types

type DiskCapture

type DiskCapture struct {
	// Source identifies the disk on the origin machine (informational):
	// "\\.\PhysicalDrive0", "/dev/sda", or an image path.
	Source string     `json:"source"`
	Layout DiskLayout `json:"layout"`
	// PrimaryGPT and BackupGPT are the verbatim bytes of the layout's
	// PrimaryRegion / BackupRegion, restored byte-exactly so disk signatures
	// and partition GUIDs (which BCD/fstab reference) are preserved.
	PrimaryGPT []byte `json:"primary_gpt"`
	BackupGPT  []byte `json:"backup_gpt"`
	// AuxBytes (#149): verbatim bytes of Layout.AuxRegions (the MBR EBR
	// chain lives in inter-partition gaps no member covers).
	AuxBytes [][]byte          `json:"aux_bytes,omitempty"`
	Members  []PartitionMember `json:"members"`
}

DiskCapture is one whole disk in a machine snapshot: its parsed layout, the verbatim GPT metadata regions, and the per-partition member backups.

type DiskLayout

type DiskLayout struct {
	// Scheme is "gpt" or "mbr" (#149); "" in manifests written before MBR
	// support means gpt.
	Scheme         string      `json:"scheme,omitempty"`
	SectorSize     int         `json:"sector_size"`
	DiskSize       int64       `json:"disk_size"`
	DiskGUID       string      `json:"disk_guid"`
	FirstUsableLBA uint64      `json:"first_usable_lba"`
	LastUsableLBA  uint64      `json:"last_usable_lba"`
	AlternateLBA   uint64      `json:"alternate_lba"` // backup header location
	Partitions     []Partition `json:"partitions"`

	// AuxRegions (#149, MBR only): structural sectors OUTSIDE PrimaryRegion
	// and all partitions — the EBR chain lives in inter-partition gaps and
	// must restore verbatim or logical partitions vanish.
	AuxRegions []Range `json:"aux_regions,omitempty"`

	// PrimaryRegion covers LBA0 through the end of the primary partition entry
	// array (protective MBR + primary header + entries): captured verbatim so a
	// restore reproduces boot-relevant metadata byte-exactly.
	PrimaryRegion Range `json:"primary_region"`
	// BackupRegion covers the backup entry array + backup header at the end of
	// the disk.
	BackupRegion Range `json:"backup_region"`
}

DiskLayout is a parsed GPT disk.

func Parse

func Parse(r io.ReaderAt, diskSize int64) (*DiskLayout, error)

Parse reads and validates a GPT layout from r. diskSize is the device/image size in bytes. The sector size is auto-detected (512 and 4096 probed) by locating a valid primary header; pass an explicit size via ParseWithSector when known.

func ParseWithSector

func ParseWithSector(r io.ReaderAt, diskSize int64, sectorSize int) (*DiskLayout, error)

ParseWithSector parses a GPT with a known sector size.

func (*DiskLayout) FindPartitionAt

func (l *DiskLayout) FindPartitionAt(off int64) (Partition, bool)

FindPartitionAt returns the partition covering the given byte offset, if any.

func (*DiskLayout) VerifyBackupHeader

func (l *DiskLayout) VerifyBackupHeader(r io.ReaderAt) error

VerifyBackupHeader cross-checks that the backup GPT header at AlternateLBA is present, valid, and agrees with the primary (same disk GUID). Damaged backup headers are common on cloned disks; callers decide whether to warn or fail.

type FitOptions added in v0.2.0

type FitOptions struct {
	// Grow extends the last data partition into the space a larger target
	// has beyond the captured layout.
	Grow bool
	// MoveRecoveryToEnd lets partitions that FOLLOW the last data partition
	// (a Windows Recovery partition, typically) be moved to the end of the
	// larger target so the data partition can grow; without it, growth is
	// blocked and reported.
	MoveRecoveryToEnd bool
	// Realign moves every partition to a 1 MiB (or physical-sector) boundary.
	// Off, only partitions the plan moves anyway are placed aligned; others
	// keep their captured position and are reported when misaligned.
	Realign bool
	// MinSize, when set, answers "how small can this partition's filesystem
	// go" in bytes (volumefs.MinimumSize). nil means unknown: a shrink is
	// planned to whatever size fits and WARNED as unconfirmed.
	MinSize func(p Partition) (minBytes int64, known bool)
}

FitOptions are the operator's choices.

type FitPlan added in v0.2.0

type FitPlan struct {
	Scheme           string
	SectorSize       int
	TargetSize       int64
	NewLastUsableLBA uint64
	Partitions       []PlannedPartition // in disk order
	Warnings         []string           // things the operator should know; the plan still applies
	Refusals         []string           // reasons the plan MUST NOT be applied; empty means applicable
}

FitPlan is PlanFit's answer.

func PlanFit added in v0.2.0

func PlanFit(l *DiskLayout, tg TargetGeometry, opts FitOptions) (*FitPlan, error)

PlanFit fits l onto tg. It returns a plan whose Refusals say why it must not be applied, or whose Partitions say where everything lands. An error is only for inputs that are not a layout at all.

func (*FitPlan) Applicable added in v0.2.0

func (p *FitPlan) Applicable() bool

Applicable reports whether the plan may be applied.

func (*FitPlan) Changed added in v0.2.0

func (p *FitPlan) Changed() bool

Changed reports whether any partition moves or resizes.

func (*FitPlan) Partition added in v0.2.0

func (p *FitPlan) Partition(index int) (PlannedPartition, bool)

Partition returns the planned partition for a slot index.

type GUID

type GUID [16]byte

GUID is a 16-byte GPT GUID in on-disk (mixed-endian) order: the first three fields are little-endian, the last two big-endian — so the canonical string form requires the byte swaps below (UEFI spec appendix A / RFC 4122).

func ParseGUID

func ParseGUID(s string) (GUID, error)

ParseGUID parses the canonical string form back into on-disk order.

func (GUID) IsZero

func (g GUID) IsZero() bool

IsZero reports the all-zero GUID (an unused GPT partition entry).

func (GUID) String

func (g GUID) String() string

String renders the canonical uppercase form, e.g. "C12A7328-F81F-11D2-BA4B-00A0C93EC93B".

type MachineManifest

type MachineManifest struct {
	Version   int           `json:"version"`
	MachineID string        `json:"machine_id"` // stable per machine (agent/host identity)
	Hostname  string        `json:"hostname"`
	OS        string        `json:"os"`
	CreatedAt time.Time     `json:"created_at"`
	Disks     []DiskCapture `json:"disks"`
}

MachineManifest groups one machine snapshot: every disk captured together, with identity for the recovery flow ("list machines → pick snapshot").

func LoadMachineManifest

func LoadMachineManifest(repoPath, snapshotID string) (*MachineManifest, error)

LoadMachineManifest reads and validates a machine snapshot manifest.

func UnmarshalMachineManifest

func UnmarshalMachineManifest(data []byte) (*MachineManifest, error)

UnmarshalMachineManifest decodes and validates an envelope-wrapped manifest.

type MemberKind

type MemberKind string

MemberKind says how a partition's content was captured.

const (
	// MemberVolume: the partition holds a filesystem backed up through the
	// normal volume pipeline (VSS on Windows) — content addressed by BackupID.
	MemberVolume MemberKind = "volume"
	// MemberRaw: the partition (ESP, MSR, unrecognized) was captured as raw
	// ranged reads of the disk — content addressed by BackupID of a raw-range
	// backup whose stream is exactly the partition bytes.
	MemberRaw MemberKind = "raw"
	// MemberSkipped: deliberately not captured (e.g. swap); restored as zeros.
	MemberSkipped MemberKind = "skipped"
)

type Partition

type Partition struct {
	Index      int    `json:"index"` // 0-based slot in the entry array
	TypeGUID   string `json:"type_guid,omitempty"`
	TypeName   string `json:"type_name"`
	PartGUID   string `json:"part_guid,omitempty"`
	Name       string `json:"name,omitempty"` // UTF-16LE name, decoded (GPT)
	FirstLBA   uint64 `json:"first_lba"`
	LastLBA    uint64 `json:"last_lba"` // inclusive, per spec
	Attributes uint64 `json:"attributes,omitempty"`

	// MBR fields (#149): set when the disk's Scheme is "mbr".
	MBRType  byte `json:"mbr_type,omitempty"`
	Bootable bool `json:"bootable,omitempty"`
}

Partition is one in-use GPT partition entry.

func (Partition) Length

func (p Partition) Length(sectorSize int) int64

func (Partition) Offset

func (p Partition) Offset(sectorSize int) int64

Offset and Length return the partition's byte range on disk.

type PartitionMember

type PartitionMember struct {
	Index    int        `json:"index"` // GPT entry index (matches DiskLayout.Partitions)
	Kind     MemberKind `json:"kind"`
	BackupID string     `json:"backup_id,omitempty"` // empty for skipped
	Reason   string     `json:"reason,omitempty"`    // for skipped: why
}

PartitionMember maps one partition of a captured disk to its backing backup.

type PlannedPartition added in v0.2.0

type PlannedPartition struct {
	Index    int    // slot in the entry array, as in Partition.Index
	TypeName string // for messages
	Name     string
	OldFirst uint64
	OldLast  uint64
	NewFirst uint64
	NewLast  uint64
	Shrink   bool
	Grow     bool
	Moved    bool
	MinBytes int64 // filesystem minimum the shrink was planned against; 0 = unknown
}

PlannedPartition is one partition's place on the target.

func (PlannedPartition) NewBytes added in v0.2.0

func (p PlannedPartition) NewBytes(ss int) int64

func (PlannedPartition) OldBytes added in v0.2.0

func (p PlannedPartition) OldBytes(ss int) int64

OldBytes and NewBytes are the partition's byte sizes before and after.

type Range

type Range struct {
	Offset int64 `json:"offset"`
	Length int64 `json:"length"`
}

Range is a byte range on the disk.

type TargetGeometry added in v0.2.0

type TargetGeometry struct {
	Size           int64 // bytes
	LogicalSector  int   // 512 or 4096; 0 = assume the captured layout's
	PhysicalSector int   // 512 or 4096 (512e drives: logical 512, physical 4096); 0 = unknown
}

TargetGeometry describes the drive a layout is being fitted onto.

Directories

Path Synopsis
Package gpttest builds synthetic, spec-valid GPT disk images for tests (correct header/entry CRCs, protective MBR, backup structures).
Package gpttest builds synthetic, spec-valid GPT disk images for tests (correct header/entry CRCs, protective MBR, backup structures).

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL