cowfs

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: 7 Imported by: 0

README

CowFS - Copy on Write FileSystem

Go Reference Go Report Card CI License

The cowfs package implements a Copy-on-Write FileSystem that wraps two absfs.Filer implementations. It reads from a primary read-only filesystem and directs all writes and modifications to a secondary writable filesystem, leaving the primary unchanged.

Features

  • Non-destructive writes: Primary filesystem remains unmodified
  • Transparent reads: Automatically selects primary or secondary based on modification state
  • Full write support: All modifications go to secondary filesystem

Install

go get github.com/absfs/cowfs

Example Usage

package main

import (
    "os"

    "github.com/absfs/cowfs"
    "github.com/absfs/memfs"
    "github.com/absfs/osfs"
)

func main() {
    // Create primary read-only filesystem
    primary, _ := osfs.NewFS()

    // Create secondary writable filesystem for modifications
    secondary, _ := memfs.NewFS()

    // Create copy-on-write filesystem
    fs := cowfs.New(primary, secondary)

    // Reads come from primary
    f, _ := fs.OpenFile("/config/app.conf", os.O_RDONLY, 0)
    defer f.Close()

    // Writes go to secondary, primary unchanged
    w, _ := fs.OpenFile("/config/app.conf", os.O_WRONLY, 0644)
    w.WriteString("modified content")
    w.Close()

    // Subsequent reads come from secondary
    // (since file was modified)
}

Use Cases

  • Testing with production data without modification risk
  • Implementing ephemeral filesystem overlays
  • Creating sandboxed environments

absfs

Check out the absfs repo for more information about the abstract filesystem interface and features like filesystem composition.

LICENSE

This project is governed by the MIT License. See LICENSE

Documentation

Overview

Package cowfs implements a Copy-on-Write FileSystem that wraps two absfs.Filer implementations. It reads from a primary read-only filesystem and directs all writes and modifications to a secondary writable filesystem, leaving the primary unchanged.

Example

Example demonstrates basic usage of cowfs

primary := newMockFiler()
secondary := newMockFiler()

// Add a file to the primary filesystem
primary.files["/config.txt"] = &mockFile{
	name: "/config.txt",
	data: []byte("original content"),
	mode: 0644,
}

// Create copy-on-write filesystem
fs := New(primary, secondary)

// Read from primary
f, _ := fs.OpenFile("/config.txt", os.O_RDONLY, 0)
buf := make([]byte, 100)
n, _ := f.Read(buf)
f.Close()
fmt.Println(string(buf[:n]))

// Write creates a copy in secondary
w, _ := fs.OpenFile("/config.txt", os.O_CREATE|os.O_WRONLY, 0644)
w.Write([]byte(" modified"))
w.Close()

// Subsequent reads come from secondary
f2, _ := fs.OpenFile("/config.txt", os.O_RDONLY, 0)
buf2 := make([]byte, 100)
n2, _ := f2.Read(buf2)
f2.Close()
fmt.Println(string(buf2[:n2]))

// Primary remains unchanged
fmt.Println(string(primary.files["/config.txt"].data))
Output:

original content
original content modified
original content

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type FileSystem

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

FileSystem implements absfs.Filer with copy-on-write semantics. Reads come from the primary filesystem, while writes and modifications go to the secondary filesystem. FileSystem is safe for concurrent use.

func New

func New(primary, secondary absfs.Filer) *FileSystem

New creates a new CowFS that reads from primary and writes to secondary.

func (*FileSystem) Chmod

func (fs *FileSystem) Chmod(name string, mode os.FileMode) error

Chmod changes the mode in the secondary filesystem. If the file exists only in primary, it's copied to secondary first.

Example

ExampleFileSystem_Chmod demonstrates copy-on-write for metadata operations

primary := newMockFiler()
secondary := newMockFiler()

// Add a file to the primary filesystem
primary.files["/file.txt"] = &mockFile{
	name: "/file.txt",
	data: []byte("content"),
	mode: 0644,
}

fs := New(primary, secondary)

// Changing mode triggers copy to secondary
fs.Chmod("/file.txt", 0755)

// File is now in secondary with new mode
info, _ := secondary.Stat("/file.txt")
fmt.Println(info.Mode().Perm() == 0755)

// Primary remains unchanged
fmt.Println(primary.files["/file.txt"].mode == 0644)
Output:

true
true

func (*FileSystem) Chown

func (fs *FileSystem) Chown(name string, uid, gid int) error

Chown changes the owner in the secondary filesystem. If the file exists only in primary, it's copied to secondary first.

func (*FileSystem) Chtimes

func (fs *FileSystem) Chtimes(name string, atime time.Time, mtime time.Time) error

Chtimes changes the times in the secondary filesystem. If the file exists only in primary, it's copied to secondary first.

func (*FileSystem) Mkdir

func (fs *FileSystem) Mkdir(name string, perm os.FileMode) error

Mkdir creates a directory in the secondary filesystem.

func (*FileSystem) OpenFile

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

OpenFile opens a file, reading from primary or secondary based on modification state. Write operations mark files as modified and direct them to secondary.

func (*FileSystem) ReadDir

func (cfs *FileSystem) ReadDir(name string) ([]fs.DirEntry, error)

ReadDir reads the named directory and returns a list of directory entries.

func (*FileSystem) ReadFile

func (cfs *FileSystem) ReadFile(name string) ([]byte, error)

ReadFile reads the named file and returns its contents.

func (*FileSystem) Remove

func (fs *FileSystem) Remove(name string) error

Remove removes a file from the secondary filesystem and marks it as deleted.

Example

ExampleFileSystem_Remove demonstrates deletion tracking

primary := newMockFiler()
secondary := newMockFiler()

// Add a file to the primary filesystem
primary.files["/file.txt"] = &mockFile{
	name: "/file.txt",
	data: []byte("content"),
	mode: 0644,
}

fs := New(primary, secondary)

// Remove the file
fs.Remove("/file.txt")

// File appears deleted even though it's still in primary
_, err := fs.OpenFile("/file.txt", os.O_RDONLY, 0)
fmt.Println(err == os.ErrNotExist)
Output:

true

func (*FileSystem) Rename

func (fs *FileSystem) Rename(oldpath, newpath string) error

Rename renames a file in the secondary filesystem.

func (*FileSystem) Stat

func (fs *FileSystem) Stat(name string) (os.FileInfo, error)

Stat returns file info, checking secondary first if modified.

func (*FileSystem) Sub

func (cfs *FileSystem) Sub(dir string) (fs.FS, error)

Sub returns a Filer corresponding to the subtree rooted at dir.

func (*FileSystem) TempDir

func (cfs *FileSystem) TempDir() string

TempDir returns the temp directory path from the secondary (writable) filesystem. This implements the optional temper interface so that ExtendFiler can delegate to the appropriate filesystem.

func (*FileSystem) Truncate

func (fs *FileSystem) Truncate(name string, size int64) error

Truncate truncates a file to the specified size. If the file exists only in primary, it's copied to secondary first.

Jump to

Keyboard shortcuts

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