重新链接一个匿名(未链接但打开)的文件

在Unix中,可以创build一个匿名文件的句柄,例如创build并使用creat()打开它,然后用unlink()移除目录链接 – 留下一个带有inode和存储的文件,但是没有任何可能的方法重新打开它。 这样的文件通常用作临时文件(通常这是tmpfile()返回给你的)。

我的问题:有没有办法重新将这样的文件重新附加到目录结构? 如果你能做到这一点,就意味着你可以实现文件写入,以便文件以primefacesforms出现并完全形成。 这吸引了我强迫的整洁。 ;)

当通过相关的系统调用函数戳时,我希望find一个名为flink()的链接()(与chmod()/ fchmod()比较),但至less在Linux上不存在。

附加点告诉我如何创build匿名文件,而不用简要地暴露磁盘的目录结构中的文件名。

Solutions Collecting From Web of "重新链接一个匿名(未链接但打开)的文件"

几年前提交了一个提议的Linux flink()系统调用的补丁 ,但是当Linus声称“HELL没有办法,我们可以安全地做到这一点,没有大的其他入侵” ,这几乎结束了是否添加这个。

更新:从Linux 3.11开始,现在可以使用open()和新的O_TMPFILE标志创建一个没有目录项的文件,并在/proc/self/fd/使用linkat()完全形成链接到文件系统。 /proc/self/fd/ fdAT_SYMLINK_FOLLOW标志。

以下示例在open()手册页上提供:

  char path[PATH_MAX]; fd = open("/path/to/dir", O_TMPFILE | O_RDWR, S_IRUSR | S_IWUSR); /* File I/O on 'fd'... */ snprintf(path, PATH_MAX, "/proc/self/fd/%d", fd); linkat(AT_FDCWD, path, AT_FDCWD, "/path/for/file", AT_SYMLINK_FOLLOW); 

请注意, linkat()将不允许打开的文件重新附加后,最后一个链接被删除与unlink()

我的问题:有没有办法重新将这样的文件重新附加到目录结构? 如果你能做到这一点,就意味着你可以实现文件写入,以便文件以原子形式出现并完全形成。 这吸引了我强迫的整洁。 ;)

如果这是您唯一的目标,您可以用更简单,更广泛的方式来实现。 如果您输出到a.dat

  1. 打开a.dat.part进行写入。
  2. 写下你的数据。
  3. a.dat.part重命名为a.dat

我可以理解想要整洁,但是解开一个文件并重新链接它只是为了“整洁”是愚蠢的。

在serverfault这个问题似乎表明,这种重新链接是不安全的,不支持。

感谢@ mark4o发布关于linkat(2) ,请参阅他的答案了解详情。

我试图试图看看实际上将匿名文件链接到存储在其上的文件系统中的实际情况。 (通常是/tmp ,例如firefox正在播放的视频数据)。


从Linux 3.16开始,似乎还没有办法取消删除已被删除的文件。 对于linkat(2) AT_SYMLINK_FOLLOWAT_EMPTY_PATH都不能用于删除曾经拥有名字的文件,即使是root。

唯一的选择是tail -c +1 -f /proc/19044/fd/1 > data.recov ,它会生成一个单独的副本,并且在完成后必须手动将其tail -c +1 -f /proc/19044/fd/1 > data.recov


这是我为测试准备的perl包装器。 使用strace -eopen,linkat linkat.pl - </proc/.../fd/123 newname来验证您的系统仍然无法取消删除打开的文件。 (即使使用sudo )。 显然你应该在运行之前阅读你在互联网上找到的代码,或者使用沙箱帐户。

 #!/usr/bin/perl -w # 2015 Peter Cordes <peter@cordes.ca> # public domain. If it breaks, you get to keep both pieces. Share and enjoy # Linux-only linkat(2) wrapper (opens "." to get a directory FD for relative paths) if ($#ARGV != 1) { print "wrong number of args. Usage:\n"; print "linkat old new \t# will use AT_SYMLINK_FOLLOW\n"; print "linkat - <old new\t# to use the AT_EMPTY_PATH flag (requires root, and still doesn't re-link arbitrary files)\n"; exit(1); } # use POSIX qw(linkat AT_EMPTY_PATH AT_SYMLINK_FOLLOW); #nope, not even POSIX linkat is there require 'syscall.ph'; use Errno; # /usr/include/linux/fcntl.h # #define AT_SYMLINK_NOFOLLOW 0x100 /* Do not follow symbolic links. */ # #define AT_SYMLINK_FOLLOW 0x400 /* Follow symbolic links. */ # #define AT_EMPTY_PATH 0x1000 /* Allow empty relative pathname */ unless (defined &AT_SYMLINK_NOFOLLOW) { sub AT_SYMLINK_NOFOLLOW() { 0x0100 } } unless (defined &AT_SYMLINK_FOLLOW ) { sub AT_SYMLINK_FOLLOW () { 0x0400 } } unless (defined &AT_EMPTY_PATH ) { sub AT_EMPTY_PATH () { 0x1000 } } sub my_linkat ($$$$$) { # tmp copies: perl doesn't know that the string args won't be modified. my ($oldp, $newp, $flags) = ($_[1], $_[3], $_[4]); return !syscall(&SYS_linkat, fileno($_[0]), $oldp, fileno($_[2]), $newp, $flags); } sub linkat_dotpaths ($$$) { open(DOTFD, ".") or die "open . $!"; my $ret = my_linkat(DOTFD, $_[0], DOTFD, $_[1], $_[2]); close DOTFD; return $ret; } sub link_stdin ($) { my ($newp, ) = @_; open(DOTFD, ".") or die "open . $!"; my $ret = my_linkat(0, "", DOTFD, $newp, &AT_EMPTY_PATH); close DOTFD; return $ret; } sub linkat_follow_dotpaths ($$) { return linkat_dotpaths($_[0], $_[1], &AT_SYMLINK_FOLLOW); } ## main my $oldp = $ARGV[0]; my $newp = $ARGV[1]; # link($oldp, $newp) or die "$!"; # my_linkat(fileno(DIRFD), $oldp, fileno(DIRFD), $newp, AT_SYMLINK_FOLLOW) or die "$!"; if ($oldp eq '-') { print "linking stdin to '$newp'. You will get ENOENT without root (or CAP_DAC_READ_SEARCH). Even then doesn't work when links=0\n"; $ret = link_stdin( $newp ); } else { $ret = linkat_follow_dotpaths($oldp, $newp); } # either way, you still can't re-link deleted files (tested Linux 3.16 and 4.2). # print STDERR die "error: linkat: $!.\n" . ($!{ENOENT} ? "ENOENT is the error you get when trying to re-link a deleted file\n" : '') unless $ret; # if you want to see exactly what happened, run # strace -eopen,linkat linkat.pl 

显然,这是可能的 – 例如, fsck这样做的。 但是, fsck会对主要的本地化文件系统mojo进行处理,并且显然不是可移植的,也不可能作为非特权用户执行。 它与上面的debugfs注释类似。

flink(2)调用将是一个有趣的练习。 正如ijw所指出的那样,它将提供一些优于临时文件重命名(rename,note,is guaranteed atomic)的优点。

那种迟到的游戏,但我只是发现http://computer-forensics.sans.org/blog/2009/01/27/recovering-open-but-unlinked-file-data&#x8FD9;可能会回答这个问题。 我没有测试过,所以YMMV。 它看起来很健康。