libburn、libisofs 和 libisoburn 这三个核心库

我们来深入分析 libburnlibisofslibisoburn 这三个核心库的实现逻辑、组成部分及其相互关系。

这三个库共同构成了 xorriso 项目的底层引擎,统称为 libburnia 项目。

总体关系概览

首先,用一个简单的比喻来理解它们的关系:

  • libisofs 就像建筑师和施工队。它负责设计大楼的结构(文件系统布局),并准备好所有建筑材料(文件数据)。

  • libburn 就像地基承包商和吊车。它负责在土地上打好地基(初始化光盘),并把建筑材料精确地放置到指定位置(将数据刻录到光盘轨道)。

  • libisoburn 就像总项目经理。它从建筑师那里拿到设计和材料,协调吊车进行作业,确保整个建造过程(从文件到光盘)无缝衔接。它让"造一栋楼的模型(生成ISO文件)"和"直接造一栋真实的楼(直接刻录光盘)"可以使用同一套图纸。

现在,我们分别深入每个库。


1. libburn

核心职责 : 提供对光学介质(CD, DVD, BD)的低级、直接的读写和控制

实现逻辑与组成部分
  1. 设备扫描与识别

    • 实现逻辑 : 扫描系统(如 /dev/sr0, /dev/sg1),识别出光盘驱动器,并查询其能力和状态(如支持的刻录速度、当前介质类型)。

    • 组成部分: 设备枚举模块、SCSI/ATAPI/MMC命令集封装。

  2. 介质处理

    • 实现逻辑: 与驱动器交互,完成对空白光盘的格式化(如BD-R的初始化)、获取介质信息(容量、剩余空间)。

    • 组成部分: 介质状态查询模块、格式化命令模块。

  3. 刻录引擎

    • 实现逻辑 : 这是最核心的部分。它实现了一种 "刻录源" 的概念。刻录源是一个提供连续数据流的对象。libburn 从刻录源读取数据,通过一系列 SCSI/MMC 命令(如 WRITE(10))将数据精确地写入光盘的轨道。

    • 组成部分

      • 写入模式控制: 支持 Track-At-Once (TAO), Session-At-Once (SAO), Disc-At-Once (DAO) 等刻录模式。

      • 数据流管理: 确保数据以恒定的速率供给驱动器,防止缓冲区欠载。

      • 纠错编码: 为 CD 模式生成 CIRC 纠错码,为 DVD/BD 模式生成 ECC 块。

  4. 会话与轨道管理

    • 实现逻辑: 在光盘上创建新的会话(Session)和轨道(Track)。这对于多段刻录至关重要。

    • 组成部分: 会话/轨道创建逻辑、TOC(内容表)读取。

关键抽象
  • struct burn_drive: 代表一个物理或虚拟的光盘驱动器。

  • struct burn_source: 一个提供数据流的抽象对象。这是 libburn 与上层数据生产者(如 libisoburn)的连接点。


2. libisofs

核心职责 : 在内存中构建一个符合 ISO 9660 及其扩展标准的结构,并能够将此结构序列化为一个线性的、符合规范的数据流。

实现逻辑与组成部分
  1. 文件系统节点树

    • 实现逻辑: 在内存中创建一个逻辑目录树,镜像要生成的ISO映像的目录结构。每个节点(文件或目录)都包含其元数据(名称、时间戳、大小)。

    • 组成部分

      • IsoNode: 基类。

      • IsoFile: 代表一个文件,包含指向其数据源(磁盘文件)的链接。

      • IsoDir: 代表一个目录,包含子节点列表。

      • IsoSymlink: 代表符号链接。

  2. Rock Ridge / Joliet / UDF 支持

    • 实现逻辑: 这些是"并行"的文件系统描述,它们共享同一个文件数据,但为目录树提供了不同的元数据视图。

      • Rock Ridge: 使用 ISO 9660 目录记录中的"系统使用"字段来存储类 Unix 的完整元数据(权限、UID、GID、符号链接目标)。

      • Joliet: 在卷中创建一个完全独立的目录树,使用 UCS-2 编码,支持长文件名和 Unicode。

    • 组成部分: 每个扩展都有对应的生成器,在构建映像时,它们会遍历主节点树,生成自己标准的目录记录和路径表。

  3. El Torito 引导记录

    • 实现逻辑 : 将磁盘映像文件(如 boot.img)标记为可引导映像,并在ISO文件系统的根目录创建一个特殊的引导目录,其中包含引导目录。

    • 组成部分: El Torito 规范实现模块。

  4. 空间分配与布局

    • 实现逻辑: 遍历整个节点树,计算每个文件和每个目录记录、路径表的位置和大小。它为每个数据块分配逻辑块地址(LBA)。这个过程类似于为文件系统"排版"。

    • 组成部分: 布局引擎、块分配器。

  5. 映像生成器

    • 实现逻辑 : 这是 libisofs 的最终输出阶段。它根据之前计算好的布局,按顺序"渲染"整个ISO映像:

      1. 写入系统区(引导记录等)。

      2. 写入主卷描述符、 Joliet 卷描述符等。

      3. 写入路径表。

      4. 写入目录记录。

      5. 写入文件数据区。

    • 组成部分: 一个能够按LBA顺序生成数据块的模块。

关键抽象
  • IsoImage: 代表整个ISO映像项目。

  • IsoDataSource: 一个抽象,用于读取文件内容(可以来自磁盘文件、内存缓冲区等)。


3. libisoburn

核心职责桥接 libisofslibburn ,弥合"文件系统对象"和"物理刻录流"之间的概念差距。它实现了 "刻录到文件"和"直接刻录到光盘"的统一抽象

实现逻辑与组成部分
  1. 协调 libisofs 的生成过程

    • 实现逻辑libisoburn 启动 libisofs 的布局过程,获取到整个映像的"蓝图"------即每个部分(卷描述符、路径表、目录、文件数据)在逻辑映像中的位置和大小。
  2. 实现 struct burn_source 接口

    • 实现逻辑 : 这是其最核心的魔法。libisoburn 创建一个自定义的 burn_source 对象。当 libburn 需要数据来刻录时,它会从这个 burn_source 读取。

    • 内部工作 : 当 libburn 请求第 N 到第 N+M 个逻辑扇区的数据时,libisoburnburn_source 会:

      • 根据请求的LBA范围,判断这部分数据对应 libisofs 映像的哪个部分(是卷描述符?是某个目录记录?还是某个文件的一段内容?)。

      • 即时调用 libisofs 的相应生成器 ,在内存中动态生成这块数据,然后返回给 libburn

    • 组成部分 : 一个复杂的 read 回调函数实现,它内部集成了 libisofs 的生成逻辑。

  3. 多路复用与地址转换

    • 实现逻辑 : ISO 9660 映像是一个单一的、连续的数据流。但在多扩展情况下(如 Joliet),同一个文件的数据在映像中只存储一次,但被多个目录树引用。libisoburn 需要管理这种映射,确保当 libburn 请求 Joliet 目录记录的数据时,它能正确生成并返回。
  4. 目标抽象

    • 实现逻辑libisoburn 向上层(如 libxorriso)提供一个统一的 API。无论是创建一个 .iso 文件还是刻录到光盘,上层代码的流程几乎是相同的。

      • 输出到文件libisoburn 会将其 burn_source 连接到一个小型的"文件写入适配器",这个适配器简单地读取整个 burn_source 的数据流并写入磁盘文件。

      • 输出到光盘libisoburn 将其 burn_source 直接传递给 libburn 进行刻录。

    • 组成部分: 目标管理模块。

相互关系与数据流

下图清晰地展示了三个库在直接刻录到光盘时的协作关系:

总结

  • libisofs 知道 "写什么" (What)和 "结构是什么" (Structure)。

  • libburn 知道 "往哪里写" (Where)和 "如何物理地写" (How-Physical)。

  • libisoburn 知道 "如何把'什么'转换成'物理写操作'" (How-Logical)。它通过实现一个 "按需生成"的 burn_source ,使得 libisofs 的复杂、非线性的文件系统构建过程,能够适配 libburn 简单的、线性的、流式的刻录接口。

这种解耦和桥接的设计是 libburnia 栈强大和灵活性的根本原因。