Um processo executando armazena informações, porém esta informação é perdida quando o processo termina. Assim, a gravação destas informações na forma de arquivos garante que elas possam ser lidas e utilizadas posteriormente por outros processos. Ou seja, os arquivos são uma forma de armazenar as informações em disco, para utilização futura.
Conceitos Iniciais
Arquivos comuns contém informações do usuário. Diretórios são arquivos de sistema para manter a estrutura do sistema de arquivos. Arquivos especiais de caracteres relacionam-se com a entrada/saída e são utilizados para modelar dispositivos de entrada/saída seriais como terminais, impressoras e redes.
Os arquivos mais comuns são ASCII e binários. Os arquivos ASCII possuem a vantagem de que podem ser exibidos e impressos como são, além de poderem ser editados com um editor de texto comum. Assim, quando vários programas utilizam arquivos ASCII, torna-se possível conectar a saída de um com a entrada de outro, como, por exemplo, em pipelines.
Sobre o Minix
O Minix é um sistema operacional semelhante ao Unix, que pode funcionar com quantidades pequenas de memória e de disco. Seu nome deriva de “mini-Unix”. Ele é escrito em linguagem C, gratuito e com código fonte aberto, criado por Andrew S. Tanenbaum, para explicar os conceitos do seu livro “Sistemas Operacionais: Projeto e Implementação”.
O sistema de arquivos no Minix funciona como um servidor de arquivos que é executado na própria máquina do usuário. Ele possui 39 tipos de mensagens para solicitar trabalho. Quando chega uma mensagem, é obtido o seu “tipo” para que seja chamado o procedimento adequado para este trabalho.
Arquivos
Este sistema de arquivos utiliza a estrutura de nó-i, que armazena os atributos e as localizações dos blocos de dados. Os primeiros endereços de disco ficam armazenados no próprio nó-i, assim, todas as informações de um arquivo pequeno estão diretamente no nó-i. Porém, quando há arquivos maiores, é necessário utilizar um dos endereços do nó-i para endereçar um “bloco indireto simples”. Caso o arquivo seja muito grande, também está disponível um “bloco indireto duplo” e um “triplo”, conforme mostra a Figura 1 a seguir.
Cada sistema de arquivos começa com um bloco de inicialização, que contém o código a ser executado quando o computador é ligado. Além disso, existe o superbloco, que armazena as informações que descrevem a organização do sistema de arquivos, conforme mostra a Figura 2 a seguir.
Utilizando um mapa de bits (Figura 3), o Minix controla quais nós-i e zonas estão livres. Se um arquivo é removido, o sistema procura o bloco do mapa de bits que corresponde ao nó-i e configura ele como 0. Quando um arquivo é criado, o sistema procura o primeiro nó-i livre nos blocos do mapa de bits. O superbloco possui um campo que aponta para o primeiro nó-i livre. Se nenhum nó-i estiver livre, é retornado valor 0.
Quando um arquivo é aberto, é necessário localizar seu nó-i para que ele seja carregado na tabela “inode” na memória, sendo removido quando o arquivo for fechado. As informações desta tabela permitem ao sistema de arquivos saber onde regravar o arquivo, caso seja modificado. A tabela também tem um contador, para guardar quantas vezes o arquivo for aberto, porém apenas uma cópia é mantida na memória. O nó-i também guarda informações sobre qual é o tipo do arquivo.
O sistema Minix usa um "cache" de blocos para melhorar o desempenho do seu sistema de arquivos. Este "cache" é feito com uma matriz de buffers, onde cada um possui um cabeçalho com ponteiros, contadores e sinalizadores. Os “buffers” que não estão sendo utilizados são colocados em uma lista duplamente encadeada, do mais para o menos recentemente utilizado. Também é utilizada uma tabela “hash” para saber se um bloco está ou não no "cache".
Quando o sistema de arquivos deseja acessar um bloco, ele chama o procedimento "get_block", juntamente com um número de dispositivo e um número de bloco. Se um buffer com o bloco é encontrado, incrementa-se o contador no cabeçalho, mostrando que ele está em uso, e retorna um ponteiro para ele. Se o bloco não é encontrado, pode-se utilizar o primeiro “buffer” livre. Se o bloco foi modificado, quando o sistema remover ele, deve gravá-lo no disco.
Quando o procedimento que estava usando o bloco termina, ele chama o procedimento "put_block", que libera o bloco (ou decrementa o contador, caso o bloco tenha sido aberto mais vezes). Se ele for removido, é gravado no disco. Se ocorrer a chamada de sistema SYNC, mesmo se o bloco não foi removido, mas foi modificado, ele é gravado no disco.
Diretórios
Um diretório no sistema Minix corresponde a um arquivo com entradas de 16 bytes, onde os dois primeiros formam o número do nó-i de 16 bits (1 byte = 8 bits, logo, 2 bytes = 16 bits) e os outros 14 bytes correspondem ao nome do arquivo.
Quando um arquivo é aberto, é retornado um descritor de arquivo (file descriptor) para ser utilizado pelas chamadas READ e WRITE. O número do descritor de arquivo (que é um dos campos da tabela de processos) indexa uma matriz, que é usada para localizar o arquivo correspondente ao descritor de arquivo informado.
Não podemos fazer uma entrada dessa matriz apontar diretamente para o nó-i do arquivo. É necessário utilizar uma nova tabela compartilhada, chamada "filp", onde estão todas as posições de arquivo (convém também colocar nesta tabela o ponteiro de nó-i). Assim, a matriz indexada pelo descritor de arquivo contém apenas um ponteiro para uma entrada na tabela "filp".
O sistema Minix também utiliza outra tabela, chamada "file_lock", para guardar o registro de todos os bloqueios. Cada uma das entradas da tabela indica se o arquivo está bloqueado para escrita ou leitura, o ponteiro para o nó-i do arquivo, o ID do processo que bloqueou, e os deslocamentos do primeiro e último bytes bloqueados.
Quando um processo tentar ler ou gravar em um "pipe" ("pipeline" ou canalização), o sistema de arquivos do Minix verifica o estado do "pipe" e, se a operação não pode ser feita, o sistema de arquivos registra os parâmetros da chamada de sistema na tabela de processos para reiniciar este processo quando for possível.
Em relação aos terminais e arquivos especiais de caracteres, o nó-i de cada arquivo especial possui dois números: o dispositivo principal, que indica a classe do dispositivo, por exemplo: disquete, terminal, disco rígido, disco de RAM; e o dispositivo secundário, que indica qual dispositivo deve ser usado.
Um "pipe" ("pipeline" ou canalização) é um tipo de pseudo-arquivo que pode ser usado para conectar dois processos. Se dois processos quiserem se comunicar usando um "pipe", eles devem antes disso configurá-lo. Quando um processo “A” quer enviar dados para um processo “B”, ele deve escrever no pipe como se fosse um arquivo de saída. O processo “B” poderá ler estes dados que estão no "pipe" como se ele fosse um arquivo de entrada. Ou seja, a comunicação entre processos utilizando "pipe" é parecida com leituras e escritas normais em arquivos.