按顺序、分块复制原始分区,并进行错误恢复

按顺序、分块复制原始分区,并进行错误恢复

通常,如果我想复制原始分区/dev/sdaX(读取时出现 i/o 错误),我只需使用ddrescue <src> <dst>

这里的情况是,我希望能够以较小的块复制此分区(例如,1GB 分区以 10*100MB 的块复制),但不是一次性复制,然后将它们粘合在一起。想象一下,您想将 1GB 分区从复制PC_APC_B,但您只有 100MB 的 USB 记忆棒可用。

从技术上来说这可行吗?ddrescue如果可以,怎么做?

答案1

从技术上来说这是可行的。USB 上的文件系统必须支持稀疏文件,我的方法才能奏效。

ddrescue恢复文件的一部分,请使用-m

-m file
--domain-mapfile=file
将救援范围限制在映射文件中标记为完成的块内file。[…]

来源

您需要准备多个域映射文件,每个文件描述一个救援域、一个块。它们应该一起覆盖整个设备。了解 mapfile 结构。第 0 个域映射文件chunk00.map将是:

# status line is a formality
0 + 1
# the below line describes the chunk
# pos size      status
0     104857600 +

这意味着块从偏移量 0 开始,占用 104857600 个字节。后一个数字被解释为十进制。ddrescue使用十六进制值 ( 0x…) 创建映射文件,但它理解十进制。前导零表示八进制,因此不要使用前导零。

或者,您可以使用-i-s命令行选项指定这些数字;但由于我们需要 PC_A 和 PC_B 上完全相同的数字,因此最好将它们放在可以复制的文件中。如果您在 PC_A 上使用正确的值并将文件复制到 PC_B,那么您将在 PC_B 上使用正确的值。在两个系统上分别使用-i和输入命令-s更容易出错。

104857600 字节是 100兆字节。我没有使用 100000000(100 兆字节),因为我们将使用其中之一-b 512-b 4096取决于源设备的物理扇区大小),并且块应该占用整数个扇区。104857600 是 4096 的倍数(因此也是 512 的倍数),而 100000000 不是。

chunk01.map将:

0 + 1
104857600 104857600 +

chunk02.map

0 + 1
209715200 104857600 +

依此类推。块 N+1 的起始位置是块 N 的起始位置加上块 N 的大小。一般来说,块可能会重叠,但我们不希望它们重叠。

读取第 0 个块:

# on PC_A
ddrescue -b 512 -c 32768 -m chunk00.map /dev/sdaX /mnt/usb_PC_A/chunk00.raw common.map

您需要对每个块执行此操作,您需要chunk01.rawchunk01.mapchunk02.rawchunk02.map等等生成。common.map每次都应该是相同的 mapfile,ddrescuePC_A 上的每次调用都应该更新公共 mapfile。

结果具有非零偏移量的块(即除 之外的所有块chunk00.raw)将是稀疏的。

如果 USB 上的文件系统不支持稀疏文件,那么由于开头有明确的零,每个块都会比前一个块大。最后一个块会和 一样大/dev/sdaX,这违背了目的。一种解决方法是将一个块写入支持稀疏文件的本地文件系统,以某种方式打包(带或不带压缩)并最终在 PC_B 上解压为稀疏文件。如果 USB 上的文件系统支持稀疏文件,那就容易多了。

读取每个块后,您应该将块传输到 PC_B。您需要传输chunk*.raw 其对应的chunk*.map。如果您需要将稀疏块复制到另一个文件系统,请使用cp --sparse=always …。但您不一定需要复制;可以通过直接从 USB 棒读取来构建最终映像。

在传输第 0 个块之前,请确保 PC_B 上的最终映像final.raw为空或不存在。从 USB 传输第 0 个块:

# on PC_B
ddrescue -b 512 -c 32768 -m /mnt/usb_PC_B/chunk00.map /mnt/usb_PC_B/chunk00.raw final.raw

对所有块执行此操作,写入相同的;只需记住每次都final.raw使用正确的即可。这里读取常规文件,我们不希望出现读取错误,因此不需要映射文件。chunk*.mapddrescue

以这种方式传输所有块后,final.rawPC_B 上的传输应该已完成。PC_A 上的文件common.map是相应的映射文件。就好像你这样做了

ddrescue -b 512 -c 32768 /dev/sdaX final.raw common.map

在 PC_A 上,但final.raw现在在 PC_B 上。

笔记:

  • 如果 PC_A 上出现读取错误,则块可能比您预期的要小。请参阅我的这个答案(其中“chunk”的意思是“一个或多个扇区”、“一个片段”,它与我们的chunk不同):

    输入文件最末端的不可读块 [=片段] 不会影响输出文件的整体大小。

    如果我们的最后一个块较小,那么final.rawPC_B 上的块将小于PC_A 上的块。如果您在一次运行中让其写入PC_A 上/dev/sdaX,情况将完全如此。ddrescuefinal.raw

  • 在我的测试中,一个在 内开始/dev/sdaX并超出 结尾的块sdaX会生成足够小的chunk*.raw文件。一个在 结尾之外开始的块sdaX会使ddrescuePC_A 发出抱怨并失败。这意味着您不需要关注 的大小sdaX,您不需要准确定义最后一个块。在构建chunk*.map文件时,您可以每次将起始位置增加所需的大小,直到chunk*.raw由于 的结尾而创建了一些更小的文件sdaX。然后您尝试下ddrescue一个块,Can't start reading at pos … . Input file is only … bytes long.从工具中获取,这样您就会发现整个文件sdX已被读取。common.map应该确认这一点。

相关内容