No Unix, normalmente, um arquivo é uma entrada em uma tabela de arquivos. Existem diferentes tipos de arquivos: arquivos regulares, dispositivos, links simbólicos, portas, canos, tomadas, diretórios ...
O número de inode (que você pode ver na saída de ls -i
) é o índice nessa tabela.
Agora, você não acessa arquivos por inode , mas por caminho . Um caminho é uma cadeia de entradas diretório . Você notará que não estamos falando de pasta mas do diretório aqui. Porque é o que é um diretório (pense em um diretório de telefone).
Um diretório é um tipo especial de arquivo que dá nomes a vários inodes. Uma entrada de diretório é um mapeamento de um nome para um inode.
Um determinado arquivo (um inode) pode ter mais de um nome em um diretório (assim como pode haver mais de um nome em um número de telefone) e também pode ter nomes (entradas) em mais de um diretório. Esses são chamados links também conhecidos como hard links para distinguir com soft links (um tipo especial de arquivo que é um ponteiro para um caminho).
Um arquivo (inode) monitora o número de links (de entradas em qualquer diretório) que possui, de forma que quando o número atinge 0 (quando está sendo desvinculado do último diretório em que foi referenciado), é desalocado.
Esse é o número (o número de links) que é exibido na saída ls -l
.
Quando um arquivo sem diretório é criado pela primeira vez (com as chamadas de sistema open
ou creat
(ou bind
ou mknod
para alguns tipos de arquivos), isso é feito fornecendo um caminho para o novo arquivo (como "/a/b"
). O que acontece, então, é um novo arquivo e o inode é alocado e uma nova entrada é incluída no diretório associado ao "a"
name no diretório raiz "/"
. Esse é o link inicial para que a contagem de links seja uma.
Mais links podem ser adicionados mais tarde com a chamada do sistema link()
(o comando ln
). E os links podem ser removidos com a chamada do sistema unlink()
(o comando rm
).
Você notará que os arquivos do tipo diretório geralmente têm um número de links maior ou igual a 2.
Agora, quando você cria um diretório, está chamando a chamada do sistema mkdir()
. Algo como mkdir("/a/b")
. O que ele faz é alocar um novo arquivo do tipo diretório. Nesse novo diretório, ele cria automaticamente duas entradas:
-
"."
( ponto para diretório ). Qual é um link para si mesmo. Então, a contagem de links agora é de 1.
-
".."
(para o diretório diretório ). Qual é um link para "/a"
. Assim, a contagem de links de "/a"
é incrementada em um
Em seguida, esse novo diretório é vinculado a "/a"
(uma entrada é adicionada em "/a"
para ele), portanto, sua contagem de links agora é 2. Se um diretório "/a/b/c"
for criado, por causa da entrada ".."
em "/a/b/c"
, a contagem de links de "/a/b"
se tornará 3.
A maioria dos Unices restringe a criação de links adicionais para um diretório, porque eles podem causar loops problemáticos. Quando eles permitem um link()
em um diretório, geralmente apenas o superusuário pode fazê-lo.
Alguns sistemas de arquivos como btrfs
partem dessa estrutura de diretório tradicional. Você notará que as contagens de links nos diretórios em btrfs
sistemas de arquivos são sempre um, mesmo que esses diretórios contenham uma entrada "."
com o mesmo número de inode que eles mesmos.
O fato de que a contagem de links é tradicionalmente 2 mais o número de subdiretórios tem seu uso. Por exemplo, em:
find . -name '*.c' -print
Se .
não contiver subdiretórios, mas contiver milhões de arquivos. Ao verificar a contagem de links de .
, find
pode saber que não há subdiretório. Então, tudo que o find
tem a fazer é ler o conteúdo do diretório e reportar as entradas que terminam em .c
(como grep '\.c$'
em um arquivo de poucos megabytes, não é grande coisa). Caso contrário, find
teria que verificar o tipo de cada arquivo para ver se há diretórios para lá (resultando em tantas lstat()
chamadas do sistema). É claro que esse tipo de otimização não funciona em btrfs
(embora nas versões modernas do Linux, o tipo de arquivo também seja armazenado na entrada de diretório para alguns sistemas de arquivos (incluindo btrfs
) e retornado pelo getdents(2)
chamada do sistema usada para recuperar a lista de entradas em um diretório, portanto lstat
ainda não é necessário).