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...
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.
#!/usr/local/bin/perl open(DEV, '/dev/sda6') or die "Can't open: $!\n"; while (read(DEV, $buf, 4096)) { print tell(DEV), "\n", $buf, "\n" if $buf =~ /littleWindow/; }
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.
#!/usr/local/bin/perl open(DEV, '/dev/sda6') or die "Can't open /dev/sda6: $!\n"; open(OUT, '>tmp1.txt') or die "Can't open tmp1.txt: $!\n"; seek(DEV, 946192864, 0) or die "Can't seek: $!\n"; read(DEV, $buf, 40000) or die "Can't read: $!\n"; print OUT "$buf\n"; open(OUT, '>tmp2.txt') or die "Can't open tmp2.txt: $!\n"; seek(DEV, 970662368, 0) or die "Can't seek: $!\n"; read(DEV, $buf, 40000) or die "Can't read: $!\n"; print OUT "$buf\n";
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.
In reply to Restoring deleted files under Linux by chipmunk
| For: | Use: | ||
| & | & | ||
| < | < | ||
| > | > | ||
| [ | [ | ||
| ] | ] |