纯 MoonBit 的 ISO 9660 光盘映像读写库:卷描述符、目录树、Joliet、Rock Ridge 与镜像生成
| 规范 | 读 | 写 | 独立判据 |
|---|---|---|---|
| ECMA-119(ISO 9660) | 卷描述符链、目录记录、多段文件、路径解析、文件读取 | 名字级别 1/2/3、目录记录、L/M 路径表、块分配 | pycdlib、Linux 内核 isofs、Windows CDFS |
| Joliet | 补充卷描述符、UCS-2 名字(含代理对) | 完整目录树 + UCS-2 路径表 | pycdlib、Windows 挂载 |
| IEEE P1282(SUSP / Rock Ridge) | SP / ER / RR / NM / PX / SL / CE | NM / PX / SL / TF,1.09 与 1.12 两版 | pycdlib |
| El Torito | 启动目录、默认启动项、UEFI section header | 启动记录卷描述符 + 启动目录(BIOS 与 UEFI 双启动),可选 boot info table(--boot-info-table,供 syslinux/isolinux) | pycdlib、mkisofs 约定 |
| ECMA-167(UDF) | UDF 1.02 单分区:Anchor → 描述符序列 → File Set → File Entry → FID | —(只读) | pycdlib 的 UDF 视角 |
moon add LL728/mooniso// 读一张映像
let image = @mooniso.IsoImage::open(bytes)
println(image.volume_id()) // 卷标
for entry in image.walk("/") { // 递归列树
println("{entry.path}\t{entry.size}")
}
let data = image.read_file("/HELLO.TXT") // 取内容(多段、跨扇区、越界拒绝)
// 区间读取:只取大文件的一段,避免整块拷贝
let head = image.read_range("/BIG.BIN", 0, 4096)
// 造一张映像
let builder = @mooniso.IsoBuilder::new()
builder.add_directory("/Docs")
builder.add_file("/Docs/note.md", text)
builder.add_symlink("/link.txt", "/Docs/note.md")
let image_bytes = builder.build() // -> Bytesmoon run examples/roundtrip| 子命令 | 作用 |
|---|---|
| info <iso> | 卷信息与启动信息(卷标、块大小、根目录、Joliet 级别、RR、启动项) |
| ls <iso> [path] | 列一级目录 |
| tree <iso> [path] | 递归列出子树 |
| cat <iso> <path> | 输出文件内容(按 UTF-8 解码) |
| extract <iso> <path> <out> | 落盘单个文件(二进制安全) |
| extract-all <iso> <dir> | 整树导出,跳过符号链接并报数 |
| verify <iso> | 结构体检:目录数、文件数、字节数、问题清单 |
| udf-ls <iso> [path] | 走 UDF 视角列目录 |
| udf-cat <iso> <path> | 走 UDF 视角读文件 |
| create <out.iso> <dir> | 从目录生成映像;--boot --efi --link --level --rr --boot-info-table 可选 |
# BIOS + UEFI 双启动映像,并写入一个 Rock Ridge 符号链接
moon run cmd/main -- create out.iso ./rootfs --boot /boot.bin --efi /efi.img --link /vmlinuz=/boot/vmlinuzmoon test --target wasm-gc # 单元测试
moon test --target js
python tools/fixtures/build_corpus.py # 自建映像(确定性字节)
python tools/fixtures/pycdlib_corpus.py # pycdlib 侧映像与基准清单
python tools/fixtures/udf_corpus.py
python tools/oracle/cli_expectations.py # CLI 输出与期望逐行一致
python tools/oracle/pycdlib_read.py # 读取侧对拍
python tools/oracle/pycdlib_write.py # 写入侧对拍
python tools/oracle/udf_bounds.py # UDF 版本边界:元数据/虚拟/Sparable 分区必须被拒绝
python tools/demo/terminal_cast.py # 终端动画版
pwsh -File tools/demo/narrate.ps1 # 旁白(System.Text→wav,需 Windows)
python tools/demo/official.py # 正式版| 不做 | 依据 |
|---|---|
| UDF 写入 | 写入侧产出 ISO 9660 / Joliet / Rock Ridge;UDF 只提供读取 |
| UDF 2.50 / 2.60 | 这两个版本的文件条目经元数据分区寻址(OSTA UDF 2.50 §2.3.10):去掉该层无法定位 file entry,因此不声明兼容。检测到元数据分区映射即返回 UnsupportedLayout("udf-metadata-partition"),退出码 1 |
| UDF 的 VAT(虚拟分区)、Sparable 分区、扩展文件条目(tag 266) | 多区段写入、可重写介质备用块、UDF 2.00+ 的更长文件条目头;三者都会改变寻址,检测到即返回 UnsupportedLayout,不按普通分区猜读 |
| 单个文件 > 4 GiB | ECMA-167 4/14.9 的 64 位信息长度;本实现按 32 位处理,超出报错而非截断 |
| 多段文件写入、CL/PL 深层目录重定位(写入) | ECMA-119 9.1.6、P1282 §4.1.8/§4.1.9。ECMA-119 9.4 规定目录层级上限 8:超过时 build() 直接报 UnsupportedLayout("iso9660-directory-depth"),不产出表面可读、实则不合规的映像;确需深层路径时用 allow_deep_paths(true) 显式放行 |
| 提取时还原符号链接 | 纯 MoonBit 无 FFI 时宿主无创建符号链接的 API(moonbitlang/x/fs 未提供);extract-all 报告被跳过的链接数量,需要链接语义时挂载后用系统工具复制 |
| zisofs、HFS / HFS+ 混合、FFI 绑定 | 不在 ISO 9660 本体与本项目声明的范围 |
Install
Download zip纯 MoonBit 的 ISO 9660 光盘映像读写库:卷描述符、目录树、Joliet、Rock Ridge 与镜像生成