从Unix上的文件句柄创build一个硬链接?

如果我有一个打开文件的句柄,是否有可能创build一个硬链接到该文件后,所有的引用已经从文件系统中删除?

例如,像这样的东西:

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

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

Solutions Collecting From Web of "从Unix上的文件句柄创build一个硬链接?"

不一般,不。 [ 编辑 :自Linux 3.11现在有linkat ; 看到safsaf32的答案 。 这通常不适用于POSIX系统,因为POSIX linkat仅限于目录。]这里有安全方面的考虑因素:有人可以向您传递一个打开的文件描述符,通常您不能自行open ,例如:

 mkdir lock; chmod 700 lock echo secret contents > lock/in sudoish cmd < lock/in 

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

也就是说,人们已经想出了通过inode / vnode在内部“重新链接”文件的方法(在大多数文件系统中这很容易做到),所以你可以让自己的私有系统调用它。 描述符必须在适当的挂载点上引用一个真实的文件 – 当然,没有办法将管道或套接字或设备“重新连接”成为常规文件。

否则,你会陷入“捕捉信号,清理并希望最好”或类似的伎俩,“分离一个子过程,运行它,如果成功/失败,采取适当的移动/清理行动”。


编辑添加历史记录:上面的lock例子并不是特别好,但是回到V6 Unix的日子里, MDQS使用了这个技巧的一个发烧友版本。 MDQS的各个部分今天以各种形式存在。

新发布的linux 3.11为新的O_TMPFILE open(2)标志提供了一个解决方案。 有了这个标志,你可以在某个文件系统(由该文件系统中的目录指定)中创建一个“不可见”文件(即没有硬链接的inode)。 然后,文件完成设置后,您可以使用linkat创建一个硬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); 

请注意,除了> 3.11内核要求,这也需要来自底层文件系统的支持(我在ext3上试过上面的代码,它工作,但似乎没有在btrfs上工作)。

在Linux上,你可以尝试使用/proc/self/fd尝试调用不可移植的技巧

  char pbuf[64]; snprintf (pbuf, sizeof(pbuf), "/proc/self/fd/%d", fd); link(pbuf, "/tmp/hello"); 

如果这个技巧在unlink("/tmp/foo")后面工作,我会感到惊讶……我没有尝试过。

更便携(但不太健壮)的方式是产生一个“唯一的临时路径”,或许就像

  int p = (int) getpid(); int t = (int) time(0); int r = (int) random(); sprintf(pbuf, sizeof(pbuf), "/tmp/out-p%dr%dt%d.tmp", p, r, t); int fd = open (pbuf, O_CREAT|O_WRONLY); 

一旦文件被写入并关闭,你可以rename(2)rename(2)为更合理的路径。 你可以在程序中使用atexit来进行重命名(或删除)。

并有一些cron工作每小时清理[旧] /tmp/out*.tmp