Nhờ @ mark4o đăng bài về số linkat(2)
, hãy xem câu trả lời của anh ấy để biết chi tiết.
Tôi muốn thử xem điều gì đã thực sự xảy ra khi cố gắng liên kết tệp ẩn danh với hệ thống tệp được lưu trữ trên đó. (thường là /tmp
, ví dụ: đối với dữ liệu video mà firefox đang phát).
Kể từ Linux 3.16, dường như không có cách nào để lấy lại tệp đã xóa vẫn được mở. Không phải là AT_SYMLINK_FOLLOW
cũng không phải AT_EMPTY_PATH
cho linkat(2)
thực hiện thủ thuật cho các tệp đã xóa đã từng có tên, ngay cả dưới dạng gốc.
Cách thay thế duy nhất là tail -c +1 -f /proc/19044/fd/1 > data.recov
, tạo bản sao riêng biệt và bạn phải tự xóa nó khi hoàn thành.
Đây là trình bao bọc perl mà tôi đã nấu để thử nghiệm. Sử dụng strace -eopen,linkat linkat.pl - </proc/.../fd/123 newname
để xác minh rằng hệ thống của bạn vẫn không thể phục hồi các tệp đang mở. (Tương tự áp dụng ngay cả với sudo
). Rõ ràng bạn nên đọc mã bạn tìm thấy trên Internet trước khi chạy nó, hoặc sử dụng một tài khoản sandboxed.
#!/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. Ông đề xuất một giải pháp mà cũng nên làm việc, tâm trí bạn. Mặc dù cho sự gọn gàng đầy đủ ép buộc bạn cũng có thể cần một cách để gọi creat() trên một thư mục để nó tạo ra tệp và inode nhưng không phải là mục nhập thư mục, do đó nó không bao giờ được liên kết ở nơi đầu tiên. – ijw
Bản cập nhật đầy chiến thắng. Tôi không thể +2 bạn nhưng tôi sẽ làm nếu tôi có thể. – ijw
Nhạy cảm, 'linkat()' cung cấp cho 'ENOENT' trên các nỗ lực đính kèm lại tệp mở-nhưng-hủy liên kết bình thường. (với 'AT_SYMLINK_FOLLOW' hoặc 'AT_EMPTY_PATH') –