filesystem_btrfs

package module
v0.0.0-...-92297f9 Latest Latest
Warning

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

Go to latest
Published: Jun 23, 2026 License: BSD-3-Clause Imports: 19 Imported by: 0

README

go-filesystems/btrfs

filesystem-btrfs

Go Reference CI

Pure-Go read/write access to Btrfs filesystem images — no root privileges, no external tools, no CGO.

Supports single-device Btrfs images with CRC32c metadata checksums (btrfs-progs ≥ 5.x). MBR/GPT partition tables are auto-detected.

References

https://btrfs.readthedocs.io/en/latest/

Support summary

Feature Status Notes
Open / Close Single-device images supported
Format Creates a new Btrfs image
ReadFile Full file reads supported
WriteFile Full file writes supported
MkDir / Delete / Rename Directory and rename operations supported
ReadLink / Symlinks Supported
Partitioned images MBR/GPT auto-detected

Limitations

  • Advanced Btrfs features such as snapshots, send/receive, multi-device/RAID management, quotas and reflink are not fully implemented.
  • No online device add/remove or balance operations.
  • Intended for testing and tooling; not recommended for production use.

Supported operations

Operation Status
Open / Close ✅ implemented
Format ✅ implemented
Stat ✅ implemented
ListDir ✅ implemented
ReadFile ✅ implemented
WriteFile ✅ implemented
MkDir ✅ implemented
DeleteFile ✅ implemented
DeleteDir ✅ implemented
Rename ✅ implemented
ReadLink ✅ implemented

API

Format
type FormatConfig struct {
    UUID  [16]byte // zero = randomly generated
    Label string
}

func Format(path string, sizeBytes int64, cfg FormatConfig) (*FS, error)
Open
func Open(imagePath string, partIndex int) (*FS, error)
func (fs *FS) Close() error
Read
func (fs *FS) Stat(path string) (filesystem.Stat, error)
func (fs *FS) ListDir(path string) ([]filesystem.DirEntry, error)
func (fs *FS) ReadFile(path string) ([]byte, error)
func (fs *FS) ReadLink(path string) (string, error)
Write
func (fs *FS) WriteFile(path string, data []byte, perm os.FileMode) error
func (fs *FS) MkDir(path string, perm os.FileMode) error
func (fs *FS) DeleteFile(path string) error
func (fs *FS) DeleteDir(path string) error
func (fs *FS) Rename(oldPath, newPath string) error

Integration test

Set integrationImagePath in btrfs_test.go and run:

go test -v -run TestOpen_Integration ./pkg/filesystem-btrfs

Implements

This package implements the filesystem.Filesystem contract from github.com/go-filesystems/interface. Use the interface in higher-level tools to operate on multiple filesystem backends interchangeably.

Example:

import (
    filesystem "github.com/go-filesystems/interface"
    fsb "github.com/go-filesystems/btrfs"
)

f, _ := fsb.Open("btrfs.img", -1)
defer f.Close()
var fs filesystem.Filesystem = f
_, _ = fs.ReadFile("/data")

Documentation

Overview

Package btrfs provides read/write access to Btrfs filesystem images. It targets the common Btrfs on-disk format (single device, CRC32c checksums) as used by Fedora Cloud images.

Partition tables (MBR/GPT) are detected automatically; pass partIndex = -1 to auto-select the first Linux data partition.

Supported operations:

  • Open, Close, Format (single device)
  • ReadFile, ListDir, Stat, ReadLink
  • WriteFile, MkDir, DeleteFile, DeleteDir, Rename
  • Symlink, Link, Truncate
  • Chmod, Chown, Chtimes, get/set volume label, get/set xattrs
  • Grow / Resize (shrink trims free trailing space only)

Multi-device profiles (RAID0/1/10/5/6/DUP) are decoded for reading; writes are single-device.

Package btrfs provides read/write access to Btrfs filesystem images without requiring root privileges or external tools. It targets the Btrfs on-disk format as used by Fedora Cloud images (single device, CRC32c checksums).

Partition tables (MBR/GPT) are detected automatically; pass partIndex = -1 to auto-select the first Linux data partition.

All read and write operations are fully implemented.

Index

Constants

View Source
const MaxLabelLen = 255

MaxLabelLen is the on-disk size of the btrfs volume label (sb_fname / sbfLabel, 256 bytes). The kernel imposes an additional limit of 255 (to leave room for a trailing NUL), so we mirror that.

Variables

View Source
var ErrNotFound = errors.New("not found")

ErrNotFound is returned when a path component cannot be located.

Functions

func Format

func Format(path string, sizeBytes int64, cfg FormatConfig) (filesystem.Filesystem, error)

Format creates a new Btrfs filesystem in the file at path. The file is created (or truncated) and formatted. sizeBytes must be at least 1 MiB and a multiple of 4096.

On success the newly formatted filesystem is opened and returned; the caller must Close it when done.

Types

type BlockBackend

type BlockBackend = blockBackend

BlockBackend is the exported alias of blockBackend — uniform across go-filesystems/* so a single adapter (e.g. cloud-boot init's luksAsBlock) serves every FS.

type FS

type FS interface {
	filesystem.Filesystem

	Link(oldPath, newPath string) error
	Symlink(target, linkPath string) error

	Xattrs(path string) (map[string][]byte, error)
	GetXattr(path, name string) ([]byte, error)
	SetXattr(path, name string, value []byte) error
	RemoveXattr(path, name string) error

	ExtendedStat(path string) (*InodeStat, error)
	Chown(path string, uid, gid uint32) error
	Chmod(path string, perm os.FileMode) error
	Chtimes(path string, atime, mtime time.Time) error
	Truncate(path string, newSize int64) error

	Label() string
	SetLabel(label string) error

	// Subvolume / snapshot READ support. Subvolumes enumerates the subvolumes
	// and snapshots recorded in the ROOT_TREE (including the default FS_TREE,
	// id 5). OpenSubvolumeBy{ID,Name} return a read-only filesystem.Filesystem
	// rooted at the named subvolume/snapshot tree so ReadFile / ListDir / Stat
	// / ReadLink operate within it. Creation of subvolumes/snapshots is not
	// supported (it needs ref-counted extent backrefs).
	Subvolumes() ([]Subvolume, error)
	OpenSubvolumeByID(id uint64) (filesystem.Filesystem, error)
	OpenSubvolumeByName(name string) (filesystem.Filesystem, error)

	// Filesystem-level resize. Grow extends; Shrink reduces (refuses to
	// discard live data); Resize dispatches to whichever direction the
	// new size implies (no-op when equal). All three require an idle
	// FS — concurrent writers during a resize aren't safe.
	Grow(newSizeBytes int64) error
	Shrink(newSizeBytes int64) error
	Resize(newSizeBytes int64) error
}

FS is the public interface returned by Open. It extends the common filesystem.Filesystem with btrfs-specific operations — hardlinks / symlinks creation, xattrs read+write, rich inode stat, ownership / permission / timestamp setters, truncate.

Callers that want to reach the btrfs-only operations should consume this interface type (or a type-assert from the common Filesystem) rather than the concrete *btrfsFS.

func Open

func Open(imagePath string, partIndex int) (FS, error)

Open opens a Btrfs filesystem image at imagePath, auto-detecting the partition table (MBR/GPT) and selecting the first Linux partition. Pass partIndex = -1 for auto-detection.

func OpenFromDevice

func OpenFromDevice(dev BlockBackend, partIndex int) (FS, error)

OpenFromDevice opens a Btrfs filesystem backed by an arbitrary blockBackend. Layered callers (LUKS / qcow2 / in-memory) feed the FS without an *os.File-backed image. Same shape as the ext4 / xfs / zfs equivalents.

func OpenFromDevices

func OpenFromDevices(devs []BlockBackend, partIndex int) (FS, error)

OpenFromDevices opens a multi-device Btrfs filesystem. The first element of `devs` is treated as the "primary" — its superblock is read, its dev_item.devid drives the local-stripe selection used by the legacy single-leg fast path, and its partition table (if any) determines partOffset. Additional devices in the slice are added to the pool by their dev_item.devid (read from each device's superblock) so that RAID0 / RAID10 / RAID5 / RAID6 chunks can be served.

For SINGLE / DUP / RAID1 / RAID1Cn filesystems passing just the primary works (single-leg open via dev_item.devid matching). RAID0 and the parity profiles need at least the data-bearing devices present in the slice; missing data devices surface as a clear error at read time.

btrfs uses the on-disk fsid to bind a multi-device pool together; callers are responsible for grouping legs that share the same fsid (cloud-boot-init scans /sys/block for matching fsids).

type FormatConfig

type FormatConfig struct {
	// UUID is the filesystem UUID. A random UUID is generated when all bytes are zero.
	UUID [16]byte
	// Label is the volume label (up to 255 bytes, NUL-padded on disk).
	Label string
}

FormatConfig holds optional parameters for Format. All fields are optional; sensible defaults are used when left at their zero value.

type InodeStat

type InodeStat struct {
	Inode      uint64
	Mode       uint16
	Size       uint64
	NBytes     uint64
	NLink      uint32
	UID        uint32
	GID        uint32
	Generation uint64
	TransID    uint64
	Sequence   uint64
	Flags      uint64
	ATime      time.Time
	CTime      time.Time
	MTime      time.Time
	OTime      time.Time
}

InodeStat is the full metadata view of a btrfs INODE_ITEM. The common filesystem.Filesystem interface only exposes mode/size/inode via Stat; callers that need the rich btrfs picture (uid/gid, timestamps, nlink, nbytes, transid/sequence, flags) use ExtendedStat instead.

All four timestamp fields are returned in UTC.

func (*InodeStat) IsDir

func (s *InodeStat) IsDir() bool

IsDir / IsRegular / IsSymlink mirror the on-disk mode predicates.

func (*InodeStat) IsRegular

func (s *InodeStat) IsRegular() bool
func (s *InodeStat) IsSymlink() bool

type Subvolume

type Subvolume struct {
	ID         uint64 // ROOT_ITEM objectid (subvolume / tree id)
	ParentID   uint64 // parent subvolume id (0 for the FS_TREE / unreferenced roots)
	Name       string // name within the parent's directory (empty for FS_TREE)
	RootBytenr uint64 // logical address of this tree's root node
	Generation uint64 // root_item.generation
}

Subvolume describes one subvolume or snapshot enumerated from the ROOT_TREE.

A snapshot is indistinguishable from a subvolume at this layer: both are ROOT_ITEMs in the ROOT_TREE pointing at an fs-tree root node. Name and ParentID come from the corresponding ROOT_REF; the top-level FS_TREE (id 5) has no ROOT_REF and is reported with an empty Name and ParentID 0.

Jump to

Keyboard shortcuts

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