feat(storage-analyzer): 增加 Linux 支持 - #50
Open
Mizoreww wants to merge 1 commit into
Open
Conversation
扫描、分级、报告、一键删除四条链路全部支持 Linux,保持三平台对称与 纯标准库约束,安全模型不削弱。 三个 Linux 独有的失效模式需要专门处理: - du 对 root 目录静默低估(读不到算作 0 并返回成功),因此新增按文件系统 分别进行的缺口对账,把差额如实报出而不是让报告指错大户 - 硬链接缓存(uv/pnpm/conda/nix)在多次 du 中被重复计数,实测本机超出 实际已用 11.4 GB,现输出 overlap 并要求报告注明实际释放量更小 - XDG Trash 需同时写 files/ 与 info/*.trashinfo 才能被文件管理器还原, 实现为 gio → trash-put → 标准库三级回退;跨文件系统一律拒绝, 不做"复制+删源"式的伪废纸篓 顺带修复一处影响 macOS 的既有缺陷:du 未加 -x 会把外置盘挂载点的体量 算进主盘。 破坏性操作新增五道由代码强制的防线:白名单、准入过滤(needs_sudo / $HOME 本身 / 跨文件系统 / bind mount)、严格子孙检查、mountinfo 挂载 穿透检查、父目录 fd 锚定与 inode 复核。批量请求先全量校验再执行。 实测于 Ubuntu 24.04.4 / ext4 / GNOME。经四轮对抗式代码审查,修复 8 个 High、26 个 Medium/Low;第五轮未能完成,详见 PR 描述。
Mizoreww
force-pushed
the
feat/linux-support
branch
from
July 29, 2026 17:22
576fa77 to
7455363
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
摘要
为
storage-analyzer增加 Linux 支持,并在 Ubuntu 24.04 上完成实测。设计上保持三平台对称、纯标准库、安全模型不削弱。为什么 Linux 不能照抄 macOS 分支
适配过程中撞到三个 Linux 独有的失效模式,它们不是"换个路径表"能解决的:
1.
du对 root 目录是静默低估macOS 上
du读不到会报错,能标denied;Linux 上它把读不到的算作 0 并返回成功。/var/lib/docker动辄几十 GB 却完全不出现在结果里,报告会理直气壮地指错大户。对策是
reconcile_linux():扫完拿df已用减去已归类之和,差额(gap_kb)显式报出来,归入蓝色「系统及其他」并提示用 sudo 核实。2. 硬链接缓存会导致重复计数
du只在单次调用内按 inode 去重。uv / pnpm / conda / nix 用硬链接把同一份内容挂在多处,分次du各算一遍。本机实测合计 548.3 GB 超出实际已用 537 GB —— 差 11.4 GB。不处理的话,报告会向用户承诺一个虚高的可释放空间。现在这种情况会输出
overlap_kb,要求报告注明"实际释放量可能更小",并优先推荐uv cache prune(只清无引用条目)而非uv cache clean。3. 废纸篓不是一个目录,是一份规范
XDG Trash 要求同时写
files/<name>和info/<name>.trashinfo(含原路径与删除时间)。只 move 到files/是残废的废纸篓 —— 文件管理器里点"还原"会失败。实现为三级回退:
gio trash→trash-put→ 纯标准库手写.trashinfo。第三级保证零依赖环境下功能不缺失。跨文件系统一律拒绝:规范要求写到目标盘自己的
.Trash-$UID,而shutil.move跨设备会退化成"复制 + 删源" —— 对一个 97 GB 的目录意味着先复制 97 GB(盘可能都不够),语义上是慢速删除而非"移到废纸篓"。宁可不给按钮,也不做用户以为可逆、实际不可逆的事。其他改动
du -x全局启用(影响 macOS)—— 这是 bug 修复而非 Linux 特供:du默认跨挂载点,若~/data是外置盘挂载点,扫$HOME会把整块外置盘算进主盘占用。macOS 上同样会错。sudo 项只读展示 ——
/var/lib/docker、/var/log、apt/pacman/dnf 缓存等 root 大户照常上灯、照常给命令,但trash_paths一律留空,标题带[需 sudo]。这不是铁律的例外,而是"删除命令只展示、用户自己在终端确认后运行"的标准形态。删除通道对它们结构性关闭(白名单构造时就进不去,不靠文档约定)。兜底下钻 —— 固定目标表列不全各发行版的目录,所以对
$HOME和/var各做一层通用下钻,捞出表外的大目录。与缺口对账互补:对账说"差了多少"(数字),下钻说"差在哪"(路径)。无头降级 —— 无
DISPLAY/WAYLAND_DISPLAY时不弹浏览器,打印ssh -L转发提示;SKILL.md 指示 agent 跳过 Step 3,直接在对话里给完整诊断。服务器上"/分区满了"是高频场景,产出一个要scp才能看的 HTML 文件方向反了。多挂载点 ——
system.disks收录所有本地文件系统(滤掉 tmpfs / squashfs / 网络盘),复用 Windows 分支已有的多盘列表渲染,模板无需改动。实测(Ubuntu 24.04.4 / ext4 / GNOME)
gio trash --list可见 →--restore还原到原路径,闭环通过/dev/shm(不同st_dev)验证,明确拒绝且源目录完好trash-put回退级:屏蔽gio+ 注入假二进制,验证调用契约(带--终止符防路径被当选项)env -u DISPLAY -u WAYLAND_DISPLAY验证,不弹浏览器、ssh -L端口正确rm/ sudo 项试trash全部 403;绿灯正常入废纸篓并还原未覆盖的形态
诚实说明测试边界:
LINUX_SUDO_TARGETS里 pacman / dnf / nix 的路径是按文档写的,未在对应发行版验证gap_kb > 0的分支(root 目录静默低估)未被真实数据触发 —— 这是本次改动中论证最充分但实测最薄弱的一环文件
scripts/scan.pyscan_linux/list_mounts_linux/sudo_targets_linux/uncategorized_linux/reconcile_linux(逐文件系统对账)/system_info_linux/dev_caches_linux/du_kb(判读退出码与 stderr);du_children显式比对st_dev识别挂载点scripts/server.py_trash_linux三级回退、_trash_xdg_stdlib(O_EXCL原子占位)、_xdg_trash_dir、_same_fs_as_trash、_mountpoints/_crosses_mount、_rmtree_at(fd 相对迭代删除)、has_gui、xdg-open分支、按操作类型分档的护栏、stdoutflush=Truereferences/linux.mdSKILL.mdNo space left on device/inode两个触发词;Step 1/2/3 补 Linux 分支;平台状态标注已实测scripts/build_report.pyopen/start/xdg-openassets/report_template.html未改动。代码审查过程
本 PR 经过四轮对抗式代码审查(由 Codex 以独立视角执行),累计发现并修复 8 个 High、26 个 Medium/Low。值得说明的是,其中 3 个 High 是前一轮修复本身引入的新缺陷:
_trash_windows()被编辑破坏(Windows 废纸篓崩溃);护栏对破坏性操作放宽到$HOME外;并发废纸篓静默覆盖文件;对账混用文件系统rp == HOME可使rmtree抹除整个家目录 —— 修复第 1 轮时引入第 4 轮的 bind mount 问题源于我在第 3 轮以「
/proc/self/mountinfo解析成本过高」为由驳回了该建议 —— 实测证明解析只需一次split(),该判断是错的,现已采纳。第 5 轮审查未能完成:审查工具连续四次未产出结论(失败模式各异),因此本 PR 最危险的一段代码(
_rmtree_at从递归改为显式栈迭代)仅经过作者自测,未获独立审查。自测覆盖:600/1200 层深目录树(递归版在此崩溃并留下半删状态)、50×20 宽深树的 fd 泄漏检查(零泄漏)、权限受限子目录、fifo/socket/悬空符号链接/设备节点等特殊文件、/etc/passwd未被跟随删除。安全模型的当前状态
破坏性操作(
rm/trash)现有五道独立防线,每道都由代码强制而非文档约定:trash_paths中的 realpath 可进入needs_sudo项、$HOME本身、跨文件系统路径、bind mount 一律排除,且同步从渲染数据中剔除(避免死按钮)$HOME的严格子孙/proc/self/mountinfo逐级校验祖先(st_dev, st_ino),删除全程 fd 相对操作批量请求先全量校验再执行,任一路径非法即整批拒绝且不做任何删除。