感谢@ mark4o张贴有关linkat(2)
,看到他对细节的答案。
我想试一试,看看究竟发生了什么努力实际上链接的匿名文件放回其存储在文件系统时。 (通常/tmp
,例如,firefox正在播放的视频数据)。
从Linux 3.16开始,似乎仍无法取消删除仍然保持打开状态的已删除文件。无论AT_SYMLINK_FOLLOW
也不AT_EMPTY_PATH
为linkat(2)
做的伎俩对于曾经有一个名字被删除的文件,甚至是root。
唯一的选择是tail -c +1 -f /proc/19044/fd/1 > data.recov
,使一个单独的副本,你当它完成手动杀死它。
这是我制作测试的perl包装。使用strace -eopen,linkat linkat.pl - </proc/.../fd/123 newname
来验证您的系统仍然无法取消删除打开的文件。 (即使使用sudo
也是如此)。很明显,您应该阅读运行之前在Internet上找到的代码,或者使用沙盒帐户。
#!/usr/bin/perl -w
# 2015 Peter Cordes <[email protected]>
# 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
Ta。他提出了一个也应该起作用的解决方案,请介意你。虽然对于完整的强制整洁,您可能还需要一种方法来调用目录中的creat(),以便它创建文件和inode但不是目录条目,以便它从不首先链接。 – ijw 2010-11-23 18:35:23
更新充满了胜利。我不能+2你,但我会如果我能。 – ijw 2014-05-31 06:40:45
令人困惑的是,'linkat()'在试图重新连接一个正常的打开但未链接的文件时给出了'ENOENT'。 (带有'AT_SYMLINK_FOLLOW'或'AT_EMPTY_PATH') – 2015-02-21 22:07:14