Якщо файл було видалено, але він все ще відкритий, це означає, що файл все ще існує у файловій системі (у нього є inode ), але кількість жорстких посилань становить 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}'