0

I have a MicroSD card that is 64GB in size. I wrote an image to it that is 16GB in size with this:

$ sudo dd if=my_image.img of=/dev/sdb bs=4M
3798+1 records in
3798+1 records out
15931539456 bytes (16 GB, 15 GiB) copied, 657.848 s, 24.2 MB/s

Now, I want to take an image of the first 15931539456 bytes (16GB) of the same 64GB SD card with dd, to end up with an image that has the same checksum as the image I started with.

From what I understand, dd's result above (3798+1) shows that there were 3798 complete reads from the source image, and 1 partial read, because the size of the source image doesn't split evenly into 4M chunks. So how do I tell dd to now copy 15931539456 bytes from the SD card into a new file, 4M at a time?

I'm assuming I can do something like:

sudo dd if=/dev/sdb of=new_image.img bs=1 count=15931539456

but having a buffer that small would make the operation take forever. Is there any way to tell it to use a buffer of 4M, but only copy X number of bytes, even if that results in a short read at the end?

Tal
  • 2,112
  • What if you did it the other way 'round? sudo dd if=/dev/sdb of=new_image.img bs=15931539456 count=1? Also, your file size is a multiple of several reasonable block sizes, up as high as 2^19 (512k). Or if you prefer to use a block size that is not a divisor of the file size, then transfer slightly too much data and then use truncate(1) to shrink the file to the exact size you want. – Jim L. Sep 10 '19 at 23:30
  • @JimL. That would require 16GB of RAM. Unless OP has that much RAM, that's not a good idea. – FUZxxl Sep 10 '19 at 23:51
  • @FUZxxl Sorry, yes, I tested on my machine, but I have 32GB RAM. I'd opt for the truncate route then, or the 512k blocksize. – Jim L. Sep 10 '19 at 23:54

1 Answers1

6

Few possibilities:

  1. Use a smaller bs, yet not very small:

    dd if=/dev/sdb of=new_image.img bs=512k count=30387
    

    This is not a general solution. It works here because 15931539456 can be factorized.

  2. Use your desired bs, read more and truncate on the fly:

    dd if=/dev/sdb bs=4M | head -c 15931539456 >new_image.img
    

    You don't need count=3799 here. Well, you don't even need dd:

     head -c 15931539456 /dev/sdb >new_image.img
    

    I expect head to read sane chunks and perform well. Note head -c is not required by POSIX.

  3. Use your desired bs, read more and truncate later:

    dd if=/dev/sdb of=new_image.img bs=4M count=3799
     truncate -s 15931539456 new_image.img
    

    truncate is not portable though.

  4. Use your desired bs, read less; then read the remaining part with bs=1:

     dd if=/dev/sdb of=new_image.img bs=4M count=3798
     offset=$((3798*4*1024*1024))
     remaining=$((15931539456-offset))
     dd if=/dev/sdb of=new_image.img bs=1 skip="$offset" seek="$offset" count="$remaining"
    

Note in general dd may read a partial block and this still increases the count (compare this answer). While reading from a block device this probably won't happen, still a general solution is to always specify iflag=fullblock whenever you rely on count and bs is greater than 1. Unfortunately fullblock is not required by POSIX, your dd may or may not support it.