Bug Report
Not sure whether this is a bug or intended, thus the question: WinFsp's FUSE 2 struct fuse_operations has the getdir and readlink members in a different order than libfuse 2.x has them.
WinFsp, inc/fuse/fuse.h:
struct fuse_operations
{
/* S - supported by WinFsp */
/* S */ int (*getattr)(const char *path, struct fuse_stat *stbuf);
/* S */ int (*getdir)(const char *path, fuse_dirh_t h, fuse_dirfil_t filler);
/* S */ int (*readlink)(const char *path, char *buf, size_t size);
/* S */ int (*mknod)(const char *path, fuse_mode_t mode, fuse_dev_t dev);
libfuse 2.9.9, include/fuse.h:
struct fuse_operations {
int (*getattr) (const char *, struct stat *);
int (*readlink) (const char *, char *, size_t);
/* Deprecated, use readdir() instead */
int (*getdir) (const char *, fuse_dirh_t, fuse_dirfil_t);
int (*mknod) (const char *, mode_t, dev_t);
All the other members are in the same order as in libfuse (and WinFsp's FUSE 3 struct fuse3_operations has no getdir, so there is no such difference there).
For C / C++ file systems that get compiled against WinFsp's header, this does not matter. But it does for language bindings that describe the struct layout themselves, following libfuse: fusepy / mfusepy (Python, ctypes) have getattr, readlink, getdir. With that:
- the binding's
readlink callback ends up in WinFsp's getdir slot. WinFsp only calls getdir if there is no readdir, so nothing crashes and this easily goes unnoticed.
- the binding's
getdir (NULL) ends up in WinFsp's readlink slot, so 0 != f->ops.readlink in fsp_fuse_loop_start is false, has_symlinks stays false and all S_IFLNK files are reported as regular files (no reparse point).
I have proposed to use WinFsp's order in mfusepy for Windows (mxmlnkn/mfusepy#52), so this is not urgent for us - but I wanted to ask:
- Is the different order intended (then the bindings just have to follow it, maybe it could be mentioned in the docs / in the header), or is it an accident from the early days (the header has it that way since 2016)?
- If it is an accident: I guess it can not be changed without breaking the ABI for all existing binaries, so it would rather be something to document?
How to Reproduce
Behaviors
Expected: the symlinks show up as symlinks (reparse points), readlink gets called.
Actual: readlink never gets called (not even the readlink("/") probe when the file system starts), the symlinks show up as regular files (FileAttributes=0, ReparseTag=0 in the WinFsp debug log for the Create of a symlink).
With getdir / readlink swapped in the binding's struct definition, everything works as expected (file symlinks, directory symlinks, dangling symlinks).
Environment
- OS version and build: Windows 11 Pro, 10.0.26200
- WinFsp version and build: 2.1
Bug Report
Not sure whether this is a bug or intended, thus the question: WinFsp's FUSE 2
struct fuse_operationshas thegetdirandreadlinkmembers in a different order than libfuse 2.x has them.WinFsp,
inc/fuse/fuse.h:libfuse 2.9.9,
include/fuse.h:All the other members are in the same order as in libfuse (and WinFsp's FUSE 3
struct fuse3_operationshas nogetdir, so there is no such difference there).For C / C++ file systems that get compiled against WinFsp's header, this does not matter. But it does for language bindings that describe the struct layout themselves, following libfuse: fusepy / mfusepy (Python, ctypes) have
getattr, readlink, getdir. With that:readlinkcallback ends up in WinFsp'sgetdirslot. WinFsp only callsgetdirif there is noreaddir, so nothing crashes and this easily goes unnoticed.getdir(NULL) ends up in WinFsp'sreadlinkslot, so0 != f->ops.readlinkinfsp_fuse_loop_startis false,has_symlinksstays false and allS_IFLNKfiles are reported as regular files (no reparse point).I have proposed to use WinFsp's order in mfusepy for Windows (mxmlnkn/mfusepy#52), so this is not urgent for us - but I wanted to ask:
How to Reproduce
getattr,readdir,readlinkand reportsS_IFLNKfor some path. I found this withborg mount(mount: support Windows using WinFsp (via mfusepy), fixes #2316 borgbackup/borg#10391) on a backup archive containing symlinks.Behaviors
Expected: the symlinks show up as symlinks (reparse points),
readlinkgets called.Actual:
readlinknever gets called (not even thereadlink("/")probe when the file system starts), the symlinks show up as regular files (FileAttributes=0, ReparseTag=0in the WinFsp debug log for theCreateof a symlink).With
getdir/readlinkswapped in the binding's struct definition, everything works as expected (file symlinks, directory symlinks, dangling symlinks).Environment