Se un file è stato eliminato ma è ancora aperto, significa che il file esiste ancora nel filesystem (ha un inode ) ma ha un conteggio hard link pari a 0. Poiché non esiste un collegamento al file, non è possibile aprirlo per nome . Non è possibile nemmeno aprire un file per inode.
Non c'è modo di scoprire il file attraverso il suo filesystem, e soprattutto non c'è modo di cercare il file nella directory in cui si trovava l'ultima volta. La voce della directory è sparita. Non resta che il file stesso. È possibile accedere al file con un debugger del file system, ma ciò richiede autorizzazioni di root ed è difficile da usare e soggetto a errori.
Linux espone i file aperti attraverso speciali collegamenti simbolici sotto /proc
. Questi collegamenti vengono chiamati /proc/12345/fd/42
dove 12345 è il PID di un processo e 42 è il numero di un descrittore di file in quel processo. Un programma in esecuzione con lo stesso utente di quel processo può accedere al file (le autorizzazioni di lettura / scrittura / esecuzione sono le stesse che avevi quando il file è stato eliminato).
Il nome con cui è stato aperto il file è ancora visibile nella destinazione del collegamento simbolico: se il file era /var/log/apache/foo.log
, allora la destinazione del collegamento è /var/log/apache/foo.log (deleted)
. (Se il file è stato rinominato dopo l'apertura, la destinazione del collegamento simbolico potrebbe riflettere la ridenominazione.)
Quindi puoi recuperare il contenuto di un file eliminato aperto dato il PID di un processo che lo ha aperto e il descrittore su cui è aperto in questo modo:
recover_open_deleted_file () {
old_name=$(readlink "$1")
case "$old_name" in
*' (deleted)')
old_name=${old_name%' (deleted)'}
if [ -e "$old_name" ]; then
new_name=$(TMPDIR=${old_name%/*} mktemp)
echo "$oldname has been replaced, recovering content to $new_name"
else
new_name="$old_name"
fi
cat <"$1" >"$new_name";;
*) echo "File is not deleted, doing nothing";;
esac
}
recover_open_deleted_file "/proc/$pid/fd/$fd"
Se conosci solo l'ID del processo ma non il descrittore, puoi recuperare tutti i file con
for x in /proc/$pid/fd/*; do
recover_open_deleted_file "$x"
done
Se non conosci l'ID processo, puoi cercare tra tutti i processi:
for x in /proc/[1-9]*/fd/*; do
case $(readlink "$x") in
/var/log/apache/*) recover_open_deleted_file "$x";;
esac
done
Puoi anche ottenere questo elenco analizzando l'output di lsof
, ma non è più semplice né più affidabile né più portatile (questo è comunque specifico di Linux).
lsof / | awk '(/deleted/||/abc.txt/) {print "FD :-",$4,"| File Name:-",$9}'