Skip to content

three parallel archive-as-filesystem implementations: unify fuse.py, hlfuse.py and the webdav VFS #10020

Description

@ThomasWaldmann

From a global code review of the borg2 codebase (2026-08).

Problem

borg now materializes an archive as a browsable tree in three independent places:

  • src/borg/fuse.py (~800 lines): low-level FUSE (llfuse / pyfuse3), with its own FuseBackend
  • src/borg/hlfuse.py (~740 lines): high-level FUSE (mfusepy), with a second FuseBackend
  • src/borg/webdav.py (~1060 lines): ArchiveVFS + WebDAV/HTTP server

All three re-implement the same core logic: walking archive items, building the directory tree, hardlink handling, the archives/versions views, uid/gid/mode/time mapping, chunk-stream file reads. Behavior fixes must be applied N times — e.g. the ACL/xattr exposure fix (#9954) had to touch the FUSE implementations separately, and subtle divergence between the mount variants is hard to notice in review.

Proposed direction

  • Extract one shared archive-VFS core (the new webdav.py ArchiveVFS is the cleanest starting point): tree construction, lookup, attribute mapping, and a chunk-stream file-read object.
  • Make fuse.py, hlfuse.py, and webdav thin protocol adapters over it.
  • Then consider whether llfuse (fuse2 low-level) can be dropped once mfusepy (fuse2+3) is proven — that would remove one implementation and one CI leg (the matrix currently builds/tests three FUSE variants).

Likely saves ~1k lines and, more importantly, leaves exactly one place where "what does an archive look like as a filesystem" is defined.

🤖 Generated with Claude Code

Metadata

Metadata

Labels

No labels
No labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions