通常,如果我想复制原始分区/dev/sdaX
(读取时出现 i/o 错误),我只需使用ddrescue <src> <dst>
。
这里的情况是,我希望能够以较小的块复制此分区(例如,1GB 分区以 10*100MB 的块复制),但不是一次性复制,然后将它们粘合在一起。想象一下,您想将 1GB 分区从复制PC_A
到PC_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.raw
从chunk01.map
、chunk02.raw
从chunk02.map
等等生成。common.map
每次都应该是相同的 mapfile,ddrescue
PC_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*.map
ddrescue
以这种方式传输所有块后,final.raw
PC_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.raw
PC_B 上的块将小于PC_A 上的块。如果您在一次运行中让其写入PC_A 上/dev/sdaX
,情况将完全如此。ddrescue
final.raw
在我的测试中,一个在 内开始
/dev/sdaX
并超出 结尾的块sdaX
会生成足够小的chunk*.raw
文件。一个在 结尾之外开始的块sdaX
会使ddrescue
PC_A 发出抱怨并失败。这意味着您不需要关注 的大小sdaX
,您不需要准确定义最后一个块。在构建chunk*.map
文件时,您可以每次将起始位置增加所需的大小,直到chunk*.raw
由于 的结尾而创建了一些更小的文件sdaX
。然后您尝试下ddrescue
一个块,Can't start reading at pos … . Input file is only … bytes long.
从工具中获取,这样您就会发现整个文件sdX
已被读取。common.map
应该确认这一点。