Ci sono tre cose in un "file" su filesystem POSIX:
- Il set di blocchi di dati - i contenuti effettivi del file.
- Il inode , che è una struttura che contiene l'elenco di detti blocchi e alcuni metadati (dimensioni, proprietà, permessi, numero di link e altri).
- Una o più voci di directory , che contengono un nome e un numero di inode (e altre cose)
Quello che vedi quando esegui ls
o nei browser di file sono le voci della directory, organizzate in un albero di directory e file. Ciascuna voce della directory associa il nome del file a un numero di inode. Il numero di inode viene utilizzato per individuare l'inode, che viene utilizzato per individuare i blocchi effettivi (e controllare le autorizzazioni, ecc.)
Quando crei un file, viene creato un inode con un conteggio link iniziale di uno e una voce di directory viene impostata con il nome specificato, che punta a quell'inode.
Se si crea un collegamento difficile , viene creata una seconda voce di directory con il nome scelto, ma che punta allo stesso inode - entrambe le voci della directory si riferiscono allo stesso inode (cioè ora hai due nomi che si riferiscono allo stesso file). Il conteggio dei link dell'inode viene incrementato per ogni nuovo hard link.
Quando un processo apre un file, utilizzando un nome file, il kernel esegue la ricerca della voce di directory, trova l'inode e restituisce un descrittore di file che "fa riferimento a" l'inode, non alla voce della directory. La voce della directory è irrilevante una volta che il file è stato aperto - è solo un modo conveniente per individuare l'inode giusto.
Quando elimini un file (ad esempio utilizzando rm
), non stai effettivamente eliminando il file, stai eliminando la voce della directory. Il kernel decrementa il conteggio dei link dell'inode, ma non cancella l'inode (e lo spazio di recupero) a meno che:
- quella voce di directory era l'ultima ad indirizzarla (cioè il conteggio dei collegamenti è sceso a zero - questo è ciò che
lsof +L1
elenca: apre i file completamente scollegati)
- non ci sono rimanenti descrittori di file aperti che si riferiscono ad esso
Quindi i processi possono continuare a funzionare su quel file, anche se non c'è modo di tornare indietro sfogliando il filesystem. E puoi ottenere apparenti incoerenze dall'output di df
e du
per esempio:
-
df
interroga il filesystem per vedere quanti blocchi liberi ha. I blocchi di dati dai file "nascosti" senza più voci di directory non sono liberi (ci sono ancora processi in grado di leggerli / scriverli), quindi occupano ancora spazio e continueranno a occupare quello spazio fino all'ultimo descrittore di file che fa riferimento a loro è chiuso
-
du
elenca le voci della directory e riassume le dimensioni. Non può vedere questi file non collegati e quindi restituirà meno spazio utilizzato rispetto al filesystem.
Se i file si trovano su dischi tradizionali, continuano a occupare lo spazio su disco come i normali file ancora collegati. IO succede normalmente. Non ha più requisiti di memoria principale / inizia a mangiare RAM.
Se i file non collegati ma aperti si trovano in un filesystem supportato da RAM, continuano a occupare memoria, come prima di essere scollegati. (In entrambi i casi i file possono ancora crescere o ridursi.)
Lo spazio verrà recuperato solo quando l'ultimo descrittore di file aperto viene chiuso. (Si noti che i descrittori di file ancora aperti vengono chiusi quando un processo termina o è altrimenti terminato).
Se si collega un debugger a un programma che utilizza file non collegati, non si vedrà nulla di particolarmente interessante. Le chiamate di file IO appariranno esattamente come per i file normali, ancora collegati. Niente di speciale da fare lì. Ispezionando ciò che è stato letto / scritto potresti avere qualche idea su come il processo sta usando questi file, ma questo è tutto.
Per quanto riguarda l'accesso a questi file, temo di non conoscere OS X abbastanza da dire se c'è un modo semplice. Il fdesc
pseudo-filesystem sembra simile potrebbe essere utile, ma a quanto pare ti dà solo accesso ai file del processo corrente.
Un semplice esempio di come un processo può farlo, in perl. (Può essere fatto con qualsiasi linguaggio, inclusi gli script di shell.)
Funzione di installazione e supporto:
#! /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 principale:
# 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);
Output previsto:
$ 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.
Puoi spostare lo scollegamento attorno a un bit (prima o dopo le stampe), non cambierà nulla. Non c'è nulla di speciale nell'handle del file dopo lo scollegamento, può essere usato come qualsiasi altro handle di file (purché sia mantenuto aperto).