Skip to content

mount: Ensure a hard link count > 0 for all files#21784

Merged
MichaelEischer merged 4 commits into
restic:masterfrom
jtru:fuse-mount-hardlink-count
May 14, 2026
Merged

mount: Ensure a hard link count > 0 for all files#21784
MichaelEischer merged 4 commits into
restic:masterfrom
jtru:fuse-mount-hardlink-count

Conversation

@jtru

@jtru jtru commented Apr 19, 2026

Copy link
Copy Markdown
Contributor

When using restic mount to serve a repository via a POSIX host's file system, all files backed up from Windows systems will show up on the mounting host with a (hard)link count of 0.

While this is not a problem in general and most programs do not even register this strange value, some others (such as Samba's smbd(8)) will go the extra mile and check a file's stat() results for various properties (such as a positive non-zero link count), and refuse to operate if any of the reported values appear off.

Since other inode properties absent from non-POSIX backup sources are also "faked up" (e.g., the inode number) during mount and work fine in general, the chances of this change to be in any way harmful are probably rather slim.

What does this PR change? What problem does it solve?

This makes it possible to serve up a restic mount-provided repository via the Samba project's smbd. Without it, accessing a regular file backed up from a Windows source host will cause the smb client to croak with the NT status equivalent of ENOENT.

To work around this with this patch, the fuse layer will ensure a minimal link count of 1 for all files it presents to the mounting host.

Was the change previously discussed in an issue or on the forum?

No, merely on IRC.

Checklist

  • I have added tests for all code changes, see writing tests
  • I have added documentation for relevant changes (in the manual).
  • There's a new file in changelog/unreleased/ that describes the changes for our users (see template).
  • I'm done! This pull request is ready for review.

When using `restic mount` to serve a repository via a POSIX host's file
system, all files backed up from Windows systems will show up on the
mounting host with a (hard)link count of 0.

While this is not a problem in general and most programs do not even
register this strange value, some others (such as Samba's smbd(8)) will
go the extra mile and check a file's stat() results for various
properties (such as a positive non-zero link count), and refuse to
operate if any of the reported values appear off.

Since other inode properties absent from non-POSIX backup sources are
also "faked up" (e.g., the inode number) during mount and work fine in
general, the chances of this change to be in any way harmful are
probably rather slim.
@jtru

jtru commented Apr 19, 2026

Copy link
Copy Markdown
Contributor Author

I was asked on IRC to elaborate on the setup that made me find this problem, so here goes.

Below is restic 0.18.1 having mounted a repository at /tmp/tmpsmb with the mount --time-template '2006-01-02T15_04_05Z07_00' --allow-other --no-default-permissions flags specified on my Linux host, with stat(1) displaying file metadata as reported from data backed up from a Windows 10 host's NTFS-formatted C:\ drive:

root@foex-test01:/tmp/tmpsmb/snapshots/2026-04-12T20_08_02+02_00/C/Users/Johannes/Downloads/Rufus# ls -l
total 80
-rw-rw-rw- 0 root root 81579 Oct 18  2025 rufus.log
root@foex-test01:/tmp/tmpsmb/snapshots/2026-04-12T20_08_02+02_00/C/Users/Johannes/Downloads/Rufus# stat rufus.log 
  File: rufus.log
  Size: 81579           Blocks: 160        IO Block: 512    regular file
Device: 0,56    Inode: 879487326304452967  Links: 0
Access: (0666/-rw-rw-rw-)  Uid: (    0/    root)   Gid: (    0/    root)
Access: 2025-10-18 18:20:10.060522300 +0000
Modify: 2025-10-18 18:20:10.060522300 +0000
Change: 2025-10-18 18:20:10.060522300 +0000
 Birth: -

The crucial part is the Links: 0 data right after the (faked up, since Windows does not have those) Inode: number.

When sharing the contents of /tmp/tmpsmb/ via Samba's smbd it (and potentially other software) will claim this file does not exist when trying to serve it to any authorized client, due to the 0-valued link count. The problem manifests like this over smbclient:

smb: \> cd snapshots\2026-04-12T20_08_02+02_00\C\Users\Johannes\Downloads\Rufus\
smb: \snapshots\2026-04-12T20_08_02+02_00\C\Users\Johannes\Downloads\Rufus\> ls
  .                                   D        0  Sun Sep 14 14:11:44 2025
  ..                                  D        0  Sat Apr 11 14:44:48 2026
  rufus.log                                81579  Sat Oct 18 20:20:10 2025

                0 blocks of size 1024. 0 blocks available
smb: \snapshots\2026-04-12T20_08_02+02_00\C\Users\Johannes\Downloads\Rufus\> get rufus.log 
NT_STATUS_OBJECT_NAME_NOT_FOUND opening remote file \snapshots\2026-04-12T20_08_02+02_00\C\Users\Johannes\Downloads\Rufus\rufus.log

With the patch from this PR applied on top of current master and using it to mount the repo, the result from stat(2) changes, and the same repository/snapshot looks like this instead:

root@foex-test01:/tmp/tmpsmb/snapshots/2026-04-12T20_08_02+02_00/C/Users/Johannes/Downloads/Rufus# ls -l
total 80
-rw-rw-rw- 1 root root 81579 Oct 18  2025 rufus.log
root@foex-test01:/tmp/tmpsmb/snapshots/2026-04-12T20_08_02+02_00/C/Users/Johannes/Downloads/Rufus# stat rufus.log 
  File: rufus.log
  Size: 81579           Blocks: 160        IO Block: 512    regular file
Device: 0,56    Inode: 879487326304452967  Links: 1
Access: (0666/-rw-rw-rw-)  Uid: (    0/    root)   Gid: (    0/    root)
Access: 2025-10-18 18:20:10.060522300 +0000
Modify: 2025-10-18 18:20:10.060522300 +0000
Change: 2025-10-18 18:20:10.060522300 +0000
 Birth: -

This change alone fixes smbd's odd behavior (and potentially other software) that cannot or is unwilling to deal with a link count of 0.

Since a link count of 0 would normally indicate a deleted file (which probably should not be observable on a POSIX system outside of Linux' /proc/ for fds pointing towards open file that have been unlinked in their containing file system), I think it would be a good idea to change the mimimum link count of files indicated by the fuse mount to be at least 1.

@MichaelEischer MichaelEischer left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

LGTM. Thanks a lot for finding this. After reading through the PR description twice, I'm very sure that this is finally the fix for #2034 and #4382 .

I've added a basic test (AI coded) to prevent regressing this in the future and a short changelog entry that explains this without going too much into technical details although that's surprisingly tricky here. Please take a look.

@MichaelEischer MichaelEischer self-assigned this May 13, 2026

@clrossel clrossel 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.

I would prefer updating the comment in ‎internal/fuse/file.go as noted.

Comment thread internal/fuse/file.go Outdated
Comment thread changelog/unreleased/pull-21784 Outdated
@MichaelEischer MichaelEischer force-pushed the fuse-mount-hardlink-count branch from a7d36d6 to 4547fd7 Compare May 14, 2026 09:18
@jtru

jtru commented May 14, 2026

Copy link
Copy Markdown
Contributor Author

Changes (including the test) look great - I'd be very happy if this fix were merged this way :)

@MichaelEischer MichaelEischer enabled auto-merge May 14, 2026 09:19
@MichaelEischer MichaelEischer merged commit bf14a94 into restic:master May 14, 2026
11 checks passed
@jtru jtru deleted the fuse-mount-hardlink-count branch May 14, 2026 09:42
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