8. SISTEMA DE ARQUIVOS
1. Arquivos: Os SO permitem que os usuários definam objetos chamados arquivos e apresentam operações especiais que permitem agir sobre o mesmo (criar, apagar, escrever, ler etc). Existem 3 formas comuns de organização de arquivos: 1) os arquivos são considerados como constituídos de uma seqüência de bytes (ex: UNIX); 2) os arquivos são considerados como consistindo de uma seqüência de blocos, cada um de um certo tamanho (ex: CP/M); 3) o arquivo é organizado em blocos, sendo que cada bloco consiste de certo número de regiões de dados e também de ponteiros para outros blocos semelhantes (árvore de blocos para cada arquivo). Uma forma de diferenciar arquivos fornecida pelo SO é a extensão e as atitudes do SO variam de acordo com as extensões.
2. Diretórios: os diretórios são organizados como um conjunto de diversas entradas, uma para cada arquivo. Para organização dos arquivos em diretórios podem ter:
a) um único diretório para todos os arquivos (CP/M); um diretório para cada usuário;
b) uma hierarquia de diretórios (MS-DOS e UNIX): surge a necessidade de especificar a localização de um arquivo com relação à hierarquia de diretórios, geralmente utiliza-se a especificação de um path (caminho) que pode ser indicado de duas formas: caminho absoluto – indica todo o caminho até o arquivo a partir da raiz da hierarquia; caminho relativo – indica como se faz para chegar até o arquivo partindo do diretório de trabalho atual.
Estrutura do Diretório: vamos estabelecer de que forma as informações sobre como os arquivos devem ser organizados no diretório:
1.) CP/M: possui um único diretório, que consiste de diversas entradas como a mostrada abaixo. O código de usuário associa cada arquivo a um usuário identificado por um número. O “extend” é utilizado para arquivos que ocupam mais de uma entrada no diretório. 16 espaços são reservados para os números dos blocos em cada entrada no diretório. O contador de blocos indica quantos desses 16 espaços estão efetivamente sendo utilizados (quando o arquivo ocupa mais de 16 blocos, uma nova entrada deve ser alocada para o mesmo no diretório, com o valor de extend ajustado correspondentemente).
2.) MS-DOS: o campo atributos indica qual tipo de arquivo (normal, diretório, oculto, sistema etc). Um dos campos indica o número do primeiro bloco alocado para o arquivo. Para encontrar o bloco seguinte, busca-se a entrada na FAT correspondente a esse primeiro bloco e encontra-se lá o número do bloco seguinte, repetindo-se esse procedimento até encontrar o fim do arquivo. A entrada no diretório de um arquivo apresenta também o tamanho do arquivo. Quando o atributo de um arquivo indica que ele é do tipo diretório, então, o mesmo consistirá de entradas como as apresentadas aqui, podendo apresentar entradas do tipo diretório (árvore de subdiretórios).
3.) UNIX: a estrutura de diretórios é simples, pois todas informações sobre um arquivo estão reunidas no i-node desse arquivo, ao invés de no diretório. Os diretórios são arquivos como qualquer outro, com tantos i-nodes quantos necessários. A raiz tem seu i-node armazenado em uma posição fixa do disco. Além dos arquivos normais, cada diretório possui também as entradas “.” (apresenta o i-node do próprio diretório) e “..” (apresenta o i-node do diretório pai desse diretório), geradas no momento da criação do diretório. Para a raiz “.” e “..” são iguais.
3. Projeto de Sistemas de Arquivos:
1. Gerenciamento do Espaço em Disco: uma possibilidade seria, para cada arquivo, alocar espaço no disco correspondente ao número de bytes necessários seqüencialmente. O problema é quando há necessidade de um arquivo crescer e não existir espaço consecutivo após o mesmo. Neste caso, seria necessário deslocar o arquivo para outra parte do disco, isto é lento e em disco cheio, impossível. Outro problema é a fragmentação do espaço em disco. A solução para este problema é a alocação para cada arquivo de blocos de tamanho fixo e não necessariamente contíguos nos disco. A escolha de blocos de tamanho grande implica em que mesmo arquivos pequenos irão ocupar muito espaço no disco e por outro lado, a escolha de blocos pequenos implica em um maior número de leituras em disco (aumentando o tempo de busca de trilhas e espera de setor). Os tamanhos comumente encontrados de blocos são 512 bytes, 1kb, 2kb e 4kb. Para cuidar de quais blocos do disco estão livres e quais estão ocupados temos dois métodos: lista encadeada – é preferível quando o bit map não pode ser mantido todo na memória e o disco está bastante ocupado, pois neste caso o outro método seria mais lento pois deveríamos ficar carregando as diversas partes do bit map do disco para a memória, pois como o disco está cheio, é difícil encontrar blocos vazios. Bit map – é geralmente a melhor opção, principalmente quando o bit map pode ser mantido simultaneamente na memória.
2. Armazenamento de Arquivos: vejamos de que forma podemos fazer para saber quais os blocos que estão alocados a um dado arquivo. A primeira forma seria a alocação de blocos de forma contígua, ou seja, para armazenar um determinado arquivo seria percorrido o disco buscando por um espaço de blocos contíguos que permitissem seu armazenamento. Mas, muitas vezes, não existe estes buracos contíguos no disco, então seria necessário ficar sempre reorganizando os espaços alocados no disco para criar os espaços necessários, o que inviabiliza esta solução. Um outro método é fazer uma lista encadeada utilizando os próprios blocos, de forma que, num dado bloco, alguns de seus bytes são utilizados para indicar qual o próximo bloco do arquivo. A vantagem é evitar a fragmentação que ocorre na forma contígua. O problema aqui é que para se buscar o determinado bloco de um arquivo, devemos ler todos os blocos anteriores, além do próprio bloco gerando sobrecarga de leituras em disco quando pretendemos realizar acesso aleatório às informações do arquivo. Para utilizar a lista encadeada sem os inconvenientes apresentados seria utilizar uma estrutura chamada FAT, que poderia ser chamada de lista encadeada usando tabela: consiste em formar lista dos blocos de um arquivo em uma tabela, que pode ser carregada completamente na memória. No MS-DOS a FAT funciona da seguinte forma: a entrada no diretório correspondente a um arquivo indica o primeiro setor ocupado por um arquivo; a entrada na FAT correspondente a um setor indica o próximo setor alocado ao mesmo arquivo. O problema é: como a FAT ocupa locais fixos no disco, o tamanho desta é limitado pelo número de setores alocados para a mesma e, além disso, cada entrada na FAT corresponde a um número fixo de bits, o número de setores no disco é limitado, sendo que se quisermos utilizar discos maiores, devemos alterar completamente a FAT. Outra forma existente é a tabela de índices encontrada no UNIX e apresenta grande facilidade de expansão de tamanho de arquivos. Funciona da seguinte forma: as listas de blocos de cada arquivo são mantidas em locais diferentes e a cada arquivo associa-se uma tabela, chamada i-node que possui informações de proteção, contagem, blocos e outras. No i-node existem 10 números de blocos diretos. Caso o arquivo ocupar mais que 10 blocos, um novo bloco é alocado ao arquivo, que será utilizado para armazenar tantos números de blocos desse arquivo quantos couberem no bloco. O endereço desse bloco será armazenado em um número de bloco de endereçamento indireto. Se ainda forem necessários mais blocos do que couberam nas estruturas anteriores, é reservado um novo bloco que irá apontar para blocos que contem endereços dos blocos dos arquivos. O número desse novo bloco é armazenado num bloco de endereçamento duplamente indireto, se ainda não for suficiente, é alocado um bloco de endereçamento triplamente indireto.
Vantagens: os blocos indiretos apenas são utilizados quando necessários; mesmo para os maiores arquivos, no máximo são necessários três acessos a disco para se conseguir o endereço de qualquer de seus blocos.
3. Arquivos Compartilhados:
quando usuários diferentes referem-se a arquivos compartilhados, é conveniente que esses arquivos apareçam em diretórios diferentes, mas mantendo uma única cópia do mesmo em disco (para que quando um usuário faz alterações a esse arquivo, outro usuário tenha automaticamente acesso a essas alterações, sem necessitar se preocupar em recopiar o arquivo). Em sistemas cujo diretório possui o endereço dos blocos do arquivo (ex: CP/M), poderíamos realizar a ligação pela cópia dos números de blocos dos diretórios de um usuário para o de outro. O problema é que quando um usuário faz uma alteração no arquivo, essa alteração na aparecerá para o outro. Temos duas soluções:
- não listar os números dos blocos no diretório, mas apenas um ponteiro para uma estrutura que lista esses blocos. É o caso dos i-node do UNIX. Para estabelecer a ligação, basta fazer no novo diretório onde deve aparecer um arquivo, uma entrada com o nome do mesmo e o número do seu i-node. O problema é que suponha: um usuário C é dono de um arquivo e então o usuário B faz um link para o mesmo. Se permitirmos que C apague o arquivo, o diretório de B terá uma entrada que não fará mais sentido. A solução (como no UNIX) é manter no i-node do arquivo um campo que indica quantos links foram realizados para aquele arquivo. Então quando C remover o arquivo, o SO pode perceber que outros usuários ainda querem utilizá-lo e não apaga o i-node do arquivo, removendo apenas a entrada correspondente no diretório de C, evitando que B fique com um arquivo sem sentido, mas introduz outro problema: se existirem quotas na utilização de discos (limites por usuário), teremos o fato de que C continuará pagando pela existência de um arquivo que já não lhe interessa.
- Ligação Simbólica: consiste em criar no novo diretório, uma entrada de um tipo especial (link) que contém ao invés de informações usuais sobre o arquivo, apenas um path para este. Não tem os problemas do primeiro método, pois quando o dono remove o arquivo, o mesmo é eliminado e a partir desse ponto todos os outros usuários que tentarem acessar o arquivo por ligação simbólica terão a mensagem de “arquivo inexistente”. O problema é a sobrecarga no tempo de acesso, devido a necessidade de percorrer paths extras até se chegar no arquivo e de ocupar um i-node a mais. Vantagem é que permite realizar links com outras máquinas interligadas por uma rede (ao contrário do método i-node, que só permite ligações dentro do próprio disco). As duas soluções apresentadas têm em comum uma desvantagem: o fato de que o arquivo aparece com diferentes paths no sistema, fazendo com que, para sistemas automáticos de cópia (backups), ele seja copiado diversas vezes.