Grazie al post @ mark4o su linkat(2)
, vedere la sua risposta per i dettagli.
Volevo fare un tentativo per vedere cosa è successo effettivamente quando si cerca di collegare effettivamente un file anonimo nel file system su cui è stato salvato. (spesso /tmp
, ad esempio per i dati video su cui è in esecuzione Firefox).
A partire da Linux 3.16, sembra ancora che non ci sia modo di ripristinare un file cancellato che è ancora aperto. Né AT_SYMLINK_FOLLOW
né AT_EMPTY_PATH
per linkat(2)
esegui il trucco per i file eliminati che avevano un nome, anche come root.
L'unica alternativa è tail -c +1 -f /proc/19044/fd/1 > data.recov
, che crea una copia separata, e devi ucciderla manualmente quando è terminata.
Ecco il wrapper perl che ho preparato per il test. Utilizzare strace -eopen,linkat linkat.pl - </proc/.../fd/123 newname
per verificare che il sistema non sia ancora in grado di ripristinare i file aperti. (Lo stesso vale anche con sudo
). Ovviamente dovresti leggere il codice che trovi su Internet prima di eseguirlo o utilizzare un account sandbox.
#!/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. Propone una soluzione che dovrebbe funzionare anche, attenzione. Anche se per la piena pulizia compulsiva probabilmente hai anche bisogno di un modo per chiamare creat() su una directory in modo che crei il file e l'inode ma non la voce della directory, in modo che non sia mai collegato in primo luogo. – ijw
L'aggiornamento è pieno di vittorie. Non posso +2 tu ma lo farei se potessi. – ijw
Confusamente, 'linkat()' fornisce 'ENOENT' sui tentativi di riattaccare un normale file aperto ma non collegato. (con o 'AT_SYMLINK_FOLLOW' o 'AT_EMPTY_PATH') –