/********************************************************************* * SISTEMAS DE OPERAÇÃO 2007/2008 * * ------------------------------ * * Trabalho II: Sistema de Ficheiros Virtual * * * * Grupo: * * Elemento 1: * * Elemento 2: * * Elemento 3: * *********************************************************************/ #include #include #include #include #include #include #include #include #define MAXARGS 100 #define CHECK_NUMBER 2008 #define TYPE_DIR 'D' #define TYPE_FILE 'F' #define TYPE_FREE '-' #define MAX_NAME_LENGHT 20 #define FAT_ENTRIES(TYPE) (TYPE == 8 ? 256 : TYPE == 10 ? 1024 : 4096) #define FAT_SIZE(TYPE) (FAT_ENTRIES(TYPE) * sizeof(int)) #define BLOCK(N) (blocks + N * sb->block_size) typedef struct command { char *cmd; // string apenas com o comando int argc; // número de argumentos char *argv[MAXARGS+1]; // vector de argumentos do comando } COMMAND; typedef struct superblock_entry { int check_number; // número que permite identificar o sistema como válido int block_size; // tamanho de um bloco {256, 512(default) ou 1024 bytes} int fat_type; // tipo de FAT {8, 10(default) ou 12} int root_block; // número do 1º bloco a que corresponde o directório raíz int free_block; // número do 1º bloco da lista de blocos não utilizados } superblock; typedef struct directory_entry { char type; // tipo da entrada (TYPE_DIR, TYPE_FILE ou TYPE_FREE) char name[MAX_NAME_LENGHT]; // nome da entrada unsigned char day; // dia em que foi criada (entre 1 e 31) unsigned char month; // mes em que foi criada (entre 1 e 12) unsigned char year; // ano em que foi criada (entre 0 e 255 - 0 representa o ano de 1900) int size; // tamanho em bytes (0 se TYPE_DIR) int first_block; // primeiro bloco de dados } dir_entry; // variáveis globais superblock *sb; // superblock do sistema de ficheiros int *fat; // apontador para a FAT char *blocks; // apontador para a região dos dados dir_entry *dir; // apontador para um bloco do tipo TYPE_DIR // declaração de funções void parse_argv(int argc, char *argv[]); void my_format(int fsd, int block_size, int fat_type); COMMAND parse(char *); void exec_com(COMMAND); // funções de manipulação de directórios void vfs_mkdir(char *nome_dir); void vfs_rmdir(char *nome_dir); void vfs_cd(char *nome_dir); void vfs_pwd(void); void vfs_ls(void); // funções de manipulação de ficheiros void vfs_get(char *nome_orig, char *nome_dest); void vfs_put(char *nome_orig, char *nome_dest); void vfs_cp(char *nome_orig, char *nome_dest); void vfs_mv(char *nome_orig, char *nome_dest); void vfs_rm(char *nome_fich); void vfs_cat(char *nome_fich); int main(int argc, char *argv[]) { char *linha; COMMAND com; parse_argv(argc, argv); while (1) { if ((linha = readline("vfs$ ")) == NULL) exit(0); if (strlen(linha) != 0) { add_history(linha); com = parse(linha); exec_com(com); } free(linha); } return; } void parse_argv(int argc, char *argv[]) { int i, fsd, block_size, fat_type; block_size = 512; // valor por defeito fat_type = 10; // valor por defeito for (i = 1; i < argc - 1; i++) { if (argv[i][0] == '-') { if (argv[i][1] == 'b') { block_size = atoi(&argv[i][2]); if (block_size != 256 && block_size != 512 && block_size != 1024) { printf("vfs: invalid block size (%d)\n", block_size); printf("Usage: vfs [-b[256|512|1024]] [-f[8|10|12]] FILESYSTEM\n"); exit(1); } } else if (argv[i][1] == 'f') { fat_type = atoi(&argv[i][2]); if (fat_type != 8 && fat_type != 10 && fat_type != 12) { printf("vfs: invalid fat type (%d)\n", fat_type); printf("Usage: vfs [-b[256|512|1024]] [-f[8|10|12]] FILESYSTEM\n"); exit(1); } } else { printf("vfs: invalid argument (%s)\n", argv[i]); printf("Usage: vfs [-b[256|512|1024]] [-f[8|10|12]] FILESYSTEM\n"); exit(1); } } else { printf("vfs: invalid argument (%s)\n", argv[i]); printf("Usage: vfs [-b[256|512|1024]] [-f[8|10|12]] FILESYSTEM\n"); exit(1); } } if ((fsd = open(argv[argc-1], O_RDWR)) == -1) { // o sistema de ficheiros não existe --> é necessário criá-lo if ((fsd = open(argv[argc-1], O_CREAT | O_TRUNC | O_RDWR, S_IRWXU)) == -1) { printf("vfs: cannot create filesystem (%s)\n", argv[argc-1]); printf("Usage: vfs [-b[256|512|1024]] [-f[8|10|12]] FILESYSTEM\n"); exit(1); } // e formatá-lo my_format(fsd, block_size, fat_type); } else { // faz o mapeamento do sistema de ficheiros e inicia as variáveis globais int filesystem_size; struct stat buf; stat(argv[argc-1], &buf); if ((sb = (superblock *) mmap(NULL, buf.st_size, PROT_READ | PROT_WRITE, MAP_SHARED, fsd, 0)) == MAP_FAILED) { printf("vfs: cannot map filesystem (mmap error)\n"); close(fsd); exit(1); } fat = (int *) ((int) sb + sb->block_size); blocks = (char *) ((int) fat + FAT_SIZE(sb->fat_type)); // testa se o sistema de ficheiros é válido filesystem_size = sb->block_size + FAT_SIZE(sb->fat_type) + FAT_ENTRIES(sb->fat_type) * sb->block_size; if (sb->check_number != CHECK_NUMBER || buf.st_size != filesystem_size) { printf("vfs: invalid filesystem (%s)\n", argv[argc-1]); printf("Usage: vfs [-b[256|512|1024]] [-f[8|10|12]] FILESYSTEM\n"); munmap(sb, buf.st_size); close(fsd); exit(1); } } close(fsd); return; } void my_format(int fsd, int block_size, int fat_type) { int i, filesystem_size; struct tm *cur_tm; time_t cur_time; // calcula o tamanho do sistema de ficheiros filesystem_size = block_size + FAT_SIZE(fat_type) + FAT_ENTRIES(fat_type) * block_size; printf("vfs: formatting virtual file-system (%d bytes) ... please wait\n", filesystem_size); // estende o sistema de ficheiros para o tamanho desejado lseek(fsd, filesystem_size - 1, SEEK_SET); write(fsd, "", 1); // faz o mapeamento do sistema de ficheiros e inicia as variáveis globais if ((sb = (superblock *) mmap(NULL, filesystem_size, PROT_READ | PROT_WRITE, MAP_SHARED, fsd, 0)) == MAP_FAILED) { printf("vfs: cannot map filesystem (mmap error)\n"); close(fsd); exit(1); } fat = (int *) ((int) sb + block_size); blocks = (char *) ((int) fat + FAT_SIZE(fat_type)); // inicia o superblock sb->check_number = CHECK_NUMBER; sb->block_size = block_size; sb->fat_type = fat_type; sb->root_block = 0; sb->free_block = 1; // inicia a FAT fat[0] = -1; for (i = 1; i < FAT_ENTRIES(fat_type) - 1; i++) fat[i] = i + 1; fat[i] = -1; // inicia o bloco do directório raíz cur_time = time(NULL); cur_tm = localtime(&cur_time); dir = (dir_entry *) BLOCK(0); dir[0].type = dir[1].type = TYPE_DIR; strcpy(dir[0].name, "."); strcpy(dir[1].name, ".."); dir[0].day = dir[1].day = cur_tm->tm_mday; dir[0].month = dir[1].month = cur_tm->tm_mon + 1; dir[0].year = dir[1].year = cur_tm->tm_year; dir[0].size = dir[1].size = 0; dir[0].first_block = dir[1].first_block = 0; dir[2].type = TYPE_FREE; return; } COMMAND parse(char *linha) { // ... } void exec_com(COMMAND com) { // para cada comando invocar a função que o implementa }