【问题标题】:Duplicating file descriptor and seeking through both of them independently复制文件描述符并独立搜索它们
【发布时间】:2019-07-10 15:41:26
【问题描述】:

我有一个打开的文件描述符,我想复制它以便独立地执行读取和查找。我看了看

int dup(int old_fd)

系统调用。问题是它并不适合这里。手册页指出以下内容 http://man7.org/linux/man-pages/man2/dup.2.html

成功返回后,新旧文件描述符 可以互换使用。他们指的是同一个 打开文件描述(参见 open(2))并共享文件 偏移量和文件状态标志;例如,如果文件偏移量是 通过对其中一个文件描述符使用 lseek(2) 进行修改, 另一个的偏移量也发生了变化。

有没有办法复制一个文件描述符,使它们完全独立?

【问题讨论】:

    标签: c linux file-descriptor


    【解决方案1】:

    没有——至少,在 POSIX 定义的机制中没有。

    如果你想要文件描述符完全独立,你需要避免共享打开文件描述,这意味着一个独立的open()或等价物。

    有可能有一种特定于 Linux 的机制可以完成我从未听说过的工作。但是,查看http://man7.org/linux/man-pages/man2/ 的 Linux 系统调用并没有提供启示。

    【讨论】:

    • 使用/proc/<pid>/fd/NN 应该可以。正如我所规定的,这确实涉及第二个open()/proc 文件系统不适用于所有其他操作系统。
    • 问题是关于从应用程序的一个线程移动同一文件系统中的文件并从另一个线程打开/proc/pid/fd/NN。符号链接会指向同一个文件还是会引入竞争条件?
    • 我不确定你问的是什么场景。移动文件通常涉及rename() 函数——或者可能是link()unlink()。如果文件已打开,则即使在打开时重命名(或者即使文件的权限发生更改)也可以读取它。所以可能没有问题 - 但我不确定我知道上下文是什么,所以这更像是一个猜测而不是我想要的。
    • 基本上,/proc/<pid>/fd/NN 中的条目始终是最新的。有可能在线程 1 读取 fd 5 的条目之后(比如说),在它可以在任何其他系统调用中使用它之前,线程 2 已经改变了 fd 5 指向的内容,但这基本上是不可避免的。
    • /prod/<pid>/fd/NN 中的条目与您或我在目录中创建的常规符号链接不同。它位于特殊的/proc 文件系统上,它本质上提供了对内核内存中每个进程的信息的文件系统样式访问——一切都是“伪文件”或“伪目录”而不是常规文件或在常规“磁盘支持”文件系统上找到的目录(“磁盘支持”越来越用词不当,因为它更像 SSD 或内存支持)。
    【解决方案2】:

    在 Linux 中,打开 /proc/<pid>/fd/<n> 会打开当前在 fd N 打开的文件,但这是一个新副本,而不是像 dup() 和朋友那样的链接副本。

    这将创建一个包含bar、一堆零字节和foo 的文件。与使用dup()的版本对比。

    #include <unistd.h>
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <fcntl.h>
    #include <stdio.h>
    
    int main(void)
    {
        int fd1, fd2;
        char buffer[50];
    
        fd1 = open("testfile", O_CREAT | O_TRUNC | O_RDWR, 0600);
        sprintf(buffer, "/proc/self/fd/%d", fd1);
    #ifndef USE_DUP
        fd2 = open(buffer, O_RDWR);
        if (fd2 == -1) {
            perror("open");
        }
    #else
        fd2 = dup(fd1);
    #endif
        if (lseek(fd1, 16, SEEK_SET) == -1) {
            perror("lseek");
        }
        if (write(fd1, "foo", 3) == -1) {
            perror("write(fd1)");
        }
        if (write(fd2, "bar", 3) == -1) {
            perror("write(fd2)");
        }
    }
    

    【讨论】:

    • 哇,很有趣。它是否记录在某处?
    • @SomeName,我不确定。 proc(5) man page 记录了 /proc//fd 目录,但它只是说它们上的 readlink() 提供了有用的信息,并且您可以打开它们(/dev/stdin 特别指向 /proc/self/fd/0,所以打开必须工作)。我不知道是否有任何官方文档描述它们与dup() 不同。尽管它们必须是您可以从 另一个 进程的 /proc//fd. 打开文件
    • 无论如何,只要 Linux 开发人员不认真改变他们不搞乱用户空间可见行为的立场,我认为当前的行为不会改变。
    • 但是如果我们移动原始文件,符号链接会变得悬空吗?
    • @SomeName,实际上,不,它遵循重命名。打开它会直接访问 inode,但是,符号链接中显示的名称仅用于显示。它们不是正常的符号链接。 (如果你有硬链接,它可以在符号链接中显示(deleted),即使文件仍然存在,你仍然可以通过符号链接打开它)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-05-11
    • 1970-01-01
    • 2018-02-24
    • 2013-05-30
    相关资源
    最近更新 更多