diff --git a/vinapp/LEIAME b/vinapp/LEIAME deleted file mode 100644 index e69de29..0000000 diff --git a/vinapp/README.md b/vinapp/README.md new file mode 100644 index 0000000..eebcedd --- /dev/null +++ b/vinapp/README.md @@ -0,0 +1,98 @@ +Nome: Pedro Folloni Pesserl +GRR: GRR20220072 + +Esse é um trabalho desenvolvido para a disciplina CI1002 - Programação 2, do +Departamento de Informática da UFPR. Implementa um programa capaz de arquivar um +ou mais arquivos ou diretórios em um único arquivo binário (chamado aqui de "archive"). + +### Forma de uso: + +Para compilar o programa, use `make`. + +Uso: +`./vina++ -[iamxrch] [membro1 [membro2 [...]]]` + +Opções (use exatamente uma): +``` + -i [membro2 [...]] Insere um ou mais membros no archive, respeitando a ordem dos parâmetros (membro1, depois membro2 e assim por diante). Se um membro já estiver no archive, será substituído. + -a [membro2 [...]] Mesmo comportamento da opção -i, mas substitui um membro existente APENAS caso o parâmetro seja mais recente que o arquivado. + -m Move o membro indicado para imediatamente após o membro target, que deve estar presente em archive. + -x [membro1 [membro2 [...]]] Extrai os membros indicados de archive. Se não for especificado nenhum membro, extrai todos os membros. + -r [membro2 [...]] Remove os membros indicados de archive. + -c Lista o conteúdo de archive em ordem, incluindo as propriedades de cada membro (nome, UID, permissões, tamanho e data de modificação) e sua ordem no arquivo. + -h Imprime essa mensagem de ajuda. +``` + +O formato do arquivo de saída é o seguinte: +- 8 bytes iniciais: dão a posição da área de diretório do archive. +- Área dos arquivos: contém os arquivos que foram inseridos, byte a byte. +- Área de diretório: começa a partir da posição especificada, contém metadados + sobre os arquivos inseridos em archive. + Para cada arquivo, contém: + - nome; + - user id; + - group id; + - modo e permissões; + - data e hora da última modificação; + - tamanho; + - ordem no arquivo; + - posição no arquivo (dada em bytes). + +### Arquivos e diretórios contidos no pacote: + +- `libbin.[hc]`: Define macros e funções úteis para manipulação de arquivos binários; +- `libarchiver.[hc]`: Define macros e funções próprias para uso no arquivador. Inclui + `libbin.h`; +- `insert.[hc]`: Define funções para inserir arquivos no archive, tanto de forma + destrutiva (sobrescrevendo arquivos de mesmo nome já presentes) quanto preservativa + (apenas sobrescrevendo caso o novo arquivo tenha data de modificação mais nova que o + já presente). Se for passado o caminho de um diretório, inclui todos os conteúdos + do diretório, recursivamente. Inclui `libbin.h` e `libarchiver.h`; +- `remove.[hc]`: Define funções para remover um arquivo do archive. Se for passado o + caminho de um diretório, remove todos os conteúdos daquele diretório que estiverem + presentes no archive. Inclui `libbin.h` e `libarchiver.h`; +- `content.[hc]`: Define uma função para ler um archive e imprimir seus conteúdos, + em um formato similar ao do comando `tar tvf`. Inclui `libbin.h` e `libarchiver.h`; +- `move.[hc]`: Define uma função para mover um arquivo para imediatamente após + outro no archive -- move todos os bytes do arquivo internamente no archive. Inclui + `libbin.h` e `libarchiver.h`; +- `extract.[hc]`: Define funções para extrair um arquivo de archive e criá-lo no + diretório corrente. Se for passado o caminho de um diretório, extrai todos os + conteúdos do diretório que estiverem presentes no archive. Inclui `libbin.h` e + `libarchiver.h`; +- `vinapp.c`: Código do programa principal. Interpreta as opções e argumentos + passados e redireciona o programa para realizar uma das funções descritas acima. + Inclui `insert.h`, `remove.h`, `content.h`, `move.h` e `extract.h`. + +### Algoritmos e estruturas de dados utilizadas: + A principal estrutura de dados implementada foi um vetor de `struct File_info`, +definida em `libarchiver.h` da seguinte forma: +```c +struct File_info { + char name[MAX_FNAME_LEN]; + int uid; + int gid; + int perm; + time_t td; + size_t size; + size_t ord; + size_t pos; +}; +``` + Quando é inserido um arquivo novo, o vetor é realocado. Essa estrutura foi utilizada +pela praticidade da implementação e pela facilidade de leitura da seção de diretório +do archive: para lermos um vetor de metadados de arquivo, podemos simplesmente ler +a posição no início do archive, pular para essa posição e ler o vetor completo, +calculando seu tamanho em relação ao fim do archive, devido à contiguidade da memória. + + Alguns algoritmos relevantes foram implementados na `libbin.[hc]`, são eles: +`open_space()` e `remove_space()`, que servem genericamente para abrir ou remover um +bloco de um tamanho especificado de um arquivo binário. Esses algoritmos foram úteis nas +outras bibliotecas mencionadas. + + Foi considerado implementar uma versão dessa estrutura por meio de uma tabela hash; +dessa forma, o acesso aos conteúdos de archive seria indexado pelo nome do arquivo, +e teria um tempo de execução menor (na implementação com vetor, a busca pelo arquivo +é feita linearmente, comparando os nomes dos arquivos com o nome do arquivo buscado). +Porém, a implementação da tabela hash é complexa, e o vetor foi escolhido pensando +em entregar um produto funcional no tempo disponível. diff --git a/vinapp/makefile b/vinapp/makefile index 2eea5d5..6a1e13f 100644 --- a/vinapp/makefile +++ b/vinapp/makefile @@ -1,5 +1,5 @@ CC = gcc -CFLAGS = -Wall -Wextra -g +CFLAGS = -Wall -Wextra OBJ = src/vinapp.o src/libbin.o src/libarchiver.o src/insert.o src/content.o src/remove.o src/move.o src/extract.o DEPS = src/libbin.h src/libarchive.h src/insert.h src/content.h src/remove.h src/move.h src/extract.h diff --git a/vinapp/src/content.c b/vinapp/src/content.c index 37b7234..7f1ec2e 100644 --- a/vinapp/src/content.c +++ b/vinapp/src/content.c @@ -15,13 +15,17 @@ void list_archive(char *archive_path) { size_t dirnmemb = 0; struct File_info *dir = read_dir(archive, &dirnmemb); - char timestring[17] = {0}; + char usr_string[9] = {0}; + char grp_string[9] = {0}; char permstring[11] = {0}; + char timestring[17] = {0}; for (size_t i = 0; i < dirnmemb; i++) { - format_modtime(timestring, dir[i].td); + format_uid(usr_string, dir[i].uid); + format_gid(grp_string, dir[i].gid); format_perm(permstring, dir[i].perm); + format_modtime(timestring, dir[i].td); printf("%s %s/%s %8ld %s %s\n", - permstring, dir[i].uid, dir[i].gid, + permstring, usr_string, grp_string, dir[i].size, timestring, dir[i].name+2); } } diff --git a/vinapp/src/insert.c b/vinapp/src/insert.c index 4c9aa09..5cbe5d5 100644 --- a/vinapp/src/insert.c +++ b/vinapp/src/insert.c @@ -1,11 +1,11 @@ #include #include #include -#include #include #include "libarchiver.h" #include "insert.h" +// Preenche uma struct File_info com as informações necessárias sobre um arquivo. static struct File_info fill_file_info(struct File_info *dir, FILE *member, char *member_name, @@ -16,8 +16,8 @@ static struct File_info fill_file_info(struct File_info *dir, standardize_name(member_name, std); strncpy(memb.name, std, MAX_FNAME_LEN); - get_uid(memb.uid, member_name); - get_gid(memb.gid, member_name); + memb.uid = get_uid(member_name); + memb.gid = get_gid(member_name); memb.perm = get_perm(member_name); memb.td = get_modtime(member_name); memb.size = get_size(member); diff --git a/vinapp/src/libarchiver.c b/vinapp/src/libarchiver.c index 2db5d4a..e10ae5a 100644 --- a/vinapp/src/libarchiver.c +++ b/vinapp/src/libarchiver.c @@ -18,8 +18,12 @@ struct File_info *read_dir(FILE *archive, size_t *dirnmemb) { size_t dirsize = get_size(archive) - dirpos; *dirnmemb = dirsize / sizeof(struct File_info); struct File_info *dir = (struct File_info*)calloc(*dirnmemb, sizeof(struct File_info)); - if (!dir) - MEM_ERR(1, "libarchiver.c: read_dir()"); + if (!dir) { + fprintf(stderr, "Erro de alocação de memória em libarchiver.c: read_dir().\n"); + fprintf(stderr, "Certifique-se que o archive especificado está no formato"); + fprintf(stderr, " correto.\n"); + exit(1); + } fread(dir, sizeof(struct File_info), *dirnmemb, archive); rewind(archive); @@ -35,17 +39,13 @@ void write_dir(FILE *archive, struct File_info *dir, size_t dirnmemb) { rewind(archive); } -void get_uid(char *buffer, char *path) { - struct stat info; - stat(path, &info); - struct passwd *pwd = getpwuid(info.st_uid); +void format_uid(char *buffer, int uid) { + struct passwd *pwd = getpwuid(uid); strncpy(buffer, pwd->pw_name, MAX_UNAME_LEN); } -void get_gid(char *buffer, char *path) { - struct stat info; - stat(path, &info); - struct group *grp = getgrgid(info.st_gid); +void format_gid(char *buffer, int gid) { + struct group *grp = getgrgid(gid); strncpy(buffer, grp->gr_name, MAX_GNAME_LEN); } diff --git a/vinapp/src/libarchiver.h b/vinapp/src/libarchiver.h index 2d6d714..b8f189b 100644 --- a/vinapp/src/libarchiver.h +++ b/vinapp/src/libarchiver.h @@ -13,7 +13,9 @@ } while (0) struct File_info { - char name[MAX_FNAME_LEN], uid[MAX_UNAME_LEN], gid[MAX_GNAME_LEN]; + char name[MAX_FNAME_LEN]; + int uid; + int gid; int perm; // Modo e permissões do arquivo. time_t td; // Momento da última modificação no arquivo. size_t size; // Tamanho do arquivo. @@ -29,13 +31,11 @@ struct File_info *read_dir(FILE *archive, size_t *dirnmemb); // bytes do archive, e o seu conteúdo na posição destinada (após o último membro). void write_dir(FILE *archive, struct File_info *dir, size_t dirnmemb); -// Escreve em buffer uma string com o nome do usuário ao qual o arquivo de nome -// path pertence. -void get_uid(char *buffer, char *path); +// Dado um uid, escreve em buffer uma string com o nome do usuário. +void format_uid(char *buffer, int uid); -// Escreve em buffer uma string com o nome do grupo ao qual o arquivo de nome -// path pertence. -void get_gid(char *buffer, char *path); +// Dado um gid, escreve em buffer uma string com o nome do grupo. +void format_gid(char *buffer, int gid); // Dado um modo mode, escreve em buffer uma string no formato: drwxrwxrwx. void format_perm(char *buffer, int mode); diff --git a/vinapp/src/libbin.c b/vinapp/src/libbin.c index 1204dd3..bc106f2 100644 --- a/vinapp/src/libbin.c +++ b/vinapp/src/libbin.c @@ -18,6 +18,18 @@ size_t get_size(FILE *f) { return sz; } +int get_uid(char *path) { + struct stat info; + stat(path, &info); + return info.st_uid; +} + +int get_gid(char *path) { + struct stat info; + stat(path, &info); + return info.st_gid; +} + int get_perm(char *path) { struct stat info; stat(path, &info); diff --git a/vinapp/src/libbin.h b/vinapp/src/libbin.h index 45461f6..1be3c33 100644 --- a/vinapp/src/libbin.h +++ b/vinapp/src/libbin.h @@ -27,12 +27,12 @@ } while (0) #define DNE_ERR(err, filename) do { \ - fprintf(stderr, "Erro: arquivo ou diretório %s não existe.\n", filename); \ + fprintf(stderr, "Erro: arquivo %s não existe.\n", filename); \ exit(err); \ } while (0) #define DNE_WARN(filename) \ - printf("Aviso: arquivo ou diretório %s não existe. Ignorado.\n", filename); + printf("Aviso: arquivo %s não existe. Ignorado.\n", filename); #define EXISTS_WARN(filename) do { \ fprintf(stderr, "Erro: arquivo ou diretório %s já existe, e ", filename); \ @@ -42,6 +42,12 @@ // Retorna o tamanho do arquivo f em bytes. size_t get_size(FILE *f); +// Retorna o user id do arquivo de nome path. +int get_uid(char *path); + +// Retorna o group id do arquivo de nome path. +int get_gid(char *path); + // Retorna o modo e permissões do arquivo de nome path, em um // int (campo st_mode da struct stat). int get_perm(char *path); diff --git a/vinapp/src/vinapp.c b/vinapp/src/vinapp.c index 60fb767..a2d912b 100644 --- a/vinapp/src/vinapp.c +++ b/vinapp/src/vinapp.c @@ -1,10 +1,9 @@ #include #include #include -#include "libbin.h" #include "insert.h" -#include "content.h" #include "remove.h" +#include "content.h" #include "move.h" #include "extract.h"