ポインティングされたファイルが移動、削除された場合、Linux上で開いているファイルハンドルはどうなりますか


Answers

ファイルハンドルは、iノードをパスではなく指しているので、ハンドルはファイルを指しているので、ほとんどのシナリオは引き続き使用できます。

具体的には、deleteシナリオでは、関数はある理由で "unlink"と呼ばれ、ファイル名(dentry)とファイルの間の "リンク"を破棄します。 ファイルを開いてリンクを解除すると、参照カウントがゼロになるまでファイルが実際に存在します。これはハンドルを閉じるときです。

編集:ハードウェアの場合、特定のデバイスノードへのハンドルを開いています。デバイスを取り外すと、デバイスが復帰してもカーネルはすべてのアクセスを失敗します。 デバイスを閉じてもう一度開く必要があります。

Question

先ほど指摘されたファイルが次のようになると、Linux上で開いているファイルハンドルはどうなりますか?

  • 移動しました - >ファイルハンドルは有効なままですか?
  • Deleted - >これは、無効なファイルハンドルを示すEBADFにつながっていますか?
  • 新しいファイルに置き換えられます - >ファイルハンドルがこの新しいファイルを指していますか?
  • 新しいファイルへのハードリンクで置き換えられます - >私のファイルハンドルはこのリンクに "追従"していますか?
  • 新しいファイルへのソフトリンクに置き換えられました - >私のファイルハンドルがこのソフトリンクファイルにヒットしましたか?

なぜ私はそのような質問をしているのですか?私はホットプラグされたハードウェア(USBデバイスなど)を使用しています。 デバイス(とその/ dev /ファイル)がユーザまたは別のGremlinによって再接続されることがあります。

これに対処するベストプラクティスは何ですか?




ファイルハンドラ(ファイル記述子)が正常かどうかをチェックしたい場合は、この関数を呼び出すことができます。

/**
 * 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;
}



/ proc /ディレクトリの下には、現在アクティブなすべてのプロセスのリストがあります。あなたのPIDとその上にあるすべてのデータが見つかります。 interresting infoはフォルダー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;
}



Related