Skip to content

[FUSE API] Hardlink count from st_nlink is not propagated #511

@mhx

Description

@mhx

Bug Report

I believe this is a bug (or missing feature) in the WinFsp FUSE API. It seems that the hardlink count returned from a getattr call isn't propagated to the Windows filesystem layer (i.e. nNumberOfLinks in BY_HANDLE_FILE_INFORMATION always reads 1).

How to Reproduce

Use a filesystem that returns st_nlink > 1 in getattr. Checking with the stat tool I can see that two files share the same inode, but each of them has their link count reported as 1 (even though st_nlink is actually 3):

C:\Users\mhx\git\dwarfs\build-vcpkg\tmp>stat format.sh
  File: format.sh
  Size: 94              Blocks: 4          IO Block: 65536  regular file
Device: 13b1fae8h/330431208d    Inode: 31          Links: 1
Access: (0755/-rwxr-xr-x)  Uid: (197608/     mhx)   Gid: (197121/    None)
Access: 2020-11-24 23:14:05.000000000 +0100
Modify: 2020-11-24 23:14:05.000000000 +0100
Change: 2020-11-24 23:14:05.000000000 +0100
 Birth: -

C:\Users\mhx\git\dwarfs\build-vcpkg\tmp>stat foo\1\fmt.sh
  File: foo\1\fmt.sh
  Size: 94              Blocks: 4          IO Block: 65536  regular file
Device: 13b1fae8h/330431208d    Inode: 31          Links: 1
Access: (0755/-rwxr-xr-x)  Uid: (197608/     mhx)   Gid: (197121/    None)
Access: 2020-11-24 23:14:05.000000000 +0100
Modify: 2020-11-24 23:14:05.000000000 +0100
Change: 2020-11-24 23:14:05.000000000 +0100
 Birth: -

At the same time, logging from the getattr operation shows that st_nlink is returned as 3:

The service dwarfs has been started.
I 19:18:53.286122 op_getattr(/) -> st_nlink = 1
I 19:18:53.295476 op_getattr(/) -> st_nlink = 1
I 19:18:57.275441 op_getattr(/) -> st_nlink = 1
I 19:18:57.284256 op_getattr(/) -> st_nlink = 1
I 19:18:57.292798 op_getattr(/) -> st_nlink = 1
I 19:18:57.305563 op_getattr(/test.py) -> st_nlink = 1
I 19:18:57.316398 op_getattr(/perl-exec.sh) -> st_nlink = 1
I 19:18:57.321562 op_getattr(/format.sh) -> st_nlink = 3
I 19:18:57.327337 op_getattr(/foobar) -> st_nlink = 1
I 19:18:57.330381 op_getattr(/foo) -> st_nlink = 1
I 19:18:57.332785 op_getattr(/foo/bar) -> st_nlink = 1
I 19:18:57.334925 op_getattr(/foo) -> st_nlink = 1
I 19:18:57.337009 op_getattr(/empty) -> st_nlink = 1
I 19:18:57.338977 op_getattr(/dev) -> st_nlink = 1
I 19:18:57.340728 op_getattr(/bench.sh) -> st_nlink = 3
I 19:18:57.349516 op_getattr(/) -> st_nlink = 1
I 19:18:57.351154 op_getattr(/) -> st_nlink = 1
I 19:18:57.362641 op_getattr(/) -> st_nlink = 1
I 19:18:57.364635 op_getattr(/) -> st_nlink = 1
I 19:18:57.371488 op_getattr(/format.sh) -> st_nlink = 3
I 19:18:57.373200 op_getattr(/format.sh) -> st_nlink = 3
I 19:18:57.376306 op_getattr(/format.sh) -> st_nlink = 3
I 19:18:57.377897 op_getattr(/format.sh) -> st_nlink = 3
I 19:18:57.379452 op_getattr(/format.sh) -> st_nlink = 3
I 19:19:00.475283 op_getattr(/) -> st_nlink = 1
I 19:19:00.483435 op_getattr(/) -> st_nlink = 1
I 19:19:00.494293 op_getattr(/) -> st_nlink = 1
I 19:19:00.506619 op_getattr(/test.py) -> st_nlink = 1
I 19:19:00.513854 op_getattr(/perl-exec.sh) -> st_nlink = 1
I 19:19:00.520416 op_getattr(/format.sh) -> st_nlink = 3
I 19:19:00.523694 op_getattr(/foobar) -> st_nlink = 1
I 19:19:00.526209 op_getattr(/foo) -> st_nlink = 1
I 19:19:00.528573 op_getattr(/foo/bar) -> st_nlink = 1
I 19:19:00.530738 op_getattr(/foo) -> st_nlink = 1
I 19:19:00.532787 op_getattr(/empty) -> st_nlink = 1
I 19:19:00.535353 op_getattr(/dev) -> st_nlink = 1
I 19:19:00.537032 op_getattr(/bench.sh) -> st_nlink = 3
I 19:19:00.544552 op_getattr(/) -> st_nlink = 1
I 19:19:00.546592 op_getattr(/) -> st_nlink = 1
I 19:19:00.557711 op_getattr(/) -> st_nlink = 1
I 19:19:00.559188 op_getattr(/) -> st_nlink = 1
I 19:19:00.567073 op_getattr(/foo/1/fmt.sh) -> st_nlink = 3
I 19:19:00.568609 op_getattr(/foo) -> st_nlink = 1
I 19:19:00.570069 op_getattr(/foo/1) -> st_nlink = 1
I 19:19:00.571452 op_getattr(/foo/1/fmt.sh) -> st_nlink = 3
I 19:19:00.573116 op_getattr(/foo/1/fmt.sh) -> st_nlink = 3
I 19:19:00.574943 op_getattr(/foo) -> st_nlink = 1
I 19:19:00.576228 op_getattr(/foo/1) -> st_nlink = 1
I 19:19:00.578614 op_getattr(/foo/1/fmt.sh) -> st_nlink = 3
I 19:19:00.580114 op_getattr(/foo/1/fmt.sh) -> st_nlink = 3

Behaviors

I'd expect stat to report the correct hardlink count.

Environment

  • OS version and build: 10.0.22621
  • WinFsp version and build: 2.0.23075

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions