Skip to content

implement encfsr for a reverse filesystem#693

Merged
vgough merged 19 commits intomasterfrom
vgough/reverse
Mar 2, 2026
Merged

implement encfsr for a reverse filesystem#693
vgough merged 19 commits intomasterfrom
vgough/reverse

Conversation

@vgough
Copy link
Owner

@vgough vgough commented Feb 28, 2026

encfsr is a reverse filesystem which creates a virtual encrypted filesystem. That filesystem can be backed up and later mounted using encfs.

The reverse filesystem is read-only and will generate a warning if unique_iv is enabled in config since that would result in files being uniquely encoded on every open! A flag is provided with encfsctl to create a filesystem config without unique_iv enabled, which is suitable for use with encfsr.

More testing is needed, but a quick backup of a virtual encfsr directory and subsequent mount in encfs works.

vgough and others added 19 commits February 24, 2026 22:22
Four research dimensions synthesized: stack (no new deps needed, fuse_mt
reused), features (9 table-stakes items, 5 differentiators, 7 anti-features),
architecture (FileReverseReader + ReverseFilesystemMT additive design),
pitfalls (18 specific traps with code references and prevention strategies).
SUMMARY.md derives a 4-phase roadmap with confidence HIGH overall.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…tion

- Add [[bin]] stanza for encfsr in Cargo.toml pointing to src/encfsr.rs
- Implement src/encfsr.rs: clap derive CLI, source dir validation, config
  loading, password acquisition (stdin/extpass/interactive), get_cipher call,
  unique_iv check (CONF-01), and stub mount placeholder (Phase 2 boundary)
- Add help.encfsr.* locale strings to locales/help.yml
- Add encfsr.* runtime message strings to locales/main.yml
- Exit 1 with actionable error messages for missing dir, missing config,
  wrong password, and unsupported unique_iv=true
- Accept arbitrary FUSE options via trailing_var_arg without clap parse errors
- Create tests/encfsr_test.rs with 7 subprocess-based integration tests
- test_encfsr_help: --help exits 0
- test_encfsr_version: --version exits 0 with version string in stdout
- test_encfsr_missing_source_dir: nonexistent source exits 1 with error: and path
- test_encfsr_no_config_file: dir with no config exits 1 with error: and source path
- test_encfsr_rejects_unique_iv_true: CONF-01 catches uniqueIV=1 after get_cipher()
- test_encfsr_allows_chained_name_iv: CONF-02 validated (uniqueIV=0 does not trigger CONF-01)
- test_encfsr_fuse_opts_accepted: -o allow_other not rejected as unknown clap arg
- Use encfs6-std.xml fixture (password="test") for CONF-01 test
- Use inline XML fixture from unique_iv_check.rs pattern for CONF-02 test
- src/reverse_fs.rs: ReverseFs struct with resolve_source_path (COMPAT-01),
  ciphertext_size_for_plaintext (FUSE-03), readdir with encrypt_filename (FUSE-02),
  and EROFS for all mutating methods (FUSE-01); read stub returns zeros
- src/lib.rs: pub mod reverse_fs added to expose ReverseFs from the library
- Replace Phase 1 placeholder (mount_not_implemented log) with fuse_mt::mount
- Add std::ffi::{OsStr, OsString} import for FUSE option construction
- Always pass -o ro and -o default_permissions; user fuse_opts appended after
- Add test_encfsr_proceeds_to_mount_attempt: verifies Phase 1 placeholder
  is gone and encfsr now attempts mount with valid uniqueIV=0 configs
- Add write_valid_encfsr_config helper: creates properly-encrypted V6 config
  with uniqueIV=0 for subprocess and live mount tests
- Fix Rule 1 bug: validate() rejected uniqueIV=0 during load() and get_cipher(),
  preventing encfsr from processing its required config format
- Add load_for_encfsr() and get_cipher_for_encfsr() with validate_for_encfsr()
  that skip the uniqueIV=0 rejection (encfsr validates this itself via CONF-01)
- Update encfsr.rs to use load_for_encfsr() and get_cipher_for_encfsr()
…ests

Implements four live tests covering all Phase 2 requirements, gated by
ENCFS_LIVE_TESTS=1. Tests use a programmatically-generated uniqueIV=0 V6
config with a deterministic key and known password.

- test_encfsr_live_readdir_shows_encrypted_names: FUSE-02, COMPAT-01
  readdir entries are encrypted names that round-trip through decrypt_filename
- test_encfsr_live_stat_reports_ciphertext_size: FUSE-03
  stat size matches BlockLayout::physical_size_from_logical formula
- test_encfsr_live_write_returns_erofs: FUSE-01
  write attempts fail with EROFS or ReadOnlyFilesystem
- test_encfsr_live_path_resolution_correct: COMPAT-01
  encrypted path opens successfully (path translation direction correct)

EncfsrMountGuard spawns the encfsr binary with --foreground --stdinpass,
polls /proc/self/mountinfo, and cleans up via fusermount3 on Drop.
All four tests are #[ignore] no-ops without ENCFS_LIVE_TESTS=1.
Plan 03-01: FileReverseReader block encryption, virtual .encfs7 injection,
readlink symlink encryption — wires all crypto into reverse_fs.rs + encfsr.rs.

Plan 03-02: Round-trip integration tests covering block boundaries, external IV
chaining, V7 AES-GCM-SIV, symlinks, virtual config file, and multi-GB streaming.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@vgough vgough merged commit cbff883 into master Mar 2, 2026
2 checks passed
@vgough vgough deleted the vgough/reverse branch March 2, 2026 01:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant