Il arrive qu’un fichier soit effacé par erreur et que par chance il est maintenu ouvert par un processus, il est alors facile de récupérer le fichier en question.
Cela n’est valable que pour les systèmes Unix/Linux/BSD/etc car le fichier n’est réellement effacé qu’une fois qu’il est « libéré » par tous les programmes. Sous Windows il n’est pas possible de supprimer un fichier lorsqu’il est ouvert, donc le cas n’existe pas.
S’assurer que le fichier ne sera pas fermé
Si c’est par exemple le disque virtuel d’une machine virtuelle actuellement en route, on a le temps de faire les manipulations tant qu’on ne stoppe pas la machine virtuelle. Si par contre c’est un programme qui risque de terminer son travail rapidement, il est intéressant de le mettre en pause :
# mettre en pause forcée un programme :
kill -STOP ${PID_DU_PROGRAMME}
# ou
pkill -STOP ${NOM_DU_PROGRAMME}
# ou
killall -STOP ${NOM_DU_PROGRAMME}# pour remettre le programme en route :
kill -CONT ${PID_DU_PROGRAMME}
# ou
pkill -CONT ${NOM_DU_PROGRAMME}
# ou
killall -CONT ${NOM_DU_PROGRAMME}
Si c’est un programme qui fonctionne dans votre shell, évitez d’utiliser ctrl+Z car cela génère le signal STP qui peut être intercepté par le programme (le signal STOP indiqué plus haut agit directement via le noyau) et donc ignoré (on s’en rend vite compte) mais surtout qui peut générer des actions du programme, en particulier le programme peut être fait pour libérer les ressources donc éventuellement fermer le fichier qu’on souhaite récupérer, ce qui compliquerait beaucoup la tâche.
A noter que certains programmes mal faits plantent lors de la sortie de pause. Le but ici étant de récupérer un fichier effacé par erreur, c’est en principe un moindre mal.
Récupérer le fichier
Il y a plusieurs méthodes pour récupérer le fichier. La plus simple est une simple copie :
# identifier le descripteur de fichier
ls -l /proc/${PID_DU_PROGRAMME}/fd/
# on obtient alors la liste des fichiers ouverts par le processus, l’un d’eux est par exemple
# lr-x—— 1 kvm kvm 64 juin 16 2016 11 -> /srv/kvm/virt4/disk2.bin
# –> le numéro du descripteur est « 11 »# copier le fichier
cp /proc/${PID_DU_PROGRAMME}/fd/11 /nouveau/chemin/etc# certains préfèrent utiliser « tail »
tail -c +0 -f /proc/${PID_DU_PROGRAMME}/fd/11 > /nouveau/chemin/etc
On a donc une copie du fichier, et non le fichier d’origine.
Si on remet ensuite le programme en route et qu’il modifie le fichier en attente d’effacement, les modifications ne seront pas présentes dans le fichier copié.
Une autre solution est de créer un lien dur (hard link) vers le fichier en attente d’effacement :
# trouver l’inode du fichier :
lsof -p ${PID_Du_PROGRAMME}
# on filtre éventuellement avec | grep /chemin/du/fichier
# la sortie est du genre :
kvm 18480 kvm 5w REG 8,5 137659072 89104 /srv/kvm/virt4/disk2.bin (deleted)
# le fichier est bien marqué comme étant effacé
# l’inode est 89104# lancer « debugfs » pour créer le lien dur
debugfs -w /dev/xxxxx # si besoin, utiliser « mount » pour savoir quel est le bon périphérique
debugfs: cd /srv/kvm/virt4
debugfs: ln <89104> disk2.bin_tmp
debugfs: q
ATTENTION : il ne faut pas que le nouveau nom de fichier soit le même que l’ancien, car gros risque de corruption du système de fichiers.
Le nouveau fichier est un lien dur vers celui en attente d’effacement, donc les données sont « vivantes » : si on remet le programme en route, les modifications seront bien prises en compte. Une fois le programme terminé, on peut renommer le fichier pour que tout soit propre comme au départ.