Domanda

In Unix, è possibile creare un handle a un file anonimo, ad esempio, la creazione e aprirlo con creat () e poi rimuovere il link directory con unlink () - lasciando con un file con un inode e di stoccaggio, ma alcun modo possibile per ri-aprirlo. Tali file sono spesso utilizzati come file temporanei (e in genere questo è ciò che tmpfile () ritorna a voi).

La mia domanda: esiste un modo per ri-allegare un file come questo di nuovo nella struttura di directory? Se si potesse fare questo vuol dire che si potrebbe per esempio implementare scrive file in modo che il file viene visualizzato atomicamente e completamente formata. Questo appello alla mia pulizia compulsivo. ;)

Quando frugando tra le importanti funzioni di chiamata del sistema mi aspettavo di trovare una versione di collegamento () chiamato Flink () (confrontare con chmod () / fchmod ()), ma, almeno su Linux questo non esiste.

I punti bonus per dirmi come creare il file anonimo, senza esporre brevemente un nome di file nella struttura di directory del disco.

È stato utile?

Soluzione

Una patch per una proposta di chiamata di sistema Linux flink() è stata presentata alcuni anni fa, ma quando Linus ha dichiarato "non v'è alcun modo in inferno che possiamo farlo in modo sicuro senza grandi altre incursioni" , che praticamente ha chiuso il dibattito sull'opportunità di aggiungere questo.

Aggiornamento: Come di Linux 3.11, è ora possibile creare un file con alcuna voce directory utilizzando open() con la nuova bandiera O_TMPFILE, e collegarlo al filesystem una volta che è completamente formato utilizzando linkat() su /proc/self/fd/ fd con la bandiera AT_SYMLINK_FOLLOW.

Il seguente esempio è fornito sulla pagina di manuale 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);

Si noti che linkat() non permetterà i file aperti per essere ri-attaccato dopo l'ultimo anello viene rimosso con unlink().

Altri suggerimenti

  

La mia domanda: esiste un modo per ri-allegare un file come questo di nuovo nella struttura di directory? Se si potesse fare questo vuol dire che si potrebbe per esempio implementare scrive file in modo che il file viene visualizzato atomicamente e completamente formata. Questo appello alla mia pulizia compulsivo. ;)

Se questo è il vostro unico obiettivo, è possibile raggiungere questo obiettivo in un modo molto più semplice e più largamente usato. Se si viene passato a a.dat:

  1. Apri a.dat.part per la scrittura.
  2. Scrivere i propri dati.
  3. Rinomina a.dat.part a a.dat.

Posso capire voglia di essere pulito, ma scollegare un file e ricollegamento solo di essere "pulito" è una specie di sciocco.

Questa domanda su serverfault sembra indicare che questo tipo di ri-linking è pericoloso e non supportato.

Grazie a @ mark4o distacco su linkat(2), vedere la sua risposta per i dettagli.

Ho voluto dare una prova per vedere che cosa è realmente accaduto quando si cerca di collegare in realtà un file di tornare anonimo nel file system è memorizzato su. (Spesso /tmp, per esempio per i dati video che Firefox è gioco).


A partire dal Linux 3.16, ci sembra essere ancora alcun modo per ripristinare un file eliminato che è ancora tenuto aperto. Né AT_SYMLINK_FOLLOWAT_EMPTY_PATH per linkat(2) fare il trucco per i file cancellati che usato per avere un nome, anche come root.

L'unica alternativa è tail -c +1 -f /proc/19044/fd/1 > data.recov, il che rende una copia separata, e devi uccidere manualmente quando è fatto.


Ecco il perl involucro ho cucinato per test. Utilizzare strace -eopen,linkat linkat.pl - </proc/.../fd/123 newname per verificare che il sistema può ancora file aperti non undelete. (Lo stesso vale anche con sudo). Ovviamente si dovrebbe leggere il codice a trovare su Internet prima di eseguirlo, o di utilizzare un account sandbox.

#!/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

Chiaramente, questo è possibile - fsck lo fa, per esempio. Tuttavia, fsck lo fa con maggiore mojo di file localizzato sistema e chiaramente non essere portatile, nè eseguibile come utente senza privilegi. E 'simile al commento debugfs sopra.

Scrivendo quella chiamata flink(2) sarebbe un esercizio interessante. Come IJW sottolinea, sarebbe offrire alcuni vantaggi rispetto pratica corrente di cambiamento titolo temporaneo del file (rinomina, nota, è garantito atomica).

Tipo di ritardo al gioco, ma ho appena trovato http://computer-forensics.sans.org/blog/2009/01/27/recovering-open-but-unlinked-file-data che em <> possono rispondi alla domanda. Non ho ancora testato, anche se, in modo YMMV. Sembra suono.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top