#mime #media-type #file-tree #load-file

未维护 bin+lib tree_magic

通过遍历文件类型树确定文件的MIME类型

5个版本

使用旧的Rust 2015

0.2.3 2020年2月25日
0.2.2 2020年2月23日
0.2.1 2018年11月21日
0.2.0 2017年4月15日
0.1.1 2017年4月10日

#1456 in 文件系统

Download history 511/week @ 2024-03-13 639/week @ 2024-03-20 734/week @ 2024-03-27 864/week @ 2024-04-03 875/week @ 2024-04-10 641/week @ 2024-04-17 648/week @ 2024-04-24 652/week @ 2024-05-01 474/week @ 2024-05-08 576/week @ 2024-05-15 572/week @ 2024-05-22 589/week @ 2024-05-29 539/week @ 2024-06-05 459/week @ 2024-06-12 570/week @ 2024-06-19 439/week @ 2024-06-26

2,096 monthly downloads
36个crates中使用 (18 直接)

MIT授权

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:程序脚本和配置文件等文本文件可以使用正则表达式(或任何最佳工作方式)进行解析。

  • jsontomlxml等:将给定的文件与模式进行匹配,如果匹配则返回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)。出于安全原因,这可能值得处理。(尽管不是特别重要。)

并行处理

目前这是单线程的。这是一个令人尴尬的并行任务(多个文件、多个类型、每种类型的多个规则...),因此应该有巨大的速度优势。

不要做的事情

文件属性

libmagicfile默认情况下,会打印详细说明文件类型和,对于JPEG图像或ELF文件,大量元数据。这不是tree_magic将支持的,因为它完全是多余的。属性支持最好在单独的crate中处理,该crate可以根据MIME提取可预测的、机器可读的格式。

依赖关系

~4–12MB
~111K SLoC