最近在做虚拟机相关的事,需要处理一些磁盘和分区的映像文件。如何从一个磁盘映像中挂载指定的分区到本地 Linux 文件系统呢?理论上说,可以用 dd 把该分区从磁盘映像中提取出来再挂载,不过 mount 提供了针对 loop 设备的偏移量参数,方便直接从磁盘映像中挂载指定分区。笔记如下:
演示用的磁盘映像使用 qemu-img 制作。我们使用原生的 raw 格式,等价于磁盘上的原始数据流,保证它在任何 Linux 系统上都可以直接挂载。使用 Windows PE 工具盘启动该 qemu 虚拟机,创建一系列不同格式的分区并在其中建立几个文件。
root@lj-laptop:/opt/vm# qemu-img create -f raw vmtest.img 5Groot@lj-laptop:/opt/vm# qemu -hda ./vmtest.img -cdrom /dev/cdrom -boot d -m 256M -localtime
磁盘分区结构如截图:
回到宿主系统,使用 fdisk 的 -l、-u 参数查看磁盘映像。其中 -u 表示以扇区为单位显示分区起止位置,方便后续计算。
root@lj-laptop:/opt/vm# fdisk -l -u vmtest.img You must set cylinders.You can do this from the extra functions menu. Disk vmtest.img: 0 MB, 0 bytes255 heads, 63 sectors/track, 0 cylinders, total 0 sectorsUnits = sectors of 1 * 512 = 512 bytesDisk identifier: 0xbd86bd86 Device Boot Start End Blocks Id Systemvmtest.img1 63 8193149 4096543+ 83 Linuxvmtest.img2 8193150 10249469 1028160 5 Extendedvmtest.img3 10249470 10474379 112455 6 FAT16vmtest.img5 8193213 8610839 208813+ 83 Linuxvmtest.img6 8610903 9028529 208813+ 82 Linux swap / Solarisvmtest.img7 9028593 10249469 610438+ b W95 FAT32
这时我们只需要为 mount 添加 offset 参数,指定分区在磁盘映像中的逻辑地址,即可挂载这一分区。注意 offset 的单位是字节,通常一个扇区是 512 字节,因此需要用 fdisk 输出的 Start 乘以 512。以 vmtest.img3 分区为例。
root@lj-laptop:/opt/vm# mount -o loop,offset=$((10249470*512)) vmtest.img ./part/root@lj-laptop:/opt/vm# ls ./part/InFAT16.txtroot@lj-laptop:/opt/vm# umount ./part/
如果有必要,我们可以将特定的分区从硬盘映像中提取出来,方便单独使用。通过 dd 可以完成提取,简便起见使用扇区大小 512 字节作为 bs 参数,这样 skip、count 参数很容易从 fdisk 的输出中计算出来。下面提取 vmtest.img5。
root@lj-laptop:/opt/vm# dd if=vmtest.img of=linux2.img bs=512 skip=8193213 count=$((8610839-8193213+1))417627+0 records in417627+0 records out213825024 bytes (214 MB) copied, 4.67434 s, 45.7 MB/sroot@lj-laptop:/opt/vm# mount -o loop linux2.img ./part/root@lj-laptop:/opt/vm# ls ./part/InLinux2.txt lost+foundroot@lj-laptop:/opt/vm# umount ./part/
到这一步,我们已经实现了从磁盘映像中挂载或提取指定分区。其中 fdisk 帮我们完成了磁盘映像的分析,直接将分区的逻辑地址显示给了我们。现在我们再借机复习一下磁盘分区表的格式,试试手工计算相关地址。这里推荐大家阅读网上这篇《解读 Windows 操作系统分区表的秘密》,其中详解过的概念这里不再赘述,下面的内容权当对这篇文章在 Linux 平台下的补充。
首先查看磁盘映像的主引导扇区,其中分区表位于 0x1be 开始的 64 字节。
root@lj-laptop:/opt/vm# cat vmtest.img | xxd | head -32...00001b0: 0000 0000 0000 0000 86bd 86bd 0000 0001 ................00001c0: 0100 83fe 7ffd 3f00 0000 3f04 7d00 0000 ......?...?.}...00001d0: 41fe 05fe bf7d 7e04 7d00 8060 1f00 0000 A....}~.}..`....00001e0: 817e 06fe bf8b fe64 9c00 8e6e 0300 0000 .~.....d...n....00001f0: 0000 0000 0000 0000 0000 0000 0000 55aa ..............U.
对于 vmtest.img1 和 vmtest.img3 这两个主分区,我们读出它们的起始逻辑地址分别为 0x3f 和 0x9c64fe(注意在分区表中以 Little-endian 存储),换算成十进制与 fdisk 输出的一致。bash 的算术表达式支持十六进制字面值,挂载方式同上。
root@lj-laptop:/opt/vm# mount -o loop,offset=$((0x3f*512)) vmtest.img ./part/root@lj-laptop:/opt/vm# ls ./part/InLinux.txt lost+foundroot@lj-laptop:/opt/vm# umount ./part/root@lj-laptop:/opt/vm# mount -o loop,offset=$((0x9c64fe*512)) vmtest.img ./part/root@lj-laptop:/opt/vm# ls ./part/InFAT16.txtroot@lj-laptop:/opt/vm# umount ./part/
对于扩展分区 vmtest.img2,我们通过 dd 定位到它所指向的第一个逻辑分区 vmtest.img5 前面的卷引导记录,查看逻辑分区的链式分区表。
root@lj-laptop:/opt/vm# dd if=vmtest.img bs=512 skip=$((0x7d047e)) | xxd | head -32...00001b0: 0000 0000 0000 0000 0000 0000 0000 0001 ................00001c0: 41fe 83fe bf17 3f00 0000 5b5f 0600 0000 A.....?...[_....00001d0: 8118 05fe bf31 9a5f 0600 9a5f 0600 0000 .....1._..._....00001e0: 0000 0000 0000 0000 0000 0000 0000 0000 ................00001f0: 0000 0000 0000 0000 0000 0000 0000 55aa ..............U.
vmtest.img5 相对于 vmtest.img2 的偏移量为 0x3f,按此地址挂载。
root@lj-laptop:/opt/vm# mount -o loop,offset=$(((0x7d047e+0x3f)*512)) vmtest.img ./part/root@lj-laptop:/opt/vm# ls ./part/InLinux2.txt lost+foundroot@lj-laptop:/opt/vm# umount ./part/
沿着链式分区表的第二条记录(即链表指针)指示的偏移量,我们可以找到第二、第三个逻辑分区(vmtest.img6、vmtest.img7)前面的卷引导记录以及这两个分区的逻辑地址。
root@lj-laptop:/opt/vm# dd if=vmtest.img bs=512 skip=$((0x7d047e+0x65f9a)) | xxd | head -32...00001b0: 0000 0000 0000 0000 0000 0000 0000 0001 ................00001c0: 8118 82fe bf31 3f00 0000 5b5f 0600 0000 .....1?...[_....00001d0: 8132 05fe bf7d 34bf 0c00 4ca1 1200 0000 .2...}4...L.....00001e0: 0000 0000 0000 0000 0000 0000 0000 0000 ................00001f0: 0000 0000 0000 0000 0000 0000 0000 55aa ..............U.root@lj-laptop:/opt/vm# dd if=vmtest.img bs=512 skip=$((0x7d047e+0xcbf34)) | xxd | head -32...00001b0: 0000 0000 0000 0000 0000 0000 0000 0001 ................00001c0: 8132 0bfe bf7d 3f00 0000 0da1 1200 0000 .2...}?.........00001d0: 0000 0000 0000 0000 0000 0000 0000 0000 ................00001e0: 0000 0000 0000 0000 0000 0000 0000 0000 ................00001f0: 0000 0000 0000 0000 0000 0000 0000 55aa ..............U.
取得了相应的地址,挂载或提取分区当然是轻而易举的。下面挂载了 vmtest.img7、提取了 vmtest.img5。
root@lj-laptop:/opt/vm# mount -o loop,offset=$(((0x7d047e+0xcbf34+0x3f)*512)) vmtest.img ./part/root@lj-laptop:/opt/vm# ls ./part/InFAT32.txtroot@lj-laptop:/opt/vm# umount ./part/root@lj-laptop:/opt/vm# dd if=vmtest.img of=linux2.img bs=512 skip=$((0x7d047e+0x3f)) count=$((0x65f5b))417627+0 records in417627+0 records out213825024 bytes (214 MB) copied, 4.65149 s, 46.0 MB/sroot@lj-laptop:/opt/vm# mount -o loop ./linux2.img ./part/root@lj-laptop:/opt/vm# ls ./part/InLinux2.txt lost+foundroot@lj-laptop:/opt/vm# umount ./part/
建议继续学习:
- Centos挂载新硬盘开机自动挂载 (阅读:7721)
- 从磁盘映像中挂载或提取指定的 LVM 逻辑卷 (阅读:3877)
- 将远程共享文件夹挂载到linux本地目录 (阅读:3609)
- linux磁盘管理学习笔记(下):linux分区、挂载 (阅读:3090)
- Oracle hash分区的秘密 (阅读:2912)
- linux大于2T的磁盘使用GPT分区 (阅读:2836)
- LVM介绍 (阅读:2806)
- 如何删除品牌电脑中的隐藏分区 (阅读:2712)
- 用CloneZilla制作紧急恢复分区 (阅读:2642)
- CentOS分区规律大总结 (阅读:2507)
QQ技术交流群:445447336,欢迎加入!
扫一扫订阅我的微信号:IT技术博客大学习