# Release 0.4 第2周:修复 Nextcloud 桌面客户端中的 Windows 错误
Source: Dev.to
转向新的挑战
在为 OpenCTI 提交我的 pull request 后,我想在 Release 0.4 的后半段尝试一些不同的东西。我决定探索 Nextcloud 桌面客户端(GitHub),这是一款被全球数百万人使用的流行开源文件同步工具。
Nextcloud 允许用户在设备之间同步文件,同时保持对其数据的控制。桌面客户端是一个使用 C++ 编写的应用程序,深度集成了 Windows、macOS 和 Linux。这对我来说是一次显著的舒适区外的尝试,因为我的大部分经验都是在 JavaScript,而不是 C++。
我发现的 Bug
在浏览 Nextcloud 的 issue 时,我看到了 Issue #9197:
https://github.com/nextcloud/desktop/issues/9197
从用户的角度来看,问题很直接:Windows 上的自定义文件夹图标在每次 Nextcloud 同步文件时都会被重置。
在 Windows 上,用户可以通过 右键 → 属性 → 自定义 → 更改图标 来设置文件夹的自定义图标。很多人使用此功能来直观地组织文件。但有了这个 bug,每次同步都会擦除这些自定义图标,恢复为默认文件夹图标。
理解根本原因
在修复之前,我需要了解 Windows 如何处理自定义文件夹图标。经过一些研究,我了解到 Windows 使用两样东西:
- 文件夹内部的隐藏
desktop.ini文件,其中包含图标路径 - 文件夹上设置的
FILE_ATTRIBUTE_SYSTEM标志
这两者必须同时存在,才能显示自定义图标。如果缺少其中任何一个,Windows 将显示默认图标。
随后,我在 Nextcloud 代码库中寻找可能导致该属性丢失的地方。相关代码位于:
src/libsync/vfs/cfapi/cfapiwrapper.cpp
该文件处理 Windows Cloud Files API (CFAPI),Nextcloud 用它来实现虚拟文件支持。我发现,在同步操作期间,代码会将文件属性设置为默认值(FILE_ATTRIBUTE_NORMAL 或 FILE_ATTRIBUTE_DIRECTORY),而没有保留已有的属性,如 FILE_ATTRIBUTE_SYSTEM。
我的修复
解决方案是先读取当前文件属性,然后在更新时保留任何已有的标志。我在 cfapiwrapper.cpp 中修改了三个函数。
1. updatePlaceholderState()
添加了读取并保留现有属性的代码:
// Preserve existing file attributes (especially FILE_ATTRIBUTE_SYSTEM for custom folder icons)
const auto currentAttributes = GetFileAttributesW(reinterpret_cast(path.utf16()));
if (currentAttributes != INVALID_FILE_ATTRIBUTES) {
metadata.BasicInfo.FileAttributes = currentAttributes;
}
2. createPlaceholderInfo()
修改为在设置默认值之前检查现有属性:
const auto currentAttributes = GetFileAttributesW(reinterpret_cast(path.utf16()));
if (currentAttributes != INVALID_FILE_ATTRIBUTES) {
cloudEntry.FsMetadata.BasicInfo.FileAttributes = currentAttributes;
} else {
cloudEntry.FsMetadata.BasicInfo.FileAttributes = fileInfo.isDir() ? FILE_ATTRIBUTE_DIRECTORY : FILE_ATTRIBUTE_NORMAL;
}
3. 批量占位符创建(同样在 updatePlaceholderState() 中)
对批量占位符创建函数应用了相同的保留逻辑。
我遇到的挑战
- 在本地构建项目很困难。 Nextcloud Desktop 依赖复杂,包括 Qt 6 和 KDE 库。在 Windows 上搭建构建环境颇具挑战。
- 理解 CFAPI。 Windows Cloud Files API 对我而言是全新领域,我花时间阅读 Microsoft 文档以掌握其行为。
- 在庞大的 C++ 代码库中导航。 代码文件数百个,抽象层次复杂,找到合适的修改位置需要耐心和细致的追踪。
当前状态
我已经完成修复,并根据对代码库的分析确认代码更改是正确的。更改已准备好提交 pull request。
已更改文件
src/libsync/vfs/cfapi/cfapiwrapper.cpp
Issue 参考
https://github.com/nextcloud/desktop/issues/9197
我的收获
- 了解 Windows 文件属性的底层工作方式,尤其是
FILE_ATTRIBUTE_SYSTEM。 - 了解 Cloud Files API (CFAPI) 如何与同步引擎集成。
- 学会在大型陌生的 C++ 代码库中导航和理解。
- 在修改文件时保留系统状态的重要性。
展望
- 提交一个干净的 pull request 并附上完整文档。
- 响应维护者的代码审查反馈。
- 努力让修复合并。
结论
第 2 周把我推入了 C++ 和 Windows 系统编程的陌生领域。虽然过程充满挑战,但我对桌面同步应用的内部工作原理有了更深入的了解。结合第 1 周对 OpenCTI 的贡献,我觉得自己在开源之路上取得了实质性进展。在最终的博客文章中,我会分享这两项贡献的结果,并回顾整个 Release 0.4 的学习体会。