linux - tag - Volver a vincular un archivo anónimo(no vinculado pero abierto)
music tagger (5)
En Unix, es posible crear un identificador para un archivo anónimo, por ejemplo, crearlo y abrirlo con creat () y luego eliminar el enlace del directorio con unlink (), dejándolo con un archivo con inodo y almacenamiento, pero no hay forma posible de hacerlo. para volver a abrirlo. Dichos archivos a menudo se usan como archivos temporales (y típicamente esto es lo que tmpfile () le devuelve).
Mi pregunta: ¿hay alguna forma de volver a adjuntar un archivo como este en la estructura del directorio? Si pudieras hacer esto, significa que podrías, por ejemplo, implementar escrituras de archivo para que el archivo aparezca atómico y completamente formado. Esto apela a mi pulcritud compulsiva. ;)
Al hojear las funciones de llamada al sistema relevantes, esperaba encontrar una versión de link () llamada flink () (compárese con chmod () / fchmod ()) pero, al menos en Linux, esto no existe.
Puntos de bonificación por decirme cómo crear el archivo anónimo sin exponer brevemente un nombre de archivo en la estructura de directorios del disco.
Mi pregunta: ¿hay alguna forma de volver a adjuntar un archivo como este en la estructura del directorio? Si pudieras hacer esto, significa que podrías, por ejemplo, implementar escrituras de archivo para que el archivo aparezca atómico y completamente formado. Esto apela a mi pulcritud compulsiva. ;)
Si este es su único objetivo, puede lograrlo de una manera mucho más simple y más ampliamente utilizada. Si está a.dat
a a.dat
:
- Abra
a.dat.part
para escribir. - Escribe tus datos
- Cambie el nombre de
a.dat.part
aa.dat
.
Puedo entender que quiero ser limpio, pero desvincular un archivo y volver a vincularlo solo para ser "limpio" es algo tonto.
Esta pregunta sobre la falla del servidor parece indicar que este tipo de enlace no es seguro y no es compatible.
Claramente, esto es posible, fsck
hace, por ejemplo. Sin embargo, fsck
hace con el principal sistema de archivos localizado mojo y claramente no será portátil ni ejecutable como un usuario sin privilegios. Es similar al comentario de debugfs
anterior.
Escribir ese llamado flink(2)
sería un ejercicio interesante. Como señala ijw, ofrecería algunas ventajas sobre la práctica actual de cambio de nombre de archivo temporal (cambiar el nombre, nota, se garantiza atómico).
Gracias a @ mark4o publicando sobre linkat(2)
, mira su respuesta para más detalles.
Quería probarlo para ver qué sucedió realmente al intentar vincular un archivo anónimo al sistema de archivos en el que está almacenado. (a menudo /tmp
, por ejemplo, para datos de video que Firefox está reproduciendo).
A partir de Linux 3.16, todavía parece que no hay forma de recuperar un archivo eliminado que aún se mantiene abierto. Ni AT_SYMLINK_FOLLOW
ni AT_EMPTY_PATH
para linkat(2)
hacen el truco para los archivos eliminados que solían tener un nombre, incluso como raíz.
La única alternativa es tail -c +1 -f /proc/19044/fd/1 > data.recov
, que hace una copia por separado, y tienes que eliminarla manualmente cuando esté lista.
Aquí está el envoltorio de perl que preparé para probar. Utilice strace -eopen,linkat linkat.pl - </proc/.../fd/123 newname
para verificar que su sistema aún no puede recuperar los archivos abiertos. (Lo mismo se aplica incluso con sudo
). Obviamente, debería leer el código que encuentra en Internet antes de ejecutarlo, o usar una cuenta de espacio aislado.
#!/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
Hace un tiempo, 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. No lo he probado, así que, YMMV. Se ve bien.
Hace varios años se envió un parche para una llamada al sistema Linux flink()
propuesta , pero cuando Linus declaró "no hay forma de que HELL pueda hacerlo de forma segura sin otras incursiones" , eso prácticamente puso fin al debate sobre si añadir esto .
Actualización: a partir de Linux 3.11, ahora es posible crear un archivo sin entrada de directorio usando open()
con el nuevo indicador O_TMPFILE
, y vincularlo al sistema de archivos una vez que está completamente formado usando linkat()
en /proc/self/fd/
fd con el indicador AT_SYMLINK_FOLLOW
.
El siguiente ejemplo se proporciona en la página de manual de 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);
Tenga en cuenta que linkat()
no permitirá que los archivos abiertos se vuelvan a conectar después de eliminar el último enlace con unlink()
.