#path #string #encode #encoded-string #mru

paths-as-strings

paths_as_strings 是一个小型 crate,提供两个公开的 free-functions,用于将 Paths 无歧义且普遍地编码为 UTF-8 字符串,然后再将它们解码回 Paths

2 个版本

0.1.1 2019年2月14日
0.1.0 2019年2月14日

#2291 in 编码


用于 otkeep

MIT 许可证

18KB
160

paths_as_strings

一个Rust crate,用于无歧义且普遍地将 Paths 编码为 UTF-8 字符串。

Rust的paths不总是可以转换为UTF-8字符串,因为它们是操作系统兼容的,Unix和Windows都不使用UTF-8来表示路径。如果你想要将路径转换为字符串形式,例如将其存储在 MRU.txt 文件中,这会引发问题。我编写了这个crate来解决这个问题。

这个crate导出两个函数,encode_path 将路径转换为UTF-8,以及它的逆函数 decode_path,可用于进行逆编码。

用法

use std::borrow::Cow;
use std::path::PathBuf;

fn main() {
    let the_path = PathBuf::from("some/path");

    let encoded: Cow<str> = paths_as_strings::encode_path(&the_path);
    println!("encoded = {:?}", encoded);

    let decoded: PathBuf = paths_as_strings::decode_path(&encoded).unwrap();
    println!("decoded = {:?}", decoded);
}

在(非常、非常)常见的情况下,路径实际上是一个UTF-8字符串,这相当于调用 Path.to_str() 进行编码,以及调用 PathBuf::from() 进行解码。换句话说,它的开销并不比调用你通常会使用的两个方法更高。

在(非常、非常)罕见的情况下,路径不是有效的UTF-8字符串——或者包含控制字符,如 \n ——那么路径将被编码为base64,并在前面添加一个特殊的前缀,表示路径已被编码。

如果编码字符串被篡改,解码可能会失败,因此 decode_path 返回一个 Result<PathBuf, base64::DecodeError>

巧妙之处

巧妙之处在于 decode_path 如何能够识别一个经过base64编码的路径和一个未编码的路径。例如,字符串 'b478dn3hgi' 可能代表一个编码的文件名,也可能是一个实际的合法文件名。因此,必须找到一种方法来在非编码路径的命名空间中区分编码路径。这是通过在编码需要时让 encode_path 返回一个不能是有效文件名的字符串来实现的。

在Windows上,有很多字符不能用于文件名,而且在使用类似于"A:"的驱动器字母语法时,第一个字符只能是A-Z。这个crate采用的方案是在base64编码的路径前加上"::\_"。

在Linux上,这比较困难,因为除了'/'和'\0'之外的所有字符都可以在文件名的任何地方使用,这意味着base64编码所使用的所有字符在真实文件名中也是有效的。然而,POSIX 规范指出/dev/null是一个文件名,而不是一个目录,因此你永远不能有如/dev/null/xyz这样的文件。这个crate采用的方案是在base64编码的路径前加上"/dev/null/b64_"。

运行工具

paths_as_strings包含两个工具程序。

第一个是名为make_awkward_dir,可以通过命令cargo run --example make_awkward_dir运行。它将创建一个名为'awkward'的目录,其中包含所有可能的1字节文件名(Unix)或2字节文件名(Windows)。这对于测试编码/解码是否正常工作很有用。

第二个程序扫描目录以查找无法表示为UTF-8的文件,因此需要进行编码。你可以使用命令cargo run --example path_analyzer运行它。它接受一个参数,即开始扫描的目录,默认为当前工作目录。它将打印出需要编码的所有文件名,并在最后打印总数。例如

Counting paths below /home/phil/repos/paths_as_strings according to encoding needs.

Counting complete. Totals follow:
num_not_encoded = 451, num_encoded = 0

这意味着在该目录下找到的451个路径中,有451个可以直接表示为UTF-8字符串,并且它们都不需要编码。

在我Linux Mint 19系统的整个文件系统上运行时,它打印出

num_not_encoded = 8668563, num_encoded = 3

3 out of 8,668,566 paths needed encoding (and were successfully round-tripped).
This represents 0.000034607800182867614% of the total path count.

我告诉过你这是很少见的。3个无效的文件名都是来自互联网下载的文件,它们不是标准操作系统文件负载的一部分。

依赖关系

~375KB