Sistemas de Operação

Trabalho Prático 3: Sistema de Gestão de Ficheiros

Objectivo

O objectivo principal deste trabalho é permitir que os alunos adquiram maior sensibilidade e conhecimento do funcionamento de um sistema de gestão de ficheiros. Em particular, pretende-se que os alunos sejam capazes de compreender e lidar com a organização, o funcionamento e o modo de solucionar alguns dos problemas que a implementação de um tal sistema envolve.

Em traços gerais, o trabalho consiste no desenvolvimento de uma aplicação capaz de emular um sistema (simplificado) de gestão de ficheiros em UNIX. Mais concretamente, inclui o desenho da estrutura de dados para organização do sistema de ficheiros, a implementação de rotinas de I/O para acesso ao mesmo, e a implementação de um conjunto de utilitários de mais alto-nível para manipulação de ficheiros e directórios.

Etapas do Trabalho

O trabalho está estruturado por etapas para simplificar a sua execução.

Etapa 1: Estruturação do sistema de ficheiros (valorização: 20%)

Nesta 1ª etapa pretende-se que desenhe o conjunto das estruturas de dados de suporte à organização do sistema de ficheiros e que implemente um procedimento format que permita definir e formatar novos sistemas. Para tal, considere a organização que se segue:

O sistema de ficheiros pode ser visto como um conjunto contíguo de blocos de disco em que se destacam três regiões principais: o superblock (a que corresponde o bloco 0), a região dos inodes (a que correspondem os blocos seguintes, começando no 1), e a região para dados propriamente dita (a que correspondem os restantes blocos).

Como cada bloco de dados deve poder ser representado por um inode, o número total de inodes deve ser igual ao número total de blocos de dados. Se o espaço necessário para representar um inode é INODE_SIZE (64 bytes no caso da estrutura apresentada acima) então em cada bloco é possível representar BLOCK_SIZE/INODE_SIZE inodes (INODES_PER_BLOCK). Como consequência, o número de blocos de dados deve ser múltiplo de INODES_PER_BLOCK. Deste modo, o número de blocos total num sistema de ficheiros (N_BLOCKS) resulta da fórmula 1+(INODES_PER_BLOCK+1)*N para N>0, e o tamanho do sistema de ficheiros resulta da fórmula N_BLOCKS*BLOCK_SIZE.

A emulação dos sistemas de ficheiros será feita sobre ficheiros comuns estruturados segundo a organização descrita. Sendo assim, ao iniciar o emulador do sistema de gestão de ficheiros (sugestão de nome: virtual_fs) deverá indicar como argumento o ficheiro sobre o qual o emulador deverá funcionar. Exemplo: virtual_fs discoC. Se o ficheiro não corresponder a um sistema de ficheiros válido (verificar o check_number e o block_size do superblock) deve ser reportado um erro e o emulador deve terminar. Para iniciar um novo sistema de ficheiros, deverá indicar o nome de um novo ficheiro seguido da informação relativa ao tamanho de cada BLOCK_SIZE (opção -b seguido do tamanho em Kbytes: 1, 2, 4 ou 8) e ao tamanho mínimo do sistema de ficheiros (opção -s seguido do tamanho em Kbytes). Exemplo: virtual_fs -b2 -s2000 discoC. Como 2000 Kbytes não é um tamanho válido para um sistema de ficheiros com blocos de 2 Kbytes, já que não existe nenhum N tal que 2*(1+(32+1)*N) seja igual a 2000, esse tamanho deve ser arredondado para o primeiro N que resulte num valor maior que 2000. Para o exemplo em causa, o tamanho do novo sistema de ficheiros deveria ser 2048 Kbytes, já que para N = 30, 2*(1+33*N) é igual a 1982, e para N = 31, 2*(1+33*N) é igual a 2048.

Use o protótipo que se segue para o procedimento que permite formatar e iniciar todas as estruturas de dados de novos sistemas:

   void my_format(int fd, int block_size, int filesystem_size);

Etapa 2: I/O para manipulação dos blocos de dados (valorização: 10%)

De forma a manipular os blocos de dados do sistema de ficheiros implemente os seguintes procedimentos: O procedimento read_block escreve para buf o conteúdo do bloco de dados a que corresponde block_number, enquanto que write_block escreve o conteúdo de buf para o bloco de dados a que corresponde block_number. Note que em ambos os casos o tamanho de buf deve ser igual a BLOCK_SIZE.

Etapa 3: Utilitários para manipulação de directórios (valorização: 30%)

O utilizador deve poder comunicar com o emulador do sistema de gestão de ficheiros através de uma linha de comandos onde poderão ser invocados uma série de utilitários para manipulação de ficheiros e directórios.

Um ficheiro não é nada mais do que um conjunto de blocos de dados que podem ser escritos e lidos. Cada ficheiro corresponde a um inode que especifica quais os blocos de dados utilizados pelo ficheiro. A ordem dos blocos no ficheiro é a ordem representada no inode. Quando o tamanho do ficheiro excede N_DIRECT_BLOCKS blocos de dados, utiliza-se um bloco de dados auxiliar para representar os restantes blocos de dados necessários para o ficheiro. O campo indirect_block da estrutura dos inodes guarda o índice do bloco de índices para outros blocos.

A implementação de directórios é de certa forma idêntica à dos ficheiros, a diferença reside no facto dos blocos de dados para directórios seguirem um formato predefinido. Um bloco de dados para um directório, pode ser visto como um array de estruturas de dados do seguinte tipo:

   #define MAX_NAME_LENGHT 28

   typedef struct directory_entry {
      int inode;                    /* inode associado ao ficheiro/subdirectório */
      char name[MAX_NAME_LENGHT];   /* nome do ficheiro/subdirectório */
   } dir_entry;
Cada uma destas estruturas corresponde a um ficheiro/subdirectório do directório em causa. O campo name guarda o nome do ficheiro/subdirectório, enquanto o campo inode guarda a referência do inode que representa o ficheiro/subdirectório.

Nesta etapa, pretende-se que implemente os utilitários para manipulação de directórios. Segue-se uma breve descrição de cada um deles:

Note que a criação de um novo directório, implica desde logo, a criação de duas entradas, uma para o directório corrente "." e outra para o directório pai "..". O inode associado ao directório root "/" é definido pelo campo root_inode do superblock. Para todos os utilitários, considere apenas os casos em que o argumento dir é o directório corrente (.), o directório pai (..), ou um subdirectório do directório actual. Para todos os outros casos, reporte um erro apropriado (ou seja, não considere o uso de caminhos como my_dir_1/.../my_dir_n/my_fich).

Etapa 4: Utilitários para manipulação de ficheiros (valorização: 40%)

Nesta etapa, pretende-se que implemente os utilitários para manipulação de ficheiros. Segue-se uma breve descrição de cada um deles: Tal como na etapa anterior, não considere o uso de caminhos no argumento dir.

Etapa Bónus: Desfragmentar o sistema de ficheiros (valorização: 10%)

O criar, copiar e apagar de ficheiros e directórios, com o decorrer do tempo, leva a que o sistema de ficheiros comece a ficar fragmentado, isto é, os blocos de dados utilizados para representar ficheiros/directórios deixam de poder ser contíguos e passam a situar-se dispersos e intercalados no conjunto total dos blocos disponíveis.

Nesta etapa pretende-se que implemente um procedimento defrag que permita desfragmentar o sistema de ficheiros. O procedimento deve reorganizar o conjunto de blocos de dados por forma a garantir que os ficheiros e subdirectórios de um dado directório e que cada ficheiro ou subdirectório particular, fiquem representados em blocos de dados contíguos. O procedimento deve imprimir uma listagem dos blocos de dados utilizados por cada um dos ficheiros/directórios antes e depois de executar o processo de desfragmentação do sistema de ficheiros.

Prazos

O trabalho deve ser entregue via web até 24 de Maio de 2002, sendo a sua demonstração feita posteriormente em horário a marcar.