Perl 33:先写临时文件,最后才触碰有效报表
如果 report-file 一开始就以 > 打开已有目标,任何后续解析、写入、关闭错误都可能只留下截断文件。当前流程先把输入完全读完、校验并编码,再在目标同一目录写独占临时文件;print 和 close 都确认成功后才 rename 覆盖目标。只有 rename 返回成功,CLI 才发出 SAVED\n。之前生成的有效目标不会在“输入刚报错”时被打开。
图:临时文件检查完成后替换目标
1 | |
t/32-36-safe-report.t 首先写入 golden/report.txt,再用 invalid.tsv 重试:命令退出 2、无成功回执,旧文件仍逐字节等于金标。另一个反例把目标设置为已存在目录,临时文件可写而 rename 失败;实测 cannot replace report: ...,原先的有效报表和目录都还在,临时文件被清理。向不存在父目录写入则在打开锁文件时拒绝;这些都是不同的失败阶段,不应只测解析错误。
目标路径与输入指向同一现有 inode 时也拒绝,因为把输入变成输出违反日志契约。此实现假设用户给的是可信目录,尚未处理目录替换、恶意符号链接与跨进程非协作写入等安全边界;这些不在“失败保留”的已证范围里。练习:先打开旧目标再造临时文件能否满足“写入失败旧报表不变”?不能,提前截断已不可逆。参照 Perl 5.38.2 pod/perlfunc.pod 的 close/rename 及本机 File::Temp 0.2311 文档;命令与实际三通道见 examples/perl-language/evidence/32-39.md。
补课后的 save_report 还保留主错误:临时文件写入、关闭或 rename 失败后,清理临时文件与关闭锁文件若也失败,只能追加诊断,不能覆盖最早的发布失败原因。t/course-engineering.t 在本机缺少 BSD::Resource 时把文件大小限制注入记为跳过;已有 macOS 复跑证据显示 RLIMIT_FSIZE 会触发最终 flush/close 非零,而不是静默成功。旧报表保护因此按“已运行环境”和“未运行环境”分开记录。









