Что происходит с открытым дескриптором файла на Linux, если резкий файл перемещен или удалил

Что происходит с открытым дескриптором файла на Linux, если резкий файл между тем добирается:

  • Отодвинутый-> дескриптор файла остается допустимым?
  • Удаленный-> это приводит к EBADF, указывая на недопустимый дескриптор файла?
  • Замененный новым файлом-> Делает дескриптор файла, указывающий на этот новый файл?
  • Замененный жесткой ссылкой на новый файл-> мой дескриптор файла "переходит" по этой ссылке?
  • Замененный гибкой ссылкой на новый файл-> мой дескриптор файла поражает этот файл гибкой ссылки теперь?

Почему я задаю такие вопросы: я использую замененные в горячем режиме аппаратные средства (такие как USB-устройства и т.д.). Это может произойти, что устройство (и также его/dev/file) повторно прикреплено пользователем или другим Гремлином.

Что лучшая практика имеет дело с этим?

96
задан Flimzy 9 October 2019 в 13:00
поделиться

5 ответов

Значение NULL < T > реализовано как структура, а структуры являются типами значений.

-121--2434093-

Да, для идентификации элемента можно использовать локаторы XPath, CSS или DOM. В этом примере XPath может выглядеть как//lable [@ for = 'ctl00 _ content _ loginForm _ ctl01 _ username'], чтобы идентифицировать эту метку.

-121--2943682-

Если файл перемещен (в той же файловой системе) или переименован, то дескриптор файла остается открытым и может использоваться для чтения и записи файла.

Если файл удален, дескриптор файла остается открытым и может по-прежнему использоваться (некоторые люди этого не ожидают). Файл действительно не будет удален, пока не будет закрыт последний дескриптор.

Если файл заменен новым файлом, это точно зависит от способа. Если содержимое файла будет перезаписано, дескриптор файла останется действительным и получит доступ к новому содержимому. Если существующий файл не связан и новый файл создан с тем же именем или, если новый файл перемещен в существующий файл с помощью rename () , это то же самое, что и удаление (см. выше) - то есть дескриптор файла продолжит ссылаться на исходную версию файла.

В целом, как только файл открыт, файл открыт, и никто изменяющий структуру каталогов не может изменить это - они могут двинуться, переименовать файл или положить что-то еще на его место, это просто остается открытым.

В Unix нет удаления, только unlink () , что имеет смысл, поскольку он не обязательно удаляет файл - просто удаляет ссылку из каталога.


Если, с другой стороны, нижележащее устройство исчезнет (например, USB unplug), то дескриптор файла больше не будет действительным и, вероятно, даст IO/error при любой операции. Но ты все равно должен его закрыть. Это будет верно, даже если устройство будет подключено обратно, так как в этом случае нецелесообразно сохранять файл открытым.

141
ответ дан 24 November 2019 в 05:39
поделиться
[

]В каталоге /proc/ вы найдете список всех активных в данный момент процессов, просто найдите свой PID и все данные о нем. Интересующая информация - папка fd/, вы найдете все обработчики файлов, открытые процессом в данный момент. [

] [

]В конце концов вы найдете символическую ссылку на ваше устройство (под /dev/ или даже /proc/bus/usb/), если устройство зависает, ссылка будет мертва и обновить этот хэндл будет невозможно, процесс должен закрыть и открыть его снова (даже при повторном подключении)[

] [

]Этот код может прочитать текущее состояние вашей PID-ссылки[

] [
#include <unistd.h>
#include <stdio.h>
#include <dirent.h>

int main() {
    // the directory we are going to open
    DIR           *d;

    // max length of strings
    int maxpathlength=256;

    // the buffer for the full path
    char path[maxpathlength];

    // /proc/PID/fs contains the list of the open file descriptors among the respective filenames
    sprintf(path,"/proc/%i/fd/",getpid() );

    printf("List of %s:\n",path);

    struct dirent *dir;
    d = opendir(path);
    if (d) {
        //loop for each file inside d
        while ((dir = readdir(d)) != NULL) {

            //let's check if it is a symbolic link
            if (dir->d_type == DT_LNK) {

                const int maxlength = 256;

                //string returned by readlink()
                char hardfile[maxlength];

                //string length returned by readlink()
                int len;

                //tempath will contain the current filename among the fullpath
                char tempath[maxlength];

                sprintf(tempath,"%s%s",path,dir->d_name);
                if ((len=readlink(tempath,hardfile,maxlength-1))!=-1) {
                    hardfile[len]='\0';
                        printf("%s -> %s\n", dir->d_name,hardfile);

                } else
                    printf("error when executing readlink() on %s\n",tempath);

            }
        }

        closedir(d);
    }
    return 0;
}
] [

]Этот окончательный код прост, вы можете поиграть с функцией linkat.[

] [
int
open_dir(char * path)
{
  int fd;

  path = strdup(path);
  *strrchr(path, '/') = '\0';
  fd = open(path, O_RDONLY | O_DIRECTORY);
  free(path);

  return fd;
}

int
main(int argc, char * argv[])
{
  int odir, ndir;
  char * ofile, * nfile;
  int status;

  if (argc != 3)
    return 1;

  odir = open_dir(argv[1]);
  ofile = strrchr(argv[1], '/') + 1;

  ndir = open_dir(argv[2]);
  nfile = strrchr(argv[2], '/') + 1;

  status = linkat(odir, ofile, ndir, nfile, AT_SYMLINK_FOLLOW);
if (status) {
  perror("linkat failed");
}


  return 0;
}
]
1
ответ дан 24 November 2019 в 05:39
поделиться

Информация в памяти удаленного файла (все приведенные вами примеры являются экземплярами удаленного файла ), а также inodes на диске остаются в наличии, пока файл не будет закрыт.

«Горячее» подключение оборудования - это совершенно другая проблема, и вы не должны ожидать, что ваша программа просуществует долго, если inodes на диске или метаданные вообще изменились .

2
ответ дан 24 November 2019 в 05:39
поделиться

Вы должны начать: http://de.php.net/manual/en/function.readfile.php

Изменить: если веб-сервер его поддерживает, использование

header('X-Sendfile: ' . $filename);

, где имя файла содержит локальный путь, например

/var/www/www.example.org/downloads/example.zip

, быстрее, чем readfile ().

(применяются обычные соображения безопасности при использовании заголовка ())

-121--2244280-

Существует fpassthru () , который должен делать именно то, что вам нужно. См. ручную запись для ознакомления со следующим примером:

<?php

// open the file in a binary mode
$name = './img/ok.png';
$fp = fopen($name, 'rb');

// send the right headers
header("Content-Type: image/png");
header("Content-Length: " . filesize($name));

// dump the picture and stop the script
fpassthru($fp);
exit;

?>

См. здесь для всех функций файловой системы PHP.

Если это двоичный файл, который вы хотите предложить для загрузки, вы, вероятно, также хотите отправить правильные заголовки, так что откроется диалоговое окно «Save as».. В первом ответе на этот вопрос приведен хороший пример того, какие заголовки следует отправить.

-121--2244276-

Я не уверен в других операциях, но что касается удаления: удаление просто не происходит (физически, т.е. в файловой системе), пока не будет закрыт последний открытый дескриптор файла. Таким образом, невозможно удалить файл из приложения.

Некоторые приложения (которые не приходят в голову) полагаются на такое поведение, создавая, открывая и немедленно удаляя файлы, которые затем работают точно так же долго, как приложение, позволяя другим приложениям быть осведомленными о жизненном цикле первого приложения без необходимости просматривать карты процессов и т.д.

Возможно, аналогичные соображения применимы и к другим вещам.

4
ответ дан 24 November 2019 в 05:39
поделиться

Ручки файлов указывают на inode не к пути, поэтому большинство ваших сценариев все еще работают, как вы предполагаете, поскольку ручка все еще указывает на файл.

В частности, с сценарием удаления - функция называется «UnimeNe» по какой-то причине, она разрушает «ссылку» между именем файла (кунтаж) и файлом. Когда вы открываете файл, то разверните его, файл на самом деле все еще существует до тех пор, пока его ссылочный счетчик не будет до нуля, что при закрытии ручки.

Редактировать: В случае аппаратного обеспечения вы открыли ручку к определенному узлу устройств, если вы отключаете устройство, ядро ​​не удастят все доступ к нему, даже если устройство возвращается. Вам придется закрыть устройство и открыть его.

8
ответ дан 24 November 2019 в 05:39
поделиться
Другие вопросы по тегам:

Похожие вопросы: