OpenBSD团队发布rsync实现Openrsync
速览
OpenBSD 团队发布了名为 Openrsync 的项目,这是 rsync 文件同步工具的开源实现。该工具旨在提供高效、安全的文件传输功能,并遵循 OpenBSD 的高安全标准。此举为开发者提供了另一个可靠的 rsync 替代方案,有助于促进开源生态的多样性。
AI 深度解读
Openrsync:OpenBSD 团队打造的 rsync 实现深度解读
背景
openrsync 是由 OpenBSD 团队开发的一个 rsync 实现版本。该项目最初作为 rpki-client(1) 项目的一部分进行编写,旨在为 OpenBSD 提供一个 RPKI(资源公钥基础设施)验证器。该项目的开发得到了 NetNod、IIS.SE、SUNET 和 6connect 的资金支持。
目前,该系统代码已合并至 OpenBSD 的基础系统(base)中。虽然其官方支持的操作系统是 OpenBSD,但它设计为可移植的,能够在其他 UNIX 系统上编译和运行。对于希望贡献代码的开发者,补丁应发送至 [email protected]。该仓库不仅包含 OpenBSD 版本的代码,还包含了一些用于增强可移植性的胶水代码。
openrsync 采用 BSD (ISC) 许可证发布。它在功能上与现代化的 rsync(测试使用 3.1.3 版本,但任何支持协议版本 27 的版本均可)兼容,但仅接受 rsync 命令行参数的一部分。值得注意的是,系统中可以同时安装 openrsync 和标准的 rsync,两者不会发生冲突。
核心内容
文档与安装
openrsync 的权威文档是其手册页。关于协议细节请参阅 rsync(5) 和 rsyncd(5),关于 openrsync 的工具文档请参阅 openrsync(1)。对于希望编写自定义 rsync 实现的开发者,协议手册页提供了所需的全部信息。页面中的“架构”和“算法”部分旨在向开发者介绍源代码,属于非权威性介绍。
在最新的 UNIX 系统上,安装过程非常直接:
- 运行
./configure - 运行
make - 运行
# make install(需要 root 权限)
这将安装 openrsync 工具及其手册页。如果需要卸载,可运行 # make uninstall。
基本用法与交互
openrsync 既可以作为客户端也可以作为服务器运行。
- 作为客户端交互:
% rsync --rsync-path=openrsync src/* dst % openrsync --rsync-path=openrsync src/* dst - 作为服务器交互:
服务器端可以通过
ssh(1)按需执行,或者作为持久化的网络守护进程运行。当通过ssh(1)执行时,服务器端的openrsync通过--server标志与客户端区分开来。
在使用 openrsync 和标准 rsync 交互时,必须使用两者都支持的命令行标志。
rsync 算法原理
rsync 算法的核心由 Andrew Tridgell 和 Paul Mackerras 在《The rsync algorithm》一文中详细描述,并在 Tridgell 的博士论文《Efficient Algorithms for Sorting and Synchronization》中进行了更深入的探讨。
该算法包含两个主要组件:
- 发送方(Sender):管理源文件。
- 接收方(Receiver):管理目标文件。
在命令 openrsync -lrtp remote:foo/bar ~/baz/xyzzy 中,发送方是远程主机,接收方是本机;而在 openrsync -lrtp ~/foo/bar remote:baz/xyzzy 中,情况则相反。
文件列表共享与排序
算法的基础是发送方生成的文件列表,其中包含所有源文件的名称和元数据(如权限模式、修改时间等)。
- 共享:文件列表通过
flist.c在发送方和接收方之间共享。 - 排序:接收方和发送方独立地根据文件名的字典序对条目进行排序。这种排序允许文件列表以无序的方式发送和接收,同时保持“目录优先”的顺序(即先处理目录,再处理其中的文件)。
- 定位:排序后,双方可以通过在排序数组中的位置来引用文件条目。
块交换(Block Exchange)
这是 rsync 算法的核心机制,实现在 blocks.c 中。接收方遍历文件列表,将信息传递给发送方,以请求更新。
不同类型的文件处理方式不同:
- 符号链接:接收方根据文件列表中的元数据直接更新链接目标,无需向发送方请求更新。
- 目录:如果目录不存在则创建,无需向发送方请求更新。
- 常规文件:
- 检查更新:如果文件大小和最后修改时间相同,则视为已更新,无需发送方操作。
- 分块哈希:否则,接收方将文件按固定大小分块。每个块被哈希两次:
- 快速哈希:Adler-32 类型的 4 字节哈希。
- 慢速哈希:MD4 类型的 16 字节哈希。
- 这些哈希实现在
hash.c中。
- 发送哈希:接收方将文件的块哈希发送给发送方。
- 匹配查找:发送方在源文件中扫描,计算每个字段的快速哈希,并在接收方发送的块信息中寻找匹配项。如果找到快速哈希匹配,则进一步计算并检查慢速哈希。匹配逻辑实现在
block.c中。 - 数据传输:
- 如果找到匹配块,发送方首先将匹配点之前的数据作为字节流发送给接收方。
- 随后发送匹配块的标识符(若无更多数据则发送零)。
- 接收方先写入字节流,然后复制指定块的数据。
- 基础情况:如果接收方不存在该文件,则整个文件作为字节流发送。
- 完整性校验:文件传输完成后,对整个文件进行 MD4 哈希校验,成功则继续处理下一个文件。
块大小算法
块大小对协议效率至关重要。
- 通常,块大小是文件总大小的平方根取整。
- 最小块大小为 700 字节。
- 计算公式为
ceil(sqrt(file_size))。 - 出于未知原因,平方根的结果会被向上舍入到最接近的 8 的倍数。
进程架构
每个 openrsync 会话分为运行中的服务器进程和客户端进程。
- 客户端:由用户执行。
% openrsync -rlpt host:path/to/source dest - 服务器:在远程主机上执行。
- 通过
ssh(1)按需执行时,服务器通过--server标志区分。 - 作为守护进程运行时,通过协议特定的方式接收命令行参数。
- 通过
角色判定逻辑:
- 服务器进程通过
--sender标志明确指定为发送方,否则默认为接收方。 - 客户端进程通过命令行参数的本地/远程属性隐式判定角色:
openrsync path/to/source host:destination:客户端是发送方(从本地发往远程)。openrsync host:source path/to/destination:客户端是接收方(从远程收往本地)。
主机规范限制: 客户端命令行中的文件可以有以下本地性规范:
- 本地:
../path/to/source ../another - 远程服务器:
host:path/to/source :path/to/another - 远程守护进程:
rsync://host/module/path ::another
主机规范必须一致:源文件必须全部是本地或全部是同一远程主机上的远程文件。不能混合使用不同的远程源。
关键要点
- 开源与许可:
openrsync是 BSD (ISC) 许可证下的开源实现,代码已合并入 OpenBSD 基础系统。 - 兼容性:兼容支持协议版本 27 的现代 `rs
