从Unix上的文件句柄创建硬链接?

Dav*_*ver 20 unix linux macos

如果我有一个打开文件的句柄,是否可以在从文件系统中删除对该文件的所有引用后创建该文件的硬链接?

例如,像这样:

fd = fopen("/tmp/foo", "w");
unlink("/tmp/foo");
fwrite(fd, "Hello, world!\n");
create_link_from_fd(fd, "/tmp/hello");
fclose(fd);
Run Code Online (Sandbox Code Playgroud)

具体来说,我想这样做,以便我可以安全地写入大型数据文件,然后原子地将它们移动到位,而不必担心如果我的程序在写入文件的过程中被杀死后自己清理.

saf*_*f32 11

新发布的Linux 3.11通过新O_TMPFILE open(2)标志提供了解决此问题的方法.使用此标志,您可以在某个文件系统中创建"不可见"文件(即没有硬链接的inode)(由该文件系统中的目录指定).然后,在完全设置文件后,您可以使用创建硬链接linkat.它的工作原理如下:

fd = open("/tmp", O_TMPFILE | O_RDWR, 0600);
// write something to the file here
// fchown()/fchmod() it
linkat(fd, "", AT_FDCWD, "/tmp/test", AT_EMPTY_PATH);
Run Code Online (Sandbox Code Playgroud)

请注意,除了> = 3.11内核要求之外,这还需要来自底层文件系统的支持(我在ext3上尝试了上面的代码段并且它可以工作,但它似乎不适用于btrfs).


tor*_*rek 4

一般情况下不会,不会。[编辑:从 Linux 3.11 开始,现在有了linkat;请参阅safsaf32 的回答。一般来说,这在 POSIX 系统上不起作用,因为 POSIXlinkat仅限于目录。] 这里有安全考虑:有人可以向您传递一个您通常无法open自己传递的打开文件描述符,例如:

\n\n
mkdir lock; chmod 700 lock\necho secret contents > lock/in\nsudoish cmd < lock/in\n
Run Code Online (Sandbox Code Playgroud)\n\n

这里cmd运行的用户身份没有open输入文件 ( lock/in) 的名称权限,但仍可以从中读取。如果cmd可以在同一文件系统上创建新名称,则可以将文件内容传递给后续进程。(显然它可以复制这些内容,所以这个问题更多的是“错误地传递内容”而不是“故意传递内容”。)

\n\n

也就是说,人们已经想出了通过 inode/vnode 在内部“重新链接”文件的方法(在大多数文件系统中这很容易做到),因此您可以为其创建自己的私有系统调用。描述符必须引用适当安装点上的真实文件,当然\xe2\x80\x94没有办法将管道或套接字或设备“重新链接”为常规文件。

\n\n

否则,您将陷入“捕获信号并清理并希望得到最好的结果”,或类似的技巧,“分叉子进程,运行它,如果成功/失败,则采取适当的移动/清理操作” 。

\n\n
\n\n

编辑添加历史注释:上面的lock例子不是特别好,但是在 V6 Unix 时代,MDQS使用了这个技巧的更高级版本。如今,MDQS 的各个部分以各种形式存在。

\n