Conceitos em Linux (II)
2 - Arquivos:Para o Linux, arquivos têm um significado especial. São as unidades que representam recursos do sistema e oferecem um mecanismo de comunicação do núcleo com o mundo exterior.
Podemos classificar os arquivos em ordinários e especiais. Vejamos as possibilidades:
2.1 - Arquivos especiais:
2.1.1 - Dispositivos de caracteres: representam dispositivos que tratam dados como fluxos, tais como teclados, linhas seriais, etc..
2.1.2 - Dispositivos de blocos: representam dispositivos que tratam dados como grupos de blocos, como HDs, memórias, pendrives, etc., qualquer dispositivo no qual faz sentido endereçar suas partes para um acesso aleatório.
2.1.3 - Conduítes (FIFO): são arquivos que servem como “filas” de dados, usados geralmente para troca de informações entre aplicativos. FIFO vem de “first in, first out” ou “primeiro a entrar, primeiro a sair”, um resumo de como deve ser uma fila. Podem servir como “buffers” para algumas aplicações.
2.1.4 - Ligações simbólicas: arquivos que simplesmente apontam para outros arquivos. Contém apenas instruções de como achar o arquivo “verdadeiro”.
2.2 - Arquivos ordinários:
2.2.1 - Diretórios: arquivos que listam nomes de arquivos em seu conteúdo, relacionando-os às informações contidas sobre eles, no sistema de arquivos. Ficará claro mais tarde.
2.2.2 - Arquivos comuns: os arquivos aos quais estamos acostumados, com vídeos, imagens, informações do usuário, etc..
Para lidar com todos estes tipos de arquivos de uma forma homogênea, o núcleo fornece uma interface comum a todos estes tipos: o Sistema de Arquivos Virtual (ou VFS). Assim, ele pode abstrair a implementação de cada dispositivo fornecendo uma maneira simples de implementar a comunicação. Compete ao desenvolvedor dos drivers para o dispositivo específico fornecer a implementação correta de cada função especificada nesta interface. Desta forma, podemos chamar a função read() para qualquer dispositivo que a suporte e o driver “saberá” o que fazer.
É interessante notar que o VFS é orientado a objetos e obedece a todos os requisitos de tal paradigma de programação, mesmo sendo codificado numa linguagem procedural (no caso, C). Isso é feito, na minha opinião, de forma muito elegante, com técnicas tradicionais de programação. Ler o código do núcleo é uma oportunidade única de se aprender boas práticas de programação.
O sistema de arquivos virtual possui os seguintes objetos associados:
2.3 - Objetos do VFS:
2.3.1 - Objeto do superbloco: contém informações sobre o sistema de arquivos montado (um sistema específico) tais como quais são as operações permitidas (ou disponíveis), tamanho de bloco, etc..
2.3.2 - Objeto i-node: o i-node, ou nó-índice, é um objeto que contém informações sobre o arquivo que ele representa. Será melhor tratado um pouco mais tarde.
2.3.3 - Objeto de entrada de diretórios: contém informações que relacionam i-nodes com nomes de arquivos. Servem para localizar arquivos (e organizá-los, obviamente).
2.3.4 - Objeto de arquivo: a representação do arquivo propriamente dito.
Um diretório é um arquivo que contém a relação entre i-nodes e nomes de arquivos. Assim, um diretório típico contém, por exemplo:
1 .
1 ..
4 bin
7 usr
...
e assim por diante. Este é um exemplo de conteúdo de diretório raiz. Note que as entradas “.” e “..” apontam para o mesmo i-node. Isso é válido no diretório raiz pois “.” é uma referência ao próprio diretório e “..” é uma referência ao diretório pai, ambos aqui relativos ao i-node 1, o raiz. Todo diretório deve ter pelo menos estas duas entradas, uma referência ao próprio diretório e uma a seu pai.
Um i-node é um objeto que contém as informações sobre o arquivo. Entre elas, posso citar:
Permissões de acesso: todo arquivo tem um campo de 12 bits que indica quem poderá acessá-lo. Mais detalhes, futuramente.
Dono: identificador do usuário que o criou.
Grupo: identificador do grupo ao qual pertence.
Tipo de dispositivo representado: indica se é um soquete de rede, um dispositivo de blocos, um conduíte, etc..
Atributos: como data de criação, última modificação e último acesso.
Operações possíveis: registro de operações possíveis sobre o próprio i-node e sobre o arquivo que relata.
Trava: indica se o arquivo está sendo usado por outro programa (sendo escrito) para que não haja conflito entre programas que o compartilhem.
Contador de referências: indica quantos diretórios o referenciam, este é um outro mecanismo para ligações (ligações verdadeiras) e será examinado adiante.
Lista de blocos: contém a lista de endereços dos blocos do arquivo que relata.
Vejamos um exemplo de como uma busca é feita num sistema de arquivos como um HD, por exemplo:

A figura 1 mostra os conteúdos parciais (e fictícios) de diretórios e i-nodes de interesse num disco. Para localizar o arquivo (no caso o executável) /usr/bin/ls o sistema executa o seguinte procedimento:
Procura o diretório raiz;
Neste, procura a entrada referente a “usr”;
Localiza o i-node correspondente, no caso 2;
Lê as informações contidas em 2, como permissões de acesso e caso seja possível executar o arquivo, retorna o endereço do bloco onde está armazenado, no caso 350;
Em 350, executa o arquivo (no caso o diretório “usr”) e procura a entrada referente a “bin”;
Localiza o i-node correspondente, no caso 12;
Lê as informações contidas em 12, como permissões de acesso e caso seja possível executar o arquivo, retorna o endereço do bloco onde está armazenado, no caso 1050;
Em 1050, executa o arquivo (no caso o diretório “bin”) e procura a entrada referente a “ls”;
Localiza o i-node correspondente, no caso 1000;
Lê as informações contidas em 1000, como permissões de acesso e caso seja possível executar o arquivo, retorna o endereço do bloco onde está armazenado, no caso 35400;
Finalmente carrega “ls”.
Mas e se o usuário luiz quiser um atalho para /usr/bin/ls em seu diretório pessoal /home/luiz/ chamado “list”?
Luiz tem duas formas de fazer isso. Uma é criar uma ligação simbólica (symlink), um arquivo especial chamado /home/luiz/list contendo o caminho “/usr/bin/ls”. Fazendo isso, seu arquivo “luiz” da figura 1 se modificaria para o da figura 2, que também mostra o novo i-node e arquivo correspondente:

A outra é criar uma ligação verdadeira (hard link), criando uma entrada em seu diretório luiz, chamada “list” que aponta para o i-node 1000, que corresponde ao arquivo “ls”. Isso incrementaria seu contador de referências. As modificações são mostradas na figura 3:

Cada uma destas maneiras tem prós e contras. No caso de se optar por uma ligação simbólica, ao se remover o arquivo original, a ligação será quebrada e o atalho apontará para um valor inválido. No caso de se optar por uma ligação verdadeira, ao se apagar uma entrada que referencie o arquivo (qualquer uma), não se apaga o arquivo, apenas é reduzido seu contador de referências. O arquivo (ou melhor, o i-node) só é liberado quando este contador chega a zero. Porém é necessário que estejam no mesmo sistema de arquivos, uma vez que referenciam o mesmo i-node. Optar por uma forma ou por outra também influencia nas estratégias de cópias de segurança (backups) adotadas.
Como esta é uma interface necessária para o núcleo, sistemas de arquivos que não são estruturados desta maneira necessitam de módulos que os façam parecer assim para o núcleo. Este é o caso de sistemas como FAT32 ou NTFS. Tais sistemas não se estruturam como descrito acima e precisam ter os objetos do VFS criados dinamicamente. Isso explica (ao menos em parte) porque é relativamente fácil elaborar interfaces “somente-leitura” para novos sistemas de arquivos, mas pode ser muito complicado elaborar uma “leitura-escrita”, principalmente se as especificações do sistema de arquivos não são totalmente conhecidas, como ocorre em sistemas de arquivos proprietários.
Para mais informações sobre o funcionamento e implementação do Sistema de Arquivos Virtual no Linux, leia “Desenvolvimento do Kernel do Linux”, escrito por Robert Love (editora Ciência Moderna).
Para mais informações sobre implementação de sistemas de arquivos em sistemas operacionais de forma geral, leia “Sistemas Operacionais Modernos” (2ª ed.), por Andrew Tanenbaum (editora Prentice Hall).
Para informações sobre como manipular diretamente arquivos, diretórios, atributos e permissões no Linux usando a linguagem C e as bibliotecas do kernel, leia “Sistemas Distribuídos”, escrito por Uirá Ribeiro (editora Axcel).
Para informações gerais sobre hardware, software e configurações relacionadas ao Linux continuo recomendando:
www.guiadohardware.net
www.vivaolinux.com.br
Para um excelente guia de comandos e configurações recomendo:
www.guiafoca.org
Próximo tópico: multiprogramação.


2 Comments:
Oi Luiz! Mais algumas perguntas para você:
1) Há uma definição precisa do que é um bloco?
2) Por que o VFS do Linux é codificado em C, e não em C++?
Apareça! Hehehe.
Abraço
Vou te atormentar um pouquinho mais, como eu sou mau...
1) Qual é o conteúdo desses arquivos que representam os dispositivos de caracteres e os de blocos?
2) Aproveitando que você falou de conduítes e que o fluxo de dados neles é FIFO, isso me faz lembrar que nas pilhas o fluxo de dados é LIFO. Eu entendo o conceito de pilha, só não entendo porque armazenar variáveis temporárias desta forma, e não como no conduíte.
3) Qual é a vantagem de se criar uma ligação verdadeira, em comparação com a usual cópia de arquivos?
4) Quando você diz que um sistema de arquivos como o NTFS cria os objetos do VFS dinamicamente, isso significa que tal sistema escreve o código necessário em tempo real enquanto busca pelos arquivos?
E é isso aí. Não tenha pressa em responder, hein?
Abraço!
Postar um comentário
<< Home