从磁盘映像中挂载或提取指定分区

来源:互联网 发布:停止nginx的命令 编辑:程序博客网 时间:2024/06/06 01:14

转自 http://blog.linjian.org/articles/linux-mount-part-image/



  最近在做虚拟机相关的事,需要处理一些磁盘和分区的映像文件。如何从一个磁盘映像中挂载指定的分区到本地 Linux 文件系统呢?理论上说,可以用 dd 把该分区从磁盘映像中提取出来再挂载,不过 mount 提供了针对loop 设备的偏移量参数,方便直接从磁盘映像中挂载指定分区。笔记如下:
  演示用的磁盘映像使用 qemu-img 制作。我们使用原生的 raw 格式,等价于磁盘上的原始数据流,保证它在任何 Linux 系统上都可以直接挂载。使用 Windows PE 工具盘启动该 qemu 虚拟机,创建一系列不同格式的分区并在其中建立几个文件。

  1. root@lj-laptop:/opt/vm# qemu-img create -f raw vmtest.img 5G
  2. root@lj-laptop:/opt/vm# qemu -hda ./vmtest.img -cdrom /dev/cdrom -boot d -m 256M -localtime

  磁盘分区结构如截图:
从磁盘映像中挂载或提取指定分区
  回到宿主系统,使用 fdisk 的 -l、-u 参数查看磁盘映像。其中 -u 表示以扇区为单位显示分区起止位置,方便后续计算。

  1. root@lj-laptop:/opt/vm# fdisk -l -u vmtest.img
  2. You must set cylinders.
  3. You can do this from the extra functions menu.
  4.  
  5. Disk vmtest.img: 0 MB, 0 bytes
  6. 255 heads, 63 sectors/track, 0 cylinders, total 0 sectors
  7. Units = sectors of 1 * 512 = 512 bytes
  8. Disk identifier: 0xbd86bd86
  9.  
  10.      Device Boot      Start         End      Blocks   Id  System
  11. vmtest.img1              63     8193149     4096543+  83  Linux
  12. vmtest.img2         8193150    10249469     1028160    5  Extended
  13. vmtest.img3        10249470    10474379      112455    6  FAT16
  14. vmtest.img5         8193213     8610839      208813+  83  Linux
  15. vmtest.img6         8610903     9028529      208813+  82  Linux swap / Solaris
  16. vmtest.img7         9028593    10249469      610438+   b  W95 FAT32

  这时我们只需要为 mount 添加 offset 参数,指定分区在磁盘映像中的逻辑地址,即可挂载这一分区。注意 offset 的单位是字节,通常一个扇区是 512 字节,因此需要用 fdisk 输出的 Start 乘以 512。以 vmtest.img3 分区为例。

  1. root@lj-laptop:/opt/vm# mount -o loop,offset=$((10249470*512)) vmtest.img ./part/
  2. root@lj-laptop:/opt/vm# ls ./part/
  3. InFAT16.txt
  4. root@lj-laptop:/opt/vm# umount ./part/

  如果有必要,我们可以将特定的分区从硬盘映像中提取出来,方便单独使用。通过 dd 可以完成提取,简便起见使用扇区大小 512 字节作为 bs 参数,这样 skip、count 参数很容易从 fdisk 的输出中计算出来。下面提取 vmtest.img5。

  1. root@lj-laptop:/opt/vm# dd if=vmtest.img of=linux2.img bs=512 skip=8193213 count=$((8610839-8193213+1))
  2. 417627+0 records in
  3. 417627+0 records out
  4. 213825024 bytes (214 MB) copied, 4.67434 s, 45.7 MB/s
  5. root@lj-laptop:/opt/vm# mount -o loop linux2.img ./part/
  6. root@lj-laptop:/opt/vm# ls ./part/
  7. InLinux2.txt  lost+found
  8. root@lj-laptop:/opt/vm# umount ./part/

  到这一步,我们已经实现了从磁盘映像中挂载或提取指定分区。其中 fdisk 帮我们完成了磁盘映像的分析,直接将分区的逻辑地址显示给了我们。现在我们再借机复习一下磁盘分区表的格式,试试手工计算相关地址。这里推荐大家阅读网上这篇《解读 Windows 操作系统分区表的秘密》,其中详解过的概念这里不再赘述,下面的内容权当对这篇文章在 Linux 平台下的补充。
  首先查看磁盘映像的主引导扇区,其中分区表位于 0x1be 开始的 64 字节。

  1. root@lj-laptop:/opt/vm# cat vmtest.img | xxd | head -32
  2. ...
  3. 00001b0: 0000 0000 0000 0000 86bd 86bd 0000 0001  ................
  4. 00001c0: 0100 83fe 7ffd 3f00 0000 3f04 7d00 0000  ......?...?.}...
  5. 00001d0: 41fe 05fe bf7d 7e04 7d00 8060 1f00 0000  A....}~.}..`....
  6. 00001e0: 817e 06fe bf8b fe64 9c00 8e6e 0300 0000  .~.....d...n....
  7. 00001f0: 0000 0000 0000 0000 0000 0000 0000 55aa  ..............U.

  对于 vmtest.img1 和 vmtest.img3 这两个主分区,我们读出它们的起始逻辑地址分别为 0x3f 和 0x9c64fe(注意在分区表中以 Little-endian 存储),换算成十进制与 fdisk 输出的一致。bash 的算术表达式支持十六进制字面值,挂载方式同上。

  1. root@lj-laptop:/opt/vm# mount -o loop,offset=$((0x3f*512)) vmtest.img ./part/
  2. root@lj-laptop:/opt/vm# ls ./part/
  3. InLinux.txt  lost+found
  4. root@lj-laptop:/opt/vm# umount ./part/
  5. root@lj-laptop:/opt/vm# mount -o loop,offset=$((0x9c64fe*512)) vmtest.img ./part/
  6. root@lj-laptop:/opt/vm# ls ./part/
  7. InFAT16.txt
  8. root@lj-laptop:/opt/vm# umount ./part/

  对于扩展分区 vmtest.img2,我们通过 dd 定位到它所指向的第一个逻辑分区 vmtest.img5 前面的卷引导记录,查看逻辑分区的链式分区表。

  1. root@lj-laptop:/opt/vm# dd if=vmtest.img bs=512 skip=$((0x7d047e)) | xxd | head -32
  2. ...
  3. 00001b0: 0000 0000 0000 0000 0000 0000 0000 0001  ................
  4. 00001c0: 41fe 83fe bf17 3f00 0000 5b5f 0600 0000  A.....?...[_....
  5. 00001d0: 8118 05fe bf31 9a5f 0600 9a5f 0600 0000  .....1._..._....
  6. 00001e0: 0000 0000 0000 0000 0000 0000 0000 0000  ................
  7. 00001f0: 0000 0000 0000 0000 0000 0000 0000 55aa  ..............U.

  vmtest.img5 相对于 vmtest.img2 的偏移量为 0x3f,按此地址挂载。

  1. root@lj-laptop:/opt/vm# mount -o loop,offset=$(((0x7d047e+0x3f)*512)) vmtest.img ./part/
  2. root@lj-laptop:/opt/vm# ls ./part/
  3. InLinux2.txt  lost+found
  4. root@lj-laptop:/opt/vm# umount ./part/

  沿着链式分区表的第二条记录(即链表指针)指示的偏移量,我们可以找到第二、第三个逻辑分区(vmtest.img6、vmtest.img7)前面的卷引导记录以及这两个分区的逻辑地址。

  1. root@lj-laptop:/opt/vm# dd if=vmtest.img bs=512 skip=$((0x7d047e+0x65f9a)) | xxd | head -32
  2. ...
  3. 00001b0: 0000 0000 0000 0000 0000 0000 0000 0001  ................
  4. 00001c0: 8118 82fe bf31 3f00 0000 5b5f 0600 0000  .....1?...[_....
  5. 00001d0: 8132 05fe bf7d 34bf 0c00 4ca1 1200 0000  .2...}4...L.....
  6. 00001e0: 0000 0000 0000 0000 0000 0000 0000 0000  ................
  7. 00001f0: 0000 0000 0000 0000 0000 0000 0000 55aa  ..............U.
  8. root@lj-laptop:/opt/vm# dd if=vmtest.img bs=512 skip=$((0x7d047e+0xcbf34)) | xxd | head -32
  9. ...
  10. 00001b0: 0000 0000 0000 0000 0000 0000 0000 0001  ................
  11. 00001c0: 8132 0bfe bf7d 3f00 0000 0da1 1200 0000  .2...}?.........
  12. 00001d0: 0000 0000 0000 0000 0000 0000 0000 0000  ................
  13. 00001e0: 0000 0000 0000 0000 0000 0000 0000 0000  ................
  14. 00001f0: 0000 0000 0000 0000 0000 0000 0000 55aa  ..............U.

  取得了相应的地址,挂载或提取分区当然是轻而易举的。下面挂载了 vmtest.img7、提取了 vmtest.img5。

  1. root@lj-laptop:/opt/vm# mount -o loop,offset=$(((0x7d047e+0xcbf34+0x3f)*512)) vmtest.img ./part/
  2. root@lj-laptop:/opt/vm# ls ./part/
  3. InFAT32.txt
  4. root@lj-laptop:/opt/vm# umount ./part/
  5. root@lj-laptop:/opt/vm# dd if=vmtest.img of=linux2.img bs=512 skip=$((0x7d047e+0x3f)) count=$((0x65f5b))
  6. 417627+0 records in
  7. 417627+0 records out
  8. 213825024 bytes (214 MB) copied, 4.65149 s, 46.0 MB/s
  9. root@lj-laptop:/opt/vm# mount -o loop ./linux2.img ./part/
  10. root@lj-laptop:/opt/vm# ls ./part/
  11. InLinux2.txt  lost+found
  12. root@lj-laptop:/opt/vm# umount ./part/

原创粉丝点击