Skip to content

build and test on FreeBSD - #705

Merged
vgough merged 4 commits into
vgough:masterfrom
neilpang:freebsd-ci
Aug 13, 2026
Merged

build and test on FreeBSD#705
vgough merged 4 commits into
vgough:masterfrom
neilpang:freebsd-ci

Conversation

@neilpang

Copy link
Copy Markdown
Contributor

The Cirrus FreeBSD task last ran on 2026-04-01. Before that it had
failed on every commit since the Rust port landed -- 28 runs, none green
-- and allow_failures: true reported each one as neutral, so nothing
surfaced. .cirrus.yml was last edited on 2026-07-25, after it had
already stopped running.

This adds .github/workflows/freebsd.yml, shaped like ci.yml: the same
clippy, build, test and live-mount sequence. The VM boots under QEMU on
an ordinary ubuntu-latest runner, so there is no service, no dedicated
runner and no compute credits.

Package names come from the pkg database on the box rather than from
memory: fusefs-libs3 supplies fuse3.pc 3.18.1, protobuf supplies protoc,
llvm supplies the libclang bindgen needs, and fusefs.ko is already in
GENERIC so nothing has to kldload it. .cirrus.yml installs fusefs-libs,
which is FUSE 2 and carries no fuse3.pc, so that task could not have
built even while it was still running.

build.rs

protoc-bin-vendored ships binaries for Linux, macOS and Windows only, so
protoc_bin_path() returns Err on FreeBSD and .expect() panics. Leaving
PROTOC unset there lets prost-build find protoc on PATH instead.

src/reverse_fs.rs

Four uses of libc::ENODATA, which FreeBSD does not define. Every one
means "extended attribute not found", so they become Errno::ENOATTR,
which typed-fuse already gates: on Linux that IS libc::ENODATA, so the
change is bit-identical there.

the xattr name encoding -- the one worth reading

Stored attribute names are base64 of the encrypted name, and the
standard alphabet contains '/', which FreeBSD will not accept in an
attribute name. Four names differing in a single character:

setextattr user "encfs.abcdef"  v f    rc=0
setextattr user "encfs.abc+def" v f    rc=0
setextattr user "encfs.abc=def" v f    rc=0
setextattr user "encfs.abc/def" v f    rc=1  Invalid argument

Of the six distinct names this repo's own xattr tests generate, exactly
the two containing '/' are the two whose setxattr returned EINVAL:

user.encfs.LxjRlnYLUZf/KnISEoYMnw    user.empty
user.encfs.1C/+DS/JPpFmEBmUPPJXgw    user.simple

Ten of the names contained '+' and all stored fine. So on FreeBSD
roughly a third of extended attributes cannot be stored at all.

New names use the URL-safe alphabet, which spells the two disputed
characters '-' and '_'. Reads accept either, and getxattr and
removexattr fall back to the old spelling, so attributes written by
earlier builds stay reachable. The alphabets differ only in those four
characters, so a string that decodes under both contains none of them
and yields the same bytes either way: trying one and then the other
cannot return the wrong plaintext.

Two things this does not touch. Filenames go through
SslCipher::filename_base64_encode, which uses encfs's own alphabet, not
this one. And there is no compatibility to keep with the C++ encfs: it
passed attribute names to the backing file unchanged, so the encrypted
and encoded scheme has only ever existed in this port.

tests

tests/live/mod.rs defined mountinfo_has_mount for Linux and macOS only.
FreeBSD has no /proc either and its mount(8) prints the same
" on (, ...)" shape, so it joins the macOS
arm.

tests/xattr_test.rs read the backing names with llistxattr; FreeBSD gets
an extattr_list_link arm. There the namespace is not part of the name,
so what is stored is "encfs.", and the assertion says so instead of
being made to look uniform.

tests/permissions_test.rs asserted symlink mode 0o777, already excluding
macOS. Linux fixes those bits and ignores them; the BSDs give symlinks
real mode bits -- FreeBSD ships lchmod(2), "similar to chmod() but does
not follow symbolic links" -- and report 0o755, so FreeBSD joins the
exclusion.

Verified

Linux, this branch as it stands, under ci.yml: 215 tests across every
binary, 0 failed, including 29 live mount tests. No companion change
needed for this half.
https://github.com/neilpang/encfs/actions/runs/31366219652

FreeBSD 15.1: build, clippy -D warnings, 5/5 xattr, 4/4 permissions,
29/29 live mount. That run used these source files byte for byte plus a
temporary Cargo.toml patch pointing typed-fuse at the companion branch;
the patch is not in this PR.
https://github.com/neilpang/encfs/actions/runs/31364870397

Sequencing

The FreeBSD job goes green once vgough/typed-fuse#3 is in. Without it
the job stops here:

Compiling typed-fuse v0.6.0 (https://github.com/vgough/typed-fuse#dd70e273)
error[E0425]: cannot find value ENODATA in crate libc

https://github.com/neilpang/encfs/actions/runs/31366219628

typed-fuse does not build on FreeBSD today: no l*xattr syscalls, an
ungated ENODATA, a missing struct flock field, and a fuse_session_new
that libfuse 3.17 turned into a macro. Cargo.toml tracks its default
branch with no rev pin, so this picks the fix up on its own.

Two loose ends, yours to call: .cirrus.yml is dead weight now, and
ci.yml pins actions/checkout@v4 while v7 is current.

Written with the help of Claude; I read and tested all of it.

neilpang and others added 2 commits August 10, 2026 15:21
Adds a FreeBSD job on GitHub Actions, plus the changes needed to
make it pass. The Cirrus FreeBSD task last ran on 2026-04-01 and
reported neutral rather than red before that, so none of this was
visible.
The FreeBSD job on this branch failed to compile typed-fuse-core:

    error[E0425]: cannot find value `ENODATA` in crate `libc`
      --> typed-fuse-core/src/errno.rs:21:44
       |
    21 |     pub const ENODATA: Errno = Errno(libc::ENODATA);
       |                                            ^^^^^^^ not found in `libc`

vgough/typed-fuse#3 fixed that, along with the rest of what this
branch needs from typed-fuse on FreeBSD, and was merged two minutes
after that build ran.  Cargo.lock still pinned the git dependency at
dd70e27, from before the merge, so re-running the job would keep
building the old tree.

This moves the three git+ source lines to d4ec8f3, the current
typed-fuse main.  Nothing else changes: every Cargo.toml in
typed-fuse is byte-identical between dd70e27 and d4ec8f3, so the
dependency graph is the same and only the pinned revision moves.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds first-class FreeBSD CI to the Rust EncFS port and fixes a handful of FreeBSD-specific portability gaps (xattr errno, xattr name encoding, test platform gating, and protobuf toolchain discovery) so the project can build and run its full test suite under FreeBSD in GitHub Actions.

Changes:

  • Add a GitHub Actions workflow that boots a FreeBSD VM under QEMU and runs clippy/build/test + live mount tests.
  • Make xattr handling portable across Linux/FreeBSD by switching stored xattr-name base64 encoding to URL-safe (with legacy-read fallback) and using ENOATTR instead of ENODATA.
  • Adjust tests to work on FreeBSD (mount detection, xattr backing-name listing, and symlink-permission expectations) and update build.rs to avoid vendored-protoc assumptions on non-supported OSes.

Reviewed changes

Copilot reviewed 9 out of 10 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
.github/workflows/freebsd.yml New FreeBSD CI workflow running clippy/build/test/live-mount in a VM.
build.rs Stop panicking when vendored protoc is unavailable; fall back to PATH.
src/fs.rs Use new xattr-name codec + legacy fallback when reading/removing old names.
src/reverse_fs.rs Use shared xattr-name codec and ENOATTR for missing-xattr semantics.
src/xattr_name.rs New helper module for URL-safe xattr name encoding/decoding + unit tests.
src/lib.rs Export the new xattr_name module.
tests/xattr_test.rs FreeBSD-aware backing xattr listing + improved failure diagnostics.
tests/permissions_test.rs Exclude FreeBSD from symlink-mode assertions that don’t hold on BSDs.
tests/live/mod.rs Use mount(8) parsing on FreeBSD (no /proc) like macOS.
Cargo.lock Update typed-fuse git revision to a FreeBSD-fixing commit.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread tests/xattr_test.rs Outdated
Comment thread src/xattr_name.rs Outdated
Comment thread .github/workflows/freebsd.yml

@vgough vgough left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks!

@vgough
vgough merged commit 18ff8f4 into vgough:master Aug 13, 2026
2 checks passed
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.

3 participants