Rsync file recovery

It happens to the best of us. I was rsyncing about 500MB of data from a holding directory on a Linux box to a FreeBSD 5.4 developement server and inadvertently rsync'd a much older version of a parsing script into the development hierarchy. The current version of the script hadn't been checked into Subversion yet, and wasn't something easily rewritten. It was one of those Perl scripts where every regex was not l

It happens to the best of us.

I was rsyncing about 500MB of data from a holding directory on a Linux box to a FreeBSD 5.4 developement server and inadvertently rsync'd a much older version of a parsing script into the development hierarchy. The current version of the script hadn't been checked into Subversion yet, and wasn't something easily rewritten. It was one of those Perl scripts where every regex was not like the other, and would have taken several painful hours to rewrite.

What to do? Rsync synchronized the file without changing the inode, so there wasn't a deleted file to look for, or was there? It was worth it to spend 30 minutes trying to recover the file, and I had recently edited the file with vim, which creates (and more importantly, deletes) a swapfile containing the contents of the edited file before editing.

The first order of business was to install Sleuthkit and Foremost from ports on the FreeBSD box. Being lazy, I didn't take the disks offline, but rather ran the Sleuthkit tools on the mounted partition, /dev/da0s2a.

So, fls -rd /dev/da0s2a | grep scriptname gave me hope:

root@dev# fls -rd /dev/da0s2a | grep scriptname
r/r * 1271828: usr/local/sbin/scriptname.pl.swp

Ah HAH! Even though rsync hadn't deleted the file, the last vi swap file was still on the disk and those blocks hadn't been reallocated! There was hope!

So, from the fls output, I knew that the file had inode 1271828. Where was that on the disk?

root@dev# fsstat /dev/da0s2a | more
...truncated...
Group 54:
Last Written: Mon Jan 30 00:22:27 2006
Inode Range: 1271808 - 1295359
Fragment Range: 5080752 - 5174839
Super Block: 5080792 - 5080799
Group Desc: 5080800 - 5080807
Inode Table: 5080808 - 5083751
Data Fragments: 5080752 - 5080791, 5083752 - 5174839
Global Summary (from the superblock summary area):
Num of Dirs: 7
Num of Avail Blocks: 5501
Num of Avail Inodes: 23333
Num of Avail Frags: 548
Local Summary (from the group descriptor):
Num of Dirs: 7
Num of Avail Blocks: 5501
Num of Avail Inodes: 23333
Num of Avail Frags: 548
Last Block Allocated: 5114936
Last Fragment Allocated: 5114936
Last Inode Allocated: 1271828

Looks like Group 54. The block range is 5080752 - 5174839, so let's grab those:

root@dev# dls /dev/da0s2a 5080752-5174839 > recover-image.dls

Now, we have a block range where the deleted file should be. Let's carve it with foremost. First, I needed to add a definition to the foremost.conf file to cull out perl and specifically .swp files:

# Perl

pl n 10000 #!/usr/bin/perl
swp n 10000 #!/usr/bin/perl

The filesize of the script I was looking for wasn't larger than 10k, so this should work. Now, to find it.

root@dev# foremost -c ./foremost.conf -o tmprec ./recover-image.dls

This dumped everything matching the above lines into the tmprec directory. In there were two subdirs containing .pl and .swp files. Grepping for a known code snippet in the .swp directory brought me to the file containing the missing script. There was a bunch of garbage at the end of the file since my filesize estimate was slightly generous, but the missing lines of code were there, saved by vim during my last edit. I lost the last changes I made to the script, but it was far better than completely rewriting it.

Normally you would perform these actions on either a disk image or an offline, unmounted volume, so don't try this at home. However, if you're in a pinch you can recover nearly anything from a UFS2 or ext3 volume if you act quickly enough. If too much time passes the blocks will be overwritten and the data will truly be gone. In my case, I was just lucky.

From CIO: 8 Free Online Courses to Grow Your Tech Skills
Join the discussion
Be the first to comment on this article. Our Commenting Policies