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

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

Я пытался

xtricman⚓ArchVirtual⏺️~

решение1

Предполагается, что вы не сможете этого сделать (но ниже вы найдете интересное исключение).

Если бы ядро ​​позволило этому произойти, то был бы такой вызов:

fd = open(filename, O_CREAT|O_RDWR, 0666);
unlink(filename);

linkat(fd, "", 0, "/new/path", AT_EMPTY_PATH);

будет выполнен успешно, даже если индексный дескриптор, на который ссылается, fdимеет количество ссылок 0, если это выполняется процессом с CAP_DAC_READ_SEARCHограничениями.

Но ядро ​​активно препятствует этому, независимо от возможностей или привилегий процесса, который это делает.

int vfs_link(struct dentry *old_dentry, ...
{
        ...
        /* Make sure we don't allow creating hardlink to an unlinked file */
        if (inode->i_nlink == 0 && !(inode->i_state & I_LINKABLE))
                error =  -ENOENT;

Это также задокументировано на странице руководства:

AT_EMPTY_PATH(начиная с Linux 2.6.39)

Если oldpathпустая строка, создать ссылку на файл, на который ссылается olddirfd(который мог быть получен с помощью open(2) O_PATHфлага). В этом случае olddirfdможет ссылаться на любой тип файла, кроме каталога. Это, как правило, не сработает, если файл имеет нулевое количество ссылок ( исключением являются файлы, созданные с использованием O_TMPFILEи без использования ).O_EXCL. Вызывающий должен иметь CAP_DAC_READ_SEARCHвозможность использовать этот флаг. Этот флаг специфичен для Linux; определите, _GNU_SOURCEчтобы получить его определение.

на основе исходного кода ядра, похоже, нет других исключений, кроме O_TMPFILE. O_TMPFILEэто задокументировано в open(2)man-странице; ниже приведен небольшой пример, основанный на этом:

#define _GNU_SOURCE 1
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <err.h>

int main(int ac, char **av){
        char path[64]; int fd;
        if(ac < 3) errx(1, "usage: %s dir newpath", av[0]);

        if((fd = open(av[1], O_TMPFILE|O_RDWR, 0666)) == -1) err(1, "open");

        /*
         * ...
         * write stuff to fd and only "realize" the file at the end if
         * everything has succeeded
         */

        /* the following line only works with CAP_DAC_READ_SEARCH */
        /* if(linkat(fd, "", 0, av[2], AT_EMPTY_PATH)) err(1, "linkat"); */

        snprintf(path, sizeof path, "/proc/self/fd/%d", fd);
        if(linkat(AT_FDCWD, path, AT_FDCWD, av[2], AT_SYMLINK_FOLLOW))
                err(1, "linkat");
        return 0;
}

решение2

Вы можете просто catуказать этот дескриптор файла:

$ echo foo > bar
$ sleep 10m < bar & rm bar 
[1] 15743
$ ls -l /proc/15743/fd 
total 0
lr-x------ 1 olorin olorin 64 Jan 16 17:49 0 -> /tmp/bar (deleted)
lrwx------ 1 olorin olorin 64 Jan 16 17:49 1 -> /dev/pts/6
lrwx------ 1 olorin olorin 64 Jan 16 17:49 2 -> /dev/pts/6
$ cat /proc/15743/fd/0
foo
$ cat /proc/15743/fd/0 > bar
$ cat bar
foo

Вы не можете lnсоздать для этого файла жесткую ссылку, поскольку жесткие ссылки не могут охватывать файловые системы, и /procэто виртуальная файловая система ( procfs), и даже внутри нее /procваши действия ограничены (содержимое отражает состояние ядра, поэтому вы не можете выполнять произвольные операции).

Связанный контент