diskiso

package module
v0.0.0-...-ffbe2be Latest Latest
Warning

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

Go to latest
Published: May 12, 2026 License: MIT Imports: 7 Imported by: 0

README

diskiso

A pure-Go library for reading ISO 9660 disc images. diskiso detects and exposes all filesystem layers present in an image — ISO 9660, Joliet, Rock Ridge, and UDF — behind a single clean interface.

Features

  • Multi-layer detection — probes every layer in one pass and ranks them by richness
  • UDF (ECMA-167) — full partition/FSD/ICB chain, handles the oscdimg EFE offset bug found in Windows ISOs
  • Joliet — UCS-2BE long Unicode filenames via the Supplementary Volume Descriptor
  • Rock Ridge — POSIX names, symlinks, and permissions via SUSP extensions
  • ISO 9660 — baseline ECMA-119 compatibility layer, always present
  • Streaming readsOpen returns an fs.File backed by a section reader; large files are never fully buffered
  • No CGo, no OS mounts — works on Linux, macOS, and Windows from a single binary

Installation

go get github.com/carbon-os/diskiso

Requires Go 1.21 or later.

Quick start

package main

import (
    "fmt"
    "github.com/carbon-os/diskiso"
)

func main() {
    disc, err := diskiso.Attach("windows-arm64.iso")
    if err != nil {
        panic(err)
    }
    defer disc.Detach()

    // Auto-picks the best available layer: UDF > Joliet > Rock Ridge > ISO 9660
    vol, err := disc.Mount()
    if err != nil {
        panic(err)
    }

    entries, err := vol.ReadDir("/")
    if err != nil {
        panic(err)
    }
    for _, e := range entries {
        fmt.Println(e.Name())
    }
}

Selecting a layer explicitly

disc, _ := diskiso.Attach("image.iso")
defer disc.Detach()

fmt.Println(disc.FilesystemNames()) // ["udf", "joliet", "iso9660"]

vol, err := disc.Mount(diskiso.Joliet)  // explicit layer

The Volume interface

Every layer is accessed through the same Volume interface:

type Volume interface {
    Type()     string                            // "udf", "joliet", "rockridge", "iso9660"
    Label()    string                            // volume label from the image

    ReadFile(path string) ([]byte, error)        // read whole file into memory
    Open(path string)     (fs.File, error)       // streaming read; caller must Close
    ReadDir(path string)  ([]fs.DirEntry, error) // list a directory
    Stat(path string)     (os.FileInfo, error)   // metadata for any path
    Readlink(path string) (string, error)        // symlink target (Rock Ridge only)
}

All paths are absolute ("/sources/install.wim").

Filesystem layers

Constant String Description
ISO9660 "iso9660" Baseline ECMA-119; uppercase ASCII, 8.3 or 31-char names
Joliet "joliet" Microsoft Unicode extension; UCS-2BE names up to 64 chars
RockRidge "rockridge" POSIX names, symlinks, and permissions via SUSP
UDF "udf" Universal Disk Format (ECMA-167); used by DVDs and modern Windows ISOs

When Mount() is called without arguments, the first detected layer in the priority order UDF → Joliet → Rock Ridge → ISO 9660 is used.

Package layout

diskiso/
├── attach.go       Attach / Detach and filesystem probing
├── disc.go         Disc type — holds the file handle and layer list
├── filesystem.go   Filesystem constants and their String() names
├── mount.go        Mount — opens a Volume for a given layer
├── volume.go       Volume interface definition
├── internal/
│   └── region/     Low-level 2048-byte sector I/O and both-endian helpers
├── iso9660/
│   ├── detect.go   PVD/SVD/Rock Ridge probe
│   ├── dirent.go   Directory record parser
│   ├── rockridge.go SUSP NM/SL/PX/TF field decoders
│   └── volume.go   iso9660.Volume implementation
└── udf/
    ├── detect.go   VRS + AVDP probe
    ├── diagnose.go UDF chain debugger (--diagnose)
    └── volume.go   udf.Volume implementation

CLI — diskiso

A command-line tool is included under ./diskiso.

go install github.com/carbon-os/diskiso/cmd/diskiso@latest
Usage
diskiso <image.iso> --info | --diagnose | --fs <cmd> [args] [--layer <fs>]
--info — inspect an image

Prints the detected layers, per-layer volume labels, and a root directory listing from the best available layer.

$ diskiso windows11-arm64.iso --info
Image : windows11-arm64.iso (5.4 GB)
Layers: udf, joliet, iso9660

LAYER    LABEL
-----    -----
udf      CCCOMA_X64FRE_EN-GB_DV9
joliet   CCCOMA_X64FRE_EN-GB_DV9
iso9660  CCCOMA_X64FRE_EN-GB_DV9

Root directory (udf):
  boot/          512 B    2024-11-14 03:12
  efi/           512 B    2024-11-14 03:12
  sources/       512 B    2024-11-14 03:12
  setup.exe      85.3 KB  2024-11-14 03:12
  ...
--fs — filesystem commands
# List a directory (default layer)
diskiso image.iso --fs ls /sources

# Force a specific layer
diskiso image.iso --fs ls / --layer joliet

# Print a text file to stdout
diskiso image.iso --fs cat /README.TXT

# Extract a file
diskiso image.iso --fs get /sources/install.wim ./install.wim

Available sub-commands: ls, cat, get.

--diagnose — debug UDF structure

Walks the full UDF chain (AVDP → VDS → FSD → root ICB) and prints every parsed field and raw byte offset. Useful when --info shows an empty root on a malformed image.

diskiso tricky.iso --diagnose

License

MIT — see LICENSE.

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Disc

type Disc struct {
	// contains filtered or unexported fields
}

Disc represents an attached ISO image. Obtain one via Attach; release resources with Detach.

func Attach

func Attach(path string) (*Disc, error)

Attach opens an ISO image file and probes it for recognised filesystem layers. The file handle is held open until Detach is called.

disc, err := diskiso.Attach("windows-arm64.iso")

func (*Disc) Detach

func (d *Disc) Detach() error

Detach closes the underlying image file and releases all resources. Calling Detach on an already-detached Disc is a no-op.

func (*Disc) FilesystemNames

func (d *Disc) FilesystemNames() []string

FilesystemNames returns the same list as human-readable strings.

disc.FilesystemNames() // → ["udf", "joliet", "iso9660"]

func (*Disc) Filesystems

func (d *Disc) Filesystems() []Filesystem

Filesystems returns the detected layers in descending priority order. The first entry is what Mount selects automatically.

disc.Filesystems() // → [UDF Joliet ISO9660]

func (*Disc) Mount

func (d *Disc) Mount(want ...Filesystem) (Volume, error)

Mount returns a read-only Volume backed by the requested filesystem layer. With no argument the best available layer is chosen automatically: UDF > Joliet > RockRidge > ISO9660.

When auto-selecting, each candidate layer is validated by reading the root directory. A layer whose root is unreadable or empty is skipped and the next candidate is tried. This handles ISOs that carry UDF Volume Recognition Sequence markers (as oscdimg and several other tools emit by default) but contain no actual UDF structures — without this check the UDF layer would be selected and return an empty filesystem.

vol, err := disc.Mount()                    // auto-pick best readable layer
vol, err := disc.Mount(diskiso.UDF)         // explicit — no fallback
vol, err := disc.Mount(diskiso.Joliet)      // explicit — no fallback

type Filesystem

type Filesystem int

Filesystem identifies a filesystem layer present within an ISO image. A single .iso typically carries several overlapping layers (e.g. ISO9660 + Joliet + UDF) that all reference the same underlying data.

const (
	// ISO9660 is the base ECMA-119 layer. Uppercase ASCII names, 8.3 or 31 chars.
	// Always present for compatibility.
	ISO9660 Filesystem = iota

	// Joliet is Microsoft's Unicode extension. UCS-2BE names up to 64 chars.
	// Stored in a Supplementary Volume Descriptor.
	Joliet

	// RockRidge adds POSIX semantics: long mixed-case names, symlinks, permissions.
	// Stored in the System Use fields of ISO9660 directory records.
	RockRidge

	// UDF is Universal Disk Format (ECMA-167). The modern standard used by DVDs,
	// Windows ISOs, and Linux-generated images.
	UDF
)

func (Filesystem) String

func (f Filesystem) String() string

type Volume

type Volume interface {
	// Type returns the layer name: "iso9660", "joliet", "rockridge", or "udf".
	Type() string

	// Label returns the volume label embedded in the image.
	Label() string

	// ReadFile reads the entire contents of a file.
	ReadFile(path string) ([]byte, error)

	// Open opens a file for streaming. The caller must Close it.
	Open(path string) (fs.File, error)

	// ReadDir lists the entries in a directory.
	ReadDir(path string) ([]fs.DirEntry, error)

	// Stat returns metadata for a path.
	Stat(path string) (os.FileInfo, error)

	// Readlink returns the symlink target. Only meaningful on RockRidge volumes;
	// all others return an error.
	Readlink(path string) (string, error)
}

Volume is a read-only view into a single filesystem layer of an ISO image. All paths are absolute (e.g. "/sources/install.wim").

Obtain a Volume via Disc.Mount; it is valid for the lifetime of the Disc.

Directories

Path Synopsis
internal
region
Package region provides low-level 2048-byte sector I/O and both-endian integer helpers shared by the iso9660 and udf packages.
Package region provides low-level 2048-byte sector I/O and both-endian integer helpers shared by the iso9660 and udf packages.

Jump to

Keyboard shortcuts

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