|Perl: the Markov chain saw|
Restoring deleted files under Linuxby chipmunk (Parson)
|on Aug 21, 2001 at 23:27 UTC||Need Help??|
Earlier today, my officemate and I were busy working on a big project, when he suddenly slammed his hands down on his keyboard, shouted 'F***!', spun his chair around, and kicked a cardboard box into the corner of the office.
He explained that he had accidentally deleted the script that he had been working on for the past four days. (He meant to delete a similarly named file with a different extension.) Of course, he wanted to know if there was any way to recover the file.
Before I go any further, I should say that it should have been possible to recover the file from CVS or a backup, but he hadn't checked the file into CVS yet, and the file was created after the most recent back up. Additionally, he had already deleted the emacs backup file. So, in the absence of those obvious and more reliable solutions...
I did a Google search for "undelete linux". One site described an unrm utility, but the download server wasn't reachable. On another site, I found a Linux FAQ with the question How Can I Undelete Files? It suggested searching the raw disk device to find the deleted file.
So, I turned to Perl, writing two quick scripts. These are just one-offs; I was more concerned at the time with recovering the file quickly rather than coding for strictness or reusability. BTW, these have to be run as root.
The first script reads the raw bytes of the device (`df` told me the file I wanted was in a directory mounted on /dev/sda6) looking for the string 'littleWindow', the name of a subroutine from the script. It prints out the byte offset and the text every time it finds a match.
The second script uses byte offsets from the first script (matches were found in two separate locations), and reads in a big chunk around each one. My coworker said the file was around 20K, so I subtracted 20000 from each offset and read in 40000 bytes.
Then I just opened up tmp1.txt and tmp2.txt in emacs and grabbed the contents of the missing file. It turned out that the file in tmp2.txt had already been partly overwritten, but the file in tmp1.txt was intact. Yay Perl!
When a file is deleted, all references to it in the file system are removed, but the actual bytes remain on disk until the space is used for a new file. I was fortunate that the deleted file was not a very busy file system, so I had time to grab the file before it was overwritten.
This is an ugly and unreliable solution; version control systems and frequent backups are much preferable. Nonetheless, Perl got the job done, and it was a great relief to recover the file.