Pregunta

En Unix, es posible crear un identificador para un archivo en el anonimato por, por ejemplo, crear y abrir con creat () y luego retirar el enlace de directorios con unlink () - dejándole con un archivo con un inodo y almacenamiento, pero hay manera posible de volver a abrirlo. Tales archivos se utilizan a menudo como archivos temporales (y por lo general esto es lo tmpfile () regresa a usted).

Mi pregunta: ¿hay alguna manera de volver a adjuntar un archivo como esta de nuevo en la estructura de directorios? Si usted puede hacer esto significa que usted podría, por ejemplo, aplicar las escrituras de archivo para que el archivo aparece formada atómicamente y completamente. Esto atrae a mi pulcritud compulsiva. ;)

Cuando se empuja a través de las funciones de llamada del sistema pertinentes que esperaba encontrar una versión de enlace () llamada Flink () (comparar con chmod () / fchmod ()), pero, al menos en Linux esto no existe.

Los puntos de bonificación por decirme cómo crear el archivo en el anonimato y sin exponer brevemente un nombre de archivo en la estructura de directorios del disco.

¿Fue útil?

Solución

Un parche para una llamada al sistema de Linux flink() propuesta fue presentado hace varios años, pero cuando Linus declaró "no hay manera en el infierno que podemos hacer esto de forma segura sin mayores incursiones otros" , que más o menos terminó el debate sobre si se debe agregar este.

Actualización: Lo de Linux 3.11, ahora es posible crear un archivo con ninguna entrada de directorio usando open() con la nueva bandera O_TMPFILE, y ligarse en el sistema de ficheros, una vez que se forma completamente usando linkat() en /proc/self/fd/ fd con la bandera AT_SYMLINK_FOLLOW.

El siguiente ejemplo se proporciona en la página open() manual de :

    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);

Tenga en cuenta que linkat() no permitirá que los archivos abiertos para ser re-adjunto después de que el último eslabón se elimina con unlink().

Otros consejos

Mi pregunta: ¿hay alguna manera de volver a adjuntar un archivo como esta de nuevo en la estructura de directorios? Si usted puede hacer esto significa que usted podría, por ejemplo, aplicar las escrituras de archivo para que el archivo aparece formada atómicamente y completamente. Esto atrae a la mi pulcritud compulsiva. ;)

Si este es su único objetivo, se puede lograr esto de una manera mucho más simple y más ampliamente utilizado. Si está dando salida a a.dat:

  1. a.dat.part abierto para escritura.
  2. Escribir sus datos.
  3. Cambiar nombre a.dat.part a a.dat.

Puedo entender querer ser ordenada, pero desvincular un archivo y volver a vincular sólo para ser "limpio" es un poco tonto.

Esta pregunta sobre serverfault parece indicar que este tipo de re-unión es inseguro y no soportado.

Gracias a @ mark4o publicación sobre linkat(2), ver su respuesta para más detalles.

Yo quería darle una oportunidad para ver lo que realmente ocurrió en realidad cuando se trata de vincular un archivo de vuelta en el anonimato en el sistema de archivos que se almacenan en. (A menudo /tmp, por ejemplo para datos de vídeo que Firefox es de juego).


A partir de Linux 3.16, todavía parece que no hay manera de recuperar un archivo borrado que todavía se mantiene abierto. Ni AT_SYMLINK_FOLLOW ni AT_EMPTY_PATH para linkat(2) hacer el truco para los archivos borrados que se utilizan para tener un nombre, incluso como root.

La única alternativa es tail -c +1 -f /proc/19044/fd/1 > data.recov, lo que hace una copia por separado, y hay que acabar con él de forma manual cuando se hace.


Aquí está el envoltorio perl cociné para la prueba. Uso strace -eopen,linkat linkat.pl - </proc/.../fd/123 newname para verificar que el sistema todavía puede abrir archivos no deshacer la eliminación. (Lo mismo se aplica incluso con sudo). Obviamente, usted debe leer el código que encuentre en Internet antes de ejecutarlo, o utilizar una cuenta de un recinto de seguridad.

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

Es evidente que esto es posible - fsck lo hace, por ejemplo. Sin embargo, fsck lo hace con gran mojo sistema de archivos localizados y será claramente no ser portátil, ni ejecutable como un usuario sin privilegios. Es similar a la observación debugfs anteriormente.

Escribir esa llamada flink(2) sería un ejercicio interesante. Como ijw señala, que ofrecería algunas ventajas sobre la práctica actual de cambio de nombre de archivo temporal (cambio de nombre, nota, está garantizada atómica).

Un poco tarde para el juego, pero acabo de encontrar http://computer-forensics.sans.org/blog/2009/01/27/recovering-open-but-unlinked-file-data que puede responder a la pregunta. Yo no lo he probado, sin embargo, por lo que tu caso es distinto. Parece sonido.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top