Se um arquivo foi excluído, mas ainda está aberto, isso significa que o arquivo ainda existe no sistema de arquivos (possui um inode ), mas possui uma contagem de links físicos igual a 0. Como não há um link para o arquivo, você não pode abri-lo pelo nome . Também não há facilidade para abrir um arquivo por inode.
Não há como descobrir o arquivo através do sistema de arquivos e, principalmente, como procurar o arquivo no diretório em que ele estava pela última vez. A entrada do diretório desapareceu. Tudo o que resta é o próprio arquivo. Você pode acessar o arquivo com um depurador do sistema de arquivos, mas isso requer permissões de root e é difícil de usar e propenso a erros.
O Linux expõe arquivos abertos por meio de links simbólicos especiais em /proc
. Esses links são chamados /proc/12345/fd/42
onde 12345 é o PID de um processo e 42 é o número de um descritor de arquivo nesse processo. Um programa executando como o mesmo usuário desse processo pode acessar o arquivo (as permissões de leitura / gravação / execução são as mesmas que você tinha quando o arquivo foi excluído).
O nome sob o qual o arquivo foi aberto ainda é visível no destino do link simbólico: se o arquivo era /var/log/apache/foo.log
, então o destino do link é /var/log/apache/foo.log (deleted)
. (Se o arquivo foi renomeado depois de aberto, o destino do link simbólico pode refletir a renomeação.)
Assim, você pode recuperar o conteúdo de um arquivo excluído aberto, considerando o PID de um processo que o abre e o descritor em que é aberto da seguinte maneira:
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 você souber apenas o ID do processo, mas não o descritor, poderá recuperar todos os arquivos com
for x in /proc/$pid/fd/*; do
recover_open_deleted_file "$x"
done
Se você também não souber o ID do processo, poderá pesquisar entre todos os processos:
for x in /proc/[1-9]*/fd/*; do
case $(readlink "$x") in
/var/log/apache/*) recover_open_deleted_file "$x";;
esac
done
Você também pode obter essa lista analisando a saída de lsof
, mas ela não é mais simples, nem mais confiável nem mais portátil (de qualquer maneira, isso é específico do Linux).
lsof / | awk '(/deleted/||/abc.txt/) {print "FD :-",$4,"| File Name:-",$9}'