unionfs

package module
v1.0.0 Latest Latest
Warning

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

Go to latest
Published: Dec 12, 2025 License: MIT Imports: 11 Imported by: 0

README

UnionFS - Multi-Layer Filesystem Composition

Go Reference Go Report Card CI License

A layered filesystem implementation for Go providing Docker-style overlay filesystem capabilities with copy-on-write support.

Overview

UnionFS enables the composition of multiple filesystem layers into a single unified view. This is similar to how Docker and other container systems build images through layering, where each layer can add, modify, or delete files from lower layers.

Key Features:

  • Multiple filesystem layer composition
  • Copy-on-write (CoW) semantics for modifications
  • Whiteout support for deletions across layers
  • Read-only base layers with writable overlay
  • Efficient file lookup through layer precedence
  • Full afero.Fs interface compatibility
  • absfs.Filer interface implementation for ecosystem integration
  • Composable with other absfs packages (cachefs, rofs, metricsfs, etc.)

Use Cases:

  • Container filesystem implementations
  • Immutable base configurations with user overrides
  • Multi-tenant systems with shared base + per-tenant customization
  • Build systems with cached base layers
  • Testing with fixture data + test-specific modifications

Architecture

┌─────────────────────────────────────────────────────────────┐
│                      UnionFS Interface                       │
│                     (afero.Fs compatible)                    │
└─────────────────────────────────────────────────────────────┘
                              │
                              ▼
┌─────────────────────────────────────────────────────────────┐
│                    Layer Resolution Logic                    │
│  - Path lookup through layers (top to bottom)                │
│  - Whiteout detection (.wh.filename markers)                 │
│  - Copy-on-write for modifications                           │
│  - Directory merging across layers                           │
└─────────────────────────────────────────────────────────────┘
                              │
        ┌─────────────────────┼─────────────────────┐
        ▼                     ▼                     ▼
┌──────────────┐     ┌──────────────┐     ┌──────────────┐
│  Layer 2     │     │  Layer 1     │     │  Layer 0     │
│ (Writable)   │     │ (Read-only)  │     │ (Read-only)  │
│              │     │              │     │              │
│ /app/config/ │     │ /app/bin/    │     │ /usr/lib/    │
│   custom.yml │     │   myapp      │     │   libc.so    │
│ .wh.old.yml  │     │ /app/config/ │     │ /usr/bin/    │
│              │     │   default.yml│     │   bash       │
└──────────────┘     └──────────────┘     └──────────────┘
  (Top layer)        (Middle layer)       (Base layer)

Logical View:
/usr/lib/libc.so     → Layer 0
/usr/bin/bash        → Layer 0
/app/bin/myapp       → Layer 1
/app/config/default.yml → Layer 1
/app/config/custom.yml  → Layer 2 (added)
/app/config/old.yml     → (deleted via whiteout in Layer 2)

Implementation Plan

Phase 1: Core Layer Management

Layer Stack

  • Define Layer type wrapping afero.Fs with metadata
  • Implement layer ordering (top = highest precedence)
  • Layer validation and initialization
  • Support for read-only vs writable layer designation

Path Resolution

  • Traverse layers from top to bottom for file lookup
  • First match wins for file operations
  • Implement efficient path caching with invalidation
  • Handle absolute vs relative path normalization
Phase 2: Whiteout Support

Deletion Semantics

  • Implement AUFS-style whiteout files (.wh.filename)
  • Directory whiteout markers (.wh.__dir_opaque)
  • Whiteout detection during path resolution
  • Proper handling of directory deletion across layers

File Operations with Whiteouts

  • Create whiteout on file deletion in overlay layer
  • Remove whiteout when file is recreated
  • Stat operations respect whiteouts
  • Directory listing excludes whiteout entries
Phase 3: Copy-on-Write Operations

Write Operations

  • Detect writes to files in lower (read-only) layers
  • Copy file to writable layer before modification
  • Preserve file metadata (permissions, timestamps)
  • Handle partial writes and seeks efficiently

File Modification

  • OpenFile with write flags triggers CoW
  • Truncate operations
  • Chmod, Chown, Chtimes propagation
  • Atomic operations where possible
Phase 4: Directory Operations

Directory Merging

  • Merge directory listings across all layers
  • Apply whiteouts to merged results
  • Handle duplicate entries (top layer wins)
  • Efficient iteration with lazy evaluation

Directory Mutations

  • MkdirAll across layer boundaries
  • RemoveAll with whiteout creation
  • Rename within and across layers
  • Directory permission updates
Phase 5: Advanced Features

Symlink Handling

  • Resolve symlinks within layer context
  • Cross-layer symlink resolution
  • Detect and prevent symlink loops
  • Relative vs absolute symlink handling

Performance Optimizations

  • Negative lookup caching (non-existent paths)
  • Stat cache with TTL or invalidation
  • Lazy layer initialization
  • Concurrent layer access where safe

Special Cases

  • Hard link handling (may not span layers)
  • File locking behavior across layers
  • Memory-mapped file support
  • Large file optimization
Phase 6: Testing and Documentation

Test Coverage

  • Unit tests for each layer operation
  • Integration tests for multi-layer scenarios
  • Property-based tests for filesystem invariants
  • Benchmark suite for performance testing
  • Compatibility tests with afero test suite

Documentation

  • API documentation with examples
  • Architecture decision records
  • Performance tuning guide
  • Migration guide from other union filesystem implementations

API Design

Basic Usage
package main

import (
    "github.com/absfs/unionfs"
    "github.com/spf13/afero"
)

func main() {
    // Create base layer (read-only)
    baseLayer := afero.NewOsFs()

    // Create overlay layer (writable)
    overlayLayer := afero.NewMemMapFs()

    // Create union filesystem
    ufs := unionfs.New(
        unionfs.WithWritableLayer(overlayLayer),
        unionfs.WithReadOnlyLayer(baseLayer),
    )

    // Reads fall through to base layer if not in overlay
    data, err := afero.ReadFile(ufs, "/etc/config.yml")

    // Writes go to overlay layer
    err = afero.WriteFile(ufs, "/etc/custom.yml", []byte("key: value"), 0644)

    // Modifications trigger copy-on-write
    file, err := ufs.OpenFile("/etc/config.yml", os.O_RDWR, 0)
    file.Write([]byte("modified")) // Copies to overlay first
}
Advanced Configuration
// Multiple read-only layers with single writable layer
ufs := unionfs.New(
    unionfs.WithWritableLayer(overlayLayer),      // Top: writable
    unionfs.WithReadOnlyLayer(configLayer),       // Middle: configs
    unionfs.WithReadOnlyLayer(appLayer),          // Middle: app files
    unionfs.WithReadOnlyLayer(systemLayer),       // Bottom: system files
)

// Custom whiteout strategy
ufs := unionfs.New(
    unionfs.WithWritableLayer(overlayLayer),
    unionfs.WithReadOnlyLayer(baseLayer),
    unionfs.WithWhiteoutFormat(unionfs.OpaqueWhiteout),
)

// Performance tuning
ufs := unionfs.New(
    unionfs.WithWritableLayer(overlayLayer),
    unionfs.WithReadOnlyLayer(baseLayer),
    unionfs.WithStatCache(true, 5*time.Minute),
    unionfs.WithCopyBufferSize(128*1024),
)
Container-Style Workflow
// Docker-style layer building
func BuildContainerFS() afero.Fs {
    // Layer 0: Base OS
    baseOS := loadLayer("ubuntu:latest")

    // Layer 1: App dependencies
    deps := loadLayer("app-deps:1.0")

    // Layer 2: Application code
    app := loadLayer("myapp:2.3.4")

    // Layer 3: Runtime modifications
    runtime := afero.NewMemMapFs()

    return unionfs.New(
        unionfs.WithWritableLayer(runtime),
        unionfs.WithReadOnlyLayer(app),
        unionfs.WithReadOnlyLayer(deps),
        unionfs.WithReadOnlyLayer(baseOS),
    )
}

Usage Examples

Example 1: Configuration Override System
// Base configuration + environment-specific overrides
func LoadConfig(env string) afero.Fs {
    baseConfig := afero.NewOsFs() // /etc/app/defaults/
    envConfig := afero.NewOsFs()  // /etc/app/env/production/
    userConfig := afero.NewMemMapFs() // Runtime overrides

    ufs := unionfs.New(
        unionfs.WithWritableLayer(userConfig),
        unionfs.WithReadOnlyLayer(envConfig),
        unionfs.WithReadOnlyLayer(baseConfig),
    )

    // Read config.yml - checks user, then env, then base
    config, _ := afero.ReadFile(ufs, "/config.yml")
    return ufs
}
Example 2: Testing with Fixtures
// Immutable test fixtures + test-specific modifications
func TestWithFixtures(t *testing.T) {
    fixtures := afero.NewReadOnlyFs(afero.NewOsFs())
    testOverlay := afero.NewMemMapFs()

    ufs := unionfs.New(
        unionfs.WithWritableLayer(testOverlay),
        unionfs.WithReadOnlyLayer(fixtures),
    )

    // Tests can modify files without affecting fixtures
    afero.WriteFile(ufs, "/data/test.json", []byte("{}"), 0644)

    // Cleanup is automatic - just discard testOverlay
}
Example 3: Multi-Tenant Application
// Shared application base + tenant-specific customization
func TenantFilesystem(tenantID string) afero.Fs {
    // Shared application files (read-only)
    appBase := afero.NewReadOnlyFs(afero.NewOsFs())

    // Tenant-specific storage (writable)
    tenantFS := getTenantStorage(tenantID)

    ufs := unionfs.New(
        unionfs.WithWritableLayer(tenantFS),
        unionfs.WithReadOnlyLayer(appBase),
    )

    return ufs
}

Test Strategy

Unit Tests
  • Individual layer operations (read, write, stat, etc.)
  • Whiteout creation and detection
  • Copy-on-write triggering and execution
  • Path resolution through layer stack
  • Edge cases: empty layers, missing files, permissions
Integration Tests
  • Multi-layer file operations
  • Directory merging across layers
  • Complex rename and move operations
  • Concurrent access patterns
  • Whiteout interaction with directory operations
Compatibility Tests
  • Full afero.Fs interface compliance
  • Drop-in replacement verification
  • Edge case compatibility with standard library
  • Cross-platform behavior (Windows, Linux, macOS)
Performance Tests
  • Lookup performance vs layer count
  • Copy-on-write overhead measurement
  • Directory merge scalability
  • Cache effectiveness
  • Memory usage profiling
Property-Based Tests
  • Filesystem invariants (e.g., after write, read succeeds)
  • Layer precedence consistency
  • Whiteout correctness
  • CoW correctness (original unchanged)

Performance Considerations

Lookup Optimization
  • Stat caching: Cache file existence and metadata with TTL
  • Negative caching: Remember non-existent paths to avoid repeated layer scans
  • Path index: Optional in-memory index of all files across layers
  • Lazy layer loading: Don't scan layers until needed
Copy-on-Write Efficiency
  • Sparse file support: Preserve sparse files during copy
  • Streaming copy: Use buffered I/O for large files
  • Metadata-only CoW: Some operations only need metadata copy
  • Deferred copy: Delay copy until actual write occurs
Directory Operations
  • Lazy merging: Only merge directories when iterated
  • Iterator chaining: Stream results from multiple layers
  • Duplicate elimination: Efficient dedup of directory entries
  • Parallel layer scan: Concurrent ReadDir on independent layers
Memory Usage
  • Stream-based operations: Avoid loading entire files
  • Limited cache size: Bounded stat cache with LRU eviction
  • Shared layer instances: Reuse layer objects across union instances
  • Lazy whiteout detection: Check for whiteouts on-demand
Scaling Considerations
  • Layer count limits: Performance degrades with many layers (>10-20)
  • File count: Large directories may need special handling
  • Deep paths: Nested directory structures increase lookup cost
  • Write amplification: CoW can cause significant copying

absfs Ecosystem Integration

UnionFS is part of the absfs ecosystem and follows its philosophy of single responsibility and composability.

Philosophy

Each absfs package does one thing well:

  • unionfs (this package): Multi-layer composition + copy-on-write
  • cachefs: Performance caching
  • rofs: Read-only enforcement
  • metricsfs: Observability/metrics
  • retryfs: Retry logic
  • permfs: Access control

Complex behaviors emerge from simple composition:

// Each layer adds ONE responsibility
base := unionfs.New(...).FileSystem()    // Multi-layer composition
cached := cachefs.New(base)               // Add caching
readOnly := rofs.New(cached)              // Make read-only
monitored := metricsfs.New(readOnly)      // Add metrics

// Result: Cached, read-only, monitored, multi-layer filesystem
Interface Compatibility

UnionFS implements:

  • afero.Fs - Compatible with afero ecosystem
  • absfs.Filer - Minimal absfs interface (8 core methods)
  • absfs.FileSystem - Via FileSystem() method (adds working directory, convenience methods)
// Use as afero.Fs
data, _ := afero.ReadFile(ufs, "/path/to/file")

// Use as absfs.FileSystem
fs := ufs.FileSystem()
fs.Chdir("/app")
file, _ := fs.Open("config.yml") // Relative path support
Examples

See examples/absfs-composition for detailed composability examples.

Docker Overlay2
AUFS (Another UnionFS)
  • URL: http://aufs.sourceforge.net/
  • Description: Original union filesystem for Linux
  • Key Ideas: Branch layering, whiteout markers, copy-on-write
OverlayFS
go-dockerclient overlayfs
afero LayeredFs (inspiration)
containerd snapshotter

Implementation Notes

Whiteout Format

Following AUFS/Docker conventions:

  • File deletion: .wh.filename in same directory
  • Directory deletion: .wh.__dir_opaque marker
  • Whiteout files are hidden from normal directory listings
Layer Precedence
  • Layers are searched top to bottom
  • First match wins for file lookup
  • Writes always go to topmost writable layer
  • Only one writable layer supported initially
Atomic Operations
  • File creation: Direct write to writable layer
  • File modification: CoW then modify
  • File deletion: Create whiteout in writable layer
  • Directory operations: May span multiple layers
Error Handling
  • Read errors in lower layers are masked if higher layer has file
  • Write errors fail immediately
  • Permission errors respect highest layer with file
  • Path resolution errors bubble up

Future Enhancements

  • Multiple writable layers (advanced use cases)
  • Layer compaction and squashing
  • Efficient diff generation between layer states
  • Layer import/export (tar/zip archives)
  • Network-backed remote layers
  • Encryption at layer boundary
  • Compression per layer
  • Layer deduplication
  • Snapshot management
  • Layer garbage collection

Contributing

Contributions welcome! Please ensure:

  • Full test coverage for new features
  • Benchmark comparisons for performance changes
  • Documentation updates
  • Afero interface compatibility maintained

License

MIT License - see LICENSE file for details

Documentation

Overview

Package unionfs provides a layered filesystem implementation for Go with Docker-style overlay capabilities and copy-on-write support.

Overview

UnionFS enables the composition of multiple filesystem layers into a single unified view. This is similar to how Docker and other container systems build images through layering, where each layer can add, modify, or delete files from lower layers.

Key Features

  • Multiple filesystem layer composition
  • Copy-on-write (CoW) semantics for modifications
  • Whiteout support for deletions across layers
  • Read-only base layers with writable overlay
  • Efficient file lookup through layer precedence
  • Full afero.Fs interface compatibility

Architecture

The UnionFS maintains a stack of layers, ordered from top (highest precedence) to bottom. When a file is accessed, layers are searched from top to bottom, and the first match wins. Write operations always go to the topmost writable layer.

Basic Usage

package main

import (
    "github.com/absfs/unionfs"
    "github.com/spf13/afero"
)

func main() {
    // Create base layer (read-only)
    baseLayer := afero.NewOsFs()

    // Create overlay layer (writable)
    overlayLayer := afero.NewMemMapFs()

    // Create union filesystem
    ufs := unionfs.New(
        unionfs.WithWritableLayer(overlayLayer),
        unionfs.WithReadOnlyLayer(baseLayer),
    )

    // Reads fall through to base layer if not in overlay
    data, err := afero.ReadFile(ufs, "/etc/config.yml")

    // Writes go to overlay layer
    err = afero.WriteFile(ufs, "/etc/custom.yml", []byte("key: value"), 0644)

    // Modifications trigger copy-on-write
    file, err := ufs.OpenFile("/etc/config.yml", os.O_RDWR, 0)
    file.Write([]byte("modified")) // Copies to overlay first
}

Multiple Layers

You can stack multiple read-only layers with a single writable layer on top:

ufs := unionfs.New(
    unionfs.WithWritableLayer(overlayLayer),      // Top: writable
    unionfs.WithReadOnlyLayer(configLayer),       // Middle: configs
    unionfs.WithReadOnlyLayer(appLayer),          // Middle: app files
    unionfs.WithReadOnlyLayer(systemLayer),       // Bottom: system files
)

Layers are searched in order, so files in higher layers take precedence over lower layers.

Copy-on-Write

When you modify a file that exists in a read-only lower layer, the file is automatically copied to the writable layer before modification. This ensures the original file in the lower layer remains unchanged:

// File exists in baseLayer
afero.WriteFile(baseLayer, "/config.txt", []byte("original"), 0644)

// Create union with overlay
ufs := unionfs.New(
    unionfs.WithWritableLayer(overlay),
    unionfs.WithReadOnlyLayer(baseLayer),
)

// Modify file - triggers copy-on-write
afero.WriteFile(ufs, "/config.txt", []byte("modified"), 0644)

// Read from union gets modified version
data, _ := afero.ReadFile(ufs, "/config.txt")  // "modified"

// Base layer still has original
data, _ = afero.ReadFile(baseLayer, "/config.txt")  // "original"

Whiteout Files

When you delete a file that exists in a lower layer, a whiteout marker is created in the writable layer. This is a special file with the prefix ".wh." that marks the file as deleted:

// File exists in base layer
afero.WriteFile(baseLayer, "/file.txt", []byte("content"), 0644)

// Delete through union
ufs.Remove("/file.txt")

// Creates whiteout marker at /.wh.file.txt in overlay
// File no longer visible through union
_, err := ufs.Stat("/file.txt")  // os.ErrNotExist

// But still exists in base layer
_, err = baseLayer.Stat("/file.txt")  // nil error

Whiteout files follow the AUFS/Docker convention using the ".wh." prefix.

Directory Merging

When reading a directory, UnionFS merges the contents from all layers:

// Layer 0 has /dir/file1.txt
// Layer 1 has /dir/file2.txt
// Layer 2 has /dir/file3.txt

entries, _ := afero.ReadDir(ufs, "/dir")
// Returns all three files: file1.txt, file2.txt, file3.txt

Whiteouts are respected during directory merging, so deleted files don't appear in listings.

Use Cases

Configuration Management:

// Base configuration + environment-specific overrides
ufs := unionfs.New(
    unionfs.WithWritableLayer(runtimeConfig),
    unionfs.WithReadOnlyLayer(envConfig),
    unionfs.WithReadOnlyLayer(defaultConfig),
)

Testing with Fixtures:

// Immutable test fixtures + test-specific modifications
ufs := unionfs.New(
    unionfs.WithWritableLayer(testOverlay),
    unionfs.WithReadOnlyLayer(fixtures),
)

Container Filesystems:

// Layer base OS, dependencies, app code, and runtime changes
ufs := unionfs.New(
    unionfs.WithWritableLayer(runtime),
    unionfs.WithReadOnlyLayer(appCode),
    unionfs.WithReadOnlyLayer(dependencies),
    unionfs.WithReadOnlyLayer(baseOS),
)

Performance Considerations

  • File lookups traverse layers from top to bottom, so fewer layers = better performance
  • Copy-on-write operations involve copying the entire file, which can be expensive for large files
  • Directory merging may be slower for directories with many files across multiple layers
  • Consider using stat caching for frequently accessed files (see WithStatCache option)

Thread Safety

UnionFS uses read-write locks to ensure thread-safe access to the layer stack. Multiple goroutines can safely read from the filesystem concurrently, while write operations are properly synchronized.

absfs Ecosystem Integration

UnionFS is part of the absfs ecosystem and implements both afero.Fs and absfs.Filer interfaces, enabling seamless composition with other absfs packages.

Get an absfs.FileSystem view:

ufs := unionfs.New(
    unionfs.WithWritableLayer(overlay),
    unionfs.WithReadOnlyLayer(base),
)

// Get absfs.FileSystem with working directory support
fs := ufs.FileSystem()
fs.Chdir("/app")
file, err := fs.Open("config.yml") // Relative to /app

Compose with other absfs packages:

// UnionFS provides: multi-layer composition + copy-on-write
union := unionfs.New(...).FileSystem()

// Wrap with other absfs packages for additional functionality:
// - cachefs:   Add caching layer (performance)
// - rofs:      Make read-only (safety)
// - metricsfs: Add Prometheus metrics (observability)
// - retryfs:   Add retry logic (reliability)
// - permfs:    Add access control (security)

This demonstrates the absfs philosophy: each package has a single responsibility, and complex behaviors emerge from simple composition.

Compatibility

UnionFS implements both:

  • afero.Fs interface - for compatibility with afero-based code
  • absfs.Filer interface - for integration with the absfs ecosystem

Use ExtendFiler or FileSystem() to get the full absfs.FileSystem interface with convenience methods and working directory support.

Limitations

  • Only one writable layer is supported (topmost layer)
  • Hard links are not supported across layers
  • Symlink resolution is currently basic (advanced cross-layer symlinks not yet implemented)
  • File locking behavior across layers is filesystem-dependent

Package unionfs provides a layered filesystem implementation with Docker-style overlay capabilities and copy-on-write support.

Index

Constants

View Source
const (
	// WhiteoutPrefix is the prefix for whiteout files (AUFS/Docker style)
	WhiteoutPrefix = ".wh."
	// OpaqueWhiteout marks a directory as opaque (hides all lower layer contents)
	OpaqueWhiteout = ".wh.__dir_opaque"
)

Variables

View Source
var (
	// ErrNoWritableLayer is returned when a write operation is attempted but no writable layer exists
	ErrNoWritableLayer = errors.New("no writable layer configured")
	// ErrReadOnlyLayer is returned when attempting to write to a read-only layer
	ErrReadOnlyLayer = errors.New("layer is read-only")
)

Functions

This section is empty.

Types

type Cache

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

Cache provides caching capabilities for filesystem operations

func (*Cache) Stats

func (c *Cache) Stats() CacheStats

Stats returns cache statistics

type CacheStats

type CacheStats struct {
	Enabled           bool
	StatCacheSize     int
	NegativeCacheSize int
	MaxEntries        int
	StatTTL           time.Duration
	NegativeTTL       time.Duration
}

CacheStats contains cache statistics

type Layer

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

Layer represents a single filesystem layer with metadata

type Option

type Option func(*UnionFS)

Option is a functional option for configuring UnionFS

func WithCacheConfig

func WithCacheConfig(enabled bool, statTTL, negativeTTL time.Duration, maxEntries int) Option

WithCacheConfig enables caching with custom configuration

func WithCopyBufferSize

func WithCopyBufferSize(size int) Option

WithCopyBufferSize sets the buffer size for copy-on-write operations

func WithReadOnlyLayer

func WithReadOnlyLayer(fs absfs.FileSystem) Option

WithReadOnlyLayer adds a read-only layer to the layer stack Read-only layers are added in order after the writable layer

func WithStatCache

func WithStatCache(enabled bool, ttl time.Duration) Option

WithStatCache enables stat caching with the specified TTL

func WithWritableLayer

func WithWritableLayer(fs absfs.FileSystem) Option

WithWritableLayer adds a writable layer at the top of the layer stack

type UnionFS

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

UnionFS implements a union filesystem with multiple layers

func New

func New(opts ...Option) *UnionFS

New creates a new UnionFS with the specified options

func (*UnionFS) AsAbsFS deprecated

func (ufs *UnionFS) AsAbsFS() absfs.FileSystem

AsAbsFS returns an absfs.FileSystem adapter for this UnionFS. This is an alias for FileSystem() provided for clarity.

Deprecated: Use FileSystem() instead.

func (*UnionFS) CacheStats

func (ufs *UnionFS) CacheStats() CacheStats

CacheStats returns cache statistics

func (*UnionFS) Chmod

func (ufs *UnionFS) Chmod(name string, mode os.FileMode) error

Chmod changes file permissions

func (*UnionFS) Chown

func (ufs *UnionFS) Chown(name string, uid, gid int) error

Chown changes file ownership

func (*UnionFS) Chtimes

func (ufs *UnionFS) Chtimes(name string, atime, mtime time.Time) error

Chtimes changes file access and modification times

func (*UnionFS) ClearCache

func (ufs *UnionFS) ClearCache()

ClearCache removes all cache entries

func (*UnionFS) Create

func (ufs *UnionFS) Create(name string) (absfs.File, error)

Create creates a file in the writable layer

func (*UnionFS) FileSystem

func (ufs *UnionFS) FileSystem() absfs.FileSystem

FileSystem returns an absfs.FileSystem view of this UnionFS. The returned FileSystem maintains its own working directory state and provides the full absfs.FileSystem interface including convenience methods like Open, Create, MkdirAll, RemoveAll, and Truncate.

This enables seamless integration with the absfs ecosystem.

Example:

ufs := unionfs.New(
    unionfs.WithWritableLayer(overlay),
    unionfs.WithReadOnlyLayer(base),
)

// Use as absfs.FileSystem
fs := ufs.FileSystem()
fs.Chdir("/app")
file, err := fs.Open("config.yml") // Uses current working directory

func (*UnionFS) InvalidateCache

func (ufs *UnionFS) InvalidateCache(path string)

InvalidateCache removes a path from the cache

func (*UnionFS) InvalidateCacheTree

func (ufs *UnionFS) InvalidateCacheTree(pathPrefix string)

InvalidateCacheTree removes all cache entries under a path prefix

func (*UnionFS) Lchown

func (ufs *UnionFS) Lchown(name string, uid, gid int) error

Lchown changes the ownership of a symlink (without following it)

func (*UnionFS) Lstat

func (ufs *UnionFS) Lstat(name string) (os.FileInfo, error)

Lstat returns file info without following symlinks

func (*UnionFS) LstatIfPossible

func (ufs *UnionFS) LstatIfPossible(name string) (os.FileInfo, bool, error)

LstatIfPossible returns file info without following symlinks if the filesystem supports it

func (*UnionFS) Mkdir

func (ufs *UnionFS) Mkdir(name string, perm os.FileMode) error

Mkdir creates a directory in the writable layer

func (*UnionFS) MkdirAll

func (ufs *UnionFS) MkdirAll(name string, perm os.FileMode) error

MkdirAll creates a directory and all parent directories

func (*UnionFS) Name

func (ufs *UnionFS) Name() string

Name returns the name of the filesystem

func (*UnionFS) Open

func (ufs *UnionFS) Open(name string) (absfs.File, error)

Open opens a file for reading

func (*UnionFS) OpenFile

func (ufs *UnionFS) OpenFile(name string, flag int, perm os.FileMode) (absfs.File, error)

OpenFile opens a file with the specified flags and permissions

func (*UnionFS) ReadDir

func (ufs *UnionFS) ReadDir(name string) ([]fs.DirEntry, error)

ReadDir reads the named directory and returns all its directory entries, merging results from all layers. Entries from upper layers take precedence, and whiteouts are respected.

func (*UnionFS) ReadFile

func (ufs *UnionFS) ReadFile(name string) ([]byte, error)

ReadFile reads the named file and returns its contents. It reads from the first layer (highest precedence) that contains the file.

func (ufs *UnionFS) Readlink(name string) (string, error)

Readlink returns the destination of a symlink

func (*UnionFS) ReadlinkIfPossible

func (ufs *UnionFS) ReadlinkIfPossible(name string) (string, error)

ReadlinkIfPossible returns the destination of a symlink if supported

func (*UnionFS) Remove

func (ufs *UnionFS) Remove(name string) error

Remove deletes a file or empty directory by creating a whiteout

func (*UnionFS) RemoveAll

func (ufs *UnionFS) RemoveAll(name string) error

RemoveAll removes a path and all children

func (*UnionFS) Rename

func (ufs *UnionFS) Rename(oldname, newname string) error

Rename renames a file or directory

func (*UnionFS) Stat

func (ufs *UnionFS) Stat(name string) (os.FileInfo, error)

Stat returns file info, searching through layers

func (*UnionFS) Sub

func (ufs *UnionFS) Sub(dir string) (fs.FS, error)

Sub returns a filesystem rooted at the given directory, creating a sub-view across all layers.

func (ufs *UnionFS) Symlink(oldname, newname string) error

Symlink creates a symbolic link

func (*UnionFS) SymlinkFileSystem

func (ufs *UnionFS) SymlinkFileSystem() absfs.SymlinkFileSystem

SymlinkFileSystem returns an absfs.SymlinkFileSystem view of this UnionFS. The returned SymlinkFileSystem maintains its own working directory state and provides the full absfs.SymlinkFileSystem interface including symlink operations (Symlink, Readlink, Lstat, Lchown).

This enables seamless integration with the absfs ecosystem when symlink support is required.

func (*UnionFS) SymlinkIfPossible

func (ufs *UnionFS) SymlinkIfPossible(oldname, newname string) error

SymlinkIfPossible creates a symbolic link if supported

Directories

Path Synopsis
examples
absfs-composition command
Package main demonstrates composing UnionFS with other absfs ecosystem packages to build complex, layered filesystem behaviors through simple composition.
Package main demonstrates composing UnionFS with other absfs ecosystem packages to build complex, layered filesystem behaviors through simple composition.

Jump to

Keyboard shortcuts

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