Qu'arrive-t-il à un descripteur de fichier ouvert sur Linux si le fichier pointé est déplacé, supprimer


Answers

Les handles de fichiers pointent sur un inode et non sur un chemin, donc la plupart de vos scénarios fonctionnent toujours comme vous le supposez, puisque le handle pointe toujours vers le fichier.

Plus précisément, avec le scénario de suppression - la fonction est appelée "unlink" pour une raison, il détruit un "lien" entre un nom de fichier (un dentry) et un fichier. Lorsque vous ouvrez un fichier, puis le dissocier, le fichier existe toujours jusqu'à ce que son nombre de références passe à zéro, ce qui est lorsque vous fermez le handle.

Edit: Dans le cas du matériel, vous avez ouvert un handle vers un nœud de périphérique spécifique, si vous débranchez le périphérique, le noyau échouera tous les accès, même si le périphérique revient. Vous devrez fermer l'appareil et le rouvrir.

Question

Qu'advient-il d'un descripteur de fichier ouvert sur Linux si le fichier pointé entre-temps obtient:

  • Moved away -> Le gestionnaire de fichier reste-t-il valide?
  • Deleted -> Est-ce que cela conduit à un EBADF, indiquant un handle de fichier invalide?
  • Remplacé par un nouveau fichier -> Le fichier gère-t-il ce nouveau fichier?
  • Remplacé par un lien vers un nouveau fichier -> Est-ce que mon fichier gère "suivre" ce lien?
  • Remplacé par un lien logiciel vers un nouveau fichier -> Est-ce que mon identificateur de fichier rencontre maintenant ce fichier de lien logiciel?

Pourquoi je pose ces questions: j'utilise du matériel hot-plug (comme des périphériques USB, etc.). Il peut arriver que l'appareil (et aussi son / dev / file) soit rattaché par l'utilisateur ou un autre Gremlin.

Quelle est la meilleure pratique face à cela?




Sous le répertoire / proc / vous trouverez une liste de tous les processus actuellement actifs, il suffit de trouver votre PID et toutes les données qui s'y trouvent. Une information interressante est le dossier fd /, vous trouverez tous les gestionnaires de fichiers actuellement ouverts par le processus.

Finalement, vous trouverez un lien symbolique vers votre périphérique (sous / dev / ou même / proc / bus / usb /), si le périphérique se bloque, le lien sera mort et il sera impossible d'actualiser ce handle, le processus doit se fermer et l'ouvrir à nouveau (même avec la reconnexion)

Ce code peut lire l'état actuel de votre lien 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;
}

Ce code final est simple, vous pouvez jouer avec la fonction 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;
}



Si vous voulez vérifier si le gestionnaire de fichier (descripteur de fichier) est correct, vous pouvez appeler cette fonction.

/**
 * version : 1.1
 *    date : 2015-02-05
 *    func : check if the fileDescriptor is fine.
 */

#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <stdio.h>

/**
 * On success, zero is returned.  On error, -1  is  returned,  and  errno  is  set
 *      appropriately.
 */
int check_fd_fine(int fd) {
    struct stat _stat;
    int ret = -1;
    if(!fcntl(fd, F_GETFL)) {
        if(!fstat(fd, &_stat)) {
            if(_stat.st_nlink >= 1)
                ret = 0;
            else
                printf("File was deleted!\n");
        }
    }
    if(errno != 0)
        perror("check_fd_fine");
    return ret;
}

int main() {
    int fd = -1;
    fd = open("/dev/ttyUSB1", O_RDONLY);
    if(fd < 0) {
        perror("open file fail");
        return -1;
    }
    // close or remove file(remove usb device)
//  close(fd);
    sleep(5);
    if(!check_fd_fine(fd)) {
        printf("fd okay!\n");
    } else {
        printf("fd bad!\n");
    }
    close(fd);
    return 0;
}



Links