¿Se puede recuperar un archivo por su inodo?


27

Ejecuté los siguientes comandos en el orden especificado:

$ln a b
$ls -i a b
523669 a 523669 b
$rm -f a
$ls -i b
523669 b

Concluí de esta prueba que el comando en rmrealidad elimina solo el nombre de archivo ( aen esta prueba) en lugar del archivo, ya que el inodo todavía existe y podría recuperarse a través de otro nombre de archivo ( b).

Mi pregunta es, si un archivo está vinculado a un solo nombre de archivo, cuando rmse ejecuta en el archivo, ¿se elimina por completo el archivo real (es decir, el inodo)? Y si no, ¿se puede recuperar un inodo de archivo sin un nombre de archivo y solo a través del inodo?


Suena específico del sistema operativo para mí.
Ignacio Vazquez-Abrams

@Ignacio Vazquez-Abrams. ¿Quieres decir que depende de la versión?
user43312

No, quiero decir que depende del sistema operativo. Cada uno tiene formas diferentes (si las hay ) de aprovechar el VFS.
Ignacio Vazquez-Abrams

@Ignacio Vazquez-Abrams ¿Tienes alguna idea sobre RHL o RHEL?
user43312

1
@BruceEdiger Os X hace algo así. Puede acceder a un objeto del sistema de archivos utilizando una "URL de referencia de archivo" que, fundamentalmente, se crea a partir del número del sistema de archivos y el número de nodo. Sin embargo, no es oficialmente compatible para construirlos usted mismo. En su lugar, obtiene una "URL de referencia de archivo" para un archivo y luego la usa en lugar del nombre de la ruta para accesos posteriores en la misma sesión de tiempo de ejecución, de modo que su aplicación se vuelva ajena al archivo que se está moviendo a otro lugar en el mismo volumen.
Archivo analógico

Respuestas:


29

Si intenta abrir un archivo a través de su inodo, esto omite cualquier recorrido del directorio. El recorrido del directorio es necesario para determinar los permisos del archivo y los directorios que lo conducen. Sin un recorrido de directorio, el núcleo no tiene forma de determinar si el proceso de llamada puede acceder al archivo.

Hubo un parche propuesto para el kernel de Linux para permitir crear un enlace a un archivo desde un descriptor de archivo . Era rechazado porque implementar esto de forma segura hubiera sido extremadamente difícil .

En Linux (y probablemente en otras variantes de Unix por el mismo motivo), no puede crear un enlace a un archivo eliminado, por lo que si un archivo ya no tiene un nombre, no puede volver a agregar uno. Puede abrir un enlace eliminado archivo abriendo los enlaces mágicos en /proc/$pid/fd/ .

Si un archivo ya no tiene ningún enlace y ya no está abierto, ya no existe y el espacio utilizado anteriormente por sus datos puede recuperarse en cualquier momento.

¹ Puede hacer esto girando los bytes directamente en el sistema de archivos de una manera dependiente del sistema de archivos, por ejemplo con debugfspara ext2 / ext3 / ext4. Esto requiere acceso al dispositivo en el que está montado el sistema de archivos (es decir, normalmente solo el root puede intentarlo). Sin embargo, aunque debugfs puede acceder a un archivo por inodo, esto no ayuda si se elimina el archivo: el archivo se eliminará realmente si la aplicación lo cierra, y ejecutar debugfs en modo lectura-escritura en un sistema de archivos montado es una receta para desastre.


11

En Linux, debugfsel depurador interactivo del sistema de archivos ext2 / ext3 / ext4 proporciona un lncomando que puede tomar un número de inodo como filespecy crear un nuevo enlace duro al archivo correspondiente. Sin embargo, en la práctica, esto requiere que el archivo no vinculado se mantenga abierto mediante un proceso , manteniendo un descriptor de archivo abierto /proc/[pid]/fd/[n]. Intentar esto está en un archivo eliminado muy probablemente conducirá a la corrupción del sistema de archivos.

Esto se debe a que para garantizar que ext3 (y en la extensión ext4) pueda reanudar de forma segura un desvinculación después de un bloqueo, en realidad elimina los punteros de bloque en el inodo. , mientras que ext2 simplemente marca estos bloques como no utilizados en los mapas de bits de bloque y marca el inodo como "eliminado" y deja los punteros de bloque solos. Aun así, dado que el sistema de archivos necesita ser montado de lectura-escritura para crear el enlace rígido, los bloques reservados para el archivo eliminado podrían haber sido reasignados.

Antes de la versión del kernel 2.6.39, solía ser que la opción introducida en GNU coreutils v8.0 podía usarse para recuperar un archivo no vinculado a través de un descriptor de archivo abierto, si tanto el archivo no vinculado como el nuevo enlace rígido residían en un sistema de archivos tmpfs . Desde entonces, esta capacidad se ha deshabilitado debido a, como señaló Gilles , las consideraciones de seguridad involucradas en permitir la creación de enlaces duros directamente desde un descriptor de archivo.ln -L|--logical/proc/[pid]/fd/[n]


Solo intenté usar ln -Lpara recuperar un archivo eliminado de / proc y obtuve el error: "No existe tal archivo o directorio", por lo que no creo que realmente sea compatible con esto. Tengo coreutils 8.21.
wingedsubmariner

1
ln -Lno hace lo que dices que hace. Indica lnque si la fuente es un enlace simbólico, debería vincular el destino. Los enlaces simbólicos en /proc/$pid/fdson especiales, y vincular un (deleted)enlace no funciona.
Gilles 'SO- deja de ser malvado'

Tampoco debugfsayudará si el archivo se ha eliminado, a menos que quiera arriesgarse a ejecutarlo en modo de lectura-escritura en un sistema de archivos montado, que probablemente destrozará por completo todo el sistema de archivos.
Gilles 'SO- deja de ser malvado'

Se actualizó la respuesta con respecto a ln -L. Solía ​​ser posible crear enlaces duros al /proc/[pid]/fd/[n]usarlo en ciertas circunstancias especiales, pero esto ya se ha solucionado.
Thomas Nyman

1
debugfs's lnes realmente de bajo nivel y solo crea un nombre, no actualiza el conteo ni desmarca los bloques como no utilizados, por lo que es muy peligroso . Preferir debugfs's undel, que des todo eso. Advertencia: debugfsse que no se ejecuta en un sistema de archivos montado a menos que quiera tener una oportunidad en la quema de sus FS a cenizas.
Lloeki el

9

Los comandos 'ln' y 'rm' han funcionado exactamente así en todos los sistemas de archivos UNIX desde principios de los años setenta. Mac OSX, BSD y Linux heredan este diseño original.

Por sí mismo, un archivo UNIX no tiene nombre, solo un número de inodo o inum. Pero solo puede acceder a través de una entrada en un archivo especial de "directorio" que asocia un nombre con el inum en cuestión; No puede especificar el inum directamente.

Un directorio es en sí mismo un archivo, por lo que también debe acceder a él a través de (otro) directorio, etc., a través de una serie de nombres de directorio delimitados por barras diagonales (/) conocidas como "nombre de ruta". Una ruta comienza en el "directorio de trabajo actual" del proceso a menos que el nombre comience con un "/", en cuyo caso comienza con el directorio raíz del sistema de archivos. Por ejemplo, si el nombre de la ruta no contiene caracteres "/", se espera que sea una entrada en el directorio actual.

Un archivo que no es de directorio puede tener cualquier número de nombres de ruta, conocidos como "enlaces duros", y seguirá existiendo hasta que se hayan eliminado todos sus nombres de ruta y el último proceso haya cerrado el archivo. Luego, el archivo se elimina y su espacio se marca como disponible para su reutilización. Es decir, puede crear () o abrir () un archivo vinculado individualmente y luego desvincularlo () para que ya no aparezca en el espacio de nombre del sistema de archivos, pero el archivo seguirá existiendo hasta que lo cierre. Esto es útil para archivos temporales que no serán leídos por ningún otro programa.

Aunque los directorios tienen números de inodo, la mayoría de los sistemas de archivos no permiten enlaces duros a ellos; solo pueden aparecer en otro directorio. (Una excepción inusual es el sistema de archivos Mac OSX HFS +; esto permite que funcionen las copias de seguridad de Time Machine). Aún puede crear "enlaces suaves" a directorios (o cualquier otro archivo). Un enlace suave se asemeja a una entrada de directorio, excepto que contiene otro nombre de ruta en lugar de un inum.

Cada archivo UNIX tiene un propietario, un grupo y permisos de acceso. Es necesario pero no suficiente que le permitan abrir el archivo; También debe tener al menos permiso de ejecución para cada directorio en el nombre de ruta que utiliza para referirse a él. Es por eso que no hay una forma estándar de abrir un archivo UNIX por su número de inodo; eso evitaría un mecanismo de seguridad importante y ampliamente utilizado.

Pero esto no explica por qué no puede haber una forma estándar para que un usuario root (privilegiado) abra un archivo por número de inodo, ya que la verificación de permisos se omite de todos modos. Esto sería muy útil para ciertas funciones de administración del sistema, como las copias de seguridad. Que yo sepa, tales mecanismos existen, pero todos son específicos del sistema de archivos; no hay una forma general de hacerlo para ningún sistema de archivos UNIX.


1
El avance en /es silencioso, por lo que se pronuncia "barra oblicua".
ctrl-alt-delor

4

La pregunta se puede tomar teóricamente (lo que se puede lograr con debugfs ) o pragmáticamente (situación de emergencia). En el último caso, supongo que la intención es salvar el día y restaurar el contenido del archivo, posiblemente con urgencia (que es la forma en que llegué a esta pregunta, por lo que creo que sigue siendo relevante y útil).

Como no hay una API de kernel, debugfsno debe ejecutarse en un sistema de archivos en vivo porque manipula la estructura FS directamente. Por lo tanto, para hacerlo en vivo, debe obtener otro nombre de archivo. Asumiendo que el archivo todavía está abierto por algún proceso (cualquier proceso), uno puede buscar los descriptores de archivo siempre convenientes en /proc:

$ lsof -F pf "$PWD/a" | sed 's/^p//' # find pid and file descriptor number of any process having the file open
$ pid=1234
$ ls -l /proc/$pid/fd/* | grep "$PWD/a" # find file descriptor number
$ fd=42
$ cat /proc/$pid/fd/$fd > "$PWD/a.restored" # read contents to a new filename

Consejos:

  • si tiene dudas sobre el fd correcto, puede ejecutar comandos como fileen él
  • Si hay un proceso escrito en el archivo, asegúrese de detenerlo lo antes posible o no obtendrá los datos más recientes. Un truco (no probado) podría ser abrir el archivo de lectura solo a través del fd con algún otro proceso (intente tail -f < /proc/$pid/fd/$fd > /dev/null, salga del proceso de escritura para que salga limpiamente y use el fd del nuevo proceso.

2
Eso debería estar tail -f < /proc/...en el segundo consejo.
Murray Jensen

O use tail -c +0 -f para copiarlo en primer lugar en lugar de hacerlo cat, si el proceso de escritura solo se agrega (no se busca y reescribe). Salga del otro proceso antes tail, luego espere para tailllegar al final del archivo.
Peter Cordes
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.