重新打开文件描述符并使用其他访问权限?

14

假设操作系统是Linux。 假设我已经打开了一个文件并获得了一个文件描述符 fdw 用于写入。 是否可能通过不再调用 open 来获取另一个具有只读访问权限的文件描述符 fdr ? 我不想调用 open 的原因是底层文件可能已被其他进程在文件系统中移动甚至取消链接,因此重新使用同一文件名对于这些操作不可靠。 因此,我的问题是:如果只给定一个文件描述符,是否有任何方式可以打开具有不同访问权限的文件描述符? 我认为 dup 或 dup2 不会更改访问权限。

2个回答

19

没错!诀窍是通过/proc/self/fd/n访问已删除的文件。据我所知,这是仅适用于linux的技巧。

运行此程序:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

int main() {
    FILE* out_file;
    FILE* in_file;
    char* dev_fd_path;
    char buffer[128];

    /* Write “hi!” to test.txt */
    out_file = fopen("test.txt", "w");
    fputs("hi!\n", out_file);
    fflush(out_file);

    /* Delete the file */
    unlink("test.txt");

    /* Verify that the file is gone */
    system("ls test.txt");

    /* Reopen the filehandle in read-mode from /proc */
    asprintf(&dev_fd_path, "/proc/self/fd/%d", fileno(out_file));
    in_file = fopen(dev_fd_path, "r");
    if (!in_file) {
        perror("in_file is NULL");
        exit(1);
    }
    printf("%s", fgets(buffer, sizeof(buffer), in_file));

    return 0;
}

它向文件写入一些文本,删除它,但保留文件描述符并通过不同的路径重新打开它。 直到持有最后一个文件描述符的进程关闭它之前,文件实际上并没有被删除,并且在此期间,您可以通过 /proc 访问文件内容。


感谢我的老板Anatoly在我误删一些重要文件时教给我这个技巧,幸运的是这些文件仍然被另一个进程追加!


1
那是作弊,因为他明确说了“不要再调用open” - 虽然我想如果你真的想这样做,那就是你会放松的限制。而且他可能本来就是指“不要使用相同路径再次调用open”。 - tvanfosson
“/dev/proc/fd/n”是什么,这是打字错误吗?根据您的代码,它似乎应该是“/proc/self/fd/%d”。 - user541686
1
哎呀,你说得对!我已经修复了。我之前有点困惑,因为Mac没有/proc/self,但是有/dev/fd/n,不过这个技巧在那里行不通。 - andrewdotn
我可以这样做:char fname[14] = "/tmp/.zXXXXXX"; int f=mkostemp(fname, O_WRONLY); chmod(fname, S_IRUSR | S_IXUSR); int f_ro = open(fname, O_RDONLY); unlink( fname );然后写入f,关闭它并执行f_ro。 - Zibri
@Zibri 这是一个不同于 OP 所询问的问题。 - melpomene
太酷了!这就解释了为什么 echo foo > in; bash -c 'echo bar > /dev/fd/0' < in; cat in 能够正常工作(输出 "bar"),尽管 python3 -c 'import os; print(os.write(0, b"bar\n"))' < in 失败了("[Errno 9] Bad file descriptor")。 - Beni Cherniavsky-Paskin

6

不,fcntl 调用不能让你在打开的文件描述符上设置读/写位,而从现有的文件描述符获取新的文件描述符的唯一方法是使用复制功能。调用 dup/dup2/dup3(和 fcntl)不能让你更改文件访问模式。

注意:这对于Linux是正确的,但通常不适用于其他Unix。例如,在HP-UX中,[请参见(1)(2)],您可以使用fcntl在打开的文件描述符上使用F_SETFL更改读/写位。然而,由dup创建的文件描述符共享相同的状态标志,因此更改一个的访问模式必然会更改另一个的访问模式。


还要注意,freopenFILE * 流的功能上与此类似,因为访问模式是否可变取决于操作系统的实现。 - CMCDragonkai

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接