群晖桌面是 Web 页面,通过浏览器的 DevTools 可以捕获到点击排序所发出的请求。以下是在 File Station 中点击排序的请求的 Form Data:

offset: 0
limit: 1000
sort_by: "name"
sort_direction: "DESC"
action: "list"
check_dir: true
additional: ["real_path","size","owner","time","perm","type","mount_point_type","description","indexed"]
filetype: "all"
folder_path: "/music"
api: SYNO.FileStation.List
method: list
version: 2

从上可以得到关键信息 api、action 和 sort_direction,这些是排查的重要线索。

SSH 连上群晖,find / -name FileStation 我们可以发现 /usr/local/packages/@appstore/FileStation 。这很明显就是 File Station 应用所在目录。

找到应用所在目录,接下去就可以找 SYNO.FileStation.List 在哪个文件中出现。通过 grep -rn . -e 'SYNO.FileStation.List | more' 可以进行搜索。会发现 ./webapi/SYNO.FileStation.List.so,很明显这就是处理 SYNO.FileStation.List 的模块。

用 IDA 打开 SYNO.FileStation.List.so,查看字符串 sort_direction 的引用情况,可以看到被 FileStation::FileStationShareHandler::WebFMShareList 函数引用,这个函数又调用了 WfmEnum::WfmLibShareEntryListEnum,但 WfmEnum::WfmLibShareEntryListEnum 并不在 SYNO.FileStation.List.so 内。

用 grep 搜素包含 WfmLibShareEntryListEnum 的文件,可以发现 ./lib/libwebfm.so,看名字就知道是它了,继续用 IDA 进行分析。可以看到这样的调用顺序 WfmEnum::WfmLibShareEntryListEnum -> WfmEnum::EntryListSort -> std::list<DIRENTRY_INFO,std::allocator<DIRENTRY_INFO>>::sort<EnumCompare> -> EnumCompare -> EnumCompare::NaturalCmp -> SLIBCUnicodeUTF8StrCmp,最后的 SLIBCUnicodeUTF8StrCmp 并不在 libwebfm.so 内。

用 grep 搜索包含 SLIBCUnicodeUTF8StrCmp 的文件,可以发现 /usr/lib/libsynocore.so.6,也很明显肯定是这里,因为这个函数是个很基础的字符串比较,会被到处用,肯定属于 core。 继续用 IDA 进行分析。 可以看到这样的调用顺序 SLIBCUnicodeUTF8StrCmp -> SLIBCUnicodeIOpenCollator -> ucol_openucol_open 是第三方库 ICU 的函数,我们可以看到传给 ucol_open 的 locale 是个空字符串,根据 ucol_open 的文档说明,如果 locale 是空字符串,则使用 Root Collator,也就是跟你本地 LANG、LC_ALL 设置没有关系。

至此,问题排查结束。结论就是群晖在调用 ucol_open 时使用 Root Collator,而不是根据用户的语言设置来的,所以排序跟语言无关,所以中文不会按拼音排序。


参考:

https://unicode-org.github.io/icu-docs/apidoc/released/icu4c/ucol_8h.html#a4721e4c0a519bb0139a874e191223590

发表评论

电子邮件地址不会被公开。 必填项已用*标注