Skip to content

Commit

Permalink
[vinapp] make README.md
Browse files Browse the repository at this point in the history
  • Loading branch information
pedropesserl committed Jun 25, 2023
1 parent 95a0aae commit b9c26cf
Show file tree
Hide file tree
Showing 10 changed files with 147 additions and 28 deletions.
Empty file removed vinapp/LEIAME
Empty file.
98 changes: 98 additions & 0 deletions vinapp/README.md
Original file line number Diff line number Diff line change
@@ -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] <archive> [membro1 [membro2 [...]]]`

Opções (use exatamente uma):
```
-i <archive> <membro1> [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 <archive> <membro1> [membro2 [...]] Mesmo comportamento da opção -i, mas substitui um membro existente APENAS caso o parâmetro seja mais recente que o arquivado.
-m <target> <archive> <membro> Move o membro indicado para imediatamente após o membro target, que deve estar presente em archive.
-x <archive> [membro1 [membro2 [...]]] Extrai os membros indicados de archive. Se não for especificado nenhum membro, extrai todos os membros.
-r <archive> <membro1> [membro2 [...]] Remove os membros indicados de archive.
-c <archive> 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.
2 changes: 1 addition & 1 deletion vinapp/makefile
Original file line number Diff line number Diff line change
@@ -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

Expand Down
10 changes: 7 additions & 3 deletions vinapp/src/content.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
}
6 changes: 3 additions & 3 deletions vinapp/src/insert.c
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <pwd.h>
#include <time.h>
#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,
Expand All @@ -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);
Expand Down
20 changes: 10 additions & 10 deletions vinapp/src/libarchiver.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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);
}

Expand Down
14 changes: 7 additions & 7 deletions vinapp/src/libarchiver.h
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -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);
Expand Down
12 changes: 12 additions & 0 deletions vinapp/src/libbin.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
10 changes: 8 additions & 2 deletions vinapp/src/libbin.h
Original file line number Diff line number Diff line change
Expand Up @@ -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); \
Expand All @@ -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);
Expand Down
3 changes: 1 addition & 2 deletions vinapp/src/vinapp.c
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include "libbin.h"
#include "insert.h"
#include "content.h"
#include "remove.h"
#include "content.h"
#include "move.h"
#include "extract.h"

Expand Down

0 comments on commit b9c26cf

Please sign in to comment.