This is an old revision of the document!


Simulated data recovery with Testdisk and Photorec

Introduction

Testdisk is a data recovery tool. Its capabilities depend on the filesystem it's operating on. E.g., it can read backup ext3 partitions, or manually specify partition types. It's also good with deleted files or incomplete files.

In this column, I'm going to test testdisk and photorec with a simulated corrupt filesystem.

Procedure

  1. Create a filesystem,
  2. Populate it
  3. Corrupt the filesystem
  4. Attempt to recover the files

Create the filesystem

For testing I'm going to use a loopback filesystem on Linux. This means I can work within files and spare the pain of working with disks.

blacktower:~# dd if=/dev/zero of=./baddisk.img bs=1024 count=50000              50000+0 records in
50000+0 records out
51200000 bytes (51 MB) copied, 0.26165 s, 196 MB/s
blacktower:~# mkfs -t ext3 ./baddisk.img                                        mke2fs 1.41.12 (17-May-2010)
./baddisk.img is not a block special device.
Proceed anyway? (y,n) y
Filesystem label=
OS type: Linux
Block size=1024 (log=0)
Fragment size=1024 (log=0)
Stride=0 blocks, Stripe width=0 blocks
12544 inodes, 50000 blocks
2500 blocks (5.00%) reserved for the super user
First data block=1
Maximum filesystem blocks=51380224
7 block groups
8192 blocks per group, 8192 fragments per group
1792 inodes per group
Superblock backups stored on blocks:
        8193, 24577, 40961

Writing inode tables: done
Creating journal (4096 blocks): done
Writing superblocks and filesystem accounting information: done

This filesystem will be automatically checked every 24 mounts or
180 days, whichever comes first.  Use tune2fs -c or -i to override.

blacktower:~# mkdir /mnt/baddisk; mount -o loop ./baddisk.img /mnt/baddisk

Now to create some test files.

i=0; while [ $i -lt 1000 ]; do /usr/games/fortune >> /mnt/baddisk/fortunes.txt; i=$((i+1)); done
blacktower:~# cp /var/pub/testfiles/* /mnt/baddisk/
blacktower:~# ls -l /mnt/baddisk/
total 1216
-rw-r--r-- 1 root root 114616 Apr  6 11:03 fortunes.txt
-rwxr--r-- 1 root root  17920 Apr  6 11:24 libreoffice writer.doc
-rwxr--r-- 1 root root  24391 Apr  6 11:24 libreoffice writer.odt
-rwxr--r-- 1 root root  42101 Apr  6 11:24 libreoffice writer.pdf
-rwxr--r-- 1 root root  18541 Apr  6 11:24 libreoffice writer.rtf
drwx------ 2 root root  12288 Apr  6 10:55 lost+found
-rwxr--r-- 1 root root 962190 Apr  6 11:24 testimage.bmp
-rwxr--r-- 1 root root  17444 Apr  6 11:24 testimage.jpg
-rwxr--r-- 1 root root  18523 Apr  6 11:24 testimage.png

This test is very synthetic because the filesystem has never had a delete. There's no fragmentation and all the files are sitting in an optimal location.

Making the filesystem more realistic

Let's fragment! (warning, dangerous script)

#!/bin/bash
# pick a file, copy it, delete the original

targetdir=/mnt/baddisk
mkdir "$targetdir"/tmp

i=0
while [ $i -lt 10000 ]
do
        # echo $i

        set -- "$targetdir"/*
        shift $(($RANDOM%$#))
        if [[ -f $1 ]]
        then
                cp "$1" $targetdir/tmp/
                rm "$1"
                mv "$targetdir/tmp/`basename \"$1\"`" "$targetdir"
        fi
        i=$(($i+1))
done

MD5 hashes permit us to check the file integrity later. They're stored separately from the filesystem.

blacktower:~# md5sum /mnt/baddisk/*
0b5080a051d53ba2432b666c90d7c0b4  /mnt/baddisk/fortunes.txt
8f301122918ab70d8cdccebdac46c8c5  /mnt/baddisk/libreoffice writer.doc
45f1fbff8dcd6a92eef33e5639837c81  /mnt/baddisk/libreoffice writer.odt
6dbeeb8ff8b82d35296dfc5265897f92  /mnt/baddisk/libreoffice writer.pdf
9d4cb7f894983e667a7c2173f9fa59c4  /mnt/baddisk/libreoffice writer.rtf
md5sum: /mnt/baddisk/lost+found: Is a directory
ed0eda5ba4f73f8d41eade656db27517  /mnt/baddisk/testimage.bmp
3c90cdc73c1b155b7cdd5e0a13584207  /mnt/baddisk/testimage.jpg
8b40c922b02ef43be7c986fa59536260  /mnt/baddisk/testimage.png
md5sum: /mnt/baddisk/tmp: Is a directory

Corrupting the filesystem

First we'll unmount the filesystem and Check to see that it's okay.

blacktower:~# umount /mnt/baddisk
blacktower:~# fsck.ext3 ./baddisk.img
e2fsck 1.41.12 (17-May-2010)
./baddisk.img: clean, 20/12544 files, 7703/50000 blocks

To corrupt the disk, I'm throwing random nulls throughout the image with the code below.

blacktower:~/testdisk# cat ./corrupt.bash
#!/bin/bash
i=0
while [ $i -lt 100 ]
do
 target=$(( RANDOM % 5120 ))$(( RANDOM % 10000 ))
 echo $target
 #dd if=/dev/zero of=./baddisk.img bs=1 count=1 seek=$target 2> /dev/null
 ./corrupt ./baddisk.img $target
   i=$((i+1))
done
blacktower:~/testdisk# cat ./corrupt.c
#include <stdio.h>
/* program to write to specific location of a file */
 
int main(int argc, char* argv[])
{
 FILE* fh;
 
 if( argc != 3 ) {
   printf( "\nUsage: %s filename\n\n Where \"filename\" is the file to corrupt and \"location\" is the offset in bytes\n", argv[0] );
   return(1);
 }
 
 fh = fopen( argv[1], "r+" );
 
 if( fh == NULL ) {
   printf( "\nCould not open existing file for writing!\nUsage: %s filename\n\n Where \"filename\" is the file to corrupt and \"location\" is the offset in bytes\n", argv[0] );
   return(1);
 }
 
 fseek( fh, atoi(argv[2])-2, SEEK_SET );
 
 fputc( 0, fh );
 
 fclose( fh );
 return 0;
}
blacktower:~/testdisk# ./corrupt.bash
blacktower:~/testdisk# mount -o loop ./baddisk.img /mnt/baddisk/
blacktower:~/testdisk# md5sum /mnt/baddisk/* 2> /dev/null
0b5080a051d53ba2432b666c90d7c0b4  /mnt/baddisk/fortunes.txt
8f301122918ab70d8cdccebdac46c8c5  /mnt/baddisk/libreoffice writer.doc
45f1fbff8dcd6a92eef33e5639837c81  /mnt/baddisk/libreoffice writer.odt
6dbeeb8ff8b82d35296dfc5265897f92  /mnt/baddisk/libreoffice writer.pdf
9d4cb7f894983e667a7c2173f9fa59c4  /mnt/baddisk/libreoffice writer.rtf
24896c06121360c4b3daa1deca7e854f  /mnt/baddisk/testimage.bmp
3c90cdc73c1b155b7cdd5e0a13584207  /mnt/baddisk/testimage.jpg
8b40c922b02ef43be7c986fa59536260  /mnt/baddisk/testimage.png
blacktower:~/testdisk#

Looks like we hit mostly empty space. Only the bmp is corrupted.

Change the 100 random bytes to 10000 and run again:

blacktower:~/testdisk# fsck.ext3 ./baddisk.img
e2fsck 1.41.12 (17-May-2010)
./baddisk.img: clean, 20/12544 files, 7703/50000 blocks

blacktower:~/testdisk# md5sum /mnt/baddisk/* 2> /dev/null
e04f2a97d51432d04a64f642e350b1f0  /mnt/baddisk/fortunes.txt
8f301122918ab70d8cdccebdac46c8c5  /mnt/baddisk/libreoffice writer.doc
fc2475f7a1a70f2f31ae50ca59b96cb7  /mnt/baddisk/libreoffice writer.odt
6037209ee8c78156a1e6acea00b09dd1  /mnt/baddisk/libreoffice writer.pdf
16a93d89a8dedfd23ab629006104cbca  /mnt/baddisk/libreoffice writer.rtf
aaf2de72c3f2966bf414d598435dc432  /mnt/baddisk/testimage.bmp
3c8a111a8c9baaa09aea73e7d59e890e  /mnt/baddisk/testimage.jpg
e3912ad720969f46308cdccad73a66f8  /mnt/baddisk/testimage.png

Only the .doc file is safe now.

Again.

blacktower:~/testdisk# fsck.ext3 ./baddisk.img
e2fsck 1.41.12 (17-May-2010)
./baddisk.img: clean, 20/12544 files, 7703/50000 blocks
blacktower:~/testdisk#

fortune.txt is visibly corrupted, and every file fails an MD5, but the filesystem hasn't reported any problems yet.

Running Testdisk

blacktower:~/testdisk# testdisk ./baddisk.img

Seems like a lost cause. Even the size of the disk comes up wrong in the “Geometry” menu of Testdisk

Disk ./baddisk.img - 20 MB / 19 MiB - CHS 3 255 63, sector size=512

"Note: Disk capacity must be correctly detected for a successful recovery.
If a disk listed above has incorrect size, check HD jumper settings, BIOS
detection, and install the latest OS patches and disk drivers."

Additional Information