ligas físicasDe Kathy
Respondida por: Jason Creigton, Faber Fedor, Neil Youngman, Jim Dennis, Jay R. Ashworth, Ben Okopnik, Thomas Adam
Estoy confundida: si Linux no permite ligas físicas a carpetas, entonces,
¿por qué cada carpeta tiene al menos dos ligas físicas?
Gracias, Kathy
[Jason] No estoy exactamente seguro... pero http://www.linuxgazette.com/issue35/tag/links.html es una buena lectura.
[Faber] ¿Sabes?, ¡yo también estoy confundido! Mirándolo un poco más, parece que son permitidas o no las ligas físicas a las carpetas dependiendo del sistema de archivos subyacente. Sistemas del tipo vxfs (no, tampoco sé que significa)
no permiten la creación de ligas físicas de carpetas. Todavía tengo que descubrir por qué.
La razón por las que las tenemos en Linux (. y ..) es, siempre yo asumo, para que tengamos un modo de recorrer el árbol de carpetas (cd ..) hacia la carpeta raíz. De otra manera, el sistema necesitaría saber el nombre de la carpeta padre (contrariamente a saber su inodo).
¿Entonces, por qué es . una liga física a la carpeta actual? <shrug> ¿Porque la gente de un*x son flojos para escribir?
Una pregunta muy interesante, por cierto. Estoy interesado en encontrar la respuesta para mí.
[Jim] El sistema usa ligas físicas para manejar el vínculo de la carpeta padre con el inodo de la carpeta, la liga . en esa carpeta y todas las entradas de todas las subcarpetas.
A los USUARIOS (incluído el superusuario) se les prohíbe crear ligas físicas adicionales porque esto haría más dificil realizar la labor de fsck, y se podrían crear ligas físicas enlazadas a sí mismas (cíclicas) y sub árboles colgados (sin relación con algún padre).
Básicamente, la vinculación de carpetas es mantenida por el sistema de archivos para mantener pegado todo el árbol, para asegurar que es realmente una estructura de árbol acíclica con una sola raíz.
En otras palabras, es una política de administración reforzada por el núcleo del sistema. Otros sistemas UNIX han permitido al superusuario la creación de carpetas con ligas físicas; y eso podía hacerse con un editor de disco como LDE bajo Linux (aunque yo esperaría que se quejara fsck la siguiente vez que se ejecutara) -- y si uno hiciera algo que degenerara el sistema se podrían crear problemas interesantes, probablemente hasta llegar a que el núcleo considere corrupto al sistema de archivos e invoque a su manejador (remontar, ro -sólo lectura-, pánico o continuar) y quizá causar que algunos procesos del núcleo se ejecuten desbocadamente o que el sistema entre en estado de pánico.
[Neil] Tradicionalmente, en los sistemas Unix un archivo o carpeta se borra físicamente del disco cuando no hay ligas físicas a ella. Los comandos rm y rmdir ordenan la remoción de la entrada de la carpeta (la liga). Si hay más de una liga física al archivo o a la carpeta, el archivo permanece, así que a pesar de que pensamos que el comando rm eliminó el archivo, en realidad sólo eliminó la liga al archivo. Cuando no hay ligas físicas a un archivo o a una carpeta, el sistema de archivos entonces libera el espacio que actualmente es usado por el archivo. Tiene que haber ligas físicas a las carpetas o si no, serían eliminadas por el sistema de archivos.
Las ligas físicas a las carpetas sólo pueden ser creadas por mkdir para segurar que no construiremos estructuras de archivos y carpetas cíclicas; de otra manera, programas como find, que recorren el árbol de archivos podrían quedar ciclados en la misma estructura de carpetas para siempre.
En conclusión, Linux no permite ligas físicas a las carpetas, pero sí permite ligas físicas de una carpeta a sí misma y a su carpeta padre. Estas son las dos ligas físicas a las que haces referencia.
[Neil] Aquí hay algo de ambigüedad. Si hay más de una liga antes del comando rm, habrá al menos una después del comando rm, entonces el espacio del archivo no es liberado. Por supuesto que rmdir elimina ambas ligas de una carpeta.
[Jason] Okey, he examinado esto más: parece que, por alguna razón u otra (otro miembro de la Pandilla sabrá sin duda por qué), es una Mala Idea crear ligas físicas a las carpetas. Miren aquí:
root:~# ln lala foo
ln: `lala': hard link not allowed for directory
root:~# strace ln lala foo
execve("/bin/ln", ["ln", "lala", "foo"], [/* 17 vars */]) = 0
uname({sys="Linux", node="jpc.example.com", ...}) = 0
brk(0) = 0x804db0c
open("/etc/ld.so.preload", O_RDONLY) = -1 ENOENT (No such file or
directory)
open("/etc/ld.so.cache", O_RDONLY) = 3
fstat64(3, {st_mode=S_IFREG|0644, st_size=19148, ...}) = 0
mmap2(NULL, 19148, PROT_READ, MAP_PRIVATE, 3, 0) = 0x40014000
close(3) = 0
open("/lib/libc.so.6", O_RDONLY) = 3
read(3, "\177ELF\1\1\1\0\0\0\0\0\0\0\0\0\3\0\3\0\1\0\0\0\20\\\1"..., 1024) =
1024
fstat64(3, {st_mode=S_IFREG|0755, st_size=1494904, ...}) = 0
mmap2(NULL, 1256324, PROT_READ|PROT_EXEC, MAP_PRIVATE, 3, 0) = 0x40019000
mprotect(0x40144000, 31620, PROT_NONE) = 0
mmap2(0x40144000, 24576, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED, 3,
0x12a) = 0x40144000
mmap2(0x4014a000, 7044, PROT_READ|PROT_WRITE,
MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x4014a000
close(3) = 0
mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) =
0x4014c000
munmap(0x40014000, 19148) = 0
stat64("foo", 0xbffffc10) = -1 ENOENT (No such file or
directory)
lstat64("lala", {st_mode=S_IFDIR|0755, st_size=48, ...}) = 0
write(2, "ln: ", 4ln: ) = 4
write(2, "`lala\': hard link not allowed fo"..., 43`lala': hard link not
allowed for directory) = 43
write(2, "\n", 1 ) = 1
exit_group(1) = ?
Tómese en cuenta que en el resultado de strace, link() no es realmente llamado. Así que este 'ln', ¿sólo está tratando de salvarnos de nosotros mismos, o es el núcleo del sistema, o glibc? Yo escribí este rápido programa en C:
Véase archivo adjunto creighton.c-link.c.txt
root:~# link=/home/jason/prog/c/link
root:~# $link lala foo
Error while linking: Operation not permitted
root:~# strace $link lala foo
<sniped syscall trace that looks very similar to ln's strace output....the
important line is:
link("lala", "foo") = -1 EPERM (Operation not permitted)
<sniped more>
root:~#
Pues, 'ln' ve que uno está tratando de crear ligas físicas a carpetas y ni siquiera lo intenta; en vez de eso, proporciona un útil mensaje de error. Y ya que vemos que es ejecutada la llamada de sistema link(), eso significa que el núcleo no permite la creación de ligas físicas a carpetas, y no es el empacador glibc el que rehúsa la creación de las ligas físicas a carpetas (si hubiera sido glibc, ni siquiera hubiéramos visto link() ser ejecutada: la llamada link() en glibc hubiera regresado el control sin haber llamado a link()).
Ahora, de regreso a tu pregunta original: no tengo idea de por qué crear ligas físicas a una carpeta es una mala idea (debe serlo, si no, Linux permitiría que el superusuario lo hiciera). La columna Hombre Respuesta (Answer Guy) del número 35 de LG tiene algo al respecto (tomado del artículo al que agregué un hipervínculo en mi otro mensaje de correo-e):
<quote>
Algunas versiones de Unix han históricamente permitido que el superusuario cree ligas físicas a carpetas -- pero las utilerías GNU en Linux no lo permitirán -- así que tienes que escribir tu propio código o tienes que modificar directamente el sistema de archivos con un editor hexadecimal.
<end quote>
Bueno, obviamente es el núcleo del sistema el que lo impide, no las
utilerías GNU. Sin embargo, el número 35 de LG se publicó hace algún tiempo,
así que las cosas pudieran haber sido diferentes entonces.
[jra] Las ligas físicas a carpetas agregadas por usuarios están prohibidas porque rompen la estructura gráfica acíclica y dirigida del sistema de archivos (lo cual es una afirmación en Unixiana, aproximadamente), y puesto que ellos confunden el infierno fuera de los 'recorredores de árboles de archivos' (file-tree-walkers) -- un término que los Multicianos reconocerán a primera vista, aunque los muy adentrados en Unix pueden probablemente entender, también, sin problemas).
(¿Lo dije bien, Ben?)![]()
Y por supuesto, cualquiera que alguna vez haya hecho
# rm -rf .*
en una carpeta base de usuario la remoción de todos los archivos punto (los ocultos) antes de eliminar al usuario, entenderán, sin duda, por qué aún el sistema que crea tres ligas con una carpeta (. en ., .. en los hijos, y la mencionada liga en el padre) son a menudo dos demasiado.
[Jason] ¡Auch! Nunca pensé en eso, tengo que recordar eso...
[Jason] Sí, escribí eso antes de tener que leer el resto de la cadena (de mensajes). Con las ligas simbólicas, por lo menos es fácil decir cuándo hay un bucle (por cierto, me parece recordar una opción en Wine para ignorar las ligas simbólicas porque ellas causan que algunos programas de Windows se confundan mucho, mucho).
~/tmp$ ln -s file1 file2
~/tmp$ ln -s file2 file1
~/tmp$ ls -l file*
lrwxrwxrwx 1 jason users 5 Jul 20 16:59 file1 -> file2
lrwxrwxrwx 1 jason users 5 Jul 20 16:59 file2 -> file1
~/tmp$ cat file1
cat: file1: Too many levels of symbolic links
~/tmp$ strace -e trace=open cat file1
open("/etc/ld.so.preload", O_RDONLY) = -1 ENOENT (No such file or directory)
open("/etc/ld.so.cache", O_RDONLY) = 3
open("/lib/libc.so.6", O_RDONLY) = 3
open("file1", O_RDONLY|O_LARGEFILE) = -1 ELOOP (Too many levels of symbolic links)
cat: file1: Too many levels of symbolic links
[Jason] Acabo de pensar en algo más:
La administración de espacio en disco y la de memoria son la misma cosa.
UNIX ha elegido el conteo de referencia para la administración del espacio en disco. El conteo de referencias no puede tratar con las estructuras de datos cíclicas (¿es correcta la palabra? me refiero a las estructuras de datos que se refieren a sí mismas) y, por tanto, el ligar físicamente carpetas está prohibido. Si Linux usara la recolección de basura, estaría bien ligar físicamente carpetas, si fuera confuso.
Pero usar GC en los sistemas de archivos se volvería lento y no ofrecería ventajas verdaderas, así que el conteo de referencias está bien.
Bien, el superusuario debe ser capaz de crear ligas físicas, debido
a la opción ln --directory (-d, -F).
[Jason] Pruébalo:
root:~# mkdir dir1 root:~# ln -d dir1 dir2 ln: creating hard link `dir2' to `dir1': Operation not permitted
[Thomas]
Entonces en la misma cadena....
[jra]
Y por supuesto, quien ha hecho:
# rm -rf .*
[Jim] La versión GNU de 'rm' rehusará intentar la recursión dentro o el desligue de las entradas . o ..
Sin embargo, ésta es aún una clásica pregunta técnica de administración de sistemas. Es tan común como: "¿cómo elimino un archivo llamado -fr?".
[Ben]
rm -- -fr
rm ./-fr
perl -we'unlink "-fr"'
"F8" en Midnight Commander
![]()
[Thomas] Olvidaste mencionar usando Emacs... Tampoco mencionaste mandar el disco al espacio...
[Jim] ¿Cómo eliminas EN FORMA SEGURA todos los archivos punto y las carpetas punto que están en la carpeta actual?
Mi mejor respuesta en Bash es
rm -fr .??* .[^.]
[Ben]
rm -rf .[^.]*
es lo que siempre he usado; esto podría, por supuesto, ignorar archivos llamados "..." y demás, pero no es mucho problema en la práctica.
[Jim] ... esto obtiene cualquier cosa que empiece con un punto y le sigan al menos dos caracteres (por tanto . y .. no concordarán) y también obtiene cualquier cosa que empiece con un punto y le siga cualquier carácter único distinto de un punto (por tanto, obtiene entradas poco probables como . y .\? etc). Esta pareja de patrones glob debe concordar cada posible entrada punto, excepto . y ..
Sin embargo, yo uso un prefijo con ella en bash. Ocurre que sé que funcionará en ash, zsh, tcsh y muchos otros intérpretes de comandos modernos. Empero, si estuviera en un intérprete antiguo, tendría que verificarlo. La clase de caracteres negados podría no estar en la biblioteca glob de los primeros intérpretes Bourne y C.
Si tuviera que escribir un archivo de comandos a máxima portabilidad:
rm -fr .??*; rm -fr `echo .? | grep -v '\.\.' `
...eliminaría todas las entradas grandes de la manera obvia, luego deja que echo haga concordar las entradas de dos caracteres y, usando grep, extraería la entrada .. explícitamente.
[Ben] Otras soluciones interesantes salen cuando quieres eliminar un archivo cuyo nombre está en un idioma extranjero. Me he topado con el nombre de una canción rusa que ni aún Midnight Commander podría manejar. Cortando y pegando en 'rm' tampoco ayudó (claramente, algunos de los caracteres eran del tipo de caracteres "escapados" -escape chars-, pero no tenía idea cuáles -- en pocas palabras, la máquina no tenía archivo de fuentes de caracteres rusos). Incluso el comando 'ls -b' falló con lo mismo ya mencionado, por cualquiera que fuera la razón. Terminé haciendo algo como:
perl -wle'/match/&&print for <*>'
donde "match" era una pequeña cadena de caracteres del nombre. No hay necesidad de decirlo, "print" se convirtió en "unlink" cuando me di cuenta que el único archivo apropiado había concordado.
Índice Actual de La Pandilla de las Respuestas
Conoce a la Pandilla
1
2
3
4
5
6
|