Linux 在Unix上从文件句柄创建硬链接?
如果我有一个打开文件的句柄,那么在文件系统中删除对该文件的所有引用之后,是否可以创建指向该文件的硬链接 例如,类似这样的内容:Linux 在Unix上从文件句柄创建硬链接?,linux,macos,unix,Linux,Macos,Unix,如果我有一个打开文件的句柄,那么在文件系统中删除对该文件的所有引用之后,是否可以创建指向该文件的硬链接 例如,类似这样的内容: fd = fopen("/tmp/foo", "w"); unlink("/tmp/foo"); fwrite(fd, "Hello, world!\n"); create_link_from_fd(fd, "/tmp/hello"); fclose(fd); fd = open("/tmp", O_TMPFILE | O_RDWR, 0600); // write
fd = fopen("/tmp/foo", "w");
unlink("/tmp/foo");
fwrite(fd, "Hello, world!\n");
create_link_from_fd(fd, "/tmp/hello");
fclose(fd);
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);
特别是,我想这样做,这样我就可以安全地写入大数据文件,然后将它们移动到原子的位置,而不必担心在我的程序被写入文件时被杀死后自我清理。 在Linux上,你可以尝试调用< <代码> /PRO/FUD/FD>代码>的不可移植的技巧,试图调用< /P>
char pbuf[64];
snprintf (pbuf, sizeof(pbuf), "/proc/self/fd/%d", fd);
link(pbuf, "/tmp/hello");
如果在取消链接(“/tmp/foo”)
后,这个技巧起作用,我会感到惊讶。。。我没有试过
一种更具可移植性(但不那么健壮)的方法是生成一条“唯一的临时路径”,可能类似于
int p = (int) getpid();
int t = (int) time(0);
int r = (int) random();
sprintf(pbuf, sizeof(pbuf), "/tmp/out-p%d-r%d-t%d.tmp", p, r, t);
int fd = open (pbuf, O_CREAT|O_WRONLY);
写入并关闭文件后,您可以将其重命名为更合理的路径。您可以在程序中使用atexit
来进行重命名(或删除)
还有一些cron
工作,每小时清理一次[old]/tmp/out*.tmp
一般来说不是,不是。[编辑:自Linux 3.11以来,现在有了linkat
;请参阅。这通常不适用于POSIX系统,因为POSIXlinkat
仅限于目录。]这里有一些安全注意事项:有人可以向您传递一个打开的文件描述符,您通常无法自己打开该描述符,例如:
mkdir lock; chmod 700 lock
echo secret contents > lock/in
sudoish cmd < lock/in
mkdir锁;chmod 700锁
回显秘密内容>锁定/进入
sudoish cmd
此处,cmd
以用户身份运行,该用户无权按名称打开输入文件(lock/in
),但仍可从中读取。如果cmd
可以在同一文件系统上创建新名称,则可以将文件内容传递给后续进程。(很明显,它可以复制这些内容,所以这个问题更多的是“错误地传递内容”,而不是“故意传递内容”。)
这就是说,人们已经想出了在内部通过inode/vnode“重新链接”文件的方法(在大多数文件系统中很容易做到),因此您可以为它调用自己的私有系统。描述符必须引用相应装入点上的真实文件,当然,无法将管道、套接字或设备“重新链接”为常规文件
否则,您将陷入“捕捉信号、清理并期待最好的结果”或类似的伎俩,“放弃子流程,运行它,如果它成功/失败,则采取适当的移动/清理操作”
编辑以添加历史注释:上面的lock
示例并不特别好,但在V6 Unix时代,使用了这个技巧的更高级版本。如今,MDQ的各个部分以各种形式存在。最新发布的linux 3.11使用新的O_TMPFILE
open(2)
标志为这个问题提供了解决方案。使用此标志,您可以在某些文件系统(由该文件系统中的目录指定)中创建一个“不可见”文件(即没有硬链接的inode)。然后,在完全设置文件后,可以使用linkat
创建硬链接。它的工作原理如下:
fd = fopen("/tmp/foo", "w");
unlink("/tmp/foo");
fwrite(fd, "Hello, world!\n");
create_link_from_fd(fd, "/tmp/hello");
fclose(fd);
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上似乎不起作用)。为了避免安全问题,可以通过以下方法来证实这一点,即使用/proc/self/fd/n
“唯一和临时路径”,而是使用POSIXmkstemp
(3)调用创建唯一名称,并在一次调用中打开它。