Если файл был удален, но все еще открыт, это означает, что файл все еще существует в файловой системе (он имеет индекс ), но имеет жесткое число ссылок, равное 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}'