2个版本
0.9.1 | 2022年1月10日 |
---|---|
0.9.0 | 2021年10月26日 |
#392 in 压缩
3.5MB
5K SLoC
bitbottle
Bitbottle:一种现代归档格式。
Bitbottle是一种用于归档文件和文件夹集合的数据和文件格式,如"tar"、"zip"和"winrar"。其主要区别特点包括
- 保留所有重要的POSIX属性(所有者 & 组 按名称、权限、创建/修改时间戳、符号链接)。
- 文件内容存储为使用buzhash的数据库中去重块,类似于常见的备份工具。
- 该格式对读者友好:元数据和内容列表在文件内容之前出现,允许提取子集文件时进行最小缓冲。
- 压缩可以按文件或整个归档进行,使用snappy(非常快)或LZMA2(非常紧凑)。
- 加密是内置的:AES-128-GCM或XCHACHA20-POLY1305(*),使用SSH风格的Ed25519密钥或argon2id密码进行认证。
- 容器格式(bottle)易于扩展以支持未来的压缩或加密算法。
(*) 我为这些荒谬的名称道歉。我没有命名这些算法中的任何一个。
从crate安装
cargo install bitbottle
当前状态
从2015年开始写了一些typescript草案,这是一个针对更广泛受众的rust版本。截至2021年10月,基本的工具可以构建归档并展开。虽然我不太可能以向后不兼容的方式更改文件格式,但我保留在达到1.0之前为紧急情况保留权利。
文件格式在docs/format.md中进行了文档化。
到目前为止,有几个用于测试的命令行工具。所有这些工具都响应--help
。
我的意图是将此项目作为库而不是一组CLI工具来使用,但当前的API有点不灵活,在冻结之前需要一些爱护。
bitbottle
"bitbottle"从文件和文件夹列表创建归档。为了使用SSH公钥(测试)和"snappy"压缩加密bitbottle源归档
> ./target/release/bitbottle -v --snappy --pub ./tests/data/test-key.pub -o ./src-test.bb src
Encrypting for robey@togusa (34fd22aae3c59072fd6f48147309eb302ea30f6ae5fc6376f683df3e74485a7c)
drwxrwxr-x robey robey 2021-10-16 16:01:41 src/
-rw-rw-r-- robey robey 12.0K 2021-10-23 12:15:15 src/bottle.rs
-rw-rw-r-- robey robey 9.7K 2021-10-22 16:29:15 src/file_list.rs
[...]
Creating archive: 30 files, 225K bytes
Scanned unique blocks: 30 blocks, 225K bytes
Wrote 85.5K bytes.
unbottle
"unbottle"可以显示归档的内容
> ./target/release/unbottle -v --info ./src-test.bb
Bitbottle encrypted with XCHACHA20_POLY1305, 1 public key (ED25519_NACL_SEALED)
Block size: 1.00M
Encrypted for: robey@togusa (34fd22aae3c59072fd6f48147309eb302ea30f6ae5fc6376f683df3e74485a7c)
ERROR: No key or password provided for encrypted bottle
如果归档加密,则必须使用秘密密钥来解密它。对于ED25519
,这意味着一个SSH私钥
> ./target/release/unbottle -v --info --secret ./tests/data/test-key ./src-test.bb
Decrypting with key: robey@togusa
Bitbottle encrypted with XCHACHA20_POLY1305, 1 public key (ED25519_NACL_SEALED)
Block size: 1.00M
Encrypted for: robey@togusa (34fd22aae3c59072fd6f48147309eb302ea30f6ae5fc6376f683df3e74485a7c)
Bitbottle compressed with SNAPPY
drwxrwxr-x robey robey 2021-10-16 16:01:41 src/
-rw-rw-r-- robey robey 12.0K 2021-10-23 12:15:15 src/bottle.rs
-rw-rw-r-- robey robey 9.7K 2021-10-22 16:29:15 src/file_list.rs
[...]
Bitbottle: 30 files, 30 blocks, 225KB -> 85.5KB (BLAKE3 hash)
它还可以展开归档
> ./target/release/unbottle -v --secret ./tests/data/test-key ./src-test.bb -d /tmp/src-test
Decrypting with key: robey@togusa
Bitbottle encrypted with XCHACHA20_POLY1305, 1 public key (ED25519_NACL_SEALED)
Block size: 1.00M
Encrypted for: robey@togusa (34fd22aae3c59072fd6f48147309eb302ea30f6ae5fc6376f683df3e74485a7c)
Bitbottle compressed with SNAPPY
drwxrwxr-x robey robey 2021-10-16 16:01:41 src/
-rw-rw-r-- robey robey 12.0K 2021-10-23 12:15:15 src/bottle.rs
-rw-rw-r-- robey robey 9.7K 2021-10-22 16:29:15 src/file_list.rs
[...]
Bitbottle: 30 files, 30 blocks, 225KB -> 85.5KB (BLAKE3 hash)
Extracted 30 file(s) (225K bytes) to /tmp/src-test
buzscan
"buzscan" 是 buzhash 块分割算法的 Rust 实现。它主要是一个用于构建 bitbottle 存档所使用的算法的演示和测试工具。
Buzhash 是一种 滚动哈希,它对数据滑动窗口进行哈希计算,向前滚动直到找到指定数量的尾随零。它将这些边界上的文件分割成大致相等的块,并输出每个块的大小及其哈希(通常是 Blake3,但可配置)。这可以被归档器用来识别重复的块。它在寻找大文件中的相同哈希值方面表现良好,即使数据被移动后也是如此。
一些实现,如 borg (C 代码) 使用随机表或伪随机数生成器来映射字节。Buzscan 使用一个确定性表,该表由选择的递归应用 CRC-32 构建而成,这些 CRC-32 具有良好的位分布。
"buzscan" 命令行工具将遍历文件和文件夹列表(递归),构建一组块,寻找重复项,并报告找到的数据的去重大小。因为它对找到的每一项都进行哈希计算,所以非常慢。
> ./target/release/buzscan .
[00:00:01] 935 files, 885 blocks, total disk space: 236M, 154M unique
构建
一些模块显然不是纯 Rust,包括 argonautica 和 rust-lzma。它们需要一些本地包安装
- pkg-config
- liblzma-dev
- libclang(用于 argonautica)
(我希望这些软件包有本地版本!请帮忙!)
cargo build --release
./target/release/bitbottle --help
要运行完整的测试套件,其中包括一些用 Python 编写的集成测试
make test
存档格式
标准文件存档包括
- (可选)一个包含
- (可选)一个包含
- 文件列表,包含
- 一个或多个文件(元数据,块列表)
- 一个或多个数据块
也就是说,存档本身是一个文件列表。文件列表可能被压缩,压缩的数据也可能被加密。如果使用加密,则加密必须是外层。文件列表只是文件和块的计数,然后是每个文件和每个块的单独瓶子。
要构建存档,write_archive
(在 archive.rs 中)接受一个起始路径列表。它递归地扫描每个路径,构建一个包含要包含的每个文件的列表,然后使用 buzhash 将每个文件分割成大致相同大小的块(默认为 1MB)。每个块由其大小和哈希(默认为 Blake3)标识。如果我们看到具有相同大小和哈希的多个块,它们是重复的,我们只需要写每个块一次。
扫描完成后,我们将每个文件的元数据(其“地图”)作为单独的瓶子写入:标题包含其路径、权限、大小以及其整体内容的哈希,以进行额外的验证。文件夹和符号链接也被写入,大小为零,没有哈希,没有块。对于普通文件,瓶子流是组成其内容的块的哈希列表。(如果文件只有一个块,我们跳过此步骤,因为文件的整体哈希也是其唯一块的哈希。)然后为每个扫描的块写入一个单独的瓶子。
要展开存档,expand_archive
执行相反的操作:它读取每个文件的元数据,并使用块哈希列表重新组装文件。
bitbottle 文件的低级格式和瓶子的结构在 docs/format.md 中进行了文档说明。
对于使用 SSH 密钥进行加密,目前仅支持 Ed25519 密钥,并且仅支持 OpenSSH 密钥文件:[OpenSSH 密钥文件格式的技术描述](https://code.lag.net/robey/docs/openssh-keys.md)。
作者
- Robey Pointer <[email protected]> https://mastodon.technology/@robey
许可
Apache 2.0 许可协议,包含在 LICENSE.txt
中。
依赖项
~11–14MB
~241K SLoC