Hay tres cosas en un "archivo" en los sistemas de archivos POSIX:
- El conjunto de bloques de datos: el contenido real del archivo.
- El inodo , que es una estructura que contiene la lista de dichos bloques y algunos metadatos (tamaño, propiedad, permisos, recuento de enlaces y algunos otros).
- Una o más entradas de directorio , que contienen un nombre y un número de inodo (y otras cosas)
Lo que ve cuando ejecuta ls
o en los navegadores de archivos son las entradas de directorio, organizadas en un árbol de directorios y archivos. Cada una de las entradas del directorio asigna el nombre del archivo a un número de inodo. El número de inodo se utiliza para localizar el inodo, que se utiliza para localizar los bloques reales (y verificar los permisos, etc.)
Cuando crea un archivo, se crea un inodo con un recuento de enlace inicial de uno, y se configura una entrada de directorio con el nombre que especificó, apuntando a ese inodo.
Si crea un enlace hard , se crea una segunda entrada de directorio con el nombre que eligió, pero apuntando al inem same : ambas entradas de directorio se refieren a la misma inode (es decir, ahora tiene dos nombres que se refieren al mismo archivo). El recuento de enlaces del inodo se incrementa para cada nuevo enlace físico.
Cuando un proceso abre un archivo, utilizando un nombre de archivo, el núcleo realiza la búsqueda de entradas de directorio, encuentra el inodo y devuelve un descriptor de archivo que "se refiere" al inodo, no a la entrada de directorio. La entrada del directorio es irrelevante una vez que se ha abierto el archivo; es solo una forma conveniente de ubicar el inodo correcto.
Cuando eliminas un archivo (por ejemplo, utilizando rm
), en realidad no estás eliminando el archivo, estás eliminando la entrada del directorio. El kernel disminuye el número de enlaces del inodo, pero no elimina el inodo (y reclama espacio) a menos que:
- la entrada del directorio fue la última que lo señaló (es decir, el recuento de enlaces se redujo a cero; esto es lo que
lsof +L1
enumera: archivos abiertos que están completamente desvinculados)
- no hay descriptores de archivo abiertos restantes que se refieran a él
Por lo tanto, los procesos pueden continuar operando en ese archivo, incluso si no hay manera de volver a él desde el sistema de archivos. Y puede obtener inconsistencias aparentes de la salida de df
y du
por ejemplo:
-
df
interroga el sistema de archivos para ver cuántos bloques libres tiene. Los bloques de datos de los archivos "ocultos" que ya no tienen entradas en el directorio no son libres (todavía hay procesos que pueden leerlos / escribirlos), por lo que aún ocupan espacio y continuarán ocupando ese espacio hasta el último descriptor de archivo que se refiere a ellos. está cerrado
-
du
enumera las entradas de directorio y resume los tamaños. No puede ver estos archivos no vinculados y, por lo tanto, devolverá menos espacio utilizado que el sistema de archivos.
Si los archivos están en discos tradicionales, continúan ocupando espacio en el disco al igual que los archivos normales, aún vinculados. IO sucede como normal. No tiene más requisitos de memoria principal / empieza a comer RAM.
Si los archivos no vinculados pero abiertos están en un sistema de archivos respaldado por RAM, entonces continúan ocupando memoria, como lo hicieron antes de ser desvinculados. (En ambos casos, los archivos también pueden crecer / reducirse).
El espacio se reclamará solo cuando se cierre el último descriptor de archivo abierto. (Tenga en cuenta que los descriptores de archivos aún abiertos se cierran cuando un proceso sale o finaliza de otro modo).
Si adjunta un depurador a un programa que utiliza archivos no vinculados, no verá nada particularmente interesante. Las llamadas de archivos IO se verán exactamente igual que los archivos normales, aún vinculados. No pasa nada especial allí. Al inspeccionar lo que está leído / escrito, puede obtener algunas ideas sobre para qué sirve el proceso de estos archivos, pero eso es todo.
En cuanto al acceso a estos archivos, me temo que no conozco OS X lo suficiente como para saber si hay una manera fácil. El pseudo-sistema de archivos se parece al fdesc
podría ser útil, pero aparentemente solo le da acceso a los archivos del proceso actual.
Un ejemplo simple de cómo un proceso puede hacer esto, en perl. (Se puede hacer con casi cualquier idioma, incluidos los scripts de shell).
Configuración y función de ayuda:
#! /usr/bin/perl
use strict;
use warnings;
use Fcntl qw(SEEK_SET); # for rewinding
my $fh; # file descriptor/handle
my $test_file = "./test_file";
sub status { # checks if the file is "visible"
my @st = stat($test_file);
if (@st) {
print "$test_file: file exists\n";
} else {
print "$test_file: error: $!\n";
}
}
La parte principal:
# open file in read/write mode, creating it if it doesn't exist
# (overwriting it if it does)
if (!open($fh, '+>', $test_file)) {
die "Failed to open $test_file: $!";
}
print $fh "Some data before unlink.\n";
status();
unlink($test_file);
status();
print $fh "Some data after unlink.\n";
# Rewind
seek($fh, 0, SEEK_SET);
# Print file contents
foreach my $line (<$fh>) {
print "read: $line";
}
# Close
close($fh);
Salida esperada:
$ perl test.pl
./test_file: file exists
./test_file: error: No such file or directory
read: Some data before unlink.
read: Some data after unlink.
Puede mover el desvío un poco (antes o después de las impresiones), no cambiará nada. No hay nada especial en el identificador de archivos después del desvincular, se puede usar como cualquier otro manejador de archivos (siempre que se mantenga abierto).