Skip to content

FreeBSD support#998

Open
ankushjp wants to merge 9 commits intorfjakob:masterfrom
ankushjp:freebsd-support
Open

FreeBSD support#998
ankushjp wants to merge 9 commits intorfjakob:masterfrom
ankushjp:freebsd-support

Conversation

@ankushjp
Copy link

This PR adds support for the FreeBSD operating system, as mentioned in this discussion.

The FreeBSD build has been added to the crossbuild.bash script.

Note that on FreeBSD, bash is not installed at /bin/bash (it is installed at /usr/local/bin/bash) - its may be a good idea to modify the other bash scripts (e.g. tests/*.bash) to invoke bash via the more portable #!/usr/bin/env bash shebang.

@ankushjp ankushjp changed the title Freebsd support FreeBSD support Feb 17, 2026
@schlomie
Copy link

So some interesting findings using rsync.

Just as a test, I am rsyncing the gocryptfs repo into a gocryptfs mount. Every file write has these errors:

rsync: [receiver] failed to set permissions on "/home/user/pub/tests/root_test/btrfs_test.go": No such file or directory (2)
rsync: [receiver] failed to set permissions on "/home/user/pub/tests/root_test/issue893_test.go": No such file or directory (2)
rsync: [receiver] failed to set permissions on "/home/user/pub/tests/root_test/main_test.go": No such file or directory (2)
rsync: [receiver] failed to set permissions on "/home/user/pub/tests/root_test/root_test.go": No such file or directory (2)
rsync: [receiver] failed to set permissions on "/home/user/pub/tests/sharedstorage/sharedstorage_test.go": No such file or directory (2)
rsync: [receiver] failed to set permissions on "/home/user/pub/tests/stress_tests/extractloop.bash": No such file or directory (2)
rsync: [receiver] failed to set permissions on "/home/user/pub/tests/stress_tests/extractloop_plot_csv.m": No such file or directory (2)
rsync: [receiver] failed to set permissions on "/home/user/pub/tests/stress_tests/fsstress-gocryptfs.bash": No such file or directory (2)
rsync: [receiver] failed to set permissions on "/home/user/pub/tests/stress_tests/fsstress.collect-crashes.sh": No such file or directory (2)
rsync: [receiver] failed to set permissions on "/home/user/pub/tests/stress_tests/linux-3.0.md5sums": No such file or directory (2)
rsync: [receiver] failed to set permissions on "/home/user/pub/tests/stress_tests/parallel_cp.sh": No such file or directory (2)
rsync: [receiver] failed to set permissions on "/home/user/pub/tests/stress_tests/pingpong.bash": No such file or directory (2)
rsync: [receiver] failed to set permissions on "/home/user/pub/tests/symlink_race/.gitignore": No such file or directory (2)
rsync: [receiver] failed to set permissions on "/home/user/pub/tests/symlink_race/main.go": No such file or directory (2)
rsync: [receiver] failed to set permissions on "/home/user/pub/tests/test_helpers/helpers.go": No such file or directory (2)
rsync: [receiver] failed to set permissions on "/home/user/pub/tests/test_helpers/mount_unmount.go": No such file or directory (2)
rsync: [receiver] failed to set permissions on "/home/user/pub/tests/xattr/xattr_fd_test.go": No such file or directory (2)
rsync: [receiver] failed to set permissions on "/home/user/pub/tests/xattr/xattr_integration_test.go": No such file or directory (2)
rsync error: some files/attrs were not transferred (see previous errors) (code 23) at main.c(1359) [sender=3.4.1]

But all of the files are indeed written...

$ find gocryptfs -type f -exec rhash --md5 {} \; | awk '{ print $1 }' | sort | rhash --md5 -
7d09bc1c0c447d499b83091068631390  (stdin)
$ find pub -type f -exec rhash --md5 {} \; | awk '{ print $1 }' | sort | rhash --md5 -
7d09bc1c0c447d499b83091068631390  (stdin)

The perms are indeed not set correctly after writing.

...
-rw-------   1 user user  2.2K Feb 24 15:08 profiling.go
-rw-------   1 user user  139B Feb 24 15:08 race.go
-rw-------   1 user user  463B Feb 24 15:08 sendusr1.go
-rw-------   1 user user   83B Feb 24 15:14 test-without-openssl.bash
-rw-------   1 user user  3.9K Feb 24 15:14 test.bash
drwx------  18 user user   25B Feb 24 15:14 tests/
-rw-------   1 user user  2.1K Feb 24 15:08 version.go

umask is 0022, so I would expect it to match

...
-rw-r--r--   1 user user  2.2K Feb 24 15:08 profiling.go
-rw-r--r--   1 user user  139B Feb 24 15:08 race.go
-rw-r--r--   1 user user  463B Feb 24 15:08 sendusr1.go
-rwxr-xr-x   1 user user   83B Feb 24 15:14 test-without-openssl.bash
-rwxr-xr-x   1 user user  3.9K Feb 24 15:14 test.bash*
drwxr-xr-x  18 user user   24B Feb 24 15:14 tests/
-rw-r--r--   1 user user  2.1K Feb 24 15:08 version.go

As a thought experiment, I wanted to try mounting the fs with -allow_other. In FreeBSD, normal users cannot mount fuse with the allow other flag - you need elevated privileges.

So repeating above, now mounted with the allow other flag as root, I no longer get the No such file errors, but now get failed to set times errors on all files

rsync: [receiver] failed to set times on "/home/user/pub/package-release-tarballs.bash": Operation not permitted (1)
rsync: [receiver] failed to set times on "/home/user/pub/profiling.go": Operation not permitted (1)
rsync: [receiver] failed to set times on "/home/user/pub/race.go": Operation not permitted (1)
rsync: [receiver] failed to set times on "/home/user/pub/sendusr1.go": Operation not permitted (1)
rsync: [receiver] failed to set times on "/home/user/pub/test-without-openssl.bash": Operation not permitted (1)
rsync: [receiver] failed to set times on "/home/user/pub/test.bash": Operation not permitted (1)
rsync: [receiver] failed to set times on "/home/user/pub/version.go": Operation not permitted (1)

The permissions that get set are also interesting

-rw-------  1 root user  2.2K Feb 26 10:11 profiling.go
-rw-------  1 root user  139B Feb 26 10:11 race.go
-rw-------  1 root user  463B Feb 26 10:11 sendusr1.go
-rw-------  1 root user   83B Feb 26 10:11 test-without-openssl.bash
-rw-------  1 root user  3.9K Feb 26 10:11 test.bash
drwx------  2 root user    3B Feb 26 10:11 tests/
-rw-------  1 root user  2.1K Feb 26 10:11 version.go

I suppose this makes sense - since the fuse daemon is running as root - but it's interesting the group was set correctly. Also note, no files in any sub directory under pub/ was copied over - which also makes sense, since now as the normal user I only have perms to the top of pub/ during writes.

Anyway... I don't know if these findings are related to the missing implementation in the API stubs or limitations in the FreeBSD fuse driver. Likely the former... but I'll do some more digging.

Thanks again!

FreeBSD supports the Fchmodat system call, with the AT_SYMLINK_NOFOLLOW
flag. FchmodatNofollow has been modified to use this system call and
flag.
@ankushjp
Copy link
Author

ankushjp commented Mar 1, 2026

@schlomie Great test with rsync! I think the issue you have observed with rsync was due to the implementation of the FchmodatNofollow function in internal/syscallcompat/sys_freebsd.go‎. The open file descriptors for the current process is not exposed via procfs (/proc/self/fd/) on FreeBSD - I think FreeBSD exposes the currently open files via /dev/fd/ (man 4 fdescfs).

However, FreeBSD also supports the fchmodat system call, with the AT_SYMLINK_NOFOLLOW flag (man 2 chmod) - I've updated the FchmodatNofollow function to make use of this system call and flag on FreeBSD.

As a side note, it looks like Linux added support for the fchmodat syscall with the AT_SYMLINK_NOFOLLOW flag in the Linux 6.5 kernel release (man 2 chmod).

As a test, I created the following directory with test files and a test directory, to be copied over to the gocryptfs mount point:

$ tree copytest
copytest
├── a.txt
├── b.txt
└── c.dir
    └── d.txt

2 directories, 3 files

Then I issued the command to mount the (empty) gocryptfs directory to the mount point plain:

$ gocryptfs cipher plain

I then used rsync to copy the files from copytest into plain, and it succeeded with no errors:

$ rsync -a copytest/ plain
$ tree plain
plain
├── a.txt
├── b.txt
└── c.dir
    └── d.txt

2 directories, 3 files

I'd been keen to see the results of your previous test with the new commit.

Thanks!

@rfjakob
Copy link
Owner

rfjakob commented Mar 1, 2026

@ankushjp I see you also merged in my commits from https://github.com/rfjakob/gocryptfs/commits/freebsd-support/ . Very good.

Can you post the freebsd results of

./test-without-openssl.bash

with your latest commit?

@ankushjp
Copy link
Author

ankushjp commented Mar 1, 2026

Output from ./test-without-openssl.bash:

$ ./test-without-openssl.bash
flock is not available, skipping
fatal: No names found, cannot describe anything.
gocryptfs [no_tags_found].freebsd-support without_openssl; go-fuse v2.9.0; 2026-03-02 go1.25.7 freebsd/amd64
staticcheck not installed - skipping
shellcheck not installed - skipping
Testing on TMPDIR=/var/tmp, filesystem: ./test.bash: line 83: findmnt: command not found
?
ok    github.com/rfjakob/gocryptfs/v2  0.006s
?     github.com/rfjakob/gocryptfs/v2/contrib/atomicrename  [no test files]
?     github.com/rfjakob/gocryptfs/v2/contrib/findholes  [no test files]
?     github.com/rfjakob/gocryptfs/v2/contrib/findholes/holes  [no test files]
?     github.com/rfjakob/gocryptfs/v2/contrib/getdents-debug/readdirnames  [no test files]
?     github.com/rfjakob/gocryptfs/v2/contrib/statfs  [no test files]
?     github.com/rfjakob/gocryptfs/v2/contrib/statvsfstat  [no test files]
?     github.com/rfjakob/gocryptfs/v2/ctlsock  [no test files]
?     github.com/rfjakob/gocryptfs/v2/gocryptfs-xray  [no test files]
ok    github.com/rfjakob/gocryptfs/v2/gocryptfs-xray/xray_tests  0.228s
ok    github.com/rfjakob/gocryptfs/v2/internal/configfile  0.616s
ok    github.com/rfjakob/gocryptfs/v2/internal/contentenc  0.010s
ok    github.com/rfjakob/gocryptfs/v2/internal/cryptocore  0.340s
ok    github.com/rfjakob/gocryptfs/v2/internal/ctlsocksrv  0.005s
?     github.com/rfjakob/gocryptfs/v2/internal/ensurefds012  [no test files]
?     github.com/rfjakob/gocryptfs/v2/internal/exitcodes  [no test files]
?     github.com/rfjakob/gocryptfs/v2/internal/fido2  [no test files]
ok    github.com/rfjakob/gocryptfs/v2/internal/fusefrontend  0.062s
ok    github.com/rfjakob/gocryptfs/v2/internal/fusefrontend_reverse  0.006s
ok    github.com/rfjakob/gocryptfs/v2/internal/inomap  0.017s
ok    github.com/rfjakob/gocryptfs/v2/internal/nametransform  0.008s
?     github.com/rfjakob/gocryptfs/v2/internal/openfiletable  [no test files]
ok    github.com/rfjakob/gocryptfs/v2/internal/pathiv  0.005s
ok    github.com/rfjakob/gocryptfs/v2/internal/readpassword  0.025s
ok    github.com/rfjakob/gocryptfs/v2/internal/siv_aead  0.006s
ok    github.com/rfjakob/gocryptfs/v2/internal/speed  0.006s [no tests to run]
?     github.com/rfjakob/gocryptfs/v2/internal/stupidgcm  [no test files]
syscallcompat.Openat() int 7 error <nil>
syscallcompat.Openat() int 6 error <nil>
syscallcompat.Openat() int 7 error <nil>
syscallcompat.Openat() int 6 error <nil>
syscallcompat.Openat() int -1 error not a directory
--- FAIL: TestRenameExchange (0.00s)
    rename_exchange_test.go:43: Failed to read file1 after exchange: open /var/tmp/renameat2_test1166636971/file1.txt: no such file or directory
syscallcompat.Openat() int -1 error no such file or directory
syscallcompat.Openat() int 6 error <nil>
syscallcompat.Openat() int 8 error <nil>
--- FAIL: TestSymlinkat (0.00s)
    sys_common_test.go:229: Wrong mode, have 0120755, want 0120777
syscallcompat.Fstatat(dirfd = 4, path = fstatat, flags = 512) error <nil>
syscallcompat.Fstatat(dirfd = 4, path = fstatatSymlink, flags = 512) error <nil>
FAIL
FAIL  github.com/rfjakob/gocryptfs/v2/internal/syscallcompat  0.013s
ok    github.com/rfjakob/gocryptfs/v2/internal/tlog  0.006s
test_helpers: warning: testParentDir "/var/tmp/gocryptfs-test-parent-1001" does not reside on ext4, we will miss failures caused by ino reuse
warning: haveFusermount2: fork/exec /bin/fusermount: no such file or directory
--- FAIL: TestBadname (0.18s)
    cli_test.go:813: open /var/tmp/gocryptfs-test-parent-1001/1516419524/TestBadname.2267552034.mnt/file: no such file or directory
Invalid cipherdir: directory /var/tmp/gocryptfs-test-parent-1001/1516419524/TestInitNotEmpty not empty
--- FAIL: TestSharedstorage (0.23s)
    cli_test.go:1007: link /var/tmp/gocryptfs-test-parent-1001/1516419524/TestSharedstorage.4187873053.mnt/foo1 /var/tmp/gocryptfs-test-parent-1001/1516419524/TestSharedstorage.4187873053.mnt/foo2: input/output error
--- FAIL: TestOrphanedSocket (0.29s)
    cli_test.go:1089: invalid argument
mount_fusefs: /dev/fuse on /var/tmp/gocryptfs-test-parent-1001/1516419524/TestDirectMount.2732603006.mnt: Operation not permitted (extended error FUSE daemon requires privileges due to 'allow_other' option)
fs.Mount failed: mount_fusefs: exited with status 71
--- FAIL: TestDirectMount (0.34s)
    directmount_test.go:70: wrong FSType: "fusefs.gocryptf"
    directmount_test.go:47: checkOptionPresent: max_read=: want=true have=false. Full string:
    directmount_test.go:52: mount failed: exit status 19
--- FAIL: TestLongnamemax100Reverse (0.23s)
    longnamemax_test.go:103: l=64: should see a longname now
    longnamemax_test.go:103: l=65: should see a longname now
    longnamemax_test.go:103: l=66: should see a longname now
    longnamemax_test.go:103: l=67: should see a longname now
    longnamemax_test.go:103: l=68: should see a longname now
    longnamemax_test.go:103: l=69: should see a longname now
    longnamemax_test.go:103: l=70: should see a longname now
    longnamemax_test.go:103: l=71: should see a longname now
    longnamemax_test.go:103: l=72: should see a longname now
    longnamemax_test.go:103: l=73: should see a longname now
    longnamemax_test.go:103: l=74: should see a longname now
    longnamemax_test.go:103: l=75: should see a longname now
    longnamemax_test.go:103: l=76: should see a longname now
    longnamemax_test.go:103: l=77: should see a longname now
    longnamemax_test.go:103: l=78: should see a longname now
    longnamemax_test.go:103: l=79: should see a longname now
    longnamemax_test.go:103: l=80: should see a longname now
    longnamemax_test.go:103: l=81: should see a longname now
    longnamemax_test.go:103: l=82: should see a longname now
    longnamemax_test.go:103: l=83: should see a longname now
    longnamemax_test.go:103: l=84: should see a longname now
    longnamemax_test.go:103: l=85: should see a longname now
    longnamemax_test.go:103: l=86: should see a longname now
    longnamemax_test.go:103: l=87: should see a longname now
    longnamemax_test.go:103: l=88: should see a longname now
    longnamemax_test.go:103: l=89: should see a longname now
    longnamemax_test.go:103: l=90: should see a longname now
    longnamemax_test.go:103: l=91: should see a longname now
    longnamemax_test.go:103: l=92: should see a longname now
    longnamemax_test.go:103: l=93: should see a longname now
    longnamemax_test.go:103: l=94: should see a longname now
    longnamemax_test.go:103: l=95: should see a longname now
    longnamemax_test.go:103: l=96: should see a longname now
    longnamemax_test.go:103: l=97: should see a longname now
    longnamemax_test.go:103: l=98: should see a longname now
    longnamemax_test.go:103: l=99: should see a longname now
    longnamemax_test.go:103: l=100: should see a longname now
    longnamemax_test.go:103: l=101: should see a longname now
    longnamemax_test.go:103: l=102: should see a longname now
    longnamemax_test.go:103: l=103: should see a longname now
    longnamemax_test.go:103: l=104: should see a longname now
    longnamemax_test.go:103: l=105: should see a longname now
    longnamemax_test.go:103: l=106: should see a longname now
    longnamemax_test.go:103: l=107: should see a longname now
    longnamemax_test.go:103: l=108: should see a longname now
    longnamemax_test.go:103: l=109: should see a longname now
    longnamemax_test.go:103: l=110: should see a longname now
    longnamemax_test.go:103: l=111: should see a longname now
    longnamemax_test.go:103: l=112: should see a longname now
    longnamemax_test.go:103: l=113: should see a longname now
    longnamemax_test.go:103: l=114: should see a longname now
    longnamemax_test.go:103: l=115: should see a longname now
    longnamemax_test.go:103: l=116: should see a longname now
    longnamemax_test.go:103: l=117: should see a longname now
    longnamemax_test.go:103: l=118: should see a longname now
    longnamemax_test.go:103: l=119: should see a longname now
    longnamemax_test.go:103: l=120: should see a longname now
    longnamemax_test.go:103: l=121: should see a longname now
    longnamemax_test.go:103: l=122: should see a longname now
    longnamemax_test.go:103: l=123: should see a longname now
    longnamemax_test.go:103: l=124: should see a longname now
    longnamemax_test.go:103: l=125: should see a longname now
    longnamemax_test.go:103: l=126: should see a longname now
    longnamemax_test.go:103: l=127: should see a longname now
    longnamemax_test.go:103: l=128: should see a longname now
    longnamemax_test.go:103: l=129: should see a longname now
    longnamemax_test.go:103: l=130: should see a longname now
    longnamemax_test.go:103: l=131: should see a longname now
    longnamemax_test.go:103: l=132: should see a longname now
    longnamemax_test.go:103: l=133: should see a longname now
    longnamemax_test.go:103: l=134: should see a longname now
    longnamemax_test.go:103: l=135: should see a longname now
    longnamemax_test.go:103: l=136: should see a longname now
    longnamemax_test.go:103: l=137: should see a longname now
    longnamemax_test.go:103: l=138: should see a longname now
    longnamemax_test.go:103: l=139: should see a longname now
    longnamemax_test.go:103: l=140: should see a longname now
    longnamemax_test.go:103: l=141: should see a longname now
    longnamemax_test.go:103: l=142: should see a longname now
    longnamemax_test.go:103: l=143: should see a longname now
    longnamemax_test.go:103: l=144: should see a longname now
    longnamemax_test.go:103: l=145: should see a longname now
    longnamemax_test.go:103: l=146: should see a longname now
    longnamemax_test.go:103: l=147: should see a longname now
    longnamemax_test.go:103: l=148: should see a longname now
    longnamemax_test.go:103: l=149: should see a longname now
    longnamemax_test.go:103: l=150: should see a longname now
    longnamemax_test.go:103: l=151: should see a longname now
    longnamemax_test.go:103: l=152: should see a longname now
    longnamemax_test.go:103: l=153: should see a longname now
    longnamemax_test.go:103: l=154: should see a longname now
    longnamemax_test.go:103: l=155: should see a longname now
    longnamemax_test.go:103: l=156: should see a longname now
    longnamemax_test.go:103: l=157: should see a longname now
    longnamemax_test.go:103: l=158: should see a longname now
    longnamemax_test.go:103: l=159: should see a longname now
    longnamemax_test.go:103: l=160: should see a longname now
    longnamemax_test.go:103: l=161: should see a longname now
    longnamemax_test.go:103: l=162: should see a longname now
    longnamemax_test.go:103: l=163: should see a longname now
    longnamemax_test.go:103: l=164: should see a longname now
    longnamemax_test.go:103: l=165: should see a longname now
    longnamemax_test.go:103: l=166: should see a longname now
    longnamemax_test.go:103: l=167: should see a longname now
    longnamemax_test.go:103: l=168: should see a longname now
    longnamemax_test.go:103: l=169: should see a longname now
    longnamemax_test.go:103: l=170: should see a longname now
    longnamemax_test.go:103: l=171: should see a longname now
    longnamemax_test.go:103: l=172: should see a longname now
    longnamemax_test.go:103: l=173: should see a longname now
    longnamemax_test.go:103: l=174: should see a longname now
    longnamemax_test.go:103: l=175: should see a longname now
    longnamemax_test.go:103: l=176: should see a longname now
    longnamemax_test.go:103: l=177: should see a longname now
    longnamemax_test.go:103: l=178: should see a longname now
    longnamemax_test.go:103: l=179: should see a longname now
    longnamemax_test.go:103: l=180: should see a longname now
    longnamemax_test.go:103: l=181: should see a longname now
    longnamemax_test.go:103: l=182: should see a longname now
    longnamemax_test.go:103: l=183: should see a longname now
    longnamemax_test.go:103: l=184: should see a longname now
    longnamemax_test.go:103: l=185: should see a longname now
    longnamemax_test.go:103: l=186: should see a longname now
    longnamemax_test.go:103: l=187: should see a longname now
    longnamemax_test.go:103: l=188: should see a longname now
    longnamemax_test.go:103: l=189: should see a longname now
    longnamemax_test.go:103: l=190: should see a longname now
    longnamemax_test.go:103: l=191: should see a longname now
    longnamemax_test.go:103: l=192: should see a longname now
    longnamemax_test.go:103: l=193: should see a longname now
    longnamemax_test.go:103: l=194: should see a longname now
    longnamemax_test.go:103: l=195: should see a longname now
    longnamemax_test.go:103: l=196: should see a longname now
    longnamemax_test.go:103: l=197: should see a longname now
    longnamemax_test.go:103: l=198: should see a longname now
    longnamemax_test.go:103: l=199: should see a longname now
    longnamemax_test.go:103: l=200: should see a longname now
    longnamemax_test.go:103: l=201: should see a longname now
    longnamemax_test.go:103: l=202: should see a longname now
    longnamemax_test.go:103: l=203: should see a longname now
    longnamemax_test.go:103: l=204: should see a longname now
    longnamemax_test.go:103: l=205: should see a longname now
    longnamemax_test.go:103: l=206: should see a longname now
    longnamemax_test.go:103: l=207: should see a longname now
    longnamemax_test.go:103: l=208: should see a longname now
    longnamemax_test.go:103: l=209: should see a longname now
    longnamemax_test.go:103: l=210: should see a longname now
    longnamemax_test.go:103: l=211: should see a longname now
    longnamemax_test.go:103: l=212: should see a longname now
    longnamemax_test.go:103: l=213: should see a longname now
    longnamemax_test.go:103: l=214: should see a longname now
    longnamemax_test.go:103: l=215: should see a longname now
    longnamemax_test.go:103: l=216: should see a longname now
    longnamemax_test.go:103: l=217: should see a longname now
    longnamemax_test.go:103: l=218: should see a longname now
    longnamemax_test.go:103: l=219: should see a longname now
    longnamemax_test.go:103: l=220: should see a longname now
    longnamemax_test.go:103: l=221: should see a longname now
    longnamemax_test.go:103: l=222: should see a longname now
    longnamemax_test.go:103: l=223: should see a longname now
    longnamemax_test.go:103: l=224: should see a longname now
    longnamemax_test.go:103: l=225: should see a longname now
    longnamemax_test.go:103: l=226: should see a longname now
    longnamemax_test.go:103: l=227: should see a longname now
    longnamemax_test.go:103: l=228: should see a longname now
    longnamemax_test.go:103: l=229: should see a longname now
    longnamemax_test.go:103: l=230: should see a longname now
    longnamemax_test.go:103: l=231: should see a longname now
    longnamemax_test.go:103: l=232: should see a longname now
    longnamemax_test.go:103: l=233: should see a longname now
    longnamemax_test.go:103: l=234: should see a longname now
    longnamemax_test.go:103: l=235: should see a longname now
    longnamemax_test.go:103: l=236: should see a longname now
    longnamemax_test.go:103: l=237: should see a longname now
    longnamemax_test.go:103: l=238: should see a longname now
    longnamemax_test.go:103: l=239: should see a longname now
    longnamemax_test.go:103: l=240: should see a longname now
    longnamemax_test.go:103: l=241: should see a longname now
    longnamemax_test.go:103: l=242: should see a longname now
    longnamemax_test.go:103: l=243: should see a longname now
    longnamemax_test.go:103: l=244: should see a longname now
    longnamemax_test.go:103: l=245: should see a longname now
    longnamemax_test.go:103: l=246: should see a longname now
    longnamemax_test.go:103: l=247: should see a longname now
    longnamemax_test.go:103: l=248: should see a longname now
    longnamemax_test.go:103: l=249: should see a longname now
    longnamemax_test.go:103: l=250: should see a longname now
    longnamemax_test.go:103: l=251: should see a longname now
    longnamemax_test.go:103: l=252: should see a longname now
    longnamemax_test.go:103: l=253: should see a longname now
    longnamemax_test.go:103: l=254: should see a longname now
    longnamemax_test.go:103: l=255: should see a longname now
FAIL
FAIL  github.com/rfjakob/gocryptfs/v2/tests/cli  9.522s
ok    github.com/rfjakob/gocryptfs/v2/tests/cluster  0.005s
test_helpers: warning: testParentDir "/var/tmp/gocryptfs-test-parent-1001" does not reside on ext4, we will miss failures caused by ino reuse
syscallcompat.Openat() int 6 error <nil>
buggy on non-linux platforms, disabling SEEK_DATA & SEEK_HOLE
setfacl: /var/tmp/gocryptfs-test-parent-1001/2489438672/TestAcl543: acl_get_file() failed: Operation not supported
--- FAIL: TestOpenTruncateRead (0.02s)
    main_test.go:85: truncate /var/tmp/gocryptfs-test-parent-1001/2489438672/default-plain/TestTruncateWrite: no such file or directory
panic: truncate /var/tmp/gocryptfs-test-parent-1001/2489438672/default-plain/TestXfs124: no such file or directory

goroutine 30 [running]:
github.com/rfjakob/gocryptfs/v2/tests/defaults.TestXfs124.func1()
  /home/ankush/go/gocryptfs/tests/defaults/main_test.go:142 +0xb2
created by github.com/rfjakob/gocryptfs/v2/tests/defaults.TestXfs124 in goroutine 29
  /home/ankush/go/gocryptfs/tests/defaults/main_test.go:136 +0x157
FAIL  github.com/rfjakob/gocryptfs/v2/tests/defaults  1.077s
ok    github.com/rfjakob/gocryptfs/v2/tests/deterministic_names  0.212s
ok    github.com/rfjakob/gocryptfs/v2/tests/example_filesystems  3.969s
ok    github.com/rfjakob/gocryptfs/v2/tests/fsck  1.678s
ok    github.com/rfjakob/gocryptfs/v2/tests/hkdf_sanity  0.218s
test_helpers: warning: testParentDir "/var/tmp/gocryptfs-test-parent-1001" does not reside on ext4, we will miss failures caused by ino reuse
syscallcompat.Openat() int 6 error <nil>
2026/03/02 10:34:33 truncate /var/tmp/gocryptfs-test-parent-1001/3021134731/default-plain/TestConcurrentReadWrite: no such file or directory
FAIL  github.com/rfjakob/gocryptfs/v2/tests/matrix  0.039s
ok    github.com/rfjakob/gocryptfs/v2/tests/plaintextnames  0.137s
test_helpers: warning: testParentDir "/var/tmp/gocryptfs-test-parent-1001" does not reside on ext4, we will miss failures caused by ino reuse
--- FAIL: TestLongnameStat (0.07s)
    correctness_test.go:30: VerifyExistence: inconsistent result on "xx": stat=true open=true readdir=false, path="/var/tmp/gocryptfs-test-parent-1001/576429017/c/xx"
    correctness_test.go:31: failed to verify "/var/tmp/gocryptfs-test-parent-1001/576429017/c/xx"
syscallcompat.Fstatat(dirfd = -100, path = /var/tmp/gocryptfs-test-parent-1001/576429017/x.151565908.mnt/MnTnY6ilVvVe8qtC2nl3FA, flags = 512) error <nil>
syscallcompat.Fstatat(dirfd = -100, path = /var/tmp/gocryptfs-test-parent-1001/576429017/x.151565908.mnt/MnTnY6ilVvVe8qtC2nl3FA, flags = 512) error <nil>
syscallcompat.Fstatat(dirfd = -100, path = /var/tmp/gocryptfs-test-parent-1001/576429017/x.151565908.mnt/q0OQ0ik8sxbOhCYiCKpOog, flags = 512) error <nil>
syscallcompat.Fstatat(dirfd = -100, path = /var/tmp/gocryptfs-test-parent-1001/576429017/x.151565908.mnt/q0OQ0ik8sxbOhCYiCKpOog, flags = 512) error <nil>
syscallcompat.Fstatat(dirfd = -100, path = /var/tmp/gocryptfs-test-parent-1001/576429017/x.151565908.mnt/gocryptfs.conf, flags = 512) error <nil>
syscallcompat.Fstatat(dirfd = -100, path = /var/tmp/gocryptfs-test-parent-1001/576429017/x.151565908.mnt/gocryptfs.conf, flags = 512) error <nil>
syscallcompat.Fstatat(dirfd = -100, path = /var/tmp/gocryptfs-test-parent-1001/576429017/x.151565908.mnt/gocryptfs.diriv, flags = 512) error <nil>
syscallcompat.Fstatat(dirfd = -100, path = /var/tmp/gocryptfs-test-parent-1001/576429017/x.151565908.mnt/gocryptfs.diriv, flags = 512) error <nil>
2026/03/02 10:34:35 ino 2893980 not found
--- FAIL

@schlomie
Copy link

schlomie commented Mar 2, 2026

@ankushjp thanks! I built with your latest commits and observed your results - no errors. I think that will work.

I also tried the allow other flag - again mounted as root and observed the failed to set time errors as before (as well as permission errors in sub folders - which is kind of expected with fuse running as root.)

As to the failures in your test-without-openssl.bash run - much of that is due to Linux specific commands. FreeBSD has neither fusermount nor findmnt. And flock is not installed in the base system. I installed flock from ports and ran it on my machine...

build.bash: warning: could not determine gocryptfs version
gocryptfs [unknown] without_openssl; go-fuse v2.9.0; 2026-03-02 go1.26.0 freebsd/amd64
staticcheck not installed - skipping
shellcheck not installed - skipping
Testing on TMPDIR=/var/tmp, filesystem: ./test.bash: line 83: findmnt: command not found
?
ok  	github.com/rfjakob/gocryptfs/v2	0.005s
?   	github.com/rfjakob/gocryptfs/v2/contrib/atomicrename	[no test files]
?   	github.com/rfjakob/gocryptfs/v2/contrib/findholes	[no test files]
?   	github.com/rfjakob/gocryptfs/v2/contrib/findholes/holes	[no test files]
?   	github.com/rfjakob/gocryptfs/v2/contrib/getdents-debug/readdirnames	[no test files]
?   	github.com/rfjakob/gocryptfs/v2/contrib/statfs	[no test files]
?   	github.com/rfjakob/gocryptfs/v2/contrib/statvsfstat	[no test files]
?   	github.com/rfjakob/gocryptfs/v2/ctlsock	[no test files]
?   	github.com/rfjakob/gocryptfs/v2/gocryptfs-xray	[no test files]
ok  	github.com/rfjakob/gocryptfs/v2/gocryptfs-xray/xray_tests	0.328s
ok  	github.com/rfjakob/gocryptfs/v2/internal/configfile	1.142s
ok  	github.com/rfjakob/gocryptfs/v2/internal/contentenc	0.006s
ok  	github.com/rfjakob/gocryptfs/v2/internal/cryptocore	0.361s
ok  	github.com/rfjakob/gocryptfs/v2/internal/ctlsocksrv	0.006s
?   	github.com/rfjakob/gocryptfs/v2/internal/ensurefds012	[no test files]
?   	github.com/rfjakob/gocryptfs/v2/internal/exitcodes	[no test files]
?   	github.com/rfjakob/gocryptfs/v2/internal/fido2	[no test files]
ok  	github.com/rfjakob/gocryptfs/v2/internal/fusefrontend	0.066s
ok  	github.com/rfjakob/gocryptfs/v2/internal/fusefrontend_reverse	0.008s
ok  	github.com/rfjakob/gocryptfs/v2/internal/inomap	0.016s
ok  	github.com/rfjakob/gocryptfs/v2/internal/nametransform	0.013s
?   	github.com/rfjakob/gocryptfs/v2/internal/openfiletable	[no test files]
ok  	github.com/rfjakob/gocryptfs/v2/internal/pathiv	0.004s
ok  	github.com/rfjakob/gocryptfs/v2/internal/readpassword	0.024s
ok  	github.com/rfjakob/gocryptfs/v2/internal/siv_aead	0.003s
ok  	github.com/rfjakob/gocryptfs/v2/internal/speed	0.004s [no tests to run]
?   	github.com/rfjakob/gocryptfs/v2/internal/stupidgcm	[no test files]
--- FAIL: TestRenameExchange (0.00s)
    rename_exchange_test.go:43: Failed to read file1 after exchange: open /var/tmp/renameat2_test1522798330/file1.txt: no such file or directory
--- FAIL: TestSymlinkat (0.00s)
    sys_common_test.go:229: Wrong mode, have 0120755, want 0120777
FAIL
FAIL	github.com/rfjakob/gocryptfs/v2/internal/syscallcompat	0.005s
ok  	github.com/rfjakob/gocryptfs/v2/internal/tlog	0.004s
test_helpers: warning: testParentDir "/var/tmp/gocryptfs-test-parent-1000" does not reside on ext4, we will miss failures caused by ino reuse
warning: haveFusermount2: fork/exec /bin/fusermount: no such file or directory
--- FAIL: TestBadname (0.02s)
    cli_test.go:813: open /var/tmp/gocryptfs-test-parent-1000/2679087460/TestBadname.4217914360.mnt/file: no such file or directory
Invalid cipherdir: directory /var/tmp/gocryptfs-test-parent-1000/2679087460/TestInitNotEmpty not empty
--- FAIL: TestSharedstorage (0.02s)
    cli_test.go:1007: link /var/tmp/gocryptfs-test-parent-1000/2679087460/TestSharedstorage.2794845290.mnt/foo1 /var/tmp/gocryptfs-test-parent-1000/2679087460/TestSharedstorage.2794845290.mnt/foo2: input/output error
--- FAIL: TestOrphanedSocket (0.02s)
    cli_test.go:1089: invalid argument
mount_fusefs: /dev/fuse on /var/tmp/gocryptfs-test-parent-1000/2679087460/TestDirectMount.2635120714.mnt: Operation not permitted (extended error FUSE daemon requires privileges due to 'allow_other' option)
fs.Mount failed: mount_fusefs: exited with status 71
--- FAIL: TestDirectMount (0.03s)
    directmount_test.go:70: wrong FSType: "fusefs.gocryptf"
    directmount_test.go:47: checkOptionPresent: max_read=: want=true have=false. Full string: 
    directmount_test.go:52: mount failed: exit status 19
--- FAIL: TestLongnamemax100Reverse (0.06s)
    longnamemax_test.go:103: l=64: should see a longname now
    longnamemax_test.go:103: l=65: should see a longname now
    longnamemax_test.go:103: l=66: should see a longname now
    longnamemax_test.go:103: l=67: should see a longname now
    longnamemax_test.go:103: l=68: should see a longname now
    longnamemax_test.go:103: l=69: should see a longname now
    longnamemax_test.go:103: l=70: should see a longname now
    longnamemax_test.go:103: l=71: should see a longname now
    longnamemax_test.go:103: l=72: should see a longname now
    longnamemax_test.go:103: l=73: should see a longname now
    longnamemax_test.go:103: l=74: should see a longname now
    longnamemax_test.go:103: l=75: should see a longname now
    longnamemax_test.go:103: l=76: should see a longname now
    longnamemax_test.go:103: l=77: should see a longname now
    longnamemax_test.go:103: l=78: should see a longname now
    longnamemax_test.go:103: l=79: should see a longname now
    longnamemax_test.go:103: l=80: should see a longname now
    longnamemax_test.go:103: l=81: should see a longname now
    longnamemax_test.go:103: l=82: should see a longname now
    longnamemax_test.go:103: l=83: should see a longname now
    longnamemax_test.go:103: l=84: should see a longname now
    longnamemax_test.go:103: l=85: should see a longname now
    longnamemax_test.go:103: l=86: should see a longname now
    longnamemax_test.go:103: l=87: should see a longname now
    longnamemax_test.go:103: l=88: should see a longname now
    longnamemax_test.go:103: l=89: should see a longname now
    longnamemax_test.go:103: l=90: should see a longname now
    longnamemax_test.go:103: l=91: should see a longname now
    longnamemax_test.go:103: l=92: should see a longname now
    longnamemax_test.go:103: l=93: should see a longname now
    longnamemax_test.go:103: l=94: should see a longname now
    longnamemax_test.go:103: l=95: should see a longname now
    longnamemax_test.go:103: l=96: should see a longname now
    longnamemax_test.go:103: l=97: should see a longname now
    longnamemax_test.go:103: l=98: should see a longname now
    longnamemax_test.go:103: l=99: should see a longname now
    longnamemax_test.go:103: l=100: should see a longname now
    longnamemax_test.go:103: l=101: should see a longname now
    longnamemax_test.go:103: l=102: should see a longname now
    longnamemax_test.go:103: l=103: should see a longname now
    longnamemax_test.go:103: l=104: should see a longname now
    longnamemax_test.go:103: l=105: should see a longname now
    longnamemax_test.go:103: l=106: should see a longname now
    longnamemax_test.go:103: l=107: should see a longname now
    longnamemax_test.go:103: l=108: should see a longname now
    longnamemax_test.go:103: l=109: should see a longname now
    longnamemax_test.go:103: l=110: should see a longname now
    longnamemax_test.go:103: l=111: should see a longname now
    longnamemax_test.go:103: l=112: should see a longname now
    longnamemax_test.go:103: l=113: should see a longname now
    longnamemax_test.go:103: l=114: should see a longname now
    longnamemax_test.go:103: l=115: should see a longname now
    longnamemax_test.go:103: l=116: should see a longname now
    longnamemax_test.go:103: l=117: should see a longname now
    longnamemax_test.go:103: l=118: should see a longname now
    longnamemax_test.go:103: l=119: should see a longname now
    longnamemax_test.go:103: l=120: should see a longname now
    longnamemax_test.go:103: l=121: should see a longname now
    longnamemax_test.go:103: l=122: should see a longname now
    longnamemax_test.go:103: l=123: should see a longname now
    longnamemax_test.go:103: l=124: should see a longname now
    longnamemax_test.go:103: l=125: should see a longname now
    longnamemax_test.go:103: l=126: should see a longname now
    longnamemax_test.go:103: l=127: should see a longname now
    longnamemax_test.go:103: l=128: should see a longname now
    longnamemax_test.go:103: l=129: should see a longname now
    longnamemax_test.go:103: l=130: should see a longname now
    longnamemax_test.go:103: l=131: should see a longname now
    longnamemax_test.go:103: l=132: should see a longname now
    longnamemax_test.go:103: l=133: should see a longname now
    longnamemax_test.go:103: l=134: should see a longname now
    longnamemax_test.go:103: l=135: should see a longname now
    longnamemax_test.go:103: l=136: should see a longname now
    longnamemax_test.go:103: l=137: should see a longname now
    longnamemax_test.go:103: l=138: should see a longname now
    longnamemax_test.go:103: l=139: should see a longname now
    longnamemax_test.go:103: l=140: should see a longname now
    longnamemax_test.go:103: l=141: should see a longname now
    longnamemax_test.go:103: l=142: should see a longname now
    longnamemax_test.go:103: l=143: should see a longname now
    longnamemax_test.go:103: l=144: should see a longname now
    longnamemax_test.go:103: l=145: should see a longname now
    longnamemax_test.go:103: l=146: should see a longname now
    longnamemax_test.go:103: l=147: should see a longname now
    longnamemax_test.go:103: l=148: should see a longname now
    longnamemax_test.go:103: l=149: should see a longname now
    longnamemax_test.go:103: l=150: should see a longname now
    longnamemax_test.go:103: l=151: should see a longname now
    longnamemax_test.go:103: l=152: should see a longname now
    longnamemax_test.go:103: l=153: should see a longname now
    longnamemax_test.go:103: l=154: should see a longname now
    longnamemax_test.go:103: l=155: should see a longname now
    longnamemax_test.go:103: l=156: should see a longname now
    longnamemax_test.go:103: l=157: should see a longname now
    longnamemax_test.go:103: l=158: should see a longname now
    longnamemax_test.go:103: l=159: should see a longname now
    longnamemax_test.go:103: l=160: should see a longname now
    longnamemax_test.go:103: l=161: should see a longname now
    longnamemax_test.go:103: l=162: should see a longname now
    longnamemax_test.go:103: l=163: should see a longname now
    longnamemax_test.go:103: l=164: should see a longname now
    longnamemax_test.go:103: l=165: should see a longname now
    longnamemax_test.go:103: l=166: should see a longname now
    longnamemax_test.go:103: l=167: should see a longname now
    longnamemax_test.go:103: l=168: should see a longname now
    longnamemax_test.go:103: l=169: should see a longname now
    longnamemax_test.go:103: l=170: should see a longname now
    longnamemax_test.go:103: l=171: should see a longname now
    longnamemax_test.go:103: l=172: should see a longname now
    longnamemax_test.go:103: l=173: should see a longname now
    longnamemax_test.go:103: l=174: should see a longname now
    longnamemax_test.go:103: l=175: should see a longname now
    longnamemax_test.go:103: l=176: should see a longname now
    longnamemax_test.go:103: l=177: should see a longname now
    longnamemax_test.go:103: l=178: should see a longname now
    longnamemax_test.go:103: l=179: should see a longname now
    longnamemax_test.go:103: l=180: should see a longname now
    longnamemax_test.go:103: l=181: should see a longname now
    longnamemax_test.go:103: l=182: should see a longname now
    longnamemax_test.go:103: l=183: should see a longname now
    longnamemax_test.go:103: l=184: should see a longname now
    longnamemax_test.go:103: l=185: should see a longname now
    longnamemax_test.go:103: l=186: should see a longname now
    longnamemax_test.go:103: l=187: should see a longname now
    longnamemax_test.go:103: l=188: should see a longname now
    longnamemax_test.go:103: l=189: should see a longname now
    longnamemax_test.go:103: l=190: should see a longname now
    longnamemax_test.go:103: l=191: should see a longname now
    longnamemax_test.go:103: l=192: should see a longname now
    longnamemax_test.go:103: l=193: should see a longname now
    longnamemax_test.go:103: l=194: should see a longname now
    longnamemax_test.go:103: l=195: should see a longname now
    longnamemax_test.go:103: l=196: should see a longname now
    longnamemax_test.go:103: l=197: should see a longname now
    longnamemax_test.go:103: l=198: should see a longname now
    longnamemax_test.go:103: l=199: should see a longname now
    longnamemax_test.go:103: l=200: should see a longname now
    longnamemax_test.go:103: l=201: should see a longname now
    longnamemax_test.go:103: l=202: should see a longname now
    longnamemax_test.go:103: l=203: should see a longname now
    longnamemax_test.go:103: l=204: should see a longname now
    longnamemax_test.go:103: l=205: should see a longname now
    longnamemax_test.go:103: l=206: should see a longname now
    longnamemax_test.go:103: l=207: should see a longname now
    longnamemax_test.go:103: l=208: should see a longname now
    longnamemax_test.go:103: l=209: should see a longname now
    longnamemax_test.go:103: l=210: should see a longname now
    longnamemax_test.go:103: l=211: should see a longname now
    longnamemax_test.go:103: l=212: should see a longname now
    longnamemax_test.go:103: l=213: should see a longname now
    longnamemax_test.go:103: l=214: should see a longname now
    longnamemax_test.go:103: l=215: should see a longname now
    longnamemax_test.go:103: l=216: should see a longname now
    longnamemax_test.go:103: l=217: should see a longname now
    longnamemax_test.go:103: l=218: should see a longname now
    longnamemax_test.go:103: l=219: should see a longname now
    longnamemax_test.go:103: l=220: should see a longname now
    longnamemax_test.go:103: l=221: should see a longname now
    longnamemax_test.go:103: l=222: should see a longname now
    longnamemax_test.go:103: l=223: should see a longname now
    longnamemax_test.go:103: l=224: should see a longname now
    longnamemax_test.go:103: l=225: should see a longname now
    longnamemax_test.go:103: l=226: should see a longname now
    longnamemax_test.go:103: l=227: should see a longname now
    longnamemax_test.go:103: l=228: should see a longname now
    longnamemax_test.go:103: l=229: should see a longname now
    longnamemax_test.go:103: l=230: should see a longname now
    longnamemax_test.go:103: l=231: should see a longname now
    longnamemax_test.go:103: l=232: should see a longname now
    longnamemax_test.go:103: l=233: should see a longname now
    longnamemax_test.go:103: l=234: should see a longname now
    longnamemax_test.go:103: l=235: should see a longname now
    longnamemax_test.go:103: l=236: should see a longname now
    longnamemax_test.go:103: l=237: should see a longname now
    longnamemax_test.go:103: l=238: should see a longname now
    longnamemax_test.go:103: l=239: should see a longname now
    longnamemax_test.go:103: l=240: should see a longname now
    longnamemax_test.go:103: l=241: should see a longname now
    longnamemax_test.go:103: l=242: should see a longname now
    longnamemax_test.go:103: l=243: should see a longname now
    longnamemax_test.go:103: l=244: should see a longname now
    longnamemax_test.go:103: l=245: should see a longname now
    longnamemax_test.go:103: l=246: should see a longname now
    longnamemax_test.go:103: l=247: should see a longname now
    longnamemax_test.go:103: l=248: should see a longname now
    longnamemax_test.go:103: l=249: should see a longname now
    longnamemax_test.go:103: l=250: should see a longname now
    longnamemax_test.go:103: l=251: should see a longname now
    longnamemax_test.go:103: l=252: should see a longname now
    longnamemax_test.go:103: l=253: should see a longname now
    longnamemax_test.go:103: l=254: should see a longname now
    longnamemax_test.go:103: l=255: should see a longname now
FAIL
FAIL	github.com/rfjakob/gocryptfs/v2/tests/cli	4.234s
ok  	github.com/rfjakob/gocryptfs/v2/tests/cluster	0.004s
test_helpers: warning: testParentDir "/var/tmp/gocryptfs-test-parent-1000" does not reside on ext4, we will miss failures caused by ino reuse
buggy on non-linux platforms, disabling SEEK_DATA & SEEK_HOLE
setfacl: /var/tmp/gocryptfs-test-parent-1000/1904428993/TestAcl543: branding mismatch; existing ACL is NFSv4, entry to be merged is POSIX.1e
--- FAIL: TestOpenTruncateRead (0.00s)
    main_test.go:85: truncate /var/tmp/gocryptfs-test-parent-1000/1904428993/default-plain/TestTruncateWrite: no such file or directory
panic: truncate /var/tmp/gocryptfs-test-parent-1000/1904428993/default-plain/TestXfs124: no such file or directory

goroutine 40 [running]:
github.com/rfjakob/gocryptfs/v2/tests/defaults.TestXfs124.func1()
	/home/user/gocryptfs/tests/defaults/main_test.go:142 +0xb2
created by github.com/rfjakob/gocryptfs/v2/tests/defaults.TestXfs124 in goroutine 39
	/home/user/gocryptfs/tests/defaults/main_test.go:136 +0x157
FAIL	github.com/rfjakob/gocryptfs/v2/tests/defaults	0.286s
ok  	github.com/rfjakob/gocryptfs/v2/tests/deterministic_names	0.082s
ok  	github.com/rfjakob/gocryptfs/v2/tests/example_filesystems	1.616s
ok  	github.com/rfjakob/gocryptfs/v2/tests/fsck	0.749s
ok  	github.com/rfjakob/gocryptfs/v2/tests/hkdf_sanity	0.086s
test_helpers: warning: testParentDir "/var/tmp/gocryptfs-test-parent-1000" does not reside on ext4, we will miss failures caused by ino reuse
2026/03/02 08:44:54 truncate /var/tmp/gocryptfs-test-parent-1000/3673410624/default-plain/TestConcurrentReadWrite: no such file or directory
FAIL	github.com/rfjakob/gocryptfs/v2/tests/matrix	0.015s
ok  	github.com/rfjakob/gocryptfs/v2/tests/plaintextnames	0.041s
test_helpers: warning: testParentDir "/var/tmp/gocryptfs-test-parent-1000" does not reside on ext4, we will miss failures caused by ino reuse
--- FAIL: TestLongnameStat (0.01s)
    correctness_test.go:30: VerifyExistence: inconsistent result on "xx": stat=true open=true readdir=false, path="/var/tmp/gocryptfs-test-parent-1000/658197764/c/xx"
    correctness_test.go:31: failed to verify "/var/tmp/gocryptfs-test-parent-1000/658197764/c/xx"
2026/03/02 08:44:54 ino 3410 not found
--- FAIL: TestHardlinkedLongname (0.00s)
panic: ino 3410 not found [recovered, repanicked]

goroutine 45 [running]:
testing.tRunner.func1.2({0x5e2b20, 0x86f42e2c0})
	/home/user/.local/opt/golang/1.26.0/src/testing/testing.go:1974 +0x232
testing.tRunner.func1()
	/home/user/.local/opt/golang/1.26.0/src/testing/testing.go:1977 +0x349
panic({0x5e2b20?, 0x86f42e2c0?})
	/home/user/.local/opt/golang/1.26.0/src/runtime/panic.go:860 +0x13a
log.Panicf({0x6388b6?, 0x86f440e10?}, {0x86f417a60?, 0x86f417948?, 0x200?})
	/home/user/.local/opt/golang/1.26.0/src/log/log.go:460 +0x74
github.com/rfjakob/gocryptfs/v2/tests/reverse_test.findIno({0x86f26e1c0, 0x3e}, 0xd52)
	/home/user/gocryptfs/tests/reverse/inomap_test.go:34 +0x1f3
github.com/rfjakob/gocryptfs/v2/tests/reverse_test.newWorkdir(0x86f437688)
	/home/user/gocryptfs/tests/reverse/correctness_test.go:309 +0x15e
github.com/rfjakob/gocryptfs/v2/tests/reverse_test.TestHardlinkedLongname(0x86f437688)
	/home/user/gocryptfs/tests/reverse/correctness_test.go:327 +0x49
testing.tRunner(0x86f437688, 0x646cb8)
	/home/user/.local/opt/golang/1.26.0/src/testing/testing.go:2036 +0xea
created by testing.(*T).Run in goroutine 1
	/home/user/.local/opt/golang/1.26.0/src/testing/testing.go:2101 +0x4c5
FAIL	github.com/rfjakob/gocryptfs/v2/tests/reverse	0.089s
ok  	github.com/rfjakob/gocryptfs/v2/tests/root_test	0.004s
test_helpers: warning: testParentDir "/var/tmp/gocryptfs-test-parent-1000" does not reside on ext4, we will miss failures caused by ino reuse
PASS
--- FAIL: TestStaleHardlinks (0.04s)
    sharedstorage_test.go:45: newTestCase: sharedstorage=true cipherdir="/var/tmp/gocryptfs-test-parent-1000/1581196481/TestStaleHardlinks.1183556305"
    sharedstorage_test.go:116: input/output error
FAIL
FAIL	github.com/rfjakob/gocryptfs/v2/tests/sharedstorage	1.413s
?   	github.com/rfjakob/gocryptfs/v2/tests/symlink_race	[no test files]
?   	github.com/rfjakob/gocryptfs/v2/tests/test_helpers	[no test files]
test_helpers: warning: testParentDir "/var/tmp/gocryptfs-test-parent-1000" does not reside on ext4, we will miss failures caused by ino reuse
--- FAIL: TestSetGetRmRegularFile (0.00s)
    xattr_integration_test.go:100: xattr.list /var/tmp/gocryptfs-test-parent-1000/1160653494/default-plain/TestSetGetRmRegularFile: operation not supported
--- FAIL: TestSetGetRmFifo (0.00s)
    xattr_integration_test.go:113: creating fifo failed: invalid argument
--- FAIL: TestXattrSetEmpty (0.00s)
    xattr_integration_test.go:146: xattr.LSet /var/tmp/gocryptfs-test-parent-1000/1160653494/default-plain/TestXattrSetEmpty1 user.foo: operation not supported
--- FAIL: TestXattrList (0.00s)
    xattr_integration_test.go:197: xattr.LSet /var/tmp/gocryptfs-test-parent-1000/1160653494/default-plain/TestXattrList user.TestXattrList.01: operation not supported
--- FAIL: TestBase64XattrRead (0.00s)
    xattr_integration_test.go:246: xattr.get /var/tmp/gocryptfs-test-parent-1000/1160653494/default-cipher/BaGak7jIoqAZQMlP0N5uCw user.gocryptfs.LB1kHHVrX1OEBdLmj3LTKw: invalid argument
--- FAIL: TestList0000File (0.00s)
    xattr_integration_test.go:294: xattr.list /var/tmp/gocryptfs-test-parent-1000/1160653494/default-plain/TestList0000File: operation not supported
--- FAIL: TestSet0200File (0.00s)
    xattr_integration_test.go:307: xattr.LSet /var/tmp/gocryptfs-test-parent-1000/1160653494/default-plain/TestSet0200File user.foo: operation not supported
--- FAIL: TestList0000Dir (0.00s)
    xattr_integration_test.go:321: xattr.list /var/tmp/gocryptfs-test-parent-1000/1160653494/default-plain/TestList0000Dir: operation not supported
--- FAIL: TestSet0200Dir (0.00s)
    xattr_integration_test.go:335: xattr.LSet /var/tmp/gocryptfs-test-parent-1000/1160653494/default-plain/TestSet0200Dir user.foo: operation not supported
--- FAIL: TestAcl (0.00s)
    xattr_integration_test.go:365: xattr.list /var/tmp/gocryptfs-test-parent-1000/1160653494/default-plain/TestAcl: operation not supported
--- FAIL: TestSlashInName (0.00s)
    xattr_integration_test.go:379: xattr.list /var/tmp/gocryptfs-test-parent-1000/1160653494/default-plain/TestSlashInName: operation not supported
FAIL
FAIL	github.com/rfjakob/gocryptfs/v2/tests/xattr	0.017s
FAIL

}
defer unix.Close(d.dirfd)

procPath := fmt.Sprintf("/proc/self/fd/%d/%s", d.dirfd, d.pName)
Copy link
Owner

Choose a reason for hiding this comment

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

Does not make sense on freebsd. Please fix or just stub it with EOPNOTSUPP.

Same for the other functions in this file.

Copy link
Author

Choose a reason for hiding this comment

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

The Functions in this file have been stubbed in the latest commit.

// WARNING this function is not complete, and always runs f() as if context is nil.
// FreeBSD does not support changing uid/gid per thread.
func asUser(f func() (int, error), context *fuse.Context) (int, error) {
return f()
Copy link
Owner

Choose a reason for hiding this comment

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

No, this is dangerous. This allows any user to create suid-root binaries.

If not possible to implement, log a warning and return an error.

Copy link
Author

Choose a reason for hiding this comment

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

Updated so that f() is executed is context is nil, otherwise a warning is logged and unix.EOPNOTSUPP.

@@ -1,3 +1,5 @@
//go:build darwin
Copy link
Owner

Choose a reason for hiding this comment

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

Does this cause problems on freebsd? Then please use

//go:build !freebsd

Copy link
Owner

Choose a reason for hiding this comment

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

This should be built on Linux so it can be tested on Linux

Copy link
Author

Choose a reason for hiding this comment

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

This was causing a problem on FreeBSD as the dev parameter to Mknod is uint64 on FreeBSD (instead of int used by Linux and Mac OS).

I've added the suggested build parameter to emulate.go, and created the file internal/syscallcompat/emulate_freebsd.go for FreeBSD with dev cast to uint64.

@@ -1,3 +1,4 @@
//go:build darwin
Copy link
Owner

Choose a reason for hiding this comment

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

Does this cause problems on freebsd? Then please use

//go:build !freebsd

Copy link
Author

Choose a reason for hiding this comment

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

This file will now build on FreeBSD after the above change to emulate.go.

return unix.EINVAL
}

return unix.Renameat(olddirfd, oldpath, newdirfd, newpath)
Copy link
Owner

Choose a reason for hiding this comment

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

This does not emulate RENAME_EXCHANGE at all?

Copy link
Author

Choose a reason for hiding this comment

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

Sorry, I didn't read the Linux Renameat2 properly the first time.

FreeBSD does not provide a way to atomically swap two files as far as I can tell, so I've changed the function to return a unix.EINVAL error if the flags include RENAME_EXCHANGE.

Comment on lines +1 to +28
package syscallcompat

import (
"syscall"

"golang.org/x/sys/unix"
)

// Unix2syscall converts a unix.Stat_t struct to a syscall.Stat_t struct.
// A direct cast does not work because the padding is named differently in
// unix.Stat_t for some reason ("X__unused" in syscall, "_" in unix).
func Unix2syscall(u unix.Stat_t) syscall.Stat_t {
return syscall.Stat_t{
Dev: u.Dev,
Ino: u.Ino,
Nlink: u.Nlink,
Mode: u.Mode,
Uid: u.Uid,
Gid: u.Gid,
Rdev: u.Rdev,
Size: u.Size,
Blksize: u.Blksize,
Blocks: u.Blocks,
Atimespec: syscall.NsecToTimespec(unix.TimespecToNsec(u.Atim)),
Mtimespec: syscall.NsecToTimespec(unix.TimespecToNsec(u.Mtim)),
Ctimespec: syscall.NsecToTimespec(unix.TimespecToNsec(u.Ctim)),
}
}
Copy link
Owner

Choose a reason for hiding this comment

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

Doesn't unix2syscall_darwin.go also work for FreeBSD? If so, adjust the build contraints to build on both.

Copy link
Author

Choose a reason for hiding this comment

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

I've renamed internal/syscallcompat/unix2syscall_darwin.go to internal/syscallcompat/unix2syscall_darwin_freebsd.go, so it builds on both Mac OS and FreeBSD. I've removed internal/syscallcompat/unix2syscall_freebsd.go.

Comment on lines +1 to +9
package matrix

import (
"syscall"
)

func extractAtimeMtime(st syscall.Stat_t) [2]syscall.Timespec {
return [2]syscall.Timespec{st.Atimespec, st.Mtimespec}
}
Copy link
Owner

Choose a reason for hiding this comment

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

Identical to atime_darwin.go. Please instead adjust the build contraints in atime_darwin.go.

Copy link
Author

Choose a reason for hiding this comment

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

Same as above, modified file names to build on the appropriate OSes.

* Functions in fusefrontend_reverse/node_xattr_freebsd.go have been
  stubbed for now.

* asuser_freebsd.go updated to only run f() when context is nil;
  otherwise log a warning and return an error.

* emulate.go build flags updated, and FreeBSD specific version added.

* sys_freebsd.go bug in Renameat2 with RENAME_EXCHANGE flag fixed.
  FreeBSD does not support atomic file swapping, so this flag now
  returns an error.

* unix2syscall and atime is identical between FreeBSD and Darwin,
  updated filenames so Go will build the file for FreeBSD and Mac OS.
@ankushjp
Copy link
Author

ankushjp commented Mar 3, 2026

I've attempted to fix/address all the PR comments.

Here is the output of ./test-without-openssl.bash with the latest commit.

$ ./test-without-openssl.bash
flock is not available, skipping
Warning: unmounting leftover filesystem: /var/tmp/gocryptfs-test-parent-1001/67873825/x.1524900168.mnt
Warning: unmounting leftover filesystem: /var/tmp/gocryptfs-test-parent-1001/2919641388/default-plain
Warning: unmounting leftover filesystem: /var/tmp/gocryptfs-test-parent-1001/2055645294/x.2082279410.mnt
umount: unmount of /var/tmp/gocryptfs-test-parent-1001/2055645294/x.2082279410.mnt failed: Device busy
Warning: unmounting leftover filesystem: /var/tmp/gocryptfs-test-parent-1001/2055645294/c
Warning: unmounting leftover filesystem: /var/tmp/gocryptfs-test-parent-1001/1210999660/TestBadname.1363356402.mnt
gocryptfs v2.6.1-45-g232206e.freebsd-support without_openssl; go-fuse v2.9.0; 2026-03-03 go1.25.7 freebsd/amd64
staticcheck not installed - skipping
shellcheck not installed - skipping
Testing on TMPDIR=/var/tmp, filesystem: ./test.bash: line 83: findmnt: command not found
?
ok  	github.com/rfjakob/gocryptfs/v2	0.002s
?   	github.com/rfjakob/gocryptfs/v2/contrib/atomicrename	[no test files]
?   	github.com/rfjakob/gocryptfs/v2/contrib/findholes	[no test files]
?   	github.com/rfjakob/gocryptfs/v2/contrib/findholes/holes	[no test files]
?   	github.com/rfjakob/gocryptfs/v2/contrib/getdents-debug/readdirnames	[no test files]
?   	github.com/rfjakob/gocryptfs/v2/contrib/statfs	[no test files]
?   	github.com/rfjakob/gocryptfs/v2/contrib/statvsfstat	[no test files]
?   	github.com/rfjakob/gocryptfs/v2/ctlsock	[no test files]
?   	github.com/rfjakob/gocryptfs/v2/gocryptfs-xray	[no test files]
ok  	github.com/rfjakob/gocryptfs/v2/gocryptfs-xray/xray_tests	0.040s
ok  	github.com/rfjakob/gocryptfs/v2/internal/configfile	0.350s
ok  	github.com/rfjakob/gocryptfs/v2/internal/contentenc	0.004s
ok  	github.com/rfjakob/gocryptfs/v2/internal/cryptocore	0.106s
ok  	github.com/rfjakob/gocryptfs/v2/internal/ctlsocksrv	0.003s
?   	github.com/rfjakob/gocryptfs/v2/internal/ensurefds012	[no test files]
?   	github.com/rfjakob/gocryptfs/v2/internal/exitcodes	[no test files]
?   	github.com/rfjakob/gocryptfs/v2/internal/fido2	[no test files]
ok  	github.com/rfjakob/gocryptfs/v2/internal/fusefrontend	0.015s
ok  	github.com/rfjakob/gocryptfs/v2/internal/fusefrontend_reverse	0.003s
ok  	github.com/rfjakob/gocryptfs/v2/internal/inomap	0.011s
ok  	github.com/rfjakob/gocryptfs/v2/internal/nametransform	0.029s
?   	github.com/rfjakob/gocryptfs/v2/internal/openfiletable	[no test files]
ok  	github.com/rfjakob/gocryptfs/v2/internal/pathiv	0.004s
ok  	github.com/rfjakob/gocryptfs/v2/internal/readpassword	0.012s
ok  	github.com/rfjakob/gocryptfs/v2/internal/siv_aead	0.002s
ok  	github.com/rfjakob/gocryptfs/v2/internal/speed	0.005s [no tests to run]
?   	github.com/rfjakob/gocryptfs/v2/internal/stupidgcm	[no test files]
--- FAIL: TestRenameExchange (0.00s)
    rename_exchange_test.go:37: RENAME_EXCHANGE failed: invalid argument
--- FAIL: TestSymlinkat (0.00s)
    sys_common_test.go:229: Wrong mode, have 0120755, want 0120777
FAIL
FAIL	github.com/rfjakob/gocryptfs/v2/internal/syscallcompat	0.005s
ok  	github.com/rfjakob/gocryptfs/v2/internal/tlog	0.004s
test_helpers: warning: testParentDir "/var/tmp/gocryptfs-test-parent-1001" does not reside on ext4, we will miss failures caused by ino reuse
warning: haveFusermount2: fork/exec /bin/fusermount: no such file or directory
--- FAIL: TestBadname (0.03s)
    cli_test.go:813: open /var/tmp/gocryptfs-test-parent-1001/178225175/TestBadname.4037558708.mnt/file: no such file or directory
Invalid cipherdir: directory /var/tmp/gocryptfs-test-parent-1001/178225175/TestInitNotEmpty not empty
--- FAIL: TestSharedstorage (0.07s)
    cli_test.go:1007: link /var/tmp/gocryptfs-test-parent-1001/178225175/TestSharedstorage.700866818.mnt/foo1 /var/tmp/gocryptfs-test-parent-1001/178225175/TestSharedstorage.700866818.mnt/foo2: input/output error
--- FAIL: TestOrphanedSocket (0.09s)
    cli_test.go:1089: invalid argument
mount_fusefs: /dev/fuse on /var/tmp/gocryptfs-test-parent-1001/178225175/TestDirectMount.2531835417.mnt: Operation not permitted (extended error FUSE daemon requires privileges due to 'allow_other' option)
fs.Mount failed: mount_fusefs: exited with status 71
--- FAIL: TestDirectMount (0.09s)
    directmount_test.go:70: wrong FSType: "fusefs.gocryptf"
    directmount_test.go:47: checkOptionPresent: max_read=: want=true have=false. Full string:
    directmount_test.go:52: mount failed: exit status 19
--- FAIL: TestLongnamemax100Reverse (0.06s)
    longnamemax_test.go:103: l=64: should see a longname now
    longnamemax_test.go:103: l=65: should see a longname now
    longnamemax_test.go:103: l=66: should see a longname now
    longnamemax_test.go:103: l=67: should see a longname now
    longnamemax_test.go:103: l=68: should see a longname now
    longnamemax_test.go:103: l=69: should see a longname now
    longnamemax_test.go:103: l=70: should see a longname now
    longnamemax_test.go:103: l=71: should see a longname now
    longnamemax_test.go:103: l=72: should see a longname now
    longnamemax_test.go:103: l=73: should see a longname now
    longnamemax_test.go:103: l=74: should see a longname now
    longnamemax_test.go:103: l=75: should see a longname now
    longnamemax_test.go:103: l=76: should see a longname now
    longnamemax_test.go:103: l=77: should see a longname now
    longnamemax_test.go:103: l=78: should see a longname now
    longnamemax_test.go:103: l=79: should see a longname now
    longnamemax_test.go:103: l=80: should see a longname now
    longnamemax_test.go:103: l=81: should see a longname now
    longnamemax_test.go:103: l=82: should see a longname now
    longnamemax_test.go:103: l=83: should see a longname now
    longnamemax_test.go:103: l=84: should see a longname now
    longnamemax_test.go:103: l=85: should see a longname now
    longnamemax_test.go:103: l=86: should see a longname now
    longnamemax_test.go:103: l=87: should see a longname now
    longnamemax_test.go:103: l=88: should see a longname now
    longnamemax_test.go:103: l=89: should see a longname now
    longnamemax_test.go:103: l=90: should see a longname now
    longnamemax_test.go:103: l=91: should see a longname now
    longnamemax_test.go:103: l=92: should see a longname now
    longnamemax_test.go:103: l=93: should see a longname now
    longnamemax_test.go:103: l=94: should see a longname now
    longnamemax_test.go:103: l=95: should see a longname now
    longnamemax_test.go:103: l=96: should see a longname now
    longnamemax_test.go:103: l=97: should see a longname now
    longnamemax_test.go:103: l=98: should see a longname now
    longnamemax_test.go:103: l=99: should see a longname now
    longnamemax_test.go:103: l=100: should see a longname now
    longnamemax_test.go:103: l=101: should see a longname now
    longnamemax_test.go:103: l=102: should see a longname now
    longnamemax_test.go:103: l=103: should see a longname now
    longnamemax_test.go:103: l=104: should see a longname now
    longnamemax_test.go:103: l=105: should see a longname now
    longnamemax_test.go:103: l=106: should see a longname now
    longnamemax_test.go:103: l=107: should see a longname now
    longnamemax_test.go:103: l=108: should see a longname now
    longnamemax_test.go:103: l=109: should see a longname now
    longnamemax_test.go:103: l=110: should see a longname now
    longnamemax_test.go:103: l=111: should see a longname now
    longnamemax_test.go:103: l=112: should see a longname now
    longnamemax_test.go:103: l=113: should see a longname now
    longnamemax_test.go:103: l=114: should see a longname now
    longnamemax_test.go:103: l=115: should see a longname now
    longnamemax_test.go:103: l=116: should see a longname now
    longnamemax_test.go:103: l=117: should see a longname now
    longnamemax_test.go:103: l=118: should see a longname now
    longnamemax_test.go:103: l=119: should see a longname now
    longnamemax_test.go:103: l=120: should see a longname now
    longnamemax_test.go:103: l=121: should see a longname now
    longnamemax_test.go:103: l=122: should see a longname now
    longnamemax_test.go:103: l=123: should see a longname now
    longnamemax_test.go:103: l=124: should see a longname now
    longnamemax_test.go:103: l=125: should see a longname now
    longnamemax_test.go:103: l=126: should see a longname now
    longnamemax_test.go:103: l=127: should see a longname now
    longnamemax_test.go:103: l=128: should see a longname now
    longnamemax_test.go:103: l=129: should see a longname now
    longnamemax_test.go:103: l=130: should see a longname now
    longnamemax_test.go:103: l=131: should see a longname now
    longnamemax_test.go:103: l=132: should see a longname now
    longnamemax_test.go:103: l=133: should see a longname now
    longnamemax_test.go:103: l=134: should see a longname now
    longnamemax_test.go:103: l=135: should see a longname now
    longnamemax_test.go:103: l=136: should see a longname now
    longnamemax_test.go:103: l=137: should see a longname now
    longnamemax_test.go:103: l=138: should see a longname now
    longnamemax_test.go:103: l=139: should see a longname now
    longnamemax_test.go:103: l=140: should see a longname now
    longnamemax_test.go:103: l=141: should see a longname now
    longnamemax_test.go:103: l=142: should see a longname now
    longnamemax_test.go:103: l=143: should see a longname now
    longnamemax_test.go:103: l=144: should see a longname now
    longnamemax_test.go:103: l=145: should see a longname now
    longnamemax_test.go:103: l=146: should see a longname now
    longnamemax_test.go:103: l=147: should see a longname now
    longnamemax_test.go:103: l=148: should see a longname now
    longnamemax_test.go:103: l=149: should see a longname now
    longnamemax_test.go:103: l=150: should see a longname now
    longnamemax_test.go:103: l=151: should see a longname now
    longnamemax_test.go:103: l=152: should see a longname now
    longnamemax_test.go:103: l=153: should see a longname now
    longnamemax_test.go:103: l=154: should see a longname now
    longnamemax_test.go:103: l=155: should see a longname now
    longnamemax_test.go:103: l=156: should see a longname now
    longnamemax_test.go:103: l=157: should see a longname now
    longnamemax_test.go:103: l=158: should see a longname now
    longnamemax_test.go:103: l=159: should see a longname now
    longnamemax_test.go:103: l=160: should see a longname now
    longnamemax_test.go:103: l=161: should see a longname now
    longnamemax_test.go:103: l=162: should see a longname now
    longnamemax_test.go:103: l=163: should see a longname now
    longnamemax_test.go:103: l=164: should see a longname now
    longnamemax_test.go:103: l=165: should see a longname now
    longnamemax_test.go:103: l=166: should see a longname now
    longnamemax_test.go:103: l=167: should see a longname now
    longnamemax_test.go:103: l=168: should see a longname now
    longnamemax_test.go:103: l=169: should see a longname now
    longnamemax_test.go:103: l=170: should see a longname now
    longnamemax_test.go:103: l=171: should see a longname now
    longnamemax_test.go:103: l=172: should see a longname now
    longnamemax_test.go:103: l=173: should see a longname now
    longnamemax_test.go:103: l=174: should see a longname now
    longnamemax_test.go:103: l=175: should see a longname now
    longnamemax_test.go:103: l=176: should see a longname now
    longnamemax_test.go:103: l=177: should see a longname now
    longnamemax_test.go:103: l=178: should see a longname now
    longnamemax_test.go:103: l=179: should see a longname now
    longnamemax_test.go:103: l=180: should see a longname now
    longnamemax_test.go:103: l=181: should see a longname now
    longnamemax_test.go:103: l=182: should see a longname now
    longnamemax_test.go:103: l=183: should see a longname now
    longnamemax_test.go:103: l=184: should see a longname now
    longnamemax_test.go:103: l=185: should see a longname now
    longnamemax_test.go:103: l=186: should see a longname now
    longnamemax_test.go:103: l=187: should see a longname now
    longnamemax_test.go:103: l=188: should see a longname now
    longnamemax_test.go:103: l=189: should see a longname now
    longnamemax_test.go:103: l=190: should see a longname now
    longnamemax_test.go:103: l=191: should see a longname now
    longnamemax_test.go:103: l=192: should see a longname now
    longnamemax_test.go:103: l=193: should see a longname now
    longnamemax_test.go:103: l=194: should see a longname now
    longnamemax_test.go:103: l=195: should see a longname now
    longnamemax_test.go:103: l=196: should see a longname now
    longnamemax_test.go:103: l=197: should see a longname now
    longnamemax_test.go:103: l=198: should see a longname now
    longnamemax_test.go:103: l=199: should see a longname now
    longnamemax_test.go:103: l=200: should see a longname now
    longnamemax_test.go:103: l=201: should see a longname now
    longnamemax_test.go:103: l=202: should see a longname now
    longnamemax_test.go:103: l=203: should see a longname now
    longnamemax_test.go:103: l=204: should see a longname now
    longnamemax_test.go:103: l=205: should see a longname now
    longnamemax_test.go:103: l=206: should see a longname now
    longnamemax_test.go:103: l=207: should see a longname now
    longnamemax_test.go:103: l=208: should see a longname now
    longnamemax_test.go:103: l=209: should see a longname now
    longnamemax_test.go:103: l=210: should see a longname now
    longnamemax_test.go:103: l=211: should see a longname now
    longnamemax_test.go:103: l=212: should see a longname now
    longnamemax_test.go:103: l=213: should see a longname now
    longnamemax_test.go:103: l=214: should see a longname now
    longnamemax_test.go:103: l=215: should see a longname now
    longnamemax_test.go:103: l=216: should see a longname now
    longnamemax_test.go:103: l=217: should see a longname now
    longnamemax_test.go:103: l=218: should see a longname now
    longnamemax_test.go:103: l=219: should see a longname now
    longnamemax_test.go:103: l=220: should see a longname now
    longnamemax_test.go:103: l=221: should see a longname now
    longnamemax_test.go:103: l=222: should see a longname now
    longnamemax_test.go:103: l=223: should see a longname now
    longnamemax_test.go:103: l=224: should see a longname now
    longnamemax_test.go:103: l=225: should see a longname now
    longnamemax_test.go:103: l=226: should see a longname now
    longnamemax_test.go:103: l=227: should see a longname now
    longnamemax_test.go:103: l=228: should see a longname now
    longnamemax_test.go:103: l=229: should see a longname now
    longnamemax_test.go:103: l=230: should see a longname now
    longnamemax_test.go:103: l=231: should see a longname now
    longnamemax_test.go:103: l=232: should see a longname now
    longnamemax_test.go:103: l=233: should see a longname now
    longnamemax_test.go:103: l=234: should see a longname now
    longnamemax_test.go:103: l=235: should see a longname now
    longnamemax_test.go:103: l=236: should see a longname now
    longnamemax_test.go:103: l=237: should see a longname now
    longnamemax_test.go:103: l=238: should see a longname now
    longnamemax_test.go:103: l=239: should see a longname now
    longnamemax_test.go:103: l=240: should see a longname now
    longnamemax_test.go:103: l=241: should see a longname now
    longnamemax_test.go:103: l=242: should see a longname now
    longnamemax_test.go:103: l=243: should see a longname now
    longnamemax_test.go:103: l=244: should see a longname now
    longnamemax_test.go:103: l=245: should see a longname now
    longnamemax_test.go:103: l=246: should see a longname now
    longnamemax_test.go:103: l=247: should see a longname now
    longnamemax_test.go:103: l=248: should see a longname now
    longnamemax_test.go:103: l=249: should see a longname now
    longnamemax_test.go:103: l=250: should see a longname now
    longnamemax_test.go:103: l=251: should see a longname now
    longnamemax_test.go:103: l=252: should see a longname now
    longnamemax_test.go:103: l=253: should see a longname now
    longnamemax_test.go:103: l=254: should see a longname now
    longnamemax_test.go:103: l=255: should see a longname now
FAIL
FAIL	github.com/rfjakob/gocryptfs/v2/tests/cli	3.720s
ok  	github.com/rfjakob/gocryptfs/v2/tests/cluster	0.004s
test_helpers: warning: testParentDir "/var/tmp/gocryptfs-test-parent-1001" does not reside on ext4, we will miss failures caused by ino reuse
buggy on non-linux platforms, disabling SEEK_DATA & SEEK_HOLE
setfacl: /var/tmp/gocryptfs-test-parent-1001/2826684717/TestAcl543: acl_get_file() failed: Operation not supported
--- FAIL: TestOpenTruncateRead (0.00s)
    main_test.go:85: truncate /var/tmp/gocryptfs-test-parent-1001/2826684717/default-plain/TestTruncateWrite: no such file or directory
panic: truncate /var/tmp/gocryptfs-test-parent-1001/2826684717/default-plain/TestXfs124: no such file or directory

goroutine 28 [running]:
github.com/rfjakob/gocryptfs/v2/tests/defaults.TestXfs124.func1()
	/home/ankush/go/gocryptfs/tests/defaults/main_test.go:142 +0xb2
created by github.com/rfjakob/gocryptfs/v2/tests/defaults.TestXfs124 in goroutine 27
	/home/ankush/go/gocryptfs/tests/defaults/main_test.go:136 +0x157
FAIL	github.com/rfjakob/gocryptfs/v2/tests/defaults	0.186s
ok  	github.com/rfjakob/gocryptfs/v2/tests/deterministic_names	0.043s
ok  	github.com/rfjakob/gocryptfs/v2/tests/example_filesystems	0.792s
ok  	github.com/rfjakob/gocryptfs/v2/tests/fsck	0.311s
ok  	github.com/rfjakob/gocryptfs/v2/tests/hkdf_sanity	0.033s
test_helpers: warning: testParentDir "/var/tmp/gocryptfs-test-parent-1001" does not reside on ext4, we will miss failures caused by ino reuse
2026/03/03 17:57:46 truncate /var/tmp/gocryptfs-test-parent-1001/518249844/default-plain/TestConcurrentReadWrite: no such file or directory
FAIL	github.com/rfjakob/gocryptfs/v2/tests/matrix	0.019s
ok  	github.com/rfjakob/gocryptfs/v2/tests/plaintextnames	0.032s
test_helpers: warning: testParentDir "/var/tmp/gocryptfs-test-parent-1001" does not reside on ext4, we will miss failures caused by ino reuse
--- FAIL: TestLongnameStat (0.00s)
    correctness_test.go:30: VerifyExistence: inconsistent result on "xx": stat=true open=true readdir=false, path="/var/tmp/gocryptfs-test-parent-1001/635931259/c/xx"
    correctness_test.go:31: failed to verify "/var/tmp/gocryptfs-test-parent-1001/635931259/c/xx"
2026/03/03 17:57:46 ino 12019551 not found
--- FAIL: TestHardlinkedLongname (0.00s)
panic: ino 12019551 not found [recovered, repanicked]

goroutine 40 [running]:
testing.tRunner.func1.2({0x5dfcc0, 0x86c092180})
	/usr/local/go125/src/testing/testing.go:1872 +0x237
testing.tRunner.func1()
	/usr/local/go125/src/testing/testing.go:1875 +0x35b
panic({0x5dfcc0?, 0x86c092180?})
	/usr/local/go125/src/runtime/panic.go:783 +0x132
log.Panicf({0x632ffc?, 0x86c0e2550?}, {0x86c11aa60?, 0x86c11a948?, 0x200?})
	/usr/local/go125/src/log/log.go:460 +0x74
github.com/rfjakob/gocryptfs/v2/tests/reverse_test.findIno({0x86c020040, 0x3e}, 0xb7675f)
	/home/ankush/go/gocryptfs/tests/reverse/inomap_test.go:34 +0x1e5
github.com/rfjakob/gocryptfs/v2/tests/reverse_test.newWorkdir(0x86c083340)
	/home/ankush/go/gocryptfs/tests/reverse/correctness_test.go:309 +0x14f
github.com/rfjakob/gocryptfs/v2/tests/reverse_test.TestHardlinkedLongname(0x86c083340)
	/home/ankush/go/gocryptfs/tests/reverse/correctness_test.go:327 +0x49
testing.tRunner(0x86c083340, 0x641450)
	/usr/local/go125/src/testing/testing.go:1934 +0xea
created by testing.(*T).Run in goroutine 1
	/usr/local/go125/src/testing/testing.go:1997 +0x465
FAIL	github.com/rfjakob/gocryptfs/v2/tests/reverse	0.061s
ok  	github.com/rfjakob/gocryptfs/v2/tests/root_test	0.004s
test_helpers: warning: testParentDir "/var/tmp/gocryptfs-test-parent-1001" does not reside on ext4, we will miss failures caused by ino reuse
PASS
--- FAIL: TestStaleHardlinks (0.07s)
    sharedstorage_test.go:45: newTestCase: sharedstorage=true cipherdir="/var/tmp/gocryptfs-test-parent-1001/1886892974/TestStaleHardlinks.865376700"
    sharedstorage_test.go:116: input/output error
FAIL
FAIL	github.com/rfjakob/gocryptfs/v2/tests/sharedstorage	1.285s
?   	github.com/rfjakob/gocryptfs/v2/tests/symlink_race	[no test files]
?   	github.com/rfjakob/gocryptfs/v2/tests/test_helpers	[no test files]
test_helpers: warning: testParentDir "/var/tmp/gocryptfs-test-parent-1001" does not reside on ext4, we will miss failures caused by ino reuse
--- FAIL: TestSetGetRmRegularFile (0.00s)
    xattr_integration_test.go:100: xattr.list /var/tmp/gocryptfs-test-parent-1001/838471562/default-plain/TestSetGetRmRegularFile: operation not supported
--- FAIL: TestSetGetRmFifo (0.00s)
    xattr_integration_test.go:113: creating fifo failed: invalid argument
--- FAIL: TestXattrSetEmpty (0.00s)
    xattr_integration_test.go:146: xattr.LSet /var/tmp/gocryptfs-test-parent-1001/838471562/default-plain/TestXattrSetEmpty1 user.foo: operation not supported
--- FAIL: TestXattrList (0.00s)
    xattr_integration_test.go:197: xattr.LSet /var/tmp/gocryptfs-test-parent-1001/838471562/default-plain/TestXattrList user.TestXattrList.01: operation not supported
--- FAIL: TestBase64XattrRead (0.00s)
    xattr_integration_test.go:246: xattr.get /var/tmp/gocryptfs-test-parent-1001/838471562/default-cipher/BaGak7jIoqAZQMlP0N5uCw user.gocryptfs.LB1kHHVrX1OEBdLmj3LTKw: attribute not found
--- FAIL: TestList0000File (0.00s)
    xattr_integration_test.go:294: xattr.list /var/tmp/gocryptfs-test-parent-1001/838471562/default-plain/TestList0000File: operation not supported
--- FAIL: TestSet0200File (0.00s)
    xattr_integration_test.go:307: xattr.LSet /var/tmp/gocryptfs-test-parent-1001/838471562/default-plain/TestSet0200File user.foo: operation not supported
--- FAIL: TestList0000Dir (0.00s)
    xattr_integration_test.go:321: xattr.list /var/tmp/gocryptfs-test-parent-1001/838471562/default-plain/TestList0000Dir: operation not supported
--- FAIL: TestSet0200Dir (0.00s)
    xattr_integration_test.go:335: xattr.LSet /var/tmp/gocryptfs-test-parent-1001/838471562/default-plain/TestSet0200Dir user.foo: operation not supported
--- FAIL: TestAcl (0.00s)
    xattr_integration_test.go:365: xattr.list /var/tmp/gocryptfs-test-parent-1001/838471562/default-plain/TestAcl: operation not supported
--- FAIL: TestSlashInName (0.00s)
    xattr_integration_test.go:379: xattr.list /var/tmp/gocryptfs-test-parent-1001/838471562/default-plain/TestSlashInName: operation not supported
FAIL
FAIL	github.com/rfjakob/gocryptfs/v2/tests/xattr	0.013s
FAIL

Thanks.

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