Mounting a hard disk image including partitions using Linux

A while ago I thought it would be a good idea to make a backup of my Linux server by just dumping the complete disk to a file. In retrospect, it would have been much easier had I just dumped the individual filesystems.

When I finally got around to using this backup, long after the 10GB disk had perished I realized that to use the loopback device to mount a filesystem it actually needs a filesystem to mount. What I had was a disk image, including partition table and individual partitions. To further complicate matters the data partition was also not the first partition inside this image.

For reference, I created this image using the Unix ‘dd’ tool:

# dd if=/dev/hda of=hda.img
30544113+0 records in
30544113+0 records out
# ls -lh
-rw-r--r-- 1 root    root  9.6G 2008-01-22 14:12 hda.img

I followed the instructions on http://www.trekweb.com/~jasonb/articles/linux_loopback.html to try and mount the partitions inside the disk image, but ran into two problems.

To mount a partition inside the disk image you need to calculate the offset of where the partition starts. You can use fdisk to show this information to you, but you need to specify the number of cylinders if you are using a disk image.

You then also need to multiply the start and end numbers with the calculated sectors to get a byte offset.

I found another tool more useful for this task, called parted. If you are using Ubuntu, you can install it with ‘apt-get install parted’

# parted hda.img
GNU Parted 1.7.1
Using /data/rabbit/disk_image/test2
Welcome to GNU Parted! Type 'help' to view a list of commands.
(parted) unit
Unit?  [compact]? B
(parted) print
Disk /data/rabbit/disk_image/test2: 10262568959B
Sector size (logical/physical): 512B/512B
Partition Table: msdos
Number  Start        End           Size         Type     File system  Flags
1      32256B       106928639B    106896384B   primary  ext3         boot
2      106928640B   1184440319B   1077511680B  primary  linux-swap
3      1184440320B  10256924159B  9072483840B  primary  ext3
(parted) quit

Now we have the offsets and we can use those to mount the filesystems using the loopback device:

#mount -o loop,ro,offset=32256 hda.img /mnt/rabbit

That mounted the first partition, the ‘boot’ partition, but this didn’t have the data on it that I was looking for. Lets try to mount partition number 3.

#umount /mnt/rabbit
#mount -o loop,ro,offset=1184440320 test2 /mnt/rabbit
#mount: wrong fs type, bad option, bad superblock on /dev/loop0,
missing codepage or helper program, or other error
In some cases useful info is found in syslog - try
dmesg | tail  or so

Oops, that doesn’t look right. According the article referred to above if you are using a util-linux below v2.12b then you cannot specify an offset higher than 32bits. I’m using util-inux 2.13 which shouldn’t have that problem, and besides, my offset is well below the 32bit limit.

The article also offers an alternative loopback implementation that supports mounting partitions within an image, but that requires patching and recompiling your kernel which I would rather not do.

Instead I decided to extra ct the filesystem from the image which would then allow me to mount it without specifying an offset.
Doing this is quite straightforward with ‘dd’. You need to give ‘dd’ a skip count, or, how far into the source to start copying, and a count, how much to copy.
Here you can either use the single byte offsets retrieved with parted or divide them by 512 and let ‘dd’ use 512 byte blocks. Copying just one byte at a time takes a very long time, so I suggest using a larger block size.

Here is the command I used to extract my filesystem. Skip is 2313360 (1184440320/512) and Count is 17719695 (9072483840/4)

#dd if=hda.img of=hda3.img bs=512 skip=2313360 count=17719695
17719695+0 records in
17719695+0 records out
9072483840 bytes (9.1 GB) copied, 485.679 seconds, 18.7 MB/s

After extracting the filesystem I was able to mount it without any problems.

# mount -o loop hda3.img /mnt/rabbit/
# df -h /mnt/rabbit
Filesystem            Size  Used Avail Use% Mounted on
/data/rabbit/image/hda3.img
8.4G  6.3G  1.7G  80% /mnt/rabbit

71 thoughts on “Mounting a hard disk image including partitions using Linux”

  1. This is one solution, but a more elegant solution is to use the offset-flag in loop-mounting.

    In stead of splitting up your image you can just type inn mount -o loop,offset=[same offset as calculated above].

    1. That option is also proposed behind, and i traied also and doesnt work.

      The problem was the ro option. I tried without that and works fine. Thanks.

  2. I do mention the offset option in my article, but that it has limitations. I offered the splitting as an alternative to using that if you’re having problems with it.

    1. Your problem arose when you tried to mount test2 instead of hda.img. Other than that minor oops, the offset=xxxxx works famously. I’ve used this approach to mount partitions from images created with ddrescue from failing drives on a number of occasions. Works great! (still)

    2. Thank you for this wonderful approach. with this method you can accurately dissect the image and know exctaly which partition is corrupted and so replace/fix it.

  3. Thanks for your article, it really heped me a lot while I was trying to find out what is wrong with my Xen disk image with multiple partitions.

  4. Very helpful!
    I spent one whole afternoon on mounting a dd image found on the DVD from the book ‘Real Digital Forensics’.
    By following your steps, it just cost me one minute.
    I love you!

  5. Makes sense. I made a backup of latptop disk with 1 ntfs partition and 1 dos partition using dd if=/dev/sda and was trying to figure out how to extract the partition. This is what I was looking for. I hope it works.

  6. Great article!

    I would just like to point to a small error :
    “.. and Count is 17719695 (9072483840/4) ”

    It should be “.. and Count is 17719695 (9072483840/512)” .

  7. All useful information – just a followup. If your ext3 partition has been uncleanly unmounted (or you took a dump from a live system, say running as a VM) then you won’t be able to mount it directly as the journal is unclean. Follow the “dd” instructions above to extract just the partition, then run

    “fsck.ext3 hda3.img”

    to repair the filesystem before mounting.

  8. To follow up on comment #8 — here’s a page I found that explains very clearly where the “wrong fs type, bad option, bad superblock” mount error is coming from, and how to deal with it.

    (Spoiler alert: Yes, it’s all because of an unclean journal. :))

  9. This worked well for me. This article also applies to loading a vmware disk image that has several partitions.

    I used this to mount my vmware disk as a disk image…

    sudo vmware-mount -f Frog/Frog.vmdk /mnt/frog/

    I could then mount individual partitions in the image like this….

    sudo mount -t ntfs -o loop,offset=10487232000B /mnt/frog/flat /mnt/toad/

    vmware-mount seems to have issues with partitioned disks. This provided a great way to work around those issues.

  10. I was just going to backup a drive with dd, realized I’d never actually mounted a partition within a (partitioned) disk image, and went looking to see if I should dd by partition instead of device. Thanks for the useful answer.

  11. The easiest way for me seems just to use the tool testdisk:

    testdisk IMAGEFILE

    you can simply see all partitions under advanced tools
    and also can extract partitions as an image file

  12. Thanks for this useful post. I often work with partial disk images and parted does not like to print information about the partition table when the partition goes beyond the end of the image. But I found an offset of 32256 works more often than not!

  13. Thank you so much. Due to the completely undocumented removal of lomount from any toolkits, including xen-utils, getting at an individual partition seemed impossible (go man pages) until I came across this article.

    Btw – if you wanted to specify a filesystem in particular for a loop mounted partition….how would you do that? I dont know why you’d want to override mount’s auto findings but still….power is power.

    Cheers
    Jon

  14. An easy way to mount a partition is the follwing command:
    IMG=”hda.img”;PART=1;mount -o loop,ro,offset=$(parted $IMG -s unit b print|awk ‘$1==’$PART’ {sub(/B/,””,$2);print $2}’) $IMG /mnt/rabbit
    .
    If you must copy this partition you can use similar subcommands to calculate the offset. You can use the bc command to calculate skip and count if the blocksize (bs) is larger as 1.

  15. Using parted to work out the partition offsets allowed me to salvage some important files from a VirtualBox disk image that I converted to a raw image as it wouldn’t boot. Thanks!

    1. Do not miss @mikko’s answer! kpartx creates the device files for your image file so you can use the partitions just like a real disk.

      kpartx -a hda.img
      mount /dev/mapper/hda.img3

      Thanks mikko.

      1. Kpartx is the easy solution to this problem. Works like a charm.
        I’m really glad I read the comments, thanks. (750Gb of disk space saved)

  16. I know its an old article, but I wanted to comment that the reason your command to mount your offset partition inside your original disk image did not work could be because of a possible typo.

    # parted hda.img
    GNU Parted 1.7.1
    Using /data/rabbit/disk_image/test2

    You say the disk image is hda.img with your parameter for parted, but then parted says you are using a whole other file (/data/rabbit/disk_image/test2). When I run parted, my output is like so:

    esoul@dionysus:/twoTB/eSoulBackup$ sudo parted ./taylor.dd
    GNU Parted 2.3
    Using /twoTB/eSoulBackup/taylor.dd

    I know the version numbers are different and mine is newer, but it doesn’t have any effect on using mount to mount the partition at an offset. What really kills it for could be your mount parameters —

    #mount -o loop,ro,offset=1184440320 test2 /mnt/rabbit

    This fails possibly because you are not in the same folder as test2. Either cd to the directory or put the full path to the disk image and all is fine. Like so —

    esoul@dionysus:/twoTB/eSoulBackup$ sudo mount -o ro,loop,offset=1573912576 taylor.dd /mnt/temp
    esoul@dionysus:/twoTB/eSoulBackup$

    No errors, no complaints, I can list directory contents just fine.

    This is also a disk image with a NTFS file system and a “hidden” partiton before it. I have plenty of disk images sitting on my backup server and everyone of them will mount partitions inside of the device image with no problems.

  17. @16
    Thanks a ton! Testdisk is infinitely better! I’ve been trying ChromeOS builds from Hexxah but since they’re built automatically sometimes they are corrupted. Using Testdisk I can quickly check to make sure that everything is ok. Testdisk even allows filebrowsing and much more! Will be using this tool from now on.

  18. In the line:
    #mount -o loop,ro,offset=1184440320 test2 /mnt/rabbit
    Was “test2” supposed to be “test2”, or was it supposed to be “hda.img”?
    That could make a difference.

  19. At least for Ubuntu Lucid, mounting offsets well beyond a 32-bit limit works flawlessly. Thanks for saving me a ton of time and copying!

    I really prefer to image the whole drive so that I get boot sectors, etc and it can boot from a restored image with zero hassle. I just always thought that it came with the drawback of not being able to access the partitions in these images…

  20. For whoever searched for this solution and found this page… In regards to this error when mounting with an offset:

    [root@LAKITU:backup] 14# mount -o loop,ro,offset=1074790400 /media/backup/ssd.img /media/oldUbuntu/
    mount: wrong fs type, bad option, bad superblock on /dev/loop0,
    missing codepage or helper program, or other error
    In some cases useful info is found in syslog – try
    dmesg | tail or so

    The problem was:
    [ 3432.775087] Buffer I/O error on device loop0, logical block 7816661
    [ 3432.814275] EXT4-fs (loop0): INFO: recovery required on readonly filesystem
    [ 3432.814277] EXT4-fs (loop0): write access unavailable, cannot proceed

    Mounting once with write-support enabled allowed for recovery.

  21. Pingback: The Hijax!
  22. You saved my day as I was unable to boot my xen machine for the simple reason that a non xen kernel was specified in grub.conf as default.
    With your mount examples I was able to mount the boot partition of the disk image file and change the default kernel.

  23. Pingback: Mount a .img file
  24. Great solution, here’s a way to get the offset to mount with: -o loop,offset=

    echo | fdisk -l /path/to/image.img | grep -A 20 “Device Boot” | awk ‘{print $1,$3 * 512}’

    1. Made a mistake sorry, simplest solution is this and works without additional software installation:

      fdisk -l /path/to/image.img | awk ‘{print $1,$3 * 512}’

      You should discard the top 9 lines

      1. made another mistake oops, sorry for spam, here it is:

        fdisk -l /path/to/image.img | awk ‘{print $1,$2,$3 * 512,$4,$5,$6,$7}’

        1. Thanks for magic line 🙂 In my try first partition shows 0-track multiplied with 512, second partitions 0-track not multiplied… Ubuntu 18.04 / Win2008r2 defaultinstall with 100MB first partition.
          Removed *512 like this:
          ” fdisk -l [/path/to/image.img or /path/to/lvmdisk] | awk ‘{print $1,$2,$3,$4,$5,$6,$7}’ ”
          and then used calculator or brain to multiply partition 0-sector ($3 in our scriptline) to 512. Sector size from the same scriptline output and its something like this: ” Sector size (logical/physical): 512 bytes / 512 ”
          Numbers guide from the same output: ” Device Boot 0 End Sectors Size Id ”
          Used “0” from there to identify each partition 0-sector. Noticed “Boot” is marked with “*” if partition is bootable, else there is nothing.
          Thanks anyone, great guide for dumb (me) OSX user 🙂

          Also there is nonscripted possibility, example:
          # fdisk -l /dev/vg666/win9 #your lvm disk
          multiple desired partition with sector size (you see it from the same output), usually 512. Then:
          # mount -t ntfs -o loop,offset=[part0track*512] /dev/vg666/win9 /mnt/win9

  25. Thanks for this post – just the info I needed and it was clearly explained. Thanks too to @mikko’s kpartx suggestion which does recovering on the filesystem for you automatically.

  26. I wish people wouldn’t act like this is a good solution. I’m trying to mount a whole image including the boot sectors, this is not going to allow that. How do I mount the entire image?

    1. The term ‘mounting’ usually refers to mounting a filesystem. I am not sure what you mean by mounting the whole image including the boot sectors? This article deals with mounting a filesystem that is contained within a whole-disk image.

  27. Thank you. I had purchased Mass Effect 3 during the steam winter sale for US$15 but I am a hopeless linux die hard and when upgrading the hardware I did the unbelievable and went from Windows XP to Windows 8. Please understand that I love linux, but also love video games. I used dd to preserve my old windows disc to linux. I upgraded to Windows 8 as part of a major upgrade to my already complex home network, backups and such. A kind of hand me down one might see in a large family. Anyhoo I was able to import my Mass Effect 2 character using the offset parameter and using dual boot linux to scp the save files. Messy beyond comprehension but bliss when it worked. I elected to be an adept and the game imported my abilities, so I shower them with singularities, pulls, and assorted nonsense.

    I really think movies are at one level, and immersive games are the next level. We want to be involved. I want to be in Lexington, or Concord, for just 20 hours. That would be a game.

  28. No need to dd out the image, you can use the mount command to do all this, you do need to define the offset correctly though:

    Use mmls to work out your offsets and byte size to multiply by:
    #mmls -t dos /mnt/first-mount-point/VM-Image.vmdk.raw

    Then mount it! This is assuming it’s EXT4, so we have to give some extra mount options to handle the potentially dirty journal “noload” :

    mount -o ro,loop,noload,offset=$((391168*512)) /mnt/first-mount-point/VM-Image.vmdk.raw -t ext4 /mnt/second-mount-point

  29. how do you know what the skip is? Why isn’t there a program with a GUI? Windows has one called OSFMount, you can mount one, or all partitions of an image., it’s click, mount, go.. This is chaos and confusing.

    1. I totally agree, Linux has not progressed any further than when I last had a melt down in 2008. Even then it was painful to use, not very friendly and the Ubuntu tribe are an anal lot who do not take critical remarks well.

      For three weeks I have tried to get an image of a drive I have taken to mount, every example and sadly this here on this tutorial has failed.

      Theres nothing wrong with the drive or the image, the drive (physical) mounts, unmounts and does back flips. The *.img of that drive taken with `dd` and checked with `cmp` indicate an exact match.

      However, the *.img file that was made via dd if=/dev/sda of=/media/mark/extdrive/folder/ssd.img, the file made without any errors, refuses to mount.

      I keep on getting these errors

      mount: wrong fs type, bad option, bad superblock on /dev/loop0,
      missing codepage or helper program, or other error

      In some cases useful info is found in syslog – try
      dmesg | tail or so.

      and it makes no difference what example I follow after asking a question in `ask ubuntu` the result is the same, a non mounting device.

      The problem is that windows fails to boot, I get as far as AVG loading and it stalls at a driver, so my idea was to get the image of the drive mounted, see if it does actually boot before I start playing with a HEX editor and edit the file directly, the error has to be in the second partition where windows files are, in the 32256 bytes between the Extended and Logical drive. Drive C is listed as the boot which is the first partition (originally with windows on it but had to be replaced when a power failure corrupted the install)

      I explained this to one Linux forum and all I got in return was that `this is not a ‘Windows’ help form` which I considered utterly rude and not helping as the problem is a Linux one, in as far as nothing mounts manually and GUI seems to not see certain things that if it did, life would be much simpler.

      1. @MarkG: I had the same problem as you, “mount” with offset just did not work and there were weird error message. The solution that worked for me was kpartx which can be installed using apt-get install kpartx on Debian and Ubuntu. Just run it with “kpartx -v -a imagefile” and it will create block device nodes in /dev/mapper/ with names like “loop0p1” which can then be used similar to /dev/sdXY, so using “mount /dev/mapper/loop0p1 /mnt” mounts partition 1 to directory /mnt. HTH!

  30. You seem to have an error here:
    Here is the command I used to extract my filesystem. Skip is 2313360 (1184440320/512) and Count is 17719695 (9072483840/4)

    Since you use block size 512, skip is right. But count is wrong.
    9072483840/4 = 2268120960 != 17719695

    You should correct your article to say:
    Count is 17719695 (9072483840/512)

    Then you’re correct. 🙂

  31. There is an easier way:
    sudo losetup -P /dev/loop3 hda.img
    Run lsblk to make sure /dev/loop3 is not already used (otherwise use another number than 3). If successful lsblk will show a new loop block device with all parititions listed, you can then mount them normally.

Leave a Reply