diskiso

package module
v0.0.0-...-bd3e65a 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.

vol, err := disc.Mount()                    // auto-pick
vol, err := disc.Mount(diskiso.UDF)         // explicit
vol, err := disc.Mount(diskiso.Joliet)      // 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