如何使用 dd 复制具有特定开头和结尾的磁盘的三个分区?

如何使用 dd 复制具有特定开头和结尾的磁盘的三个分区?

使用该fdisk -l命令我得到以下答案:

   Device Boot      Start         End      Blocks   Id  System
/dev/sda1   *        2048    28266495    14132224   27  Hidden NTFS WinRE
/dev/sda2        28268544    28473343      102400    7  HPFS/NTFS/exFAT
/dev/sda3        28473344   132552703    52039680    7  HPFS/NTFS/exFAT
/dev/sda4   *   132556798   625141759   246292481    5  Extended
/dev/sda5       193996800   198092799     2048000   82  Linux swap / Solaris
/dev/sda6       234960896   625141759   195090432    7  HPFS/NTFS/exFAT
/dev/sda7       198094848   234950316    18427734+  83  Linux
/dev/sda8       132556800   183756018    25599609+  83  Linux

我想使用该dd命令将磁盘的前三个分区复制到映像中。所以我安装了一个外部硬盘驱动器,进入其文件夹并输入:

# dd count=$((132552703-2048)) if=/dev/sda of=./newImage.image

但是这个命令将所有 sda 磁盘复制到我的外部硬盘驱动器,而不是仅仅复制到 sda3 分区末尾。

如何使用dd创建一个从 sda1 开头开始并在 sda3 结尾结束的映像?

答案1

首先,方法如下:


  1. 首先做几乎就像你之前做的那样,但没有减法 - 并在计数上加一。

    dd  count=132552704 </dev/sda >img
    
  2. 接下来在一个进程中打印分区表sed,该进程可以筛选出您要删除的分区。

    • sed将向已打开您的d第二个命令写入一个elete命令fdiskimgsda4 及以上的每个分区的文件。

      fdisk -l img | sed -e'/sda4 /,$id' -e'g;$aw' | fdisk img
      
  3. 没有 3。你就完成了。


其次,原因如下:


  • 部分成功...

    • 我很确定你的命令几乎有效,但我敢打赌它比你想象的要好。

    • 我希望当你这么说的时候复制所有 sda您认为是因为fdisk -l该映像的一个表明所有分区都包含在其中。不过,根据dd您问题中的命令,provided/dev/sda的扇区大小是相当标准的 512 字节(因此与dd的默认块大小相同)那么您应该复制从/dev/sdaonly 的字节 0 到除最后 2k 扇区之外的所有扇区/dev/sda3

  • 关于部门...

    • 您可以在下面看到fdisk输出报告单位。这就是每一个的大小部门报道fdisk称。一个磁盘部门 可能为 4096 字节 - 如果它是最近制造的磁盘并处理高级格式扇区大小 - 否则很难找到未按标准逻辑 512 字节扇区大小分区的磁盘。

    • 就是这样fdiskman页面说:

    • -u,--units[=unit]

      • 列出分区表时,显示大小部门或在气缸默认显示尺寸为部门。为了向后兼容,可以使用该选项而不使用单元参数 - 那么使用默认值。请注意,可选的单位参数不能与-u选项由空格组成,正确的形式例如-u=cylinders
    • 更多相关内容请点击这里

  • 还有一些关于dd...

    • dd 不能 默默地丢失数据。事实上,如果发生短读,dd就是指定的成为非常对此发声:

    • 部分输入块是read()返回小于输入块大小的输入块。部分输出块是用比输出块大小指定的字节少的字节写入的输出块......

    • ...当有最后一个截断块,截断块的数量应写入标准错误...

    • "%u truncated %s\n",<number of truncated blocks>,"record[s]"

  • 阻止输入/输出...

    • 但无论如何,那实际上不能发生在块设备 I/O 上。这就是块设备成为块设备的原因——有一个额外的层(有时是几个)对块设备(而不是字符设备)的缓冲保护。正是这种区别使得 POSIX 能够保证lseek()块设备上存在的文件 - 这是阻塞 I/O 的一个非常基本的原则。
  • 总结...

    • 所以你已经复制了全部您的设备直到您指定的点,但问题是,第一的2k 个扇区/dev/sda将包含其全部的分区表,因此您可以将所述分区表复制到您的映像中,因此fdisk -l您的映像将报告全部的分区/dev/sda,无论这些分区的数据是否实际驻留在该映像文件中。当然,cat如果您愿意,您可以将单独的数据分区单独放入单独的映像文件中 - 但在这种情况下,您会完全丢失分区表。您真正要做的就是删除未复制的分区,并确保复制全部你所做的那些。

第三,我是这样知道的:


  • 这将创建一个4G./img文件充满 NUL。

    </dev/zero >./img \
    dd ibs=8k obs=8kx1b count=1kx1b 
    

    524288+0 records in
    1024+0 records out
    4294967296 bytes (4.3 GB) copied, 3.53287 s, 1.2 GB/s
    
  • 这将分区./img将您的磁盘与前三个分区匹配,但比例为 1/16:

    (set "$((p=0))" 28266495     27 \
          28268544  28473343  2\\n7 \
          28473344 132552703  3\\n7
    while   [ "$#" -ge "$((p+=1))" ]
    do      printf "n\np\n$p\n%.0d\n%d\nt\n%b\n" \
                   "$(($1/16))" "$(($2/16))" "$3"
            shift 3
    done;   echo w
    )| fdisk ./img >/dev/null
    
  • 现在我们可以看看它。

    fdisk -l ./img
    

    Disk ./img: 4 GiB, 4294967296 bytes, 8388608 sectors
    Units: sectors of 1 * 512 = 512 bytes
    Sector size (logical/physical): 512 bytes / 512 bytes
    I/O size (minimum/optimal): 512 bytes / 512 bytes
    Disklabel type: dos
    Disk identifier: 0x5659b81c
    
    Device     Boot   Start     End Sectors   Size Id Type
    ./img1             2048 1766655 1764608 861.6M 27 Hidden NTFS WinRE
    ./img2          1766784 1779583   12800   6.3M  7 HPFS/NTFS/exFAT
    ./img3          1779584 8284543 6504960   3.1G  7 HPFS/NTFS/exFAT
    
  • 我还将在三个分区上放置一些实际的文件系统和文件。

    sudo sh -c ' trap "$1" 0
        cd /tmp; mkdir -p mnt
        for p in "$(losetup --show -Pf "$0")p"*
        do    mkfs.vfat "$p"
              mount "$p" mnt
              echo  "my part# is ${p##*p}" \
                     >./mnt/"part${p##*p}"
              sync; umount mnt
        done' "$PWD/img" 'losetup -D'
    
  • 这是所有结束位置的字节偏移量......

    grep -Ebao '(my[^0-9]*|PART)[123]' <./img
    

    2826272:PART1
    2830336:my part# is 1
    904606240:PART2
    904624640:my part# is 2
    917656608:PART3
    917660672:my part# is 3
    

但是您是否注意到,fdisk在我们使用文件系统格式化分区之前,它非常乐意报告分区的大小?这是因为分区表位于磁盘的最头部 - 它只是一个布局,仅此而已。不需要实际存在任何分区即可进行报告。它们仅在 的前 1M 内逻辑地映射出来./img。手表:

  • 让我们尝试只删除前两个分区./img......

    <./img >./img2 dd count=1779583
    

    1779583+0 records in
    1779583+0 records out
    911146496 bytes (911 MB) copied, 1.84985 s, 493 MB/s
    
  • 我们再来grep一次...

    grep -Ebao '(my[^0-9]*|PART)[123]' <./img2
    

    2826272:PART1
    2830336:my part# is 1
    904606240:PART2
    904624640:my part# is 2
    
  • 并获取fdisk报告...

    fdisk -l ./img2
    

    Disk ./img2: 869 MiB, 911146496 bytes, 1779583 sectors
    Units: sectors of 1 * 512 = 512 bytes
    Sector size (logical/physical): 512 bytes / 512 bytes
    I/O size (minimum/optimal): 512 bytes / 512 bytes
    Disklabel type: dos
    Disk identifier: 0xcbcab4d8
    
    Device     Boot   Start     End Sectors   Size Id Type
    ./img2p1           2048 1766655 1764608 861.6M 27 Hidden NTFS WinRE
    ./img2p2        1766784 1779583   12800   6.3M  7 HPFS/NTFS/exFAT
    ./img2p3        1779584 8284543 6504960   3.1G  7 HPFS/NTFS/exFAT
    

现在这很好奇。fdisk似乎仍然相信有第三个分区扩展到磁盘的 4G,它也似乎相信大小只有 869M!

  • 也许我们应该从分区表中删除第三个分区。

    printf %s\\n d 3 w |
    fdisk ./img2 >/dev/null
    
  • 现在让我们看看是否可以挂载我们复制的分区以及我们的文件是否保持不变......

    sudo sh -c ' trap "$1" 0
        cd /tmp; mkdir -p mnt
        for p in "$(losetup --show -Pf "$0")p"*
        do    mount "$p" mnt
              grep . /dev/null ./mnt/*
              umount mnt
        done' "$PWD/img2" 'losetup -D'
    

    ./mnt/part1:my part# is 1
    ./mnt/part2:my part# is 2
    

显然这并非不可能。

答案2

这是不可能的,因为 dd 只是直接 1 个输入到 1 个输出 - 恢复会受到损害,因为您将 3 个分区合并为一个,而这不是备份,而 dd 仅适用于相同的副本。

你的答案可能是:

dd if=/dev/sda1 of=~/hdadisk1.img; 
dd if=/dev/sda2 of=~/hdadisk2.img
dd if=/dev/sda3 of=~/hdadisk3.img 

(如果需要,可以在脚本中)最后,您可以使用 hdadisk{1,3,3}.img 创建映像,不过将这些映像保存在分区中进行备份是更好的做法。

答案3

dd count=$((132552703-2048))从输入的开头复制 132552703-2048 个 512 字节的块。块大小为fdisk1 kB = 1024 字节。所以你面临三个问题:

  • 您指定的尺寸是您想要的尺寸的一半。
  • 您没有表明您想以偏移量开始复制。
  • 你的减法有一个栅栏错误:它错过了最后一个块——块的数量是(结束块偏移)-(起始块偏移)+ 1。

所以你可以用

dd bs=1k skip=2048 count=$((132552703-2048+1)) if=/dev/sda of=./newImage.image

我认为这会起作用——dd可能会默默地丢失数据,但我认为块设备上的 1kB 块或 Linux 上的常规文件就可以了。但很慢

复制单个分区的最直接方法就是直接复制它。

cat /dev/sda1 >sda1.image
cat /dev/sda2 >sda2.image
cat /dev/sda3 >sda3.image

最好将分区复制到单独的文件中,否则不在文件开头的分区将难以使用。如果您确实希望将三个分区放在同一个文件中,可以将它们连接起来:

cat /dev/sda1 /dev/sda2 /dev/sda3 >newImage.image

答案4

简单快速的答案是:

dd skip=2048 count=132552703 status=progress if=/dev/sda of=./newImage.image

默认情况下,fdisk -l 返回分区大小(以扇区为单位),每个扇区 512 字节

您可以确认在 fdisk 输出中应该显示如下内容:

Disk /dev/sda: 256 GiB, 274877906944 bytes, 536870912 sectors
Disk model: Virtual Disk
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes

dd 还使用 512 字节作为开关“bs”、“cbs”、“ibs”和“obs”的默认值

  bs=BYTES        read and write up to BYTES bytes at a time (default: 512);
                  overrides ibs and obs
  cbs=BYTES       convert BYTES bytes at a time
  conv=CONVS      convert the file as per the comma separated symbol list
  count=N         copy only N input blocks
  ibs=BYTES       read up to BYTES bytes at a time (default: 512)
  if=FILE         read from FILE instead of stdin
  iflag=FLAGS     read as per the comma separated symbol list
  obs=BYTES       write BYTES bytes at a time (default: 512)
  of=FILE         write to FILE instead of stdout
  oflag=FLAGS     write as per the comma separated symbol list
  seek=N          skip N obs-sized blocks at start of output
  skip=N          skip N ibs-sized blocks at start of input
  status=LEVEL    The LEVEL of information to print to stderr;
                  'none' suppresses everything but error messages,
                  'noxfer' suppresses the final transfer statistics,
                  'progress' shows periodic transfer statistics

确认您可以使用 dd 本身创建一个块文件,如下所示:

dd if=/dev/urandom of=测试计数=1

文件大小应为 512 字节

因此,要创建一个分区或一组分区的映像,您所要做的就是从 fdisk 的输出中获取分区或第一个分区开头的扇区数,并将其用作 dd 参数“skip”的值",然后是分区末尾或最后一个分区的扇区数,并将其设置为 dd 参数“count”的值。

如果 fdisk 和 dd 之间存在块大小差异,您始终可以使用参数“bs”在 dd 中指定块大小,以确保 fdisk 输出与 dd 将使用的块大小匹配。

相关内容