5个版本
使用旧的Rust 2015
0.2.3 | 2020年2月25日 |
---|---|
0.2.2 |
|
0.2.1 | 2018年11月21日 |
0.2.0 | 2017年4月15日 |
0.1.1 | 2017年4月10日 |
#1456 in 文件系统
2,096 monthly downloads
在36个crates中使用 (18 直接)
66KB
1K SLoC
tree_magic
tree_magic是一个Rust crate,用于确定给定文件或字节流的MIME类型。
请参阅https://docs.rs/tree_magic/中的文档
stable
用户:即使您将其用作库,可能也需要包含cli
功能标志!(在nightly
上已修复)
与libmagic和file(1)使用的典型方法不同,该方法基于子类在树中加载所有文件类型。(例如:application/vnd.openxmlformats-officedocument/wordprocessingml/document
(MS Office 2007)的子类 application/zip
,该子类是 application/octet-stream
的子类)然后,它不是将文件与每种文件类型进行核对,而是可以沿着树向下遍历,并只核对有意义的文件类型。(毕竟,最快的检查是根本不会运行的检查。)
此库还提供了检查文件是否为特定类型的能力,而不需要逐个核对每种文件类型。
还提供了一个简单的命令行客户端tmagic
,它充当file --mime-type
的替代品,不包括字符集信息。
性能
这很快。非常快。
这是在OpenSUSE Tumbleweed上对我下载文件夹的测试(抱歉,找不到一个很好的公开可用的随机文件集)。tmagic
是用cargo build --release
编译的,而file
来自OpenSUSE仓库。这是一个预热运行,这意味着我已经多次运行了这两个程序。系统是双核Intel Core i7 640M,结果是用time
测量的。
程序 | 实数 | 用户 | 系统 |
---|---|---|---|
tmagic 0.2.0 | 0m0.063s | 0m0.052s | 0m0.004s |
file-5.30 --mime-type | 0m0.924s | 0.800s | 0.116s |
导致这种情况的原因有几个。主要是
-
由于图形方法,需要解析的类型更少。
-
首先加载文件的4K,然后传递给所有解析器,而不是不断地从磁盘重新加载。(这样做时,时间大约是 ~0.130s。)
-
在检查特殊类型之前,首先检查最常见类型(如 image/png、image/jpeg、application/zip 等)。
-
所有可以在 lazy_static! 中处理的内容都会被处理。
夜间用户还可以运行 cargo bench
进行一些基准测试。对于相同硬件上的 tree_magic 0.2.0
test from_u8::application_zip ... bench: 17,086 ns/iter (+/- 845)
test from_u8::image_gif ... bench: 5,027 ns/iter (+/- 520)
test from_u8::image_png ... bench: 4,421 ns/iter (+/- 1,795)
test from_u8::text_plain ... bench: 112,578 ns/iter (+/- 11,778)
test match_u8::application_zip ... bench: 222 ns/iter (+/- 144)
test match_u8::image_gif ... bench: 140 ns/iter (+/- 14)
test match_u8::image_png ... bench: 139 ns/iter (+/- 18)
test match_u8::text_plain ... bench: 44 ns/iter (+/- 3)
然而,应该注意的是,FreeDesktop.org 的 magic 文件比 libmagic 使用的 magic 文件少。 (在我的系统上,tree_magic 支持 400 种类型,而 /usr/share/misc/magic
包含 855 个 !:mime
标签。)然而,它解析起来要容易得多,因为它只覆盖了魔数,而没有属性或其他内容。有关修复此问题的计划,请参阅 TODO 部分。
兼容性
这已在 Windows 7 和 OpenSUSE Tumbleweed Linux 上使用 Rust Stable 和 Nightly 进行了测试。
所有 MIME 信息和关系信息都从 https://specifications.freedesktop.org/shared-mime-info-spec/shared-mime-info-spec-latest.html 中描述的共享 MIME 信息数据库加载。如果您认为您的系统上不存在此数据库,请关闭 sys_fdo_magic
功能标志。
这提供了最常见的文件类型,但仍缺少一些重要的类型,如 LibreOffice 或 MS Office 2007+ 支持或 ISO 文件。随着 zip
检查器的添加,预计这将得到改善。
架构
tree_magic
被拆分为不同的 "检查器" 模块。每个检查器处理一组特定的文件类型,仅处理这些类型。例如,basetype
检查器处理 inode/*
和 text/plain
类型,而 fdo_magic
检查器处理具有魔数的任何内容。这里的想法是,我们不必遵循 libmagic
的路线,即拥有一种适合所有文件的通用魔数描述符格式,我们可以专门选择最适合文件格式的检查器。
在库初始化期间,会查询每个检查器支持的类型以及它们之间的父 -> 子关系。在此期间,检查器可以加载任何规则、模式等到内存中。这里的一个大哲学是,检查阶段的时间比初始化阶段的时间宝贵得多。库只初始化一次,库可以在程序的生命周期中检查成千上万的文件。
根据文件类型和关系的列表,构建一个有向图,并将每个节点添加到哈希表中。如果需要,库用户可以直接使用这些节点来查找给定 MIME 的父节点、子节点等。
当需要检查文件与特定 MIME 的一致性(match_*)时,会查询每个检查器以查看它是否支持该类型,如果是,则运行检查器。如果检查器返回 true,则它必须是那种类型。
当需要确定文件的MIME类型时(来自_from_*),库从类型图的all/all
节点开始(或用户指定的任何节点)向下遍历树。如果找到匹配项,它将继续搜索该分支。如果没有找到匹配项,它将检索找到的最深MIME类型。
待办事项
改进fdo-magic检查器
目前,fdo-magic
检查器不处理字节序。它也不处理存储在用户家目录中的魔术文件。
附加检查器
计划为许多类型提供自定义文件检查函数。以下是一些想法
-
zip
:可以进一步通过查看zip的目录列表来确定所有继承自application/zip
的内容。 -
grep
:程序脚本和配置文件等文本文件可以使用正则表达式(或任何最佳工作方式)进行解析。 -
json
、toml
、xml
等:将给定的文件与模式进行匹配,如果匹配则返回true。(此时,潜在的匹配项应该足够少,以至于可以安全地加载整个文件) -
(专用解析器):没有魔术的(二进制或文本)文件可以通过快速且简单的
nom
解析器进行检查,而不是使用libmagic使用的奇怪启发式方法。
要添加其他检查器类型,请添加一个新的导出模块
-
初始化::获取支持() -> Vec<(String)>
-
初始化::获取子类() -> Vec<String, String)>
-
测试::从u8(&[u8], &str) -> bool
-
测试::从filpath(&str, &str) -> 结果<bool, std::io::错误>
然后将这些函数的引用添加到lib.rs
中的CHECKERS lazy_static!。底部条目首先进行搜索。
缓存
从现在起,对于检查器(如basetype的元数据,或json/toml/xml示例)能够缓存文件的内存表示至关重要,这样就不必为每个新类型重新加载和解析。在当前架构中,这相当难以实现。
多种文件类型
有些奇怪的文件是多种文件类型(例如,多语言quines)。出于安全原因,这可能值得处理。(尽管不是特别重要。)
并行处理
目前这是单线程的。这是一个令人尴尬的并行任务(多个文件、多个类型、每种类型的多个规则...),因此应该有巨大的速度优势。
不要做的事情
文件属性
libmagic
和file
默认情况下,会打印详细说明文件类型和,对于JPEG图像或ELF文件,大量元数据。这不是tree_magic
将支持的,因为它完全是多余的。属性支持最好在单独的crate中处理,该crate可以根据MIME提取可预测的、机器可读的格式。
依赖关系
~4–12MB
~111K SLoC