本地与远程行为对照
以下说明针对 bcmr 0.7.1 的本地与远程行为。
目标路径规则
本地复制、上传、下载及传统 SSH 回退通道采用以下同一规则:
| 目标写法 | 行为 |
|---|---|
| 已有目录 | 在目录内保留源文件或目录名。 |
不存在、末尾有 / | 自动创建目录,保留源文件或目录名。 |
| 单个源、不存在的裸目标 | 作为新文件名或目录名。 |
| 多个源 | 要求目标是已有目录,或显式以 / 结尾。 |
| 完整文件路径、父目录缺失 | 自动创建父目录。 |
已有普通文件后加 / | 报错并保留原文件。 |
| dry-run | 使用相同路径解释,不建目录、不删除源文件。 |
bcp report.pdf new/test/ # new/test/report.pdf
bcp report.pdf 'host:~/new/test/' # ~/new/test/report.pdf
bcp 'host:report.pdf' new/test/ # new/test/report.pdf
bcp -r project renamed # renamed/下直接放 project 的内容
bcp -r project new/ # new/project/下放原内容
源目录末尾的 / 不会隐式切换为 rsync 风格的“只复制内容”。源路径的 * 在计算目标前统一展开一次。
已统一的行为
-p在复制内容完成后,按从内到外的顺序恢复根目录、子目录和空目录的普通权限及时间;不会先把目标目录设成只读而阻止写入。- 排除规则同时检查源路径和源目录内的相对路径。匹配父目录会剪枝整个子树,预演、目录创建、文件传输、大小统计和移动清理采用同一选择规则。
- 复制默认跟随文件及目录链接;
--no-deref在本地、上传和下载中保留链接,包括断裂链接。循环或断裂的跟随目标会明确报错;被排除的链接不触发遍历。serve 限定根目录外的目标会被拒绝。 - 移动保留链接本身,与原生重命名相同,不删除链接目标;源链接末尾带
/也遵守这条规则。--no-deref对移动可接受但无需额外指定。 - 已有目标目录按文件合并,叶子文件采用同样的覆盖规则。本地无强制移动使用操作系统的原子“不替换”重命名,保护并发出现的目标。
-f覆盖已有文件时,本地和远程使用同样的确认规则;无人值守明确使用-f -y。拒绝确认会取消操作,移动不会随后清理源文件。dry-run 不请求覆盖许可。- 新的传统 SSH 上传和下载先写临时对象;内容长度、可选校验及属性处理成功后才发布。serve 的上传
-p/-V同样先完成暂存文件的最终检查,避免在属性或校验失败后替换原目标。 - 本地、远程和多目标移动支持
--exclude。清理只删除复制前捕获的选中条目;被排除或后来出现的条目会保留。检测到源文件被改写或替换时会报错并保留数据,必要时给出隔离副本的恢复路径。
有理由保留的差异与边界
这些限制不应通过降低其他通道的保证来“统一”:
| 边界 | 原因与行为 |
|---|---|
| 整棵目录移动的原子性 | 同一文件系统可直接重命名;跨文件系统或主机必须先复制再清理,无法成为一次原子事务。失败时可能留下已完成的目标文件;清理也可能在部分条目移除后失败。 |
| 写入期间的源变化 | 捕获身份与高精度元数据、隔离后复查可保护文件名替换。持有已打开文件描述符且不配合锁的写入者,仍可能在最终检查后修改同一 inode;清理硬链接时,需要在自身重命名/解除链接后重读共享 inode 的 ctime,这个短窗口内保留 mtime 的并发改写也无法与自身变化区分。没有全目录快照或协作锁就不能承诺事务隔离。 |
| 续传和追加 | 它们明确操作已有的部分文件,沿用各自的前缀验证规则,不能同时承诺失败时完整回滚旧内容。普通新传输采用暂存发布。 |
| 属性可表示范围 | 普通权限及时间按平台和后端可表达的精度保存。传统 POSIX 时间工具仅提供秒级时间;所有者、特殊权限位及任意 ACL/xattr 不是跨平台 -p 的承诺。替换已有文件时仍尽力保留其安全元数据,无法可靠保留时拒绝发布。 |
| 源硬链接拓扑 | 原生重命名保留硬链接关系;可移植复制阶段不承诺重建它。这更适合作为明确的归档保真能力,普通复制按每个选中文件传输内容。清理阶段仍正确处理共享 inode 的多个源路径。 |
| 非 UTF-8 远程名称 | 远程清单、下载名称与保留链接的目标字符串使用 UTF-8。选中不可表示的远程条目会明确报错;被排除的名称先剪枝。既有上传路径接口不承诺原始字节名称的无损传输,完整支持需扩展协议与路径接口。 |
| Windows 文件名与链接权限 | Windows 无法表示全部 Unix 文件名,创建链接也受权限限制。拒绝不可安全表示的路径,比自动改名或写出目标目录更可靠。 |
| serve 根目录限制 | 显式 --root 是访问边界,跟随链接不得越界。Unix 文件读写、属性查询和目录创建通过固定的根目录句柄执行;Linux/macOS/FreeBSD 的 LIST 也使用同一个根目录句柄。其他平台保留路径检查,不承诺抵御攻击者并发替换祖先目录的全部竞态。 |
| 传输后端 | 保留远程链接的操作目前通过 SSH 辅助命令及普通负载通道完成,兼容没有新增协议能力的远端。它与 serve 的吞吐、持久化能力并不相同。 |
--sync 的具体可用组合和持久化限制见远程复制说明;无法兑现 fsync 保证的通道会在写入前明确拒绝。
SSH 临时参数、远程中转和 SFTP-only 等属于独立能力建设,见 scp 功能对照。
SFTP 移动以内容哈希和协议提供的属性保护源,无法提供 inode/ctime 身份;SFTP 覆盖与目录持久化的边界见 传输后端。