WinFsp passthrough-fuse 深度解析:用 FUSE 接口在 Windows 上实现文件系统直通(Pass-through)

发布时间:2026/9/25 22:39:39
WinFsp passthrough-fuse 深度解析:用 FUSE 接口在 Windows 上实现文件系统直通(Pass-through) 存储驱动开发【免费下载链接】winfspWindows File System Proxy - FUSE for Windows项目地址https://gitcode.com/gh_mirrors/wi/winfsp点击查看免费下载本篇技术指南围绕 WinFsp 仓库中的tst/passthrough-fuse示例展开剖析一个把所有文件系统操作原样转发pass-through给底层文件系统的 FUSE 文件系统它同时是理解 FUSE for Windows 编程模型的最小可运行范本、以及验证多种构建链路Visual Studio / Cygwin GCC / CYGFUSE的样板工程。读完本文你将掌握 passthrough-fuse 的操作覆盖、fh句柄编码、能力协商、命令行参数解析等实现要点并能独立把它当作模板改造成自己的 Windows FUSE 文件系统。一、passthrough-fuse 是什么关联文档 tst/passthrough-fuse/README.md 对它的定位只有一句话Passthrough-fuseis a simple FUSE file system that passes all file system operations to an underlying file system.即这是一个简单 FUSE 文件系统将全部文件系统操作转发给底层文件系统。它本身不管理任何数据只是把 WinFsp 的 FUSE 接口调用映射为对真实目录rootdir的 POSIX 风格操作因此非常适合做 FUSE API 的教学样例和功能验证基准。1.1 仓库中的文件布局文件作用passthrough-fuse.c核心实现全部 FUSE 操作回调与main()passthrough-fuse.sln / passthrough-fuse.vcxprojVisual Studio 工程MakefileCygwin GCC 构建脚本winfsp-fuse/cygfuse两个目标winposix.h / winposix.c面向 Windows 的最小 POSIX 适配层winposix.c 同目录直通所需的 POSIX 文件 API 的 Windows 实现仓库中还有同一主题的姊妹工程passthrough-fuse3面向 FUSE 3 API 的直通实现、passthrough-cppC 版本直接使用 WinFsp 原生接口以及 memfs-fuse内存文件系统。对比阅读可以清晰看出 FUSE 抽象层对文件系统开发的简化作用。二、三种构建方式详解关联文档明确给出了 passthrough-fuse 的三种构建路径下面结合仓库文件逐一展开。2.1 方式一Visual Studiowinfsp.slnREADME 标注为使用winfsp.sln解决方案构建。从 passthrough-fuse.vcxproj 可以看到工程的关键配置预处理器定义FSP_FUSE_USE_STAT_EX启用增强的 stat 结构携带st_flags文件属性位、WIN32、_DEBUG/_CONSOLE等头文件搜索路径$(MSBuildProgramFiles32)\WinFsp\inc\fuse;$(MSBuildProgramFiles32)\WinFsp\inc即链接的是已安装的 WinFsp SDK中随附的 FUSE 兼容头文件与仓库内 inc/fuse 同源链接库winfsp-$(PlatformTarget).libx64 为winfsp-x64.libx86 为winfsp-x86.lib并配合DelayLoadDLLswinfsp-$(PlatformTarget).dll/DelayLoadDLLs延迟加载平台支持工程覆盖Debug/Release × Win32/x64/ARM64六种配置ARM64 输出名为passthrough-fuse-a64源文件同时编译 passthrough-fuse.c 与 winposix.c因此整个实现可以在原生 Windows 上以_WIN64/_WIN32路径编译。2.2 方式二Cygwin GCC WinFsp-FUSEmake winfsp-fuseMakefile 中对应目标如下passthrough-winfsp-fuse: export PKG_CONFIG_PATH$(PWD)/winfsp.install/lib passthrough-winfsp-fuse: passthrough-fuse.c ln -nsf regtool --wow32 get /HKLM/Software/WinFsp/InstallDir | cygpath -au -f - winfsp.install gcc $^ -o $ -g -Wall pkg-config fuse --cflags --libs要点通过regtool --wow32 get /HKLM/Software/WinFsp/InstallDir读取注册表中 WinFsp 的安装目录再用cygpath转成 Cygwin 路径软链接为winfsp.install设置PKG_CONFIG_PATH$(PWD)/winfsp.install/lib后pkg-config fuse会命中 WinFsp 自带的 fuse.pcName: fuse、Version: 2.8Cflags: -I${incdir}Libs: ${implib}其中 implib 指向bin/winfsp-${arch}.dll从而直接链接 WinFsp DLL编译参数为gcc -g -Wall产物名为passthrough-winfsp-fuse。2.3 方式三Cygwin GCC CYGFUSEmake cygfusepassthrough-cygfuse: passthrough-fuse.c gcc $^ -o $ -g -Wall pkg-config fuse --cflags --libs该目标不做任何 WinFsp 特定处理直接使用 Cygwin 环境提供的 FUSE 开发包CYGFUSE其实现位于 opt/cygfuse/fuse/cygfuse.c包含 fuse/fuse3 两套Makefile。此时源码走#else分支#include dirent.h、#include unistd.h并使用标准 POSIX 系统调用。也就是说同一份 passthrough-fuse.c 既可编译成原生 Windows 程序WinFsp FUSE也可编译成 Cygwin 程序CYGFUSE这正是 WinFsp FUSE 兼容 API 设计目标的最好例证。三、核心实现把 FUSE 操作直通到宿主文件系统3.1 私有数据结构与路径拼接passthrough-fuse.c 定义了核心状态typedef struct { const char *rootdir; size_t rootlen; } PTFS;rootdir是被直通的底层目录。所有路径操作的第一步都是把 FUSE 传来的虚拟路径拼接到rootdir之后#define concat_path(ptfs, fn, fp) (sizeof fp (unsigned)snprintf(fp, sizeof fp, %s%s, ptfs-rootdir, fn)) #define ptfs_impl_fullpath(n) \ char full ## n[PATH_MAX * 4]; \ if (!concat_path(((PTFS *)fuse_get_context()-private_data), n, full ## n))\ return -ENAMETOOLONG; \ n full ## n注意两点细节栈上缓冲大小为PATH_MAX * 4Windows 下winposix.h把PATH_MAX定义为 1024winposix.h为 UTF-8 多字节文件名预留了足够空间拼接失败缓冲区溢出时返回-ENAMETOOLONG遵循 FUSE 回调返回负 errno的约定。rootdir和文件系统私有数据通过fuse_main(argc, argv, ptfs_ops, ptfs)的第 4 个参数传入回调内用fuse_get_context()-private_data取回见ptfs_init的返回值passthrough-fuse.c。3.2 fuse_operations 注册表覆盖哪些操作ptfs_ops 是核心它把 FUSE 回调一一映射到 POSIX 调用FUSE 操作底层实现底层系统调用getattrptfs_getattrlstatmkdir/unlink/rmdir/rename同名回调mkdir/unlink/rmdir/renamechmod/chownptfs_chmod/ptfs_chownchmod/lchowntruncate/ftruncateptfs_truncate/ptfs_ftruncatetruncate/ftruncateopen/createptfs_open/ptfs_createopen(path, fi-flags[, mode])read/writeptfs_read/ptfs_writepread/pwrite按 offset 定位release/fsync同名回调close/fsyncstatfsptfs_statfsstatvfssetxattr/getxattr/listxattr/removexattr同名回调lsetxattr/lgetxattr/llistxattr/lremovexattropendir/readdir/releasedir同名回调opendir/readdir(filler)/closedirinitptfs_init能力协商见 3.5fgetattrptfs_fgetattrfstatutimensptfs_utimens由PTFS_UTIMENS宏控制否则退化为utimeutimensat(AT_FDCWD, path, tv, AT_SYMLINK_NOFOLLOW)Windows 扩展getpath/setcrtime/chflagsgetpath/fgetpath/setcrtime/lchflags从 errno.i 等 WinFsp FUSE 实现可见每个回调成功返回0/字节数失败返回-errno错误码最终由 WinFsp 映射为 NTSTATUS。这是编写任何 WinFsp FUSE 文件系统都必须遵守的约定。3.3 文件句柄编码一个fh同时装下 fd 与目录指针passthrough-fuse.c 用一组宏把 64 位fi-fh的最高位当作目录位#define fi_dirbit (0x8000000000000000ULL) #define fi_fh(fi, MASK) ((fi)-fh (MASK)) #define fi_setfh(fi, FH, MASK) ((fi)-fh (intptr_t)(FH) | (MASK)) #define fi_fd(fi) (fi_fh(fi, fi_dirbit) ? \ dirfd((DIR *)(intptr_t)fi_fh(fi, ~fi_dirbit)) : (int)fi_fh(fi, ~fi_dirbit)) #define fi_dirp(fi) ((DIR *)(intptr_t)fi_fh(fi, ~fi_dirbit)) #define fi_setfd(fi, fd) (fi_setfh(fi, fd, 0)) #define fi_setdirp(fi, dirp) (fi_setfh(fi, dirp, fi_dirbit))文件打开时fi_setfd(fi, fd)低 63 位存文件描述符目录打开时fi_setdirp(fi, dirp)最高位置 1、低 63 位存DIR *读取时fi_fd(fi)统一取出 fd对目录句柄fi_fd通过dirfd(dirp)拿到 WinFsp FUSE 需要的目录句柄Windows 下winposix.c的dirfd返回底层CreateFileW得到的 HANDLE 值。这种一字段两用的技巧避免了为文件/目录维护两张句柄映射表是直通型文件系统常见的工程手法。3.4 readdir 直通与 STAT_EX 增强static int ptfs_readdir(const char *path, void *buf, fuse_fill_dir_t filler, fuse_off_t off, struct fuse_file_info *fi) { DIR *dirp fi_dirp(fi); struct dirent *de; rewinddir(dirp); for (;;) { errno 0; if (0 (de readdir(dirp))) break; #if defined(_WIN64) || defined(_WIN32) if (0 ! filler(buf, de-d_name, de-d_stat, 0)) #else if (0 ! filler(buf, de-d_name, 0, 0)) #endif return -ENOMEM; } return -errno; }filler每接收一个目录项即向 WinFsp 缓冲区写入一项若缓冲区满返回非 0回调返回-ENOMEM。Windows 构建下还会把de-d_stat由 winposix.c 的readdir用FindFirstFileW/FindNextFileW填充随目录项传给 FUSE配合FSP_FUSE_CAP_READDIR_PLUS能力减少后续getattr往返。3.5 init 回调与能力协商ptfs_init在挂载初始化时向内核协商增强能力passthrough-fuse.cconn-want | (conn-capable FSP_FUSE_CAP_READDIR_PLUS); conn-want | (conn-capable FSP_FUSE_CAP_STAT_EX); conn-want | (conn-capable FSP_FUSE_CAP_CASE_INSENSITIVE);对应的能力位定义在 inc/fuse/fuse_common.hFSP_FUSE_CAP_READDIR_PLUS(121)、FSP_FUSE_CAP_STAT_EX(123)以及FUSE_CAP_CASE_INSENSITIVE(129)声明文件系统大小写不敏感贴合 Windows 语义。conn-want | conn-capable ...的写法是标准的只请求内核支持的能力协商模式。3.6 Windows 专有扩展getpath / setcrtime / chflags在_WIN64/_WIN32分支下passthrough-fuse 还注册了 WinFsp FUSE 的扩展回调getpathpassthrough-fuse.c根据句柄反查文件的虚拟路径。有fi时用fgetpath(fd)无fi时用getpath(path)再把返回的绝对路径减去ptfs-rootlen前缀还原成挂载点内的虚拟路径若结果为空则返回/。这是 Windows 文件系统支持路径查询如GetFinalPathNameByHandle场景所必需的setcrtimepassthrough-fuse.c设置文件创建时间Windows 特有语义chflagspassthrough-fuse.c仅在定义FSP_FUSE_USE_STAT_EX时注册映射到lchflags对应 Windows 的隐藏/只读/系统/归档属性位见 winposix.c 中MapFileAttributesToFlags/MapFlagsToFileAttributes的双向映射。四、main 入口参数解析、rootdir 与 WinFsp 加载4.1 命令行格式passthrough-fuse.c 定义了用法usage: passthrough-fuse [FUSE options] rootdir mountpointmain()的解析逻辑passthrough-fuse.cif (3 argc - ! argv[argc - 2][0] - ! argv[argc - 1][0]) { ptfs.rootdir realpath(argv[argc - 2], 0); argv[argc - 2] argv[argc - 1]; argc--; }即最后两个位置参数分别是 rootdir被直通的真实目录和 mountpoint挂载点盘符/目录且二者不能以-开头。realpath会把 rootdir 规范化为绝对路径。随后调用fuse_main(argc, argv, ptfs_ops, ptfs)进入 WinFsp FUSE 的主循环。4.2 --UNC / --VolumePrefix配合 WinFsp.Launcher 以服务方式运行Windows 构建下如果 rootdir 尚未确定main()会扫描命令行中的--UNC与--VolumePrefix参数passthrough-fuse.c。其语法为--VolumePrefix\passthrough-fuse\C$\Path解析时把C$还原为盘符C:后再realpath。这样文件系统就可以由 WinFsp.Launcher见 src/launcher/launcher.c以服务方式启动并通过 UNC 共享方式挂载net use z: \\passthrough-fuse\C$\Path也就是说net use的共享名passthrough-fuse就是这里传入的--VolumePrefix前缀。4.3 fuse_main 内部流程fuse_main最终落到 WinFsp FUSE 实现的 fsp_fuse_main_real其执行序列是fsp_fuse_parse_cmdline解析 FUSE 选项与挂载点fuse_main.cfsp_fuse_mount(mountpoint, args)创建 WinFsp 卷并挂载fsp_fuse_new(ch, args, ops, opsize, data)创建 FUSE 会话注册回调表env-daemonize(foreground)按前台/后台模式运行env-set_signal_handlers(f)安装信号处理multithreaded ? fsp_fuse_loop_mt(env, f) : fsp_fuse_loop(env, f)进入事件循环退出时依次fsp_fuse_destroy、fsp_fuse_unmount并返回!!result0 成功、1 失败。选项解析表fuse_main.c定义了 FUSE 标准选项选项含义-h/--help打印帮助-ho仅打印挂载选项帮助-d/-o debug开启调试输出隐含-f前台-f前台运行-s关闭多线程运行-V/--version打印版本五、winposix支撑直通语义的 Windows POSIX 层原生 Windows 没有 POSIX 文件 API而 passthrough-fuse.c 写的却是标准 POSIX 调用。为此仓库提供了 winposix.c约 1050 行其文件头注释明确说明This is a very simple Windows POSIX layer. It handles all the POSIX file APIs required to implement passthrough-fuse in POSIX, however the API handling is rather unsophisticated. Ways to improve it: use the FspPosix* APIs to properly handle file names and security.也就是说它是为支撑 passthrough-fuse 而裁剪的最小 POSIX 适配层并指出可用 WinFsp 的FspPosix*API 进一步完善文件名与安全语义。其主要工作句柄抽象open用CreateFileW返回 HANDLE强转成 int 作为 fdpread/pwrite用OVERLAPPED实现带偏移读写fsync映射FlushFileBufferswinposix.c路径处理uncpath把 POSIX 路径转换为\\?\前缀的 Windows 绝对路径并归一化/与\winposix.cxattr → NTFS EAlsetxattr/lgetxattr/llistxattr/lremovexattr基于NtSetEaFile/NtQueryEaFile实现源码顶部以NTSYSAPI声明了这两个 ntdll 导出函数并做了名称长度≤254、值长度≤0xffff等校验winposix.c时间戳转换用FspPosixFileTimeToUnixTime/FspPosixUnixTimeToFileTime在 Windows FILETIME 与 POSIX timespec 之间转换错误映射maperror把GetLastError()的 Windows 错误码映射为 errno如ERROR_FILE_NOT_FOUND → ENOENT、ERROR_ACCESS_DENIED → EACCES、ERROR_FILE_EXISTS → EEXIST见 winposix.c 起的 switch 表stat 填充fstat/readdir用GetFileInformationByHandle/WIN32_FIND_DATAW填充fuse_statst_mode 固定0777、st_nlink 固定 1size 由 64 位文件大小拼装并在FSP_FUSE_USE_STAT_EX下填充st_flags安全相关chmod与lchown直接返回 0不实现文件安全符合直通但简化的定位。六、运行与验证6.1 直接运行在 Windows 命令行下以 x64 为例passthrough-fuse-x64 C:\real\folder Z:把真实目录C:\real\folder挂载为盘符Z:此后对Z:的一切读写都会落到C:\real\folder。调试运行可加-d -f调试输出 前台运行。通过 WinFsp.Launcher 以服务方式运行并使用 UNC 挂载net use z: \\passthrough-fuse\C$\Path6.2 测试覆盖WinFsp 的测试套件 tst/winfsp-tests/fuse-test.c 等针对 FUSE 兼容层进行系统性测试仓库构建流程appveyor.yml、tools/run-tests.bat也会编译并运行这些示例。passthrough-fuse 同时作为 WinFsp 教程 涉及的样例之一是验证 FUSE 文件系统行为是否符合 Windows 语义的参考载体。七、从 passthrough-fuse 到你自己的文件系统passthrough-fuse 的工程价值在于它是一份操作覆盖最全、逻辑最简单的参考实现学习 FUSE 编程模型对照 inc/fuse/fuse.h 与 inc/fuse/fuse_common.h 中fuse_operations、fuse_file_info含fh、flags、fuse_conn_info的定义结合本示例逐回调理解语义作为新文件系统的起点复制passthrough-fuse.c的结构替换回调中的底层调用即可实现映射型/虚拟型文件系统如仓库中的 memfs-fuse 就是直通→内存的变体验证构建链路三种构建方式VS / WinFsp-FUSE / CYGFUSE可用来验证目标环境的工具链配置其中 CYGFUSE 实现位于 opt/cygfuse/fuse/cygfuse.c了解 WinFsp 专有能力getpath、setcrtime、chflags、READDIR_PLUS、STAT_EX、CASE_INSENSITIVE等扩展展示了 FUSE 抽象如何承载 Windows 特有文件系统语义这些能力在编写面向 Windows 用户的真实文件系统时几乎必不可少。如果你需要 FUSE 3 版本直接对照 passthrough-fuse3 即可看到同一直通逻辑在 fuse3 兼容层下的写法差异——这也是从 FUSE 2 迁移到 FUSE 3 的绝佳对照教材。赞分享存储驱动开发【免费下载链接】winfspWindows File System Proxy - FUSE for Windows项目地址https://gitcode.com/gh_mirrors/wi/winfsp点击查看免费下载相关推荐本文内容总结本文内容总结 这篇文章详细介绍了 s3fs fuse 工具的核心原理、架构设计、关键组件实现以及性能优化策略帮助用户理解如何通过 s3fs fuse 将AWS后端对象存储存储告别跨平台壁垒WinFsp FUSE桥接实现Linux文件系统无缝迁移Windows告别跨平台壁垒WinFsp FUSE桥接实现Linux文件系统无缝迁移Windows 你是否在Windows环境下开发时因Linux特有的文件系统功能如F存储驱动开发从零开始理解s3fs-fuse深入解析FUSE接口实现的核心机制从零开始理解s3fs fuse深入解析FUSE接口实现的核心机制 s3fs fuse是一款基于FUSE用户空间文件系统技术的工具它能够将Amazon S后端对象存储存储创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考