De acordo com as Leis 12.965/2014 e 13.709/2018, que regulam o uso da Internet e o tratamento de dados pessoais no Brasil, ao me inscrever na newsletter do portal DICAS-L, autorizo o envio de notificações por e-mail ou outros meios e declaro estar ciente e concordar com seus Termos de Uso e Política de Privacidade.


Revisitando o hard-vs soft link

Colaboração: Fernando Roxo

Data de Publicação: 11 de novembro de 2019

Há alguns anos eu escrevi uma dica sobre o assunto. Infelizmente o artigo apontado por lá não está mais disponível. Na época alguns leitores colocaram lá seus comentários mas, por alguma razão, eles passaram despercebidos e não respondi na ocasião.

Um dos leitores, identificado como Marco, perguntou:

Uma dúvida que tenho há muito tempo: o que acontece quando um hardlink é gravado, quero dizer, numa operação como append?

Para responder a essa pergunta é interessante que seja compreendida a estrutura de um arquivo e a diferença entre os dois tipos de ligação.

Em princípio pode-se pensar um arquivo como uma estrutura de dados que compreende o(s) inode(s) e mais uma sequência de unidades de alocação que realmente receberá o conteúdo dos arquivos.

Vamos tentar esmiuçar um pouco mais essa estrutura. Em princípio o inode é uma estrutura no sistema de arquivos que contém pelo menos:

  • o tipo de arquivo (regular, symlink, socket, diretório, device,..)
  • a identificação do proprietário (usuário e grupo)
  • as autorizações de acesso em quatro grupos de três bits. Essas autorizações são do tipo rwx (leitura, escrita e execução) para os três dos grupos, o outro grupo têm alguns significados especiais que acho que não vale a pena detalhar aqui.
  • link count que é um contador de quantas entradas de diretório apontam para esse inode.
  • tamanho, em bytes, do conteúdo do arquivo.
  • localização dos blocos de dados e, se necessário, a localização de outros inodes contendo relação de mais blocos.

Os blocos de dados se referem a unidades mínimas de alocação de dados, que realmente vão registrar o conteúdo do arquivo. Normalmente um bloco desses tem algo como 4KB e os dados registrados são de apenas um arquivo. Nesse caso se um arquivo contiver somente um byte de dado, o espaço alocado para ele será uma unidade mínima de alocação, ou seja 4KiB.

É obvio que podem haver variações sobre o tema. A unidade mínima de alocação pode ser maior ou menor, a depender da estrutura do sistema de arquivos, da geometria do dispositivo e mais alguns outros fatores. Da mesma forma o inode pode conter outras informações não listadas, mas essas acima devem estar em todas as estruturas que fazem esse papel. Se não me engano, o sistema de arquivos ReiserFS, que fez muito sucesso há algum tempo, permitia o compartilhamento de unidades de alocação entre arquivos. Em resumo, essa descrição é super simplificada e não dá conta de um monte de sofisticação dos sistemas de arquivo correntes, mas é o necessário para entender muito do que acontece.

Tá, tudo muito bonito, tudo muito elegante mas a idade deve estar afetando esse tal de Roxo, como ele esqueceu o nome do arquivo? O fato é que, embora realmente esteja ficando velho, eu não esqueci do nome do arquivo. Na verdade o nome NÃO é uma informação do arquivo. Ensandeceu de vez? Como não? Como ter acesso a um arquivo sem nome? Não há problema algum. Se tiver acesso ao inode os dados serão acessíveis, mesmo que não exista nenhum nome associado ao arquivo. É possível um programa estar utilizando um arquivo somente para leitura e esse ser apagado. O que acontece com o programa? Se tudo correr como deve, o programa vai executar até o fim e, após fechar o arquivo, o mesmo será eliminado pelo sistema, se o link count for zero. O nome do arquivo só é usado para localizar o inode, depois disso todos os acessos (abertura, avanço, retorno, gravação, leitura, .... ) só utilizam a estrutura do inode para serem executados.

Para que tudo isso?

Bem, uma das coisas importantes para a compreensão da diferença do hard link e do soft link, é como os dois tipos funcionam. Vamos retomar o exemplo do primeiro artigo:

$  date > blah.txt
$  cat blah.txt
qua ago 22 20:50:52 -03 2018
$  ls -l blah.txt
-rw-r--r-- 1 roxo roxo 29 ago 22 20:50 blah.txt

A notar, pulando o primeiro - na listagem acima temos três grupos de indicadores, que são as autorizações de acesso (rw- r-- r--) para o dono, o grupo do dono e para o resto do mundo. ;) O primeiro -, que desprezamos, é o tipo do arquivo. O roxo roxo é a descrição do dono (usuário e grupo). O 29 é o número de bytes do conteúdo do arquivo. A data e hora correspondem a quando o arquivo foi alterado pela última vez. Todas essas informações vieram do inode. E o nome? O nome veio de outro lugar. Um dos tipos de arquivo possíveis é o chamado diretório, por exemplo o do diretório em que estou fazendo os experimentos, como todo diretório corrente, é chamado .:

$ ls -ld .
drwxr-xr-x 2 roxo roxo 4096 ago 22 20:50 .

Aquele d no lugar do - desprezado antes indica que esse arquivo é do tipo diretório. O - indica um arquivo regular, se fosse um s seria um socket, se fosse um c seria um dispositivo de caracteres (p.ex. um terminal) e um b seria um dispositivo de blocos (p.ex. um disco) e por aí vai.

O tal de diretório, o que é? Para simplificar pense em um diretório como um arquivo especial cujo conteúdo é uma tabela contendo um nome e um número de inode associado a esse nome. Veja que esse nome está numa tabela à parte, a única relação com o arquivo é o número de inode, que é um apontador apenas. Toda vez que é criada uma entrada em um diretório apontando para um arquivo/inode, o link count do inode é incrementado de um (1). Quando se apaga um arquivo o que o sistema faz é subtrair um do link count, somente quando o link count do inode chega a zero é que o inode é marcado como livre e todos os blocos contendo dados são liberados. Repare que eu não disse que o arquivo é apagado, o espaço é devolvido para o sistema usar, se nada for escrito na posição as informações ainda estarão lá, por isso por vezes é possível recuperar um arquivo apagado.

Entra em campo o tal do hard link. O hard link é criado quando se cria uma entrada de diretório com o ponteiro apontando para um inode em uso, nesse caso o tal do diretório ganha um novo nome e o link count do inode é incrementado:

$ ln blah.txt bleh.txt
$ ls -l bl*.txt
-rw-r--r-- 2 roxo roxo 29 ago 22 20:50 blah.txt
-rw-r--r-- 2 roxo roxo 29 ago 22 20:50 bleh.txt

A se notar que o link count que estava em 1 passou para 2, ou seja existem duas entradas de diretório apontando para o mesmo inode do arquivo. Nesse caso as duas entradas de diretório estão na mesma tabela/diretório, mass podem estar em diretórios diferentes do mesmo sistema de arquivos. Mais ainda, com exceção do nome e do link count todas as outras informações são iguais, até mesmo a data da ultima alteração, afinal ao se criar uma ligação o conteúdo do arquivo não é alterado.

O que acontece se tentamos criar um hard link para um arquivo que não existe?

$ ln blih.txt bloh.txt
ln: falha ao acessar 'blih.txt': Arquivo ou diretório inexistente

Porque o sistema reclamou? Porque para criar a entrada do diretório é necessário saber o inode que vai ser ligado, se o arquivo não existe a entrada não pode ser criada. Por essa razão um hard link obrigatoriamente terá que apontar para um inode do mesmo sistema de arquivos, afinal não há como representar, no diretório, um inode de sistema de arquivo diferente

Entra em campo o tal do soft link ou ligação simbólica. Como criar uma ligação dessas:

$ ln -s blah.txt blih.txt
$ ls -l bl*.txt
-rw-r--r-- 2 roxo roxo 29 ago 22 20:50 blah.txt
-rw-r--r-- 2 roxo roxo 29 ago 22 20:50 bleh.txt
lrwxrwxrwx 1 roxo roxo  8 ago 22 21:24 blih.txt -> blah.txt                   

Epa!! Muita coisa mudou aqui!!

Todas as informações da listagem mudaram! Tanto a autorização, data, link count e até mesmo o tipo de arquivo que passou de arquivo regular (-) para ligação simbólica (l). Porque isso? A principal mudança agora é que a ligação simbólica é um arquivo especial que contém apenas o nome do arquivo apontado, ele NÃO contém a informação do inode final de destino. Para acessar o arquivo real o sistema faz um desrreferenciamento (duvido que essa palavra exista fora do nosso meio) que é ler do arquivo do tipo ligação simbólica e, a seguir, buscar o arquivo apontado pelo nome. Veja que uma ligação simbólica pode apontar para outra ligação simbólica, nesse caso serão feitos dois desrreferenciamentos (horror dos horrores!!).

No caso acima:

$ cat blah.txt
qua ago 22 20:50:52 -03 2018
$ cat blih.txt
qua ago 22 20:50:52 -03 2018

Mas qual a utilidade disso? Uma das utilidades é conseguir se fazer referência a um arquivo em outro sistema de arquivos. Um exemplo, na minha atividade profissional, sou geofísico (ninguém é perfeito), eu mantenho as documentações dos vários projetos em que estou envolvido em uma estrutura bem organizada de diretórios, cujo conteúdo se resume a esses documentos. Quase todos os projetos envolvem localização espacial, que trabalho através de um GIS (Qgis, excelente software livre!!). Esse tipo de dado georreferenciado costuma se reproduzir mais rápido que coelho, por isso eu tenho uma outra estrutura de diretórios que espelha aquela dos documentos. Essas duas estruturas estão em sistemas de arquivos diferentes. Para facilitar a navegação do GIS para os documentos, e vice-versa, eu crio no diretório de documentos de um projeto uma ligação simbólica para o correspondente no GIS. E também crio no diretório do GIS para um projeto uma ligação simbólica para o diretório equivalente nos documentos. Dessa forma eu navego facilmente de um lado para outro sem a necessidade de percorrer toda a estrutura de diretórios dos sistema de arquivos. É claro que essas ligações cruzadas são feitas de forma automática, para evitar erros.

O exemplo acima é apenas umas das várias possibilidades do uso das ligações simbólicas.

Ok, até agora vimos que os hard links apontam diretamente os inodes e estão limitados a um sistema de arquivos. Vimos ainda que as ligações simbólicas na verdade apontam para nomes de arquivos e que podem fazer referência entre sistemas de arquivos. No artigo original eu mostro uma utilização de preservação de arquivos temporários, para exame posterior, utilizando o hard link. Vamos ver mais algumas curiosidades.

Temos no nosso diretório de exemplo:

$ ls -l bl*.txt
-rw-r--r-- 2 roxo roxo 29 ago 22 20:50 blah.txt
-rw-r--r-- 2 roxo roxo 29 ago 22 20:50 bleh.txt
lrwxrwxrwx 1 roxo roxo  8 ago 22 21:24 blih.txt -> blah.txt

Como podemos ter certeza se os arquivos são iguais ou diferentes? Uma das opções mais fáceis é pedir ao ls para listar os números inodes:

$ ls -li bl*.txt
4201904 -rw-r--r-- 2 roxo roxo 29 ago 22 20:50 blah.txt
4201904 -rw-r--r-- 2 roxo roxo 29 ago 22 20:50 bleh.txt
4201902 lrwxrwxrwx 1 roxo roxo  8 ago 22 21:24 blih.txt -> blah.txt

Repare que o número do inode das entradas que apontam para o mesmo arquivo têm o mesmo número de inode, já a ligação simbólica tem um número diferente, o que mostra que a ligação simbólica é um outro arquivo, cujo conteúdo é o nome do arquivo apontado.

Como no artigo original:

$ ls -l bl*.txt
-rw-r--r-- 2 roxo roxo 29 ago 22 20:50 blah.txt
-rw-r--r-- 2 roxo roxo 29 ago 22 20:50 bleh.txt
lrwxrwxrwx 1 roxo roxo  8 ago 22 21:24 blih.txt -> blah.txt

$ cat blah.txt
qua ago 22 20:50:52 -03 2018

$ cat blih.txt
qua ago 22 20:50:52 -03 2018

$ rm -f blah.txt
$ ls -l bl*.txt
-rw-r--r-- 1 roxo roxo 29 ago 22 20:50 bleh.txt
lrwxrwxrwx 1 roxo roxo  8 ago 22 21:24 blih.txt -> blah.txt

                                                                              
$ cat bleh.txt
qua ago 22 20:50:52 -03 2018

$ cat blih.txt
cat: blih.txt: Arquivo ou diretório inexistente

A notar que depois do comando rm o link count do hard link foi decrementado, mas o conteúdo do arquivo foi preservado porque o arquivo de fato, representado pelo inode, não foi apagado. Apesar do conteúdo estar preservado, a ligação simbólica não consegue acesso ao arquivo, porque ele faz uma referência a um nome (blah.txt) que não existe mais.

Vimos anteriormente que ao tentar um hard link para um arquivo inexistente aconteceu um erro, porque não havia um inode a ligar. No caso da ligação simbólica:

$ ln -s arquivo_inexistente bluh.txt
$ ls -l bl*.txt
-rw-r--r-- 1 roxo roxo 29 ago 22 20:50 bleh.txt
lrwxrwxrwx 1 roxo roxo  8 ago 22 21:24 blih.txt -> blah.txt
lrwxrwxrwx 1 roxo roxo 19 ago 22 22:03 bluh.txt -> arquivo_inexistente

Como a ligação simbólica só armazena um nome de um arquivo, a existência ou não desse arquivo não importa para a sua criação, só para o acesso, e a sua existência não é sequer verificada. Se um arquivo com aquele nome for criado posteriormente o acesso através da ligação simbólica funcionará normalmente.

Ufa! Um monte de informação que acho que o pessoal que está lendo, se chegou até aqui, até esqueceu da pergunta do Marco que coloquei lá em cima. E se alterarmos o arquivo, o que acontece com os hard links? A resposta curta e simples é: se a operação não envolve a liberação do inode (na verdade o decremento do link count) tudo continua como dantes:

$ ls -l bl*.txt
-rw-r--r-- 2 roxo roxo 29 ago 22 20:50 blah.txt
-rw-r--r-- 2 roxo roxo 29 ago 22 20:50 bleh.txt
lrwxrwxrwx 1 roxo roxo  8 ago 22 21:24 blih.txt -> blah.txt


$ date >> blah.txt
$ cat bleh.txt
qua ago 22 20:50:52 -03 2018
qua ago 22 22:11:03 -03 2018


$ cat blih.txt
qua ago 22 20:50:52 -03 2018
qua ago 22 22:11:03 -03 2018


$ ls -l bl*.txt
-rw-r--r-- 2 roxo roxo 58 ago 22 22:11 blah.txt
-rw-r--r-- 2 roxo roxo 58 ago 22 22:11 bleh.txt
lrwxrwxrwx 1 roxo roxo  8 ago 22 21:24 blih.txt -> blah.txt

Como a extensão do arquivo (append) não tem necessidade de liberar o inode, tudo continua quase igual, mas o conteúdo foi alterado, portanto o tamanho e a data da última alteração também mudam. A ligação simbólica não foi alterada em nada, portanto nem sua data de última alteração muda.

E se o arquivo for sobrescrito?

$ cat /etc/profile > blah.txt
$ ls -l bl*.txt
-rw-r--r-- 2 roxo roxo 581 ago 22 22:15 blah.txt
-rw-r--r-- 2 roxo roxo 581 ago 22 22:15 bleh.txt
lrwxrwxrwx 1 roxo roxo   8 ago 22 21:24 blih.txt -> blah.txt

Nesse caso o arquivo será truncado, o seu tamanho será reduzido a zero, e o novo conteúdo será escrito, mas o inode será o mesmo:

$ ls -li bl*.txt
4201904 -rw-r--r-- 2 roxo roxo 581 ago 22 22:15 blah.txt
4201904 -rw-r--r-- 2 roxo roxo 581 ago 22 22:15 bleh.txt
4201902 lrwxrwxrwx 1 roxo roxo   8 ago 22 21:24 blih.txt -> blah.txt

Confira com o que foi listado lá mais acima e verá que o número do inode não se alterou.

Curiosidade: Uma ligação simbólica pode apontar para ela mesma, o que pode enlouquecer sistemas menos robustos ou muito antigos.

P.S. Grande amigo Lera, o Hercules é um emulador de hardware de mainframe. Os sistemas disponíveis para execução legal no emulador, além do Linux, são muito antigos e não têm suporte ao português. Se ainda estiver interessado, o mais fácil de instalar e usar é o Tur(n)key 4- System.

Adicionar comentário

* Campos obrigatórios
5000
Powered by Commentics

Comentários

Nenhum comentário ainda. Seja o primeiro!


Veja a relação completa dos artigos de Fernando Roxo