Skip to content

Add extra p7zip container formats with runtime backend capability probing - #6

Closed
Dai2010 wants to merge 3 commits into
hitmux:mainfrom
Dai2010:feature/sevenzip-create-probe
Closed

Dai2010 wants to merge 3 commits into
hitmux:mainfrom
Dai2010:feature/sevenzip-create-probe

Conversation

@Dai2010

@Dai2010 Dai2010 commented Sep 29, 2026

Copy link
Copy Markdown
Contributor

概要

新增的归档/容器格式交给 p7zip/7-Zip 后端处理,并且在动手之前先向后端确认一次:这个格式它到底能不能写。

本分支两个提交:

  1. Add p7zip support for additional archive and container formats — 格式分派、CLI/TUI 读取路径、文档与测试。
  2. Probe the 7-Zip backend for the formats it can actually create — 修掉 can_create() 里陈旧的硬编码假设。

前置提交 Write test scratch data somewhere every platform provides 与本仓库另一个 PR(TUI 图片预览)共用同一个提交;两个分支都基于当前的 main,先合哪一个都不会冲突。

为什么要探测后端

can_create() 原先硬编码了一份「可写格式」清单,它对应的是 p7zip 17 时代。现在的 7-Zip 已经不再提供 SWFc、lizard、lz5、lz4、zstd 的写支持,于是在这些格式上 hitpag 会先开始压缩、再在半途失败,而报错信息还把原因推给密码。

  • can_create() 保留候选清单,但会先问后端该格式是否真的可写;答案缓存,每个格式只探一次。
  • 探测手段是实际写一个丢弃用的归档,而不是解析 7z i:p7zip 与 7-Zip 那张表的分栏方式不同、列位置还会随 locale 移动,同一个解析器在 p7zip 上会读出垃圾数据。
  • 只有明确的 not implemented / unsupported archive type / unsupported method 才算「不支持」,其他失败一律视为结论不确定并按支持处理。这样某个编解码器只是不接受探测用的载荷时(SWFc 需要真正的 SWF 输入)不会被误判成不可用。
  • error::throw_operation_failed() 只在用户确实提供了密码时才追加「可能是密码错误」的提示;进程启动失败和不支持的格式不再把人引向错误方向。
  • sevenzip_test 的 SWF 用例改为按探测结果决定执行还是跳过,因此 aarch64/p7zip 17.05 与 amd64/7-Zip 26.00 上都能保持绿色。

顺带说明:未 probe 的旧版本 sevenzip_test 在 amd64 上会以 E_NOTIMPL : Not implemented 失败。把未 probe 的分支单独在 amd64 上重编一次,得到完全相同的失败,说明这不是本次工作引入的回归,而是那份硬编码清单的前提已经过期。

验证

两个平台各自完整跑了一遍,构建目录全新,无并发。

aarch64(Android/Termux,clang,p7zip 17.05)

  • ctest 3/3:tui_smoke_test、cmake_ftxui_vendored_test、sevenzip_test
  • sevenzip_test 输出:PASS: gz bz2 xz wim jar ova liz lz5 swf
  • 手工创建:ova、xz、wim、zip、lz4、zstd、liz、lz5 —— 全部成功

x86_64(Ubuntu 26.04,g++ 15.2.0,7-Zip 26.00)

  • ctest 3/3:同上三个测试

  • sevenzip_test 输出:PASS: gz bz2 xz wim jar ova / SKIP optional codec: liz / SKIP optional codec: lz5 / SKIP unsupported creation: swf

  • 手工创建:ova、xz、wim、zip、lz4、zstd —— 成功;liz、lz5、swf —— 被提前拒绝,提示为:

    This format is read-only, needs an extra workflow, or is not supported for creation by the installed 7-Zip backend.

也就是说,两端的行为差异由后端能力决定,而不是平台分支。

说明

  • 不新增 ErrorCode,OPERATION_FAILED 的退出码(7)保持不变。
  • TUI 编辑功能不会回写这些新增格式。
  • 「可写格式取决于本机 7-Zip 构建」已写进 README.md / README_zh.md。

Both test helpers wrote into /opt/hitpag/tmp, a path that only exists on
the machine the suite was written on. Everywhere else that directory is
absent or read-only, so the suite failed before doing any work:

  FAIL: unable to create test directory: Read-only file system
  CMake Error: Unable to (re)create the private pkgRedirects directory:
    /opt/hitpag/tmp/cmake_ftxui_vendored_test/CMakeFiles/pkgRedirects

The C++ helper now asks the operating system for a temp directory:
TMPDIR on Termux, where neither /tmp nor /opt exists, /tmp on Linux and
%TEMP% on Windows, with the current directory as the fallback. The CMake
script takes its directory from TEST_WORK_DIR, which ctest fills in with
the project binary directory.
can_create() hardcoded the set of writable formats, which matched the
p7zip 17 era. Current 7-Zip builds no longer ship SWFc, lizard, lz5,
lz4 or zstd for creation, so compressing to those formats started the
operation and then failed with a message that blamed the password.

- can_create() keeps the candidate list but now asks the installed
  backend whether it can really write the format, probing each one once
  and caching the answer.
- The probe writes a throwaway archive instead of parsing `7z i`: p7zip
  and 7-Zip lay that table out differently and the columns move with
  the locale, so the same parser produced junk on p7zip.
- Only an explicit "not implemented" or "unsupported archive type"
  failure counts as unsupported. Any other failure stays inconclusive
  and is treated as supported, so a codec that merely dislikes the
  probe payload (SWFc needs a real SWF input) is never blocked.
- error::throw_operation_failed() appends the "wrong password?" hint
  only when a password was supplied, so process spawn failures and
  unsupported formats stop sending users down the wrong path.
- sevenzip_test gates its SWF case on the probed capability instead of
  assuming success, which keeps it green on both aarch64/p7zip 17.05
  and amd64/7-Zip 26.00.

@caokai674 caokai674 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

当前有两个高优先级阻塞项:1) 单流提取仍会在子进程成功前截断已有目标文件;2) 无扩展名 tar.xz 仍被 XZ magic 直接归入 ARCHIVE_P7ZIP。另一个结构性问题是本 PR 与 #5 同时新增/重写 process.cpp、sevenzip.cpp、sevenzip_test.cpp 等文件,两者需要整合为一条变更线再合并。

Comment thread src/lib/process.cpp
}

bool run_command_to_file(const std::vector<std::string>& cmd, const std::string& path) {
std::ofstream output(path, std::ios::binary | std::ios::trunc);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1:这里用 std::ios::trunc 立即打开最终目标。子进程随后因损坏输入、错误密码或 codec 失败时,已有文件已经被清空/部分覆盖。请写同目录临时文件,确认 child exit=0、flush/close 成功后再原子替换目标,并覆盖已有文件保留的回归测试。

Comment thread src/lib/file_type.cpp
if (file.gcount() >= 6 && header[0] == (char)0xFD && header[1] == 0x37 && header[2] == 0x7A &&
header[3] == 0x58 && header[4] == 0x5A && header[5] == 0x00) {
return FileType::ARCHIVE_TAR_XZ;
return FileType::ARCHIVE_P7ZIP;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1:XZ magic 直接返回 ARCHIVE_P7ZIP 会让重命名或无后缀的 tar.xz 失去原来的 TAR+XZ 分派。需要区分 standalone xz 与内部为 TAR 的 xz,并加入 signature-only tar.xz 测试。

caokai674 added a commit that referenced this pull request Sep 29, 2026
Consolidate #5/#6 with transactional extraction, backend fallback, runtime capability probing, tar.xz regression coverage, portable tests, and current-main preview guards.

Copy link
Copy Markdown
Member

Superseded by #8, which consolidates the p7zip work, preserves current-main preview guards, fixes transactional extraction and tar.xz dispatch, adds runtime creation capability probing, and passed the integration CI.

@caokai674 caokai674 closed this Sep 29, 2026
@Dai2010
Dai2010 deleted the feature/sevenzip-create-probe branch September 29, 2026 07:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants