blkcache

blkcache.server

blkcache.server – userspace read-through cache via nbdkit + nbdfuse.

blkcache.file.device

Device file abstraction with ioctl support.

Device class that extends File with block device operations like sector size detection, device sizing, and rotational status.

BLKGETSIZE64

<linux/fs.h> Get device byte-length

BLKSSZGET

Get block device sector size

Device Objects

class Device(File)

Device file with block device operations.

check

@staticmethod
def check(path: Path) -> bool

Check if this is a block device.

device_size

def device_size() -> int

Get device capacity in bytes using ioctl or fallback methods.

sector_size

@property
@lru_cache(maxsize=1)
def sector_size() -> int

Get device sector size using ioctl.

blkcache.file.cached

Cache file abstraction.

CacheFile wraps another File and provides read-through caching. Opens the backing file in its enter method.

CachedFile Objects

class CachedFile(File)

Passthrough cache that wraps another File instance.

check

@staticmethod
def check(path: Path) -> bool

CacheFile doesn’t check paths - it’s a wrapper.

path

@property
def path() -> Path

Return the backing file’s path.

size

def size() -> int

Get size from backing file.

sector_size

@property
def sector_size() -> int

Get sector size from backing file.

pread

def pread(count: int, offset: int) -> bytes

Read with cache - try cache first, then backing file.

pwrite

def pwrite(data: bytes, offset: int) -> int

Write through to both cache and backing file.

fingerprint

def fingerprint(head: int = 65_536) -> str

Get fingerprint from backing file.

__getattr__

def __getattr__(name)

Delegate unknown attributes to backing file.

blkcache.file.mmapped

Memory-mapped file abstraction.

MappedFile uses mmap for efficient access to regular files. Only works with regular files that support memory mapping.

MMappedFile Objects

class MMappedFile(File)

Memory-mapped file with efficient random access.

check

@staticmethod
def check(path: Path) -> bool

Check if this is a regular file that can be memory-mapped.

pread

def pread(count: int, offset: int) -> bytes

Read count bytes at offset using memory map.

pwrite

def pwrite(data: bytes, offset: int) -> int

Write data at offset using memory map.

size

def size() -> int

Get file size from memory map.

blkcache.file.base

File Objects

class File()

Base file class with position-independent read/write operations.

check

@staticmethod
def check(path: Path) -> bool

Check if this class can handle the given path.

depends

def depends(*files)

Register file dependencies for cascading cleanup.

__getattr__

def __getattr__(name)

Delegate unknown attributes to the underlying file object.

pread

def pread(count: int, offset: int) -> bytes

Read count bytes at offset without changing file position.

pwrite

def pwrite(data: bytes, offset: int) -> int

Write data at offset without changing file position.

size

def size() -> int

Get file size without changing file position.

fingerprint

def fingerprint(head: int = 65_536) -> str

Generate content fingerprint from file header.

blkcache.file.atomic

Atomic file writes for frequently-updated or slowly written files.

AtomicFile prevents corruption of small files that are written often, like ddrescue map files, by writing to “name~” then moving into place.

AtomicFile Objects

class AtomicFile(File)

File with atomic write operations via temporary files.

check

@staticmethod
def check(path: Path) -> bool

Atomic files can handle any regular file path.

blkcache.file.removable

Removable device abstraction with media change detection.

Removable class extends Device with functionality for optical drives, USB drives, and other removable media that can be ejected or changed.

CDROM_GET_BLKSIZE

Get CDROM block size

Removable Objects

class Removable(Device)

Removable device with media change detection.

check

@staticmethod
def check(path: Path) -> bool

Check if this is a removable block device.

sector_size

@property
@lru_cache(maxsize=1)
def sector_size() -> int

Get sector size with CDROM-specific ioctl support.

watch_for_changes

def watch_for_changes(stop_event: threading.Event,
                      callback=None,
                      logger=None) -> None

Monitor device for media changes.

Arguments:

blkcache.file

File abstraction package with automatic type detection.

Provides File, Device, and Removable classes with a detect() factory function that automatically chooses the appropriate class for a given path.

detect

def detect(path: Path | str) -> Type[File]

Return the most specific file class that can handle this path.

Checks classes in order of specificity: Removable -> Device -> File Returns the first class whose check() method returns True.

blkcache.file.filemap

File mapping for tracking block/sector status.

Pure data structure for tracking status of byte ranges without any file format dependencies.

STATUS_OK

Successfully read

STATUS_ERROR

Read error

STATUS_UNTRIED

Not tried yet

STATUS_TRIMMED

Trimmed (not tried because of read error)

STATUS_SLOW

Non-trimmed, non-scraped (slow reads)

STATUS_SCRAPED

Non-trimmed, scraped (slow reads completed)

CACHED

Have data

UNCACHED

Need data

ERROR

Can’t get data

STATUSES

All valid statuses

FileMap Objects

class FileMap()

Tracks status of byte ranges using efficient transition-based representation.

Pure data structure with no file format dependencies. Uses slice notation: filemap[start:end] = status

__init__

def __init__(size: int)

Initialize with device/file size.

__setitem__

def __setitem__(key, status)

Set status for range using slice notation: filemap[start:end] = status

__getitem__

def __getitem__(key)

Get status for range using slice notation: filemap[start:end] returns transitions

pos

@property
def pos() -> int

Current position - first untried byte.

status

@property
def status() -> str

Current status - highest priority status found in transitions.

blkcache.backend

nbdkit Python backend integration for block-level device caching.

This module serves as the bridge between nbdkit and our file abstraction layer. It handles the “outside” config (nbdkit parameters) while delegating file operations to the composed file chain.

lookup

def lookup(attr: str, handle: int, table=TABLE)

Generic attribute lookup for dispatch.

open_file_context

def open_file_context(path: Path, mode: str)

Generator to manage file lifecycle.

config

def config(key: str, val: str) -> None

Stores device, cache paths and parses metadata key-value pairs.

config_complete

def config_complete() -> None

Validates required parameters.

open

def open(_readonly: bool) -> int

Opens device and returns handle ID.

get_size

def get_size(h: int) -> int

Get file size.

pread

def pread(h: int, count: int, offset: int) -> bytes

Read data at offset.

close

def close(h: int) -> None

Close file handle.

blkcache.ddrescue

ddrescue file format loading and saving.

Functions to read/write ddrescue-compatible mapfiles with comments, config, and FileMap data.

iter_filemap_ranges

def iter_filemap_ranges(filemap: FileMap)

Iterate over FileMap transitions yielding (pos, size, status) tuples.

load

def load(file, comments: List[str], filemap: FileMap,
         config: Dict[str, str]) -> None

Load ddrescue mapfile from file-like object, updating provided containers.

save

def save(file, comments: List[str], filemap: FileMap,
         config: Dict[str, str]) -> None

Save ddrescue mapfile to file-like object from provided containers.

parse_status

def parse_status(line: str) -> tuple[int, int, str]

Parse a status line returning (start, size, status).

blkcache.main

blkcache – CLI entry-point.