Undeleting Files in the Linux OSJune 2, 2006
09.12.00 by Russ Rogers
People make mistakes. It’s just that simple. And when it comes to computers, even smart people can make a huge blunder. One of those blunders is deleting files that are still needed. Under some other operating systems, like MS-DOS or even some Windows versions, un-deleting a file is as simple as using the undelete command. But LINUX flavors use a completely different type of file-system that requires a bit more strategy. Please bear in mind, however, that nothing beats a good data backup schedule.
This article deals strictly with linux 2.2.14x. Other flavors of LINUX will work similarly, but the commands and options may be slightly different. With recent developments in the linux kernel, we highly recommend that the user use a specialty application for recovering files versus doing it by hand.
There are several issues we need to concern ourselves with when we talk about recovering files on a typical LINUX file-system. One of those issues is disk fragmentation. When an operating system writes files to the hard disk, it doesn’t lay the entire file on the disk in one large segment. Instead, the file is broken up into bits and written in various places across the disk. When you delete a file, you mark all those spaces as free to use again. If any one of those small segments of the file have been reused by the operating system, complete recovery of the target file is not possible.
The second thing to consider is the number of processes running on the system. If you have a large server system with many users accessing files and writing files, then the chance is better that at least a portion of your file has been written over.
The third consideration is time. The longer it has been since the file was deleted, the less chance you have to recover it. Un-deleting a file under LINUX is best done as soon as you realize the file was deleted. Don’t wait until later. It might be too late by then.
There several methods for file un-deletion under LINUX. One method involves altering the file-system’s inode table to remove the deleted flag that has been placed on the target file. This method is usually quicker, but may or may not work. Another consideration is the size of the file. The LINUX inode table stores up to the first 12 block numbers of each file directly inside the inode table itself. If the file is larger than 12 blocks, the situation has increased in complexity, dramatically.
The second alternative is to locate all the pieces of the file on the partition and copy them over to a new file on a different partition. This method is much slower, but the results are more dependable if the file size is less than 12 blocks. In the interest of brevity, we’ll assume a file size of 12 blocks or less.
The third method is more of a recovery versus an actual undelete. The file is not brought back from the dead, but the information is actually copied to a new location.
We need to know what files have been marked as deleted recently. By using the debugfs command, we can generate a list of all files that have recently been deleted, their relative inode number, date of deletion, file size, etc. Hopefully, you will know enough about the file size and when it was deleted to locate your file in the list. To generate this listing, type the following command:
# echo lsdel | debugfs /dev/hda4 > lsdel.out
This command assumes that the file you’re looking for is on the hda4 partition. The results will look something like this:
Inode Owner Mode Size Blocks Time deleted
289732 500 100664 93 1/ 1 Mon Aug 14 08:37:10 2000
241450 500 100600 11332 3/ 3 Mon Aug 14 17:31:39 2000
772625 500 100600 115 1/ 1 Mon Aug 14 17:31:39 2000
772626 500 100600 2171 1/ 1 Mon Aug 14 17:31:39 2000
772627 500 100600 35 1/ 1 Mon Aug 14 17:31:39 2000
772628 500 100600 2233 1/ 1 Mon Aug 14 17:31:39 2000
177093 500 100600 53470 8/ 15 Tue Aug 15 09:56:06 2000
241451 500 100600 765 1/ 1 Tue Aug 15 09:56:06 2000
241452 500 100600 698 1/ 1 Tue Aug 15 09:56:06 2000
241453 500 100600 443 1/ 1 Tue Aug 15 09:56:06 2000
241454 500 100600 395 1/ 1 Tue Aug 15 09:56:06 2000
241455 500 100600 468 1/ 1 Tue Aug 15 09:56:06 2000
241456 500 100600 596 1/ 1 Tue Aug 15 09:56:06 2000
241457 500 100600 387 1/ 1 Tue Aug 15 09:56:06 2000
498999 500 100600 24691 7/ 7 Tue Aug 15 09:56:06 2000
499005 500 100600 24720 5/ 7 Tue Aug 15 09:56:06 2000
This output makes it quite easy to see how many blocks are associated with each file. But you can also see that no filenames are given. The more recently deleted files will be at the bottom of the output file.
The first method uses debugfs to modify exiting inode table information. The partition that you are altering should be mirrored to another location. Without keeping a raw, safe copy of the partition data somewhere else, you may be destroying your file-system.
Next, we bring up the debugfs interface by typing 'debugfs' at the root prompt. Once up, we type the following command to edit the inode information:
debugfs: mi <49899>
On the output the follows, we are only interested in changing the fields for 'deletion time' and 'link count'. We will change the deletion time to 0 (zero) and the link count to 1. For all the other fields, we simply press Return through them to accept the current value. If none of the blocks were overwritten, then your file may be safe.
Although the file is officially 'undeleted', we still need to update the file directory structure to reflect the change. We do this by typing the following command:
# e2fsck -f /dev/hda4
Next, we run debugfs. Once we have the interface up, we can recover the specific inode we want by typing the command:
debugfs: dump <498999> /home/tmp/foo.txt
This command dumps the data at the deleted inode location 498999 into a recovery file at /home/tmp/foo.txt. There could potentially be random garbage characters at the end of the file that can be removed by typing:
# dd count=1 if=/home/tmp/foo.txt of=/mnt/resize.000 bs=24691
This command used the file size (24691) for inode number 498999, as stated in the lsdel.out file. If the information in the recovered file contains miscellaneous garbage, then a block of your data has been overwritten. There is no way to recover this data at the level we are working. Scheduled backups will always be the quickest and easiest method for recovering lost work and data.
Method 3 is strictly for recovering text files such as programming code or emails. Using a command called 'egrep', we can search a file (or device in this case) for a string of text. We can also limit how much information around the search string is recovered. The output from the 'egrep' command will be redirected to a new file on a different partition to ensure that the data we are trying to recover is not overwritten.
Let’s assume we are looking for an email from a friend about a 'Barrier Firewall'. Our user email is normally saved under our home directory on /dev/hda4. The following command will search that drive for the string 'Barrier Firewall' and dump the output into a file named 'myemail' in the /tmp (which is on a different partition of the hard disk).
$ egrep -50 ‘Barrier.Firewall’ /dev/hda4 > /tmp/myemail
We can check the output by typing:
$ strings /tmp/myemail | more
With any luck, you’ll be able to see the email you’re looking for in the output.
Some Extra Notes:
As of two years ago, with the release of the 2.2.x kernel, recovering deleted files was made considerably easier. Without going into too much detail, the kernel does not automatically release all blocks above the initial 12 blocks listed in the inode table, as it did in previous versions. This gives you greater opportunity to restore lost blocks of data from much larger files.