Sistema de Arquivos
O sistema de arquivos é a parte do sistema operacional mais visível para os usuários. Durante o tempo todo, usuários manipulam arquivos contendo textos, planilhas, desenhos, figuras, jogos, etc. Os arquivos são normalmente implementados a partir de discos magnéticos. Como um acesso a disco demora cerca de 10000 vezes mais tempo do que um acesso à memória principal, são necessárias estruturas de dados e algoritmos que otimizem os acessos ao disco. É importante observar que os sistemas de arquivos implementam um recurso em software que não existe no hardware. O hardware oferece simplesmente espaço em disco, na forma de setores que podem ser acessados (gravados e lidos) individualmente, em ordem aleatória. O conceito de arquivo, muito mais útil que o simples espaço em disco, é uma abstração criada pelo SO.
Um arquivo pode ser genericamente definido como uma coleção de dados relacionados entre si. Normalmente, arquivos contém programas (tanto fonte como objeto) ou dados.
Arquivos são referenciados através de nomes. Além de um nome, cada arquivo possui também outros atributos, tais como: tipo, momento da criação, identificação do criador, tamanho, etc.
Tipos de arquivos
Diferentes tipos de informação podem ser armazenados em um arquivo: programas fonte, programas objeto, texto, dados numéricos, registros de funcionários, som, imagem, etc. Cada arquivo possui uma estrutura interna, conforme sua aplicação. Por exemplo, um arquivo texto é uma seqüência de caracteres organizados em linhas e parágrafos; um programa executável é uma seqüência de bytes representando instruções em código de máquina; um programa fonte é uma seqüência de caracteres que representam comandos de uma linguagem de programação (normalmente estes arquivos são do tipo “somente texto”, não admitindo qualquer tipo de formatação especial).
Uma questão importante é até que ponto o SO deve conhecer a estrutura interna dos arquivos. Para ter esse conhecimento, o SO vai ser maior e mais complexo. Além disso, para evoluir, deverá permitir a definição de novos tipos de arquivos, uma vez que novas aplicações podem expor novas demandas, e com elas, tipo de arquivos diferentes. Isto inviabiliza a pretenção de conhecer a estrutura interna dos arquivos, na prática. Em geral, o conhecimento do SO se limita às informações contidas no registro descritor do arquivo. Isto já lhe permite bloquear algumas operações inválidas. Por exemplo, pode recusar-se a imprimir um arquivo que contenha um programa executável.
Sistemas baseados em fita
Os primeiros sistemas eram baseados em fita magnética. No início, cada arquivo era mapeado para uma única fita. Isso ocasionava um enorme desperdício de espaço, porque cada fita (de 2400 pés, cerca de 750 m) era capaz de armazenar 5 gigabytes, mas a maioria dos arquivos era pequena (alguns Kb). Por outro lado, havia o problema dos arquivos muito grandes, que poderiam superar a capacidade de uma única fita.
O problema dos arquivos grandes foi resolvido com o sistema de armazenamento multi-volume. O desperdício de espaço foi resolvido permitindo a gravação de diversos arquivos em uma única fita. Como resultado, passou a ser necessário saber em que posição da fita cada arquivo estava armazenado. A solução foi adicionar à fita um diretório, onde cada entrada continha um nome de arquivo e sua posição na fita. Tais diretórios também armazenavam informações adicionais sobre os arquivos.
Passos para a leitura de um arquivo em fita:
Localizar e carregar a fita indicada pelo usuário
Localizar no diretório a entrada correspondente ao arquivo
Posicionar a fita no ponto correspondente ao início do arquivo
Iniciar a leitura
Terminar a leitura quando encontrar marca de fim de arquivo.
Para um programa poder trabalhar simultaneamente com dois arquivos, eles tinham que estar em fitas diferentes.
Sistemas baseados em disco
Muitos dos problemas dos sistemas de fita foram resolvidos com os sistemas baseados em discos. Um disco é dividido em trilhas, sendo o número de trilhas uma característica particular de cada dispositivo. Cada trilha é dividida em setores, sendo o setor a menor unidade de informação que pode ser lida ou escrita no disco. Unidades de disco fixo usualmente possuem diversos discos superpostos, cada um com duas faces magnetizadas, o que corresponde a diversas superfícies de gravação (a tecnologia atual permite sobrepor até 8 discos). Para acessar um determinado setor do disco é necessário informar: face, trilha e setor. As cabeças de leitura e gravação são deslocadas até a trilha correta (tempo de seek), chaveadas eletronicamente para a face correta e então esperam até que o setor solicitado passe por baixo (tempo de latência). Um cilindro é o conjunto de trilhas que estão na mesma posição, porém em diferentes faces. Não é necessário deslocar as cabeças para acessar trilhas de um mesmo cilindro.
Usualmente, o SO trata o disco como um grande vetor unidimensional de blocos, cada bloco correspondendo a um setor. Esses blocos são numerados desde 0 até N-1, onde N é o número de setores do disco.
A vantagem do disco em relação à fita é a possibilidade de acessar facilmente qualquer setor a qualquer momento. A fita impõe um acesso estritamente seqüencial. O acesso também é mais rápido no disco.
Assim como nas fitas, e por mais forte razão, os discos também possuem um diretório, indicando em que posições se encontram os arquivos. O diretório é armazenado no próprio disco, permitindo que o disco seja removido e utilizado mais tarde, sem que os nomes dos arquivos sejam perdidos. Na verdade, cada entrada de diretório contém todas as informações necessárias sobre o arquivo, constituindo o que se denomina registro descritor de arquivo.
Registro descritor de arquivo
A estrutura básica de um sistema de arquivos é o descritor de arquivo (DA). Para cada arquivo existente no sistema há um DA. Trata-se de um bloco (registro) que contém todas as informações sobre um determinado arquivo. Algumas informações não são visíveis aos usuários, embora sejam essenciais para o SO implementar as operações sobre arquivos. Tipicamente, um descritor de arquivo contém as seguintes informações:
Nome do arquivo;
Tipo do arquivo;
Tamanho em bytes;
Data e hora do último acesso;
Data e hora da última alteração;
Identificação do usuário que criou o arquivo;
Lista de usuários que podem acessar o arquivo e respectivos direitos de acesso;
Local no disco onde o conteúdo do arquivo foi colocado.
8.2 Suporte a arquivos
O sistema operacional permite realizar um conjunto de operações sobre arquivos. Essas operações são solicitadas através de chamadas de sistema.
Operações em arquivos
A seguir é considerado o que o SO deve fazer para realizar as diversas operações sobre arquivos (supondo um sistema baseado em disco):
- Criar um arquivo: dois passos são necessários, (a) encontrar e alocar espaço suficiente no disco para conter o arquivo (isto é, os dados do arquivo) e (b) adicionar uma entrada no diretório para conter os atributos do arquivo (nome, tamanho, localização, etc.).
- Escrever registro no arquivo: para escrever em um arquivo, o usuário executa uma chamada de sistema fornecendo o nome do arquivo e o bloco com a informação a ser escrita. O sistema procura no diretório, através do nome, a localização do arquivo no disco e a posição do ponteiro que indica o final do arquivo (onde deve ser escrito o próximo bloco).
- Ler próximo registro do arquivo: o usuário executa uma chamada de sistema passando como parâmetros o nome do arquivo e a posição na memória principal para onde as informações lidas devem ser copiadas. Novamente, o sistema procura no diretório a entrada correspondente, lê do disco e atualiza o ponteiro indicador de próximo registro a ser lido.
- Remover o arquivo: para remover o arquivo, primeiramente o diretório é pesquisado. A seguir, o espaço alocado é liberado e a entrada correspondente é removida do diretório.
- Reposicionar o arquivo: esta operação não envolve I/O de fato, pois consiste em localizar a entrada no diretório correspondente ao arquivo e modificar o valor do ponteiro indicador do próximo registro a ser acessado.
Todas as operações mencionadas acima envolvem uma pesquisa no diretório em busca da entrada correspondente ao arquivo desejado. Para evitar esta pesquisa constante no disco, muitos sistemas abrem o arquivo quando ele começa a ser utilizado. Abrir o arquivo significa trazer para a memória o seu registro descritor.
Tabela de arquivos abertos
O sistema operacional mantém na memória principal uma tabela contendo os registros descritores dos arquivos abertos (TDAA – Tabela de Descritores de Arquivos Abertos). Quando uma operação é solicitada, apenas esta tabela é pesquisada (em memória) e não todo o diretório (em disco).
Alguns sistemas abrem automaticamente o arquivo quando ele é utilizado pela primeira vez, enquanto outros exigem um pedido de abertura explícito do usuário (isto é feito através da operação open). Neste último caso, o diretório é pesquisado e a entrada correspondente ao arquivo é copiada para a tabela TDAA. É devolvido para o programa um ponteiro para a entrada nessa tabela. Nas próximas operações este ponteiro será utilizado para identificar o arquivo. O arquivo deve ser “fechado” após a utilização (operação close), o que permite liberar o espaço que seu descritor ocupava na TDAA.
A TDAA mantém informações sobre os arquivos abertos por todos os processos no sistema. Normalmente, é permitido que vários processos abram um mesmo arquivo simultaneamente. Para cada arquivo há apenas uma entrada na TDAA, a qual armazena todas as informações do arquivo em disco, mais uma informação que indica o número de processos utilizando o arquivo no momento. Quando um processo realiza a chamada de sistema close, o número de processos utilizando o arquivo em questão é decrementado. Quando esse número chega a zero, significa que nenhum processo está usando o arquivo. Nesse caso, o descritor do arquivo é atualizado em disco e a entrada da TDAA liberada.
As entradas da TDAA armazenam informações que não variam em função do processo que está acessando o arquivo Entretanto, existem informações correspondentes ao processo que acessa o arquivo. Um exemplo de informação que depende do processo é a posição corrente no arquivo. Em um dado instante, cada processo pode acessar uma parte diferente do arquivo. Logo, é necessário armazenar uma posição corrente no arquivo para cada processo. Da mesma forma, alguns processos podem abrir o arquivo para apenas leitura, enquanto outros abrem para leitura e escrita. Essa informação deve ser mantida pelo sistema de arquivos para que ele possa rejeitar chamadas de escrita quando o processo abriu o arquivo para apenas leitura.
A solução típica é criar, para cada processo, uma Tabela de Arquivos Abertos por Processo (TAAP). Cada processo possui a sua TAAP. Cada entrada ocupada na TAAP corresponde a um arquivo aberto pelo processo correspondente. No mínimo, a TAAP contém em cada entrada as seguintes informações:
Posição corrente no arquivo;
Tipo de acesso (apenas leitura ou leitura e escrita);
Apontador para a entrada correspondente na TDAA.
A Figura 8.1 ilustra o emprego conjunto das TAAP e da TDAA. No exemplo da figura, o processo 0 possui dois arquivos abertos. O arquivo A foi aberto apenas para leitura, e a sua posição corrente é 12. O arquivo B foi aberto para leitura e escrita, e a sua posição corrente é 55. O processo 1 também abriu o arquivo B. Entretanto, o processo 1 pode apenas ler o arquivo, e a sua posição corrente é 10.
Tanto a TDAA como as TAAP devem ficar na memória do sistema operacional, fora do acesso dos processos de usuário. Caso contrário, um usuário mal intencionado poderia burlar o mecanismo de controle de acesso simplesmente alterando sua TAAP.
A função open retorna para o processo o número da entrada na TAAP associada com o arquivo aberto. Dessa forma, nas chamadas de sistema após o open, o processo indica o arquivo através do número de sua correspondente entrada na TAAP. A partir da TAAP, o sistema de arquivos pode imediatamente localizar o descritor do arquivo na TDAA. No exemplo da Figura 8.4, o processo 0 acessa o arquivo B através de referências à entrada 1 da sua TAAP.
8.3 Métodos de Acesso
Existem diversas maneiras de acessar as informações contidas em um arquivo. Enquanto alguns sistemas oferecem um único método de acesso, outros sistemas implementam diversos métodos.
Acesso seqüencial
Neste método, uma leitura sempre acessa o próximo registro e avança um ponteiro sobre o arquivo. Este ponteiro indica qual a próxima posição a ser lida. O mesmo acontece com a escrita.
Acesso direto
O arquivo consiste em uma seqüência numerada de registros. Qualquer registro pode ser diretamente lido ou escrito. As operações indicam o número do bloco a ser acessado. Este número é geralmente um número de bloco relativo, ou seja, um índice em relação ao início do arquivo (usuários não lidam com números de blocos absolutos).
Outros métodos de acesso
Outros métodos de acesso podem ser construídos utilizando como base o serviço de acesso direto. Estes métodos normalmente envolvem a construção de índices nos descritores de arquivos. Os índices são utilizados para localizar a informação desejada dentro do arquivo, objetivando sempre minimizar o acesso ao disco (maximizar o desempenho). Exemplo: o ISAM (Indexed Sequential Acess Method) da IBM usa um pequeno índice mestre que aponta para blocos de disco secundários com índices secundários, que por sua vez apontam para os blocos de disco contendo os dados.
8.4 Métodos de Alocação
Na maioria das vezes muitos arquivos estarão armazenados no mesmo disco. É necessário alocar espaço para estes arquivos de forma que o disco seja utilizado eficientemente e os arquivos possam ser acessados rapidamente. Três métodos principais de alocação de espaço em disco se encontram em uso: contígua, encadeada e indexada, cada um com suas vantagens e desvantagens.
Gerência do espaço livre
Arquivos são criados e removidos freqüentemente durante a operação do sistema. Uma vez que o espaço em disco é limitado, é necessário reaproveitar todo o espaço liberado. Para manter o controle do espaço livre no disco, o sistema mantém uma lista dos setores livres. Para criar um arquivo, o espaço necessário é obtido da lista. O espaço ocupado por um arquivo é devolvido à lista quando este é removido.
Esta lista, apesar de seu nome, pode não ser implementada como uma lista, mas sim como um “mapa de bits”, onde cada bit representa um bloco do disco. Se o bloco está ocupado o bit vale 1, se o bloco está livre o bit vale 0. O tamanho do mapa (número de bytes no mapa) corresponderia a um oitavo do número de blocos do disco.
Alocação contígua
O método de alocação contígua exige que cada arquivo ocupe um conjunto de setores contíguos no disco. Para localizar um arquivo basta saber o número do setor inicial e o tamanho do arquivo, em blocos.
Para acessar o arquivo de forma seqüencial, o sistema operacional mantém o número do último bloco acessado, incrementando este valor a cada acesso. Para um acesso direto ao setor i de um arquivo que inicia no setor b, o sistema deve acessar o setor b+i. Ambos os métodos seqüencial e direto são facilmente implementados.
A dificuldade com este esquema é encontrar um espaço livre para um novo arquivo. Se o novo arquivo ocupa n setores, é necessário pesquisar a lista de setores livres até encontrar n setores contíguos livres.
O espaço em disco pode ser visto como um grande vetor de blocos. Em um determinado momento, alguns blocos estão ocupados e outros livres, compondo segmentos de blocos contíguos ocupados e segmentos de blocos contíguos livres (buracos). O problema da alocação dinâmica de armazenamento consiste em como satisfazer um pedido de n blocos livres contíguos a partir de uma lista de blocos vazios. Os algoritmos que podem ser utilizados são os mesmos já vistos no capítulo de gerência de memória (first-fit, best-fit, etc.).
O maior problema deste método é determinar o número de setores a serem alocados para cada arquivo, no momento de sua criação. Em algumas situações isto é simples, como na cópia de um arquivo existente. Mas, em geral, esta tarefa édifícil. Se pouco espaço é alocado, o arquivo talvez não possa ser estendido porque o espaço nos dois lados está ocupado. A única solução neste caso é a cópia de todo o arquivo para um espaço maior. Se o espaço alocado é maior que o necessário, o disco não estará sendo utilizado de forma eficiente.
Alocação encadeada
Neste método, cada arquivo corresponde a uma lista encadeada de blocos, estando os mesmos em qualquer local do disco. O diretório contém apenas o endereço do bloco inicial e o número de blocos (ou endereço do último bloco), e cada bloco de dados contém o endereço do bloco seguinte. Existe uma perda associada a cada bloco, uma vez que é necessário gastar bytes com ponteiros.
Com alocação encadeada, os arquivos podem ser criados com tamanho zero. Na medida em que o arquivo precisa crescer, setores serão removidos da lista de setores livres e inseridos na lista encadeada que forma o arquivo. Qualquer setor do disco, independente de sua posição, pode ser aproveitado. Os arquivos podem crescer livremente até o limite do disco.
Este método somente pode ser utilizado de forma eficiente para implementar acesso seqüencial. Para acessar diretamente o setor n, seria necessário realizar n acessos ao disco. Isto impede, na prática, o acesso direto. Além disto, este método apresenta problemas de confiabilidade: como cada setor contém o endereço do setor seguinte, basta que um setor seja danificado (hardware ou software) para que boa parte do arquivo seja perdida.
Alocação indexada
Este método é capaz de resolver o problema do crescimento dos arquivos ao mesmo tempo que permite o acesso relativo. Na alocação indexada, cada arquivo possui uma tabela de índices. Cada entrada dessa tabela contém o endereço de um dos blocos físicos que formam o arquivo.
Um acesso relativo pode ser facilmente realizado através de uma consulta à tabela de índices. O endereço no disco de qualquer bloco lógico é obtido através de um único acesso a essa tabela. Para que esse acesso seja rápido, a tabela de índices é normalmente mantida na memória principal enquanto o arquivo está aberto. Uma forma conveniente é manter a tabela de índices dentro do próprio descritor do arquivo.
Uma questão importante é o tamanho da tabela de índices. Ele define o tamanho máximo de um arquivo no sistema. Por exemplo, suponha que cada bloco físico corresponda a 4 Kbytes. Para que o tamanho máximo de um arquivo no sistema seja de 4 Gbytes, será necessário uma tabela de índices contendo “4 Gbytes 4 Kbytes” entradas, ou seja, 1.048.576 entradas (1 M na informática, ou seja, 1024 1024). Manter uma tabela de índices desse tamanho para cada arquivo é um absurdo. O tamanho médio dos arquivos em sistemas de propósito geral fica entre 10 Kbytes e 20 Kbytes. Mantendo a suposição de que cada bloco físico corresponde a 4 Kbytes, uma tabela de índices com apenas 5 entradas seria suficiente para um arquivo de 20 Kbytes.
A solução típica para compatibilizar uma maioria de arquivos pequenos com um tamanho máximo de arquivo satisfatório é empregar níveis de indireção na indexação. Por exemplo, suponha que o descritor de arquivos contém uma tabela de índices com 13 entradas. As primeiras 10 entradas (numeradas de 0 a 9) apontam para blocos de dados do arquivo, permitindo o acesso aos primeiros 40 Kbytes de cada arquivo (supondo sempre blocos de 4 Kbytes). Eles são chamados de apontadores diretos. A entrada 10 da tabela não aponta para um bloco de dados do arquivo, mas sim para um bloco que contém apontadores para blocos de dados. Supondo que os números de blocos físicos ocupem 4 bytes, um bloco de 4 Kbytes é capaz de armazenar 1024 apontadores. Como cada apontador representa um bloco físico, temos que um único apontador indireto na tabela de índices permite o acesso a 4 Mbytes de dados do arquivo.
A entrada 11 da tabela contém um apontador duplamente indireto, o que permite o acesso a até 4 Gbytes de dados. Para suportar arquivos realmente grandes, é usada a entrada 12, a qual contém um apontador triplamente indireto. Ele aponta para um bloco que contém 1024 apontadores. Esses 1024 apontadores, em conjunto, apontam para 10241024 apontadores. Cada um deles aponta para 1024 apontadores. No total temos 102410241024 apontadores para blocos de dados, o que permite indexar um total de 4 Tbytes (terabytes). As necessidades da maioria dos sistemas são atendidas apenas com a dupla indireção.
Esse esquema de apontadores indiretos é muito atraente. Considerando o exemplo, arquivos de até 40 Kbytes possuem sua tabela de índices completa dentro do descritor de arquivo, o qual é necessariamente lido para a memória quando o arquivo é aberto. Dessa forma, arquivos com até 40 Kbytes, o que corresponde à maioria, são sempre acessados rapidamente. Por sua vez, arquivos com mais de 40 Kbytes e não mais que 4 Mbytes 40 Kbytes necessitam de apenas um nível de indireção, ou seja, de um único bloco contendo apontadores. Esse bloco também pode ser mantido na memória principal todo o tempo, fazendo com que o acesso aos dados não necessite de acesso adicional ao disco para a leitura de apontadores.
Somente arquivos maiores que 4 Mbytes 40 Kbytes terão o acesso mais lento em função da necessidade de ler também os apontadores do disco. Entretanto, os blocos de apontadores utilizados com maior freqüência podem ser mantidos em cache, o que acelera o processo de localização dos dados no disco. Acessos seqüenciais são também eficientes, pois os mesmos blocos de apontadores são utilizados para acessar um longo trecho seqüencial do arquivo.
A partir dos três métodos básicos (alocação contígua, encadeada e indexada) é possível imaginar diversas combinações. Por exemplo, a técnica conhecida como FAT (File Allocation Table) é uma variação da alocação encadeada, na qual os apontadores foram removidos de cada bloco físico individual e colocados todos juntos em uma única tabela, chamada de Tabela de Alocação de Arquivos.
8.5 Sistemas de Diretórios
Um diretório na forma de lista de arquivos pode ser suficiente para um sistema monousuário, com pouco espaço em disco. Na medida em que o espaço em disco aumenta ou aumenta o número de usuários, é necessário criar um diretório cuja estrutura permita que os usuários organizem os seus arquivos. A seguir são discutidas as possíveis formas de organizar os diretórios.
Diretório de nível único
Nesta estrutura todos os arquivos fazem parte do mesmo diretório. Na medida em que o número de arquivos aumenta, aparecem problemas de organização. Por exemplo, é necessário que cada arquivo tenha um nome único.
Diretório de dois níveis
A maior desvantagem do diretório de nível único é a confusão de nomes de arquivos entre diferentes usuários. A solução mais comum é criar um diretório separado para cada usuário. Um diretório principal mantém os endereços dos diretórios dos usuários, enquanto os diretórios de usuários contêm informações sobre os respectivos arquivos.
Quando um usuário faz referência a um arquivo, apenas o seu próprio diretório é pesquisado. Logo, diferentes usuários podem ter arquivos com o mesmo nome. Os usuários estão naturalmente protegidos de acessos indevidos. É necessário de alguma forma criar diretórios para novos usuários e destruir diretórios não mais usados.
Para economizar espaço em disco, todos os utilitários do sistema (compiladores, editores, etc.) podem ser colocados em um único diretório e não duplicados em todos os diretórios dos usuários. Este é um diretório especial. Sempre que o usuário tenta executar um programa, primeiramente o diretório especial é pesquisado. Se o arquivo do programa não é encontrado, então o diretório do usuário é pesquisado. Pode-se também inverter o caminho de pesquisa.
Diretórios estruturados em árvore
Neste esquema, usuários podem criar seus próprios sub-diretórios para organizar os seus arquivos. A árvore possui um diretório raiz. Cada arquivo no sistema tem um único pathname. O pathname é o nome do arquivo composto pelos nomes de diretórios que formam o caminho da raiz até ele.
Um diretório ou sub-diretório contém um conjunto de arquivos e/ou sub-diretórios. Em cada entrada de diretório existe um campo indicando se a entrada é um arquivo ou um sub-diretório.
Os pathnames podem ser completos ou relativos. Um pathname completo inicia na raiz e vai até o arquivo a ser identificado. Se o pathname começa no diretório corrente, então ele é relativo.
8.6 Formas de Implementar Diretórios
A forma mais simples de implementar diretórios é considerá-los como arquivos especiais, manipulados pelo próprio sistema operacional. Dessa forma, todos os mecanismos de alocação, liberação e localização de blocos físicos no disco, disponíveis para arquivos, também são usados para os diretórios. Diretórios passam a ser arquivos cujo conteúdo é definido pelo sistema operacional e cujo acesso, por parte de usuários, é controlado. Como diretórios são arquivos, cada diretório possui também o seu descritor.
Um diretório pode ser organizado na forma de um conjunto de descritores de arquivos, ou como um conjunto de endereços de descritores de arquivos. No primeiro caso, o diretório contém diretamente descritores de arquivos e/ou diretórios. Nesse caso, o nome do arquivo (ou do diretório) faz parte do descritor. Nesse esquema, após a leitura do diretório, o sistema de arquivos já terá na memória todas as informações necessárias para procurar pelo nome do arquivo buscado e, caso encontre, acessar o seu conteúdo. A Figura 8.4 ilustra esta solução. Nessa figura, retângulos representam diretórios e retângulos de cantos arrendodados representam arquivos de dados. As desvantagens deste esquema são: (1) os nomes ficam fortemente vinculados aos descritores de arquivos, impedindo, por exemplo, que um mesmo arquivo possua mais de um nome; (2) os diretórios tendem a ser maiores e estão mais sujeitos a inconsistências, pois informações importantes estão espalhadas por todo o disco.
No caso do diretório ser um conjunto de endereços de descritores, tem-se em cada entrada do diretório apenas um par: nome do arquivo (ou diretório) e um ponteiro para o descritor correspondente. Neste esquema, é comum reservar uma parte do disco para armazenar exclusivamente descritores de arquivos. Esses blocos reservados constituem um vetor de descritores, no qual cada descritor pode ser perfeitamente identificado pela posição nesse vetor. Essa estrutura de dados forma o que se denomina um flat file system (na terminologia do UNIX), pois não existe nenhuma estruturação dos arquivos em diretórios, existindo apenas um diretório único (o vetor).
A estrutura em árvore é criada a partir de alguns arquivos do sistema flat (que atuam como subdiretórios), cada um organizado internamente como uma tabela contendo nomes e respectivos endereços no vetor de descritores. Dessa forma, para percorrer um caminho na árvore dos arquivos (pathname), é necessário abrir o subdiretório, procurar o nome desejado, pegar o endereço flat associado e ler o respectivo descritor de arquivo. Esse procedimento deve ser repetido para cada nome presente no caminho a ser percorrido. A Figura 8.5 ilustra essa solução, considerando novamente a árvore de arquivos que aparece na Figura 8.4. É suposto que o primeiro descritor de arquivo do vetor de descritores (índice 0) descreve o diretório raiz da árvore.
8.7 Proteção dos Arquivos
Quando a informação é mantida em um computador, ela deve ser protegida contra dano físico (confiabilidade) e acesso indevido (proteção).
A confiabilidade é obtida geralmente criando cópias dos arquivos. Muitos sistemas operacionais automaticamente copiam o conteúdo do disco para fita em intervalos regulares (uma vez ao dia ou a cada semana).
A proteção é necessária apenas nos sistemas multiusuários (se o sistema só tem um usuário, nenhuma proteção é necessária). Os mecanismos de proteção garantem acesso controlado, limitando o tipo de acesso que pode ser feito a um arquivo. Diversos tipos de acesso podem ser permitidos (ou negados), tais como: leitura, gravação, execução, criação e remoção. Vale observar que as três primeiras operações (leitura, gravação e execução) envolvem acesso a arquivos enquanto as duas últimas (criação e remoção) envolvem acesso a diretórios. Outras operações (sobre diretórios) possíveis de serem protegidas são listagem de diretório pesquisa de diretório.
Existem diferentes mecanismos de proteção, cada um com vantagens e desvantagens. O melhor mecanismo depende do sistema em questão. Um método bastante utilizado é vincular o acesso à identificação do usuário ou de um grupo de usuários com interesses afins, como ocorre no sistema Unix.
8.8 Questões de Implementação
Um sistema de arquivos envolve dois problemas de projeto bastante diferentes. Um deles é definir como o sistema de arquivos deve aparecer para o usuário (visão do usuário). Isto envolve a definição dos arquivos e de seus atributos, operações permitidas e estrutura de diretórios. O outro problema de projeto é definir quais algoritmos e estruturas de dados serão usados para mapear o sistema de arquivos lógicos visto pelo usuário, nos dispositivos físicos disponíveis ao sistema de arquivos.
Conceitualmente, um sistema de arquivos pode ser dividido em três níveis de serviço: serviço de disco, de arquivo básico e de diretório:
serviço de disco: é responsável pela leitura e escrita de setores diretamente no disco, sem interessar a forma como eles estão organizados;
serviço de arquivo básico: lida com arquivos básicos, compostos de um descritor e um conjunto de registros. Operações são a leitura e a escrita de blocos a partir de uma determinada posição do arquivo;
serviço de diretório: preocupa-se com a identificação e proteção de arquivos, descritos a partir de diretórios, de forma que eles possam ser acessados de forma segura e conveniente. O serviço de diretório tipicamente fornece objetos denominados diretórios que mapeiam nomes simbólicos de arquivos em identificadores numéricos utilizados pelo serviço de arquivo básico.