Tema representativo de entrevista

Entrevista de Linux: Enlaces duros (hard links) vs. enlaces simbólicos (symbolic links)

GeneralIntermedio
Equipo editorial de Offer.ccPublicado Actualizado

Pregunta

Un despliegue en Linux crea un enlace duro y un enlace simbólico relativo hacia el mismo archivo de configuración, y luego renombra y elimina rutas mientras un proceso mantiene el archivo abierto. Prediga qué rutas y descriptores siguen funcionando, explique por qué los enlaces duros no pueden cruzar sistemas de archivos mientras que los enlaces simbólicos sí pueden, y muestre cómo verificaría cada afirmación.

Prompt y contexto aplicable

Un servicio despliega /srv/releases/v1/app.conf. Crea /srv/live/pinned.conf como un enlace duro y /srv/live/current.conf como un enlace simbólico relativo. Un proceso worker abre el archivo de la versión antes de que un operador renombre y luego elimine entradas de directorio.

Explique a qué se refieren un nombre de archivo, un enlace duro, un enlace simbólico, un inodo y un descriptor de archivo abierto. Prediga el resultado después de cada operación. Luego elija el mecanismo adecuado para una instantánea inmutable, un puntero de versión reubicable y una referencia que cruce sistemas de archivos. La respuesta está orientada a sistemas Linux y archivos ordinarios; las instantáneas específicas del sistema de archivos y los accesos directos de Windows quedan fuera de alcance.

Qué evalúa el entrevistador

La primera señal es el modelo de objetos. Una entrada de directorio asocia un nombre a un inodo. Un enlace duro es otra entrada de directorio para el mismo inodo; ninguno de los nombres es el original. Un enlace simbólico es un objeto del sistema de archivos diferente cuya carga útil (payload) es una ruta que se resuelve en el momento en que se utiliza.

La segunda señal es el razonamiento sobre el ciclo de vida. unlink elimina una entrada de directorio, no necesariamente el objeto de archivo. El inodo y los datos permanecen mientras otro enlace duro o una descripción de archivo abierta aún los referencien. Un enlace simbólico puede permanecer presente mientras la ruta que almacena ya no se resuelva.

La tercera señal es predecir operaciones en lugar de recitar una tabla comparativa. Renombrar un enlace duro no altera a sus pares. Renombrar un enlace simbólico opera sobre el enlace simbólico en sí. Mover un enlace simbólico o su destino puede cambiar el significado de una ruta relativa. Los enlaces duros entre diferentes sistemas de archivos fallan porque la identidad del inodo es local a un solo sistema de archivos.

La señal final es el criterio operativo: inspeccionar la identidad y el conteo de enlaces, distinguir stat de lstat, realizar reemplazos atómicos en el mismo sistema de archivos cuando sea necesario, y evitar condiciones de carrera de comprobación previa a la apertura (check-then-open) en rutas controladas por un atacante.

Preguntas para aclarar antes de responder

  • ¿Están el origen y el nuevo nombre del enlace duro en el mismo sistema de archivos montado? Si no es así, link falla con EXDEV; copiar datos o usar un enlace simbólico resuelve un problema diferente.
  • ¿Necesita el llamador un objeto estable o un nombre reubicable? Un enlace duro fija un inodo. Un alias de versión generalmente debe ser un enlace simbólico cuya entrada de directorio se pueda reemplazar.
  • ¿Es el destino un archivo regular o un directorio? Linux normalmente prohíbe los enlaces duros a directorios, mientras que un enlace simbólico puede apuntar a cualquiera de los dos.
  • ¿Es el enlace simbólico absoluto o relativo? Un destino relativo se resuelve a partir del directorio que contiene el enlace simbólico, no a partir del directorio de trabajo actual del proceso.
  • ¿Tendrá algún proceso el archivo ya abierto? Renombrar o desenlazar (unlink) una ruta no redirige un descriptor existente; ese proceso continúa utilizando el objeto abierto.
  • ¿Debe ser el cambio atómico para los lectores? El reemplazo con rename es atómico solo dentro del mismo sistema de archivos montado. Un movimiento entre distintos sistemas de archivos requiere un protocolo de publicación diferente.
  • ¿Hay componentes de la ruta controlados por un usuario no confiable? Si es así, un lstat previo seguido de open presenta condiciones de carrera. La apertura en sí misma debe aplicar la política de recorrido.

Estructura de respuesta de 30 segundos

“Un enlace duro es una segunda entrada de directorio hacia el mismo inodo, por lo que ambos nombres comparten datos y metadatos. Un enlace simbólico tiene su propio inodo y almacena una ruta, que se resuelve al acceder a ella. Eliminar el nombre de un enlace duro decrementa el conteo de enlaces; el objeto sobrevive a través de otros enlaces duros y descriptores abiertos. Eliminar o renombrar el destino puede dejar un enlace simbólico roto (dangling).

Yo lo verificaría con ls -li, stat, lstat o readlink, y un descriptor previamente abierto. Usaría un enlace duro para fijar el archivo exacto dentro de un sistema de archivos, un enlace simbólico para un alias de versión reemplazable o una referencia entre sistemas de archivos, y un enlace simbólico temporal más rename en el mismo sistema de archivos para un cambio de alias atómico. Las rutas no confiables requieren una política atómica de apertura sin enlaces simbólicos o restringida por debajo del directorio, no una comprobación separada.”

Análisis detallado paso a paso

Paso 1: Construir el modelo de nombre a objeto

Para un archivo ordinario, el directorio almacena un nombre y una referencia a un inodo. El inodo contiene el tipo de archivo, propietario, modo, marcas de tiempo, tamaño, mapeo de bloques y conteo de enlaces duros. El contenido del archivo no pertenece a un “nombre de archivo original” privilegiado.

Un enlace duro agrega otra entrada de directorio a ese inodo. Cambiar bytes o el modo a través de cualquiera de los nombres es visible a través del otro. Por el contrario, un enlace simbólico tiene su propio inodo y almacena una cadena como ../releases/v1/app.conf; la resolución normal de rutas sigue esa cadena hacia otro nombre.

Paso 2: Ejecutar un experimento concreto

Los siguientes comandos establecen el escenario. El descriptor de archivo del shell se mantiene abierto deliberadamente:

bash
mkdir -p /srv/releases/v1 /srv/live
printf 'version=1\n' > /srv/releases/v1/app.conf
ln /srv/releases/v1/app.conf /srv/live/pinned.conf
ln -s ../releases/v1/app.conf /srv/live/current.conf
exec 3< /srv/releases/v1/app.conf

ls -li /srv/releases/v1/app.conf /srv/live/pinned.conf
readlink /srv/live/current.conf
stat -L -c '%F %i %h' /srv/live/current.conf
stat -c '%F %i %h' /srv/live/current.conf

mv /srv/releases/v1/app.conf /srv/releases/v1/app.conf.moved
cat /srv/live/pinned.conf
cat /srv/live/current.conf
cat <&3

rm /srv/releases/v1/app.conf.moved /srv/live/pinned.conf
cat <&3
exec 3<&-

Antes del renombrado, la ruta de la versión y pinned.conf muestran el mismo inodo y un conteo de enlaces duros de dos. readlink imprime la carga útil del enlace simbólico. El stat ordinario sigue el enlace simbólico hasta el destino, mientras que la inspección sin seguimiento en el ejemplo reporta el objeto de enlace simbólico en sí.

Paso 3: Predecir el comportamiento del renombrado

mv dentro de este sistema de archivos utiliza una operación de renombrado para la entrada de origen. El inodo no se mueve, por lo que pinned.conf y el descriptor 3 continúan funcionando. current.conf todavía almacena ../releases/v1/app.conf; debido a que ese nombre antiguo desapareció, desreferenciarlo ahora falla. Renombrar un enlace simbólico en sí movería ese objeto de enlace, no su destino, y podría cambiar el significado de una carga útil relativa porque la resolución comienza desde el nuevo directorio contenedor del enlace.

Si un despliegue necesita cambiar current sin un intervalo de nombre inexistente, cree un enlace simbólico temporal completamente preparado en el mismo directorio y reemplace current con rename. Los lectores que abran después del reemplazo resolverán la entrada de directorio antigua o la nueva. Los procesos que ya abrieron el destino antiguo conservan su descriptor antiguo.

Paso 4: Predecir el desenlazado (unlink) y la recuperación de espacio

Eliminar app.conf.moved reduce en uno el conteo de enlaces duros. pinned.conf todavía apunta al inodo, por lo que sus datos permanecen. Eliminar pinned.conf elimina la última entrada de directorio, pero el descriptor 3 aún mantiene una referencia abierta; cat <&3 continúa leyendo el archivo. El almacenamiento se vuelve recuperable solo después de que hayan desaparecido el último enlace duro y la última referencia abierta.

Esto explica por qué eliminar un archivo de registro (log) activo grande puede no liberar espacio, pero no es una razón para truncar un descriptor arbitrario. Primero identifique el proceso propietario y su contrato de rotación, luego envíele una señal o reinícielo de forma segura si es necesario.

Paso 5: Aplicar límites de sistemas de archivos y directorios

Un número de inodo es único solo dentro de su sistema de archivos. Un enlace duro no puede nombrar ese inodo desde otro sistema de archivos y link devuelve EXDEV. Un enlace simbólico puede almacenar una ruta que cruza un límite de montaje porque la búsqueda resuelve los nombres en el momento del acceso. También puede nombrar un directorio o un destino que aún no existe.

Linux evita los enlaces duros ordinarios a directorios para evitar ciclos y ambigüedad en el recorrido. Se permite un enlace simbólico a un directorio, pero mover uno relativo puede romperlo y las herramientas recursivas pueden elegir diferentes políticas de seguimiento. Especifique esas políticas para herramientas de respaldo, eliminación y despliegue.

Paso 6: Elegir según la invariante

Utilice un enlace duro cuando la invariante sea “este nombre adicional debe mantener accesible el inodo exacto”, los objetos compartan un solo sistema de archivos y se deseen metadatos compartidos. Utilice un enlace simbólico cuando la invariante sea “resolver este alias a cualquier ruta que almacene actualmente”, especialmente para directorios, punteros de versión o nombres entre sistemas de archivos. Utilice una copia cuando se requieran bytes independientes, metadatos, retención o ubicación en otro sistema de archivos.

Ninguno de los dos enlaces constituye una copia de seguridad por sí mismo. Los nombres enlazados de forma dura comparten modificaciones y corrupción. Un enlace simbólico no contiene datos del destino. Una copia de seguridad requiere límites independientes de falla y retención, además de pruebas de restauración.

Paso 7: Verificar identidad y recorrido seguro

Compare dispositivo e inodo, no solo el inodo, porque los números de inodo pueden repetirse en diferentes sistemas de archivos. Verifique el conteo de enlaces duros con stat, inspeccione el enlace simbólico en sí con un comportamiento al estilo de lstat, imprima su carga útil con readlink y pruebe la secuencia exacta de renombrado/desenlazado mientras un descriptor está abierto.

Para rutas no confiables, lstat(path) seguido de open(path) permite que un atacante reemplace un componente entre las llamadas. En Linux, abra de forma relativa a un descriptor de directorio confiable y aplique las restricciones de resolución de openat2 requeridas, como prohibir enlaces simbólicos o escapar por encima del directorio. La seguridad debe aplicarse mediante la búsqueda que devuelve el descriptor.

Respuesta de muestra sólida

“Comienzo con las entradas de directorio. app.conf y pinned.conf son dos nombres iguales para un inodo, por lo que comparten contenido, permisos, propietario y marcas de tiempo. current.conf es un inodo de enlace simbólico separado cuya carga útil es ../releases/v1/app.conf. La ruta relativa comienza en /srv/live, donde reside el enlace simbólico.

Después de renombrar la ruta de la versión, el enlace duro y el descriptor ya abierto todavía hacen referencia al mismo objeto de archivo. El enlace simbólico queda roto (dangling) porque la ruta almacenada todavía apunta a la entrada antigua. Después de eliminar el nombre movido, el enlace duro mantiene vivo el objeto. Después de eliminar también el enlace duro, el descriptor abierto sigue funcionando; el kernel puede recuperar el objeto solo cuando ese descriptor se cierra.

Usaría un enlace duro para fijar un artefacto exacto en el mismo sistema de archivos, un enlace simbólico para el alias reubicable current y una copia real para una retención independiente. Actualizaría current creando un enlace simbólico temporal y renombrándolo atómicamente en el mismo directorio. Demostraría el resultado con dispositivo/inodo, conteo de enlaces, readlink, un acceso a un enlace roto y una prueba con descriptor abierto. Si la ruta no es confiable, aplicaría reglas de no permitir enlaces simbólicos y límites de directorio durante la apertura misma.”

Errores comunes

  • Llamar al enlace duro un puntero al nombre original → todos los enlaces duros son entradas de directorio pares para un inodo → describa nombres, identidad de inodo y conteo de enlaces.
  • Decir que la eliminación siempre destruye el archivo de inmediato → pueden permanecer otros nombres o referencias abiertas → rastree tanto el conteo de enlaces duros como los descriptores abiertos.
  • Tratar un enlace simbólico como una referencia de inodo almacenada → almacena una ruta que luego puede resolverse de manera diferente o fallar → inspeccione la carga útil y la base de resolución.
  • Comparar números de inodo sin la identidad del dispositivo → los números de inodo son solo locales al sistema de archivos → compare dispositivo más inodo.
  • Usar un enlace duro entre diferentes puntos de montaje o para un directorio → Linux rechaza esos casos → use un enlace simbólico o una copia según la independencia requerida.
  • Mover un enlace simbólico relativo sin reevaluarlo → su directorio contenedor define la base → recalcule o regenere el destino después de la reubicación.
  • Llamar a cualquiera de los dos enlaces una copia de seguridad → uno comparte el objeto y el otro almacena solo una ruta → cree una copia restaurable de forma independiente.
  • Comprobar una ruta y abrirla después → un atacante puede intercambiar un enlace simbólico entre operaciones → aplique restricciones de recorrido de forma atómica durante la apertura.

Preguntas de seguimiento y respuestas

Pregunta de seguimiento 1: ¿Tienen los enlaces duros permisos o propietarios separados?

No. Los permisos, propietario, tamaño y marcas de tiempo pertenecen al inodo compartido. Cambiarlos a través de un enlace duro cambia lo que observa cada par. Los nombres de las entradas de directorio y los permisos de su directorio padre son independientes; renombrar o desenlazar un nombre se rige por el directorio contenedor.

Pregunta de seguimiento 2: ¿Por qué a veces se rompe un enlace simbólico relativo después de ser movido?

Su carga útil se interpreta de forma relativa al directorio que contiene el enlace simbólico. Mover el enlace cambia esa base mientras se preserva la cadena almacenada. Un enlace simbólico absoluto mantiene una sola ruta, pero puede ser incorrecto dentro de un contenedor, chroot, montaje alternativo u otro host. Elija después de definir las necesidades de reubicación.

Pregunta de seguimiento 3: ¿Puede rename reemplazar current de forma atómica entre distintos sistemas de archivos?

No. En Linux, rename devuelve EXDEV entre sistemas de archivos montados. Publique el destino completado dentro del sistema de archivos de destino, cree el alias temporal allí y luego renombre ese alias sobre current en el mismo directorio. Defina la limpieza y recuperación para cualquier fase de copia previa.

Pregunta de seguimiento 4: ¿Por qué el espacio en disco permanece utilizado después de que se elimina la última ruta?

Una descripción de archivo abierta aún puede hacer referencia al inodo. Localice el descriptor y el proceso propietario, luego use el procedimiento seguro de rotación o reinicio de la aplicación. El espacio se recupera después de que desaparecen el último nombre y la última referencia abierta; eliminar la ruta por sí sola solo demuestra que ese nombre ya no existe.

Pregunta de seguimiento 5: ¿En qué se diferencian stat, lstat y readlink?

stat normalmente sigue el enlace simbólico final y reporta el destino. lstat reporta el objeto de enlace simbólico. readlink devuelve su ruta almacenada sin resolverla. Utilice los tres conceptos al comprobar tanto el alias como el objeto al que llega actualmente.

Pregunta de seguimiento 6: ¿Cómo evitaría una condición de carrera con enlaces simbólicos en un directorio de subida de archivos (upload)?

Abra de forma relativa a un descriptor de directorio confiable y haga que la resolución obligue a permanecer por debajo de ese directorio y no siga enlaces simbólicos prohibidos. Luego valide el descriptor devuelto con operaciones basadas en descriptores. Una verificación de ruta seguida de una apertura separada deja una ventana de tiempo para el reemplazo.

Fuentes públicas

Preguntas relacionadas