Если файл был удален, но все еще открыт, это означает, что файл все еще существует в файловой системе (он имеет индекс ), но имеет жесткое число ссылок, равное 0. Поскольку ссылки на файл нет, вы не можете открыть его по имени , Также нет возможности открыть файл по inode.
Нет способа обнаружить файл через его файловую систему, и особенно нет способа найти файл в каталоге, где он был в последний раз. Запись каталога исчезла. Осталось только сам файл. Вы можете получить доступ к файлу с помощью отладчика файловой системы, но для этого требуются права суперпользователя, он сложен в использовании и подвержен ошибкам.
Linux предоставляет открытые файлы через специальные символические ссылки в разделе /proc. Эти ссылки называются, /proc/12345/fd/42где 12345 - это PID процесса, а 42 - номер дескриптора файла в этом процессе. Программа, работающая от имени того же пользователя, что и этот процесс, может получить доступ к файлу (права на чтение / запись / выполнение такие же, как и у вас при удалении файла).
Имя, под которым был открыт файл, по-прежнему отображается в целевом символической ссылке: если файл был /var/log/apache/foo.log, то целевой ссылкой является /var/log/apache/foo.log (deleted). (Если файл был переименован после его открытия, цель символической ссылки может отражать переименование.)
Таким образом, вы можете восстановить содержимое открытого удаленного файла, учитывая PID процесса, в котором он открыт, и дескриптор, в котором он открыт, следующим образом:
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"
Если вы знаете только идентификатор процесса, но не дескриптор, вы можете восстановить все файлы с помощью
for x in /proc/$pid/fd/*; do
recover_open_deleted_file "$x"
done
Если вы не знаете идентификатор процесса, вы можете искать среди всех процессов:
for x in /proc/[1-9]*/fd/*; do
case $(readlink "$x") in
/var/log/apache/*) recover_open_deleted_file "$x";;
esac
done
Вы также можете получить этот список, проанализировав вывод lsof, но он не является ни более простым, ни более надежным, ни более переносимым (так или иначе, это зависит от Linux).
lsof / | awk '(/deleted/||/abc.txt/) {print "FD :-",$4,"| File Name:-",$9}'