Как восстановить удаленный файл, если он все еще открыт каким-либо процессом?

19
$ cat important_file > /dev/null &
[1] 9711
$ rm important_file 
$ killall -STOP cat

[1]+  Stopped                 cat important_file > /tmp/p
$ ls -l /proc/`pidof cat`/fd/
total 0
lrwx------ 1 vi vi 64 May 13 20:32 0 -> /dev/pts/29
l-wx------ 1 vi vi 64 May 13 20:32 1 -> /tmp/p
lrwx------ 1 vi vi 64 May 13 20:32 2 -> /dev/pts/29
lr-x------ 1 vi vi 64 May 13 20:32 3 -> /home/vi/important_file (deleted)

Как это восстановить important_file?

Я пробовал что-то вроде

injcode -m dup2 -ofd=3 -ofilename=/tmp/recovered_file -oflags=O_CREAT $PID_OF_CAT

но это ничего не делает.

Vi.
источник

Ответы:

11

Если / home - это NFS, в / home / vi будет файл .nfsNNNNNNNNNN, к которому вы сможете получить доступ / скопировать. Если home является локальной файловой системой, вы можете сделать то же самое по ссылке / proc / PID / fd / 3:

cp /proc/PID/fd/3 /tmp/recovered_file

Если вы действительно хотите восстановить файл, вот пост в блоге на эту тему.

Марк Джонсон
источник
1
ОК, меня это смутило readlink /proc/13381/fd/3-> "/ home / vi / важный_файл (удалено)" и, /home/vi/important_file\ \(deleted\)очевидно, не существует.
Ви.
22

... лучше, чем копировать в определенный момент времени (и собирать только моментальный снимок содержимого файла), это " tail -f" этот файл в новый файл:

tail -c +0 -f /proc/PIDofProgram>/fd/# > /new/path/to/file

(благодаря осторожным программистам tail, они будут работать даже с двоичным выходом.)

Во время его выполнения tail -fсам файл остается открытым, надежно предотвращая его удаление с диска при завершении исходной программы. Таким образом, не останавливайте tail -fсразу же после окончания вашей исходной программы - /new/path/to/fileсначала проверьте хвост , является ли это то, что вы хотите. Если это не так (или неудовлетворительно по любой другой причине), вы можете снова скопировать исходный файл, но на этот раз после того, как вся запись в него будет завершена «Программой» и из все еще работающего tail -fфайла / proc / PIDoftail / FD / каталог.

Кристиан
источник
3
Как насчет создания жесткой ссылки на / proc / PIDofProgram> / fd / #?
Becko
2
@becko Invalid cross-device link.
Камиль Мачоровский
10

Используйте lsof, чтобы найти номер инода, и debugfs, чтобы воссоздать жесткую ссылку на него. Например:

# lsof -p 12345 | grep /var/log/messages
syslogd 12345 root    3w   REG                8,3    3000    987654 /var/log/messages (deleted)
# mount | grep var
/dev/sda2 on /var type ext3 (rw)
# debugfs -w /dev/sda2
debugfs: cd log
debugfs: ln <987654> tmp
debugfs: mi tmp
                      Mode    [0100600] 
                   User ID    [0] 
                  Group ID    [0] 
                      Size    [3181271] 
             Creation time    [1375916400] 
         Modification time    [1375916322] 
               Access time    [1375939901]
             Deletion time    [9601027] 0
                Link count    [0] 1
               Block count    [6232] 
                File flags    [0x0] 
...snip...
debugfs:  q
# mv /var/log/tmp /var/log/messages
# ls -al /var/log/messages
-rw------- 0 root root 3301 Aug  8 10:10 /var/log/messages

Прежде чем жаловаться, я фальсифицировал приведенную выше стенограмму, так как у меня нет удаленного файла, который можно передать сейчас ;-)

Я использую miдля сброса времени удаления и количества ссылок на разумные значения (0 и 1 соответственно), но это не работает должным образом - вы можете видеть, что количество ссылок остается на нуле ls. Я думаю, что ядро ​​может кэшировать данные inode. Вероятно, вы должны использовать fsck при первой же возможности после использования debugfs, чтобы быть в безопасности.

По моему опыту, вы должны создать ссылку, используя временное имя файла, а затем переименовать в правильное имя. Связывание его непосредственно с исходным именем файла может привести к повреждению каталога. YMMV!

Эндрю Галлахер
источник
Почему именно вы предлагаете это, если оно не работает должным образом и вызывает повреждение системы? Я думаю, что вы должны иметь более четкое заявление об отказе от ответа, что это просто WiP, и его не стоит использовать в производстве.
CNST
3

Вы можете просто cpфайл, то есть:

cp /proc/<pid>/fd/<fdno> /new/path/to/file

Конечно, если файл все еще изменяется, у вас возникнут проблемы с этим подходом.

ninjalj
источник