Se um arquivo foi excluído, mas ainda está aberto, isso significa que o arquivo ainda existe no sistema de arquivos (ele tem um inode ) mas tem um link link físico de 0. Como não há link para o arquivo, não é possível abri-lo até nome. Não há facilidade para abrir um arquivo por inode.
Não há como descobrir o arquivo através de seu sistema de arquivos e, especialmente, nenhuma maneira de procurar o arquivo no diretório em que ele durou. A entrada do diretório desapareceu. Tudo o que resta é o próprio arquivo. Você pode acessar o arquivo com um depurador de 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 através 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 em execução 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 for /var/log/apache/foo.log
, o destino do link será /var/log/apache/foo.log (deleted)
. (Se o arquivo foi renomeado depois que ele foi 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 tenha aberto e o descritor que ele abriu assim:
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ê conhece apenas o ID do processo, mas não o descritor, você pode recuperar todos os arquivos com
for x in /proc/$pid/fd/*; do
recover_open_deleted_file "$x"
done
Se você também não conhece o ID do processo, pode 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 não é mais simples nem mais confiável nem mais portátil (de qualquer forma, isso é específico do Linux).