重新链接匿名(未链接但打开)文件
- 2024-11-01 08:41:00
- admin 原创
- 217
问题描述:
在 Unix 中,可以创建匿名文件的句柄,例如,使用 creat() 创建并打开它,然后使用 unlink() 删除目录链接 - 留下一个具有 inode 和存储空间的文件,但无法重新打开它。此类文件通常用作临时文件(通常这就是 tmpfile() 返回给您的内容)。
我的问题是:有没有办法将这样的文件重新附加到目录结构中?如果你能做到这一点,就意味着你可以实现文件写入,这样文件就会自动地、完整地出现。这符合我的整洁强迫症。;)
当研究相关的系统调用函数时,我期望找到一个名为 flink() 的 link() 版本(与 chmod()/fchmod() 进行比较),但至少在 Linux 上它不存在。
告诉我如何创建匿名文件而不在磁盘的目录结构中短暂地暴露文件名,这将获得加分。
解决方案 1:
flink()
几年前,有人提交了一个针对拟议的 Linux系统调用的补丁,但是当 Linus 声明“在没有其他重大入侵的情况下,我们绝对不可能安全地做到这一点”时,这几乎结束了关于是否添加此功能的争论。
更新:从 Linux 3.11 开始,现在可以使用open()
新标志创建一个没有目录条目的文件,并在使用带有标志的fdO_TMPFILE
完全形成后将其链接到文件系统。linkat()
`/proc/self/fd/`AT_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()
。
解决方案 2:
感谢@mark4o 发布有关的帖子linkat(2)
,请参阅他的回答了解详情。
我想尝试一下,看看当尝试将匿名文件实际链接回其存储的文件系统中时实际发生了什么。(通常/tmp
,例如 Firefox 正在播放的视频数据)。
从 Linux 3.16 开始,似乎仍然没有办法恢复已删除但仍然保持打开状态的文件。即使是以 root 身份,也AT_SYMLINK_FOLLOW
无法AT_EMPTY_PATH
恢复linkat(2)
曾经有名称的已删除文件。
唯一的选择是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:
";
print "linkat old new # will use AT_SYMLINK_FOLLOW
";
print "linkat - <old new # to use the AT_EMPTY_PATH flag (requires root, and still doesn't re-link arbitrary files)
";
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
";
$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: $!.
" . ($!{ENOENT} ? "ENOENT is the error you get when trying to re-link a deleted file
" : '') unless $ret;
# if you want to see exactly what happened, run
# strace -eopen,linkat linkat.pl
解决方案 3:
我的问题是:有没有办法将这样的文件重新附加到目录结构中?如果你能做到这一点,就意味着你可以实现文件写入,这样文件就会自动地、完整地出现。这符合我的整洁强迫症。;)
如果这是您的唯一目标,您可以采用一种更简单、更广泛使用的方式实现此目标。如果您要输出到a.dat
:
打开
a.dat.part
以进行写入。写入您的数据。
重命名
a.dat.part
为a.dat
。
我可以理解想要整洁的想法,但只是为了“整洁”而取消链接文件并重新链接它有点愚蠢。
serverfault 上的这个问题似乎表明这种重新链接是不安全的并且不受支持。
解决方案 4:
显然,这是可能的——fsck
例如,这样做。但是,fsck
这样做会使用主要的本地化文件系统 mojo,并且显然不可移植,也无法以非特权用户身份执行。它类似于debugfs
上面的评论。
编写该flink(2)
调用将是一项有趣的练习。正如 ijw 指出的那样,与当前的临时文件重命名实践相比,它将提供一些优势(请注意,重命名保证是原子的)。
解决方案 5:
有点晚了,但我刚刚发现http://computer-forensics.sans.org/blog/2009/01/27/recovering-open-but-unlinked-file-data可能可以回答这个问题。不过我还没有测试过,所以 YMMV。看起来不错。