December 9, 2020

OpenBSD: Recover deleted files and a rm script

Yes, I do remove files from time to time.

Recently, I even came to the impressive idea of typing

$ rm -r /home/pau

for some reason. I was intending to remove a folder in my home directory but I did this amazing thing of forgetting to type the name of the folder. Even if I realised some few seconds after I hit enter, some files had been deleted. I do a backup regularly, but there was one file I had lost. This is what I do to recover files in such cases:

  1. Do not use the filesystem anymore. Don’t write, don’t remove. Nothing. Remember that rm just assigns that portion of the drive to be available for future writing operations.
  2. Make an image of the partition you managed to screw.
  3. Use tsk to recover the file.

Step by step, this is what you have to do.

Install tsk

# pkg_add sleuthkit

Make an image of the partition you “tempered” with

In my case, the partition was /home which is encrypted. What I did was to unmount it but left it of course decrypted. Then create an img of it on, say, an external USB drive.

# dd if=/dev/sd1a of=/mnt/USBRaid/home.img bs=1m

If your USB has the same filesystem, it will be fast, otherwise it can take a long time.

Get information about the image

# mmls  /mnt/USB/home.img 
BSD Disk Label
Offset Sector: 0
Units are in 512-byte sectors

      Slot      Start        End          Length       Description
000:  002       0000000000   0686994671   0686994672   Unused (0x00)
001:  Meta      0000000001   0000000001   0000000001   Partition Table
002:  000       0000000064   0686987583   0686987520   4.2BSD (0x07)

As you can see, the data starts on 64, so that in principle this command should give you information about the structure of the folders etc but, for some reason, it does not work on our filesystem, unfortunately:

# fls -o 64 -r /mnt/USB/home.img
Cannot determine file system type

(try to) Recover deleted files

Since we do not have information about the structure, we have to run it over the whole image:

# tsk_recover /mnt/USB/home.img /mnt/USB/recovered

Here /mnt/USB/recovered is obviously the target directory to recover the files. If you add the flag -e it will recover all files, both allocated and unallocated (slang for files and removed files).

If we had had information about the inodes, it would have been as easy as running it on the inode of interest:

# icat -o 64 -r /mnt/USB/home.img 325 > /mnt/USB/recovered/MyDeletedFile

Alias rm

Following the advise of a wise person, Giorgos (Vretinaris/Lioutas), I have decided to alias my rm to something different to avoid this kind of problem.

In my zshrc file I have defined

alias rm='$HOME/bin/fem.sh'

Where the script is

#!/bin/sh

# Make sure that $HOME/.fem exists

if [ -d "$HOME/.fem" ]; then
  :
else
  mkdir $HOME/.fem
  echo "Created $HOME/.fem directory"  
fi

# Record pwd of the file to be moved, along with the 
# name(s) of the file(s), in case we want to restore 
# them to their original location.

# First check that the pwd log file exists in $HOME/.fem

if [ -f "$HOME/.fem/pwdlog.txt" ]; then
  :
else
  touch $HOME/.fem/pwdlog.txt
  echo "Created pwd log file in $HOME/.fem"  
fi

# Then log it

PWD=`pwd`
APPEND=`echo $PWD`"/"$@
echo $APPEND >> $HOME/.fem/pwdlog.txt

# Since we are aliasing rm with mv, make sure that the
# rm flags do not pose a problem:
while [[ $1 = -* ]]; do
        case $1 in
                -r ) shift 1 ;;
                -f ) shift 1 ;;
                -d ) shift 1 ;;
                -i ) shift 1 ;;
                -P ) shift 1 ;;
                -R ) shift 1 ;;
                -v ) shift 1 ;;
        esac
done

# Move the file(s) and display information

mv -iv "$@" $HOME/.fem

and fem is the folder where all “deleted” files go. Of course, it will require to empty it from time to time using the real rm, i.e. /bin/rm.

Since a few of you asked, “fem” means in one of my mother tongues “I saw yesterday my neighbour Lucy playing a yellow violin while chitchatting with a pink whale on the corner”.