拓十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

WinFsp 的 Passthrough-FUSE3 文件系统:源码实现与三种构建方式深度解析

WinFsp 的 Passthrough-FUSE3 文件系统:源码实现与三种构建方式深度解析 存储驱动开发【免费下载链接】winfspWindows File System Proxy - FUSE for Windows项目地址https://gitcode.com/gh_mirrors/wi/winfsp点击查看免费下载导读本文以 WinFsp 仓库中的 tst/passthrough-fuse3/README.md 为骨架剖析passthrough-fuse3这一“把全部文件系统操作透传给底层文件系统”的 FUSE3 示例先讲透其源码级实现原理路径拼接、文件句柄编码、能力协商再完整演示 Visual Studio、Cygwin 直连 WinFsp DLL、链接 CYGFUSE3 三种构建方式最后给出命令行挂载与 WinFsp.Launcher 场景下的--VolumePrefix用法。读完你既能看懂 WinFsp-FUSE3 层如何把 FUSE 回调翻译成 Windows 文件系统请求也能直接复现、编译并挂载一个可用的透传文件系统。1. 它是什么一个透传式 FUSE3 文件系统WinFspWindows File System ProxyFUSE for Windows提供了一套让用户态程序以 FUSE API 实现 Windows 文件系统的能力。passthrough-fuse3是仓库中随附的示例之一位于 tst/passthrough-fuse3/其定位非常朴素一个简单的 FUSE3 文件系统把所有文件系统操作透传给某个底层文件系统通常是 NTFS 下的一个真实目录。换句话说用户通过这个文件系统看到的目录树实际就是磁盘上某个真实目录的内容——创建、删除、读写、改名、扩展属性等操作都会被原样转发。它天然是验证 WinFsp-FUSE3 移植层正确性的最小可用样例也是学习 FUSE3 回调接口最直接、最完整的参考实现同一目录下的 tst/memfs-fuse3/ 则是内存版的姊妹示例与之对照可以理解两种截然不同的数据存放策略。原 README 明确指出它可用以下三种工具构建使用 Visual Studiowinfsp.sln使用 Cygwin GCC 并直接链接 WinFsp DLLmake winfsp-fuse3使用 Cygwin GCC 并链接 CYGFUSE3make cygfuse3。下文将分别展开说明每种方式的原理与命令细节。2. 源码级剖析Passthrough 如何被实现2.1 核心状态一个 rootdir 就够整个文件系统只需要记住一件事底层真实目录在哪里。源码用极简的结构体承载typedef struct { const char *rootdir; } PTFS;见 tst/passthrough-fuse3/passthrough-fuse3.c。rootdir在main()中通过realpath()解析得到绝对路径之后所有操作回调都能通过fuse_get_context()-private_data取回该结构体。2.2 路径拼接宏把 FUSE 路径映射到底层路径FUSE 回调收到的path是挂载点内的相对路径如/dir/file.txt而透传实现必须把它拼到rootdir之后才能调用 POSIX 系统调用。源码用一个宏完成拼接 越界检查#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 * 4是为了容纳 Windows 路径中可能出现的宽字符编码膨胀在 Cygwin 环境下尤其必要拼接失败snprintf返回超长时直接返回-ENAMETOOLONG把错误码负值抛回 FUSE 层——FUSE3 的约定就是返回负 errno。2.3 文件句柄编码文件 fd 与目录 DIR* 共用 fh透传实现需要在open/read/write/release等回调之间保持一个打开的文件描述符同时还要在opendir/readdir/releasedir之间保持目录流。FUSE3 的struct fuse_file_info.fh是用户自定义的 64 位值源码用最高位做目录标记区分两类句柄#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))即对文件fh低位直接存放open()返回的 fd对目录fh存放opendir()返回的DIR *指针并置位最高位fi_dirbit用于区分需要 fd 时若句柄是目录则通过dirfd()取出目录对应的 fd用于fstat、ftruncate、fsync等。这种一位区分类型的技巧保证了文件与目录操作可以共用一个fuse_file_info通道无需额外的状态表。2.4 回调全景一张表把透传讲完ptfs_opsstruct fuse_operations是文件系统的菜单源码完整实现了 23 个回调见 tst/passthrough-fuse3/passthrough-fuse3.c回调底层调用说明getattrlstat/fstat有fi时走 fd 路径避免 TOCTOUmkdir/rmdirmkdir/rmdirunlink/renameunlink/renamechmod/chownchmod/lchowntruncatetruncate/ftruncate同样支持 fd 路径open/createopen(path, fi-flags[, mode])透传fi-flags返回值存入fhread/writepread/pwrite按off偏移读写返回实际字节数statfsstatvfs报告底层文件系统的容量信息releaseclose关闭 fdfsyncfsyncsetxattr/getxattr/listxattr/removexattrlsetxattr等透传扩展属性opendir/readdir/releasediropendir/readdirfiller/closedir目录枚举init—能力协商见 2.5utimensutimensat(AT_FDCWD, ..., AT_SYMLINK_NOFOLLOW)时间戳更新每个回调的通用模式是拼接 fullpath → 调用底层系统调用 → 成功返回 0/字节数失败返回-errno。例如ptfs_openstatic int ptfs_open(const char *path, struct fuse_file_info *fi) { ptfs_impl_fullpath(path); int fd; return -1 ! (fd open(path, fi-flags)) ? (fi_setfd(fi, fd), 0) : -errno; }ptfs_readdir值得单独一提在 Windows 构建下_WIN64 || _WIN32它使用FUSE_FILL_DIR_PLUS标志把struct dirent中携带的d_stat一并交给filler从而以一次回调同时返回文件名和属性配合READDIRPLUS能力可显著减少目录枚举时的属性查询次数。2.5 init 回调能力协商ptfs_init展示了 FUSE3 的能力协商机制——文件系统声明希望启用的能力但只请求内核这里是 WinFsp-FUSE3 层已经具备的部分static void *ptfs_init(struct fuse_conn_info *conn, struct fuse_config *conf) { conn-want | (conn-capable FUSE_CAP_READDIRPLUS); #if defined(FSP_FUSE_CAP_CASE_INSENSITIVE) conn-want | (conn-capable FSP_FUSE_CAP_CASE_INSENSITIVE); #endif return fuse_get_context()-private_data; }FUSE_CAP_READDIRPLUS与FSP_FUSE_CAP_CASE_INSENSITIVE均在 inc/fuse3/fuse_common.h 中定义后者即FUSE_CAP_CASE_INSENSITIVE是 WinFsp 对 FUSE 能力的 Windows 化扩展用于向 Windows 文件系统层宣告大小写不敏感语义返回fuse_get_context()-private_data作为用户数据即PTFS指针。2.6 main()参数解析与 Windows 下的 UNC 约定main()的逻辑见 tst/passthrough-fuse3/passthrough-fuse3.c检查命令行最后两个参数是否以-开头若不满足则视为rootdir mountpoint用realpath规范化 rootdir随后把它从参数表中移除剩下纯 FUSE 选项交给fuse_main若未从位置参数拿到 rootdirWindows 构建下则扫描--UNC与--VolumePrefix前缀参数从类似\\passthrough-fuse\C$\Path的形式中提取盘符路径并realpath之两者皆失败则打印用法并退出usage: passthrough-fuse [FUSE options] rootdir mountpoint第 2 步的意图在源码注释中写得很清楚让文件系统可以在WinFsp.Launcher下运行并通过形如net use z: \\passthrough-fuse\C$\Path的命令把文件系统挂载为 Windows 盘符。这里的C$约定被解析为底层真实路径C:\——也就是说用户可以通过 UNC 命名空间直接以 passthrough 视图访问某个真实磁盘目录。3. 三种构建方式详解3.1 方式一Visual Studiowinfsp.sln工程文件 tst/passthrough-fuse3/passthrough-fuse3.sln 提供Debug/Release×x86/x64/ARM64六种配置tst/passthrough-fuse3/passthrough-fuse3.vcxproj 则定义了具体的编译/链接参数其中与 WinFsp 集成相关的关键点头文件搜索路径$(MSBuildProgramFiles32)\WinFsp\inc\fuse3;$(MSBuildProgramFiles32)\WinFsp\inc即使用 WinFsp 安装目录提供的fuse3头声明在 inc/fuse3/fuse.h 等和winfsp头链接库$(MSBuildProgramFiles32)\WinFsp\lib\winfsp-$(PlatformTarget).libx86/x64ARM64 使用winfsp-a64.lib延迟加载DelayLoadDLLs winfsp-$(PlatformTarget).dll/winfsp-a64.dll程序启动时才加载 WinFsp 运行时平台宏x86 配置定义WIN32ARM64 配置产物命名为passthrough-fuse3-a64.exe另外由于 Windows 原生环境没有 POSIX 系统调用工程把 tst/passthrough-fuse3/winposix.c 一并编入由 tst/passthrough-fuse3/winposix.h 提供realpath、pread、pwrite、statvfs、opendir/readdir等 POSIX 符号的 Windows 实现。因此前提是本机已安装 WinFsp含inc与lib目录然后用 Visual Studio 打开winfsp.sln选择对应配置生成即可。这一路径产出的是原生 Windows 可执行文件直接调用winfsp-*.dll中的 FUSE3 实现。3.2 方式二Cygwin GCC 直连 WinFsp DLLmake winfsp-fuse3在 Cygwin 环境中进入 tst/passthrough-fuse3/ 执行make winfsp-fuse3对应的 Makefile 目标见 tst/passthrough-fuse3/Makefile展开后是两条核心命令passthrough-winfsp-fuse3: export PKG_CONFIG_PATH$(PWD)/winfsp.install/lib passthrough-winfsp-fuse3: passthrough-fuse3.c ln -nsf regtool --wow32 get /HKLM/Software/WinFsp/InstallDir | cygpath -au -f - winfsp.install gcc $^ -o $ -g -Wall pkg-config fuse3 --cflags --libs其中regtool --wow32 get /HKLM/Software/WinFsp/InstallDir读取 WinFsp 安装目录注册表键配合cygpath -au -f -转成 Cygwin 绝对路径并软链接为本地winfsp.install通过PKG_CONFIG_PATH指向winfsp.install/lib使pkg-config fuse3能找到 WinFsp 自带的fuse3.pc从而解析出正确的头文件路径与库链接参数编译命令为gcc -g -Wall \pkg-config fuse3 --cflags --libs。也就是说直连 WinFsp DLL意味着 Cygwin 的fuse3头文件、导入库和运行时都来自 WinFsp 安装目录而非独立的 CYGFUSE3 包可执行文件直接与 WinFsp 的 FUSE3 层绑定。3.3 方式三Cygwin GCC 链接 CYGFUSE3make cygfuse3make cygfuse3对应目标passthrough-cygfuse3: passthrough-fuse3.c gcc $^ -o $ -g -Wall pkg-config fuse3 --cflags --libs这里不再设置PKG_CONFIG_PATHpkg-config fuse3解析的是 Cygwin 发行版中的 CYGFUSE3fuse3.pc即cygfuse包参见仓库 opt/cygfuse/fuse3/fuse3.pc.in。CYGFUSE3 是 WinFsp 与 Cygwin 之间的一套胶水库opt/cygfuse/fuse3/cygfuse.c它让 Cygwin 的 FUSE3 应用无需修改即可跑在 WinFsp 之上同时保留 Cygwin POSIX 语义。3.4 三种方式的取舍构建方式编译环境链接对象适用场景Visual StudioWindows MSVCwinfsp-*.lib/.dll原生 Windows 分发产物无 Cygwin 依赖make winfsp-fuse3Cygwin GCCWinFsp 自带fuse3.pc与 DLL喜欢 POSIX 工具链且希望直接对接 WinFspmake cygfuse3Cygwin GCCCYGFUSE3cygfuse 包已有 FUSE3 应用的 Cygwin 移植/测试需要注意winfsp-fuse3目标依赖本机已安装 WinFsp用于读取注册表与头文件/导入库而cygfuse3目标依赖 Cygwin 的fuse3开发包。两种make方式均在 Cygwin 环境运行产物为 Cygwin 可执行文件。4. 运行与挂载从命令行到 WinFsp.Launcher4.1 直接命令行挂载编译产物支持两种启动形态。最直接的方式是位置参数# 把 /mnt/data 的内容通过 passthrough-fuse 暴露在挂载点 /mnt/mirror 下 ./passthrough-fuse /mnt/data /mnt/mirror挂载点参数最终交给fuse_main处理WinFsp-FUSE3 层会把它转换为 Windows 卷挂载。命令行中还可以混入任意 FUSE 选项usage提示为passthrough-fuse [FUSE options] rootdir mountpoint。4.2 配合 WinFsp.Launcher 与 UNC 命名空间若要纳入 WinFsp 的服务式管理WinFsp.Launcher 负责启动与监控文件系统进程应使用--VolumePrefix或等价的--UNC指定 UNC 前缀。源码中解析逻辑支持形如\\passthrough-fuse\C$\Path的语法提取第二个反斜杠后的C$\Path把C$归一化为真实路径C:\其余部分作为子路径。之后即可用 Windows 命令挂载net use z: \\passthrough-fuse\C$\Path这样Z:盘呈现的将是C:\Path目录树的透传视图。这种用法在 doc/WinFsp-Tutorial.asciidoc 等文档中也有对应的工作流介绍挂载后的目录操作全部经由 passthrough 回调落到真实磁盘。5. 底层支撑WinFsp-FUSE3 层如何工作passthrough-fuse3之所以零 Windows 代码源码只包含fuse.h与少量条件编译的 POSIX 头是因为 WinFsp 提供了完整的 FUSE3 兼容层头文件inc/fuse3/fuse.h、inc/fuse3/fuse_common.h、inc/fuse3/fuse_opt.h 定义了与 Linux FUSE3 对齐的 APIfuse_main、fuse_operations、fuse_file_info等实现src/dll/fuse3/fuse3.c 及 src/dll/fuse3/fuse2to3.c 负责把 FUSE3 回调转换为 WinFsp 的原生 FSDK 调用再经由 src/dll/fsop.c 等内核代理模块进入 WinFsp 文件系统驱动src/sys/与 Windows I/O 管理器交互兼容层Windows 原生构建通过winposixtst/passthrough-fuse3/winposix.h补齐 POSIX 系统调用fuse_main被宏改写为WinFspLoad()fuse_main_real(...)确保在 Windows 下也能安全地延迟加载 WinFsp 运行时能力协商FUSE_CAP_READDIRPLUS、FUSE_CAP_CASE_INSENSITIVE即FSP_FUSE_CAP_CASE_INSENSITIVE等能力位在 inc/fuse3/fuse_common.h 中定义由文件系统在init回调里声明。因此从调用链看Windows 应用 → WinFsp FUSE3 层fuse3.c→ WinFsp FSDK/用户态代理 → winfsp.sys 内核驱动 → 真实磁盘。passthrough-fuse3恰好落在链路的最上层是观察整条链路行为的最小观测点。6. 延伸阅读与 memfs-fuse3 及测试的对照内存版对照tst/memfs-fuse3/ 的memfs-fuse3是同样的 FUSE3 工程骨架C 实现g -stdgnu17但数据存于内存而非透传磁盘可对比有状态文件系统与无状态透传在回调组织上的差异FUSE2 版本tst/passthrough-fuse/ 提供 FUSE2 API 的对应实现可对照 FUSE2/FUSE3 的 API 演进回归测试仓库的 tst/winfsp-tests/ 覆盖了大量文件系统语义测试如 tst/winfsp-tests/rdwr-test.c、tst/winfsp-tests/memfs-test.c可用于验证基于 passthrough 构建的文件系统行为是否符合预期构建基础设施仓库根目录的winfsp.sln会聚合这些示例工程README.md 给出了整体构建与安装指引。7. 小结passthrough-fuse3是 WinFsp 生态中最短路径的 FUSE3 参考实现23 个回调、1 个 rootdir、1 张fuse_operations表就把透传语义完整表达。它同时示范了 WinFsp 的多工具链支持——Visual Studio 原生构建、Cygwin 直连 WinFsp DLL、CYGFUSE3 胶水库为不同背景的开发者提供了同一套代码的三种编译入口。无论你是要学习 FUSE3 回调的边界行为还是要为真实项目搭一个目录映射文件系统原型这份 README 连同其源码都是最合适的起点。赞分享存储驱动开发【免费下载链接】winfspWindows File System Proxy - FUSE for Windows项目地址https://gitcode.com/gh_mirrors/wi/winfsp点击查看免费下载相关推荐30分钟上手WinFsp从零实现Passthrough文件系统30分钟上手WinFsp从零实现Passthrough文件系统 你是否曾因Windows文件系统开发的复杂性望而却步面对驱动开发的陡峭学习曲线、内核模式的调存储驱动开发WinFsp 深入解析在 Windows 上用 WinFsp 构建用户态文件系统的完整实践指南WinFsp 深入解析在 Windows 上用 WinFsp 构建用户态文件系统的完整实践指南 WinFspWindows File System Prox存储驱动开发WinFsp深度解析重新定义Windows文件系统开发范式WinFsp深度解析重新定义Windows文件系统开发范式 在当今数据驱动的时代传统的文件系统架构已难以满足多样化的存储需求。想象一下将Git仓库、Red存储驱动开发创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表