From 182983f0ca47c55f54546588cab2dcbc6efaa4c6 Mon Sep 17 00:00:00 2001 From: womax Date: Sat, 8 Jun 2024 01:26:32 +0200 Subject: [PATCH] Change tree encoding to be compatible with git; Add cat-file and show-index command --- src/commit.c | 28 ++++---- src/fs.c | 44 +++++++----- src/fs.h | 1 + src/includes.h | 3 + src/main.c | 73 +++++++++++++++++++ src/objects.c | 107 +++++++++++++++++++++------- src/objects.h | 5 +- src/tree.c | 186 +++++++++++++++++++++++++++---------------------- src/tree.h | 17 +++-- src/types.h | 29 +++++--- 10 files changed, 334 insertions(+), 159 deletions(-) diff --git a/src/commit.c b/src/commit.c index 5429c3d..509d5f8 100644 --- a/src/commit.c +++ b/src/commit.c @@ -76,27 +76,23 @@ int commit() struct tree commit_tree = {0}; get_last_commit(&last_commit); if (last_commit.size != 0) { - hash_object(&last_commit, last_commit_checksum); + hash_object_str(&last_commit, last_commit_checksum); commit_from_object(&commit, &last_commit); struct object last_commit_tree = {0}; read_object(commit.tree, &last_commit_tree); - get_tree(last_commit_tree.content, &commit_tree); + tree_from_object(&commit_tree, &last_commit_tree); free_object(&last_commit_tree); } free_object(&last_commit); struct entry *current = index.first_entry; while(current != NULL) - { - size_t entry_size = DIGEST_LENGTH * 2 + 2 + strlen(current->filename); - char tmp[entry_size + 1]; - sprintf(tmp, "%s %s\n", current->checksum, current->filename); - + { struct object object = {0}; blob_from_file(current->filename, &object); - add_object_to_tree(&commit_tree, current->filename, &object); + add_object_to_tree(&commit_tree, current->filename, current->mode, &object); free_object(&object); current = current->next; @@ -122,7 +118,7 @@ int commit() struct object commit_tree_obj = {0}; tree_to_object(&commit_tree, &commit_tree_obj); char *commit_tree_checksum = malloc(DIGEST_LENGTH * 2 + 1); - hash_object(&commit_tree_obj, commit_tree_checksum); + hash_object_str(&commit_tree_obj, commit_tree_checksum); write_object(&commit_tree_obj); if(commit.tree != NULL) @@ -135,7 +131,7 @@ int commit() commit_to_object(&commit, &commit_obj); write_object(&commit_obj); char commit_checksum[DIGEST_LENGTH * 2 + 1]; - hash_object(&commit_obj, commit_checksum); + hash_object_str(&commit_obj, commit_checksum); update_current_branch_head(commit_checksum); @@ -167,9 +163,9 @@ int diff_commit_with_working_tree(char *checksum, int for_print) read_object(commit.tree, &obj); struct tree commit_tree = {0}; - get_tree(obj.content, &commit_tree); + tree_from_object(&commit_tree, &obj); - rmdir(TMP"/a"); + remove_dir(TMP"/a"); create_dir(TMP"/a"); dump_tree(TMP"/a", &commit_tree); @@ -218,11 +214,11 @@ int diff_commit(char* checksum_a, char* checksum_b, int for_print) read_object(commit_b.tree, &tree_b_obj); struct tree tree_a, tree_b; - get_tree(tree_a_obj.content, &tree_a); - get_tree(tree_b_obj.content, &tree_b); + tree_from_object(&tree_a, &tree_a_obj); + tree_from_object(&tree_b, &tree_b_obj); - rmdir(TMP"/a"); - rmdir(TMP"/b"); + remove_dir(TMP"/a"); + remove_dir(TMP"/b"); create_dir(TMP"/a"); create_dir(TMP"/b"); diff --git a/src/fs.c b/src/fs.c index cb5665c..e1efc0f 100644 --- a/src/fs.c +++ b/src/fs.c @@ -59,10 +59,6 @@ int init_repo() if (!index_exist()) { int fd = open(INDEX_FILE, O_WRONLY | O_CREAT | O_TRUNC, 0644); - FILE *index = fdopen(fd, "w"); - - fprintf(index, "0\n"); - fclose(index); } if (!head_file_exist(NULL)) @@ -120,13 +116,13 @@ int write_object(struct object *obj) int objects_dir_fd = dirfd(objects_dir); char checksum[DIGEST_LENGTH * 2]; - hash_object(obj, checksum); + hash_object_str(obj, checksum); int save_file_fd = openat(objects_dir_fd, checksum, O_CREAT | O_WRONLY | O_TRUNC, DEFAULT_FILE_MODE); if(save_file_fd == -1) { if (errno == EACCES) { - debug_print("Object %s already exists", checksum); + // debug_print("Object %s already exists", checksum); defer(OBJECT_ALREADY_EXIST); } defer(FS_ERROR); @@ -215,7 +211,7 @@ int create_dir(char *dir) if(stat(dir, &buffer) == 0) { - if (!S_ISREG(buffer.st_mode)) + if (S_ISDIR(buffer.st_mode)) { result = remove(dir); if (result != 0) @@ -283,14 +279,16 @@ int dump_tree(char *cwd, struct tree *tree) sprintf(filename, "%s/%s", cwd, current->filename); struct object obj = {0}; - read_object(current->checksum, &obj); + char checksum_str[DIGEST_LENGTH * 2 + 1]; + hash_to_hexa(current->checksum, checksum_str); + read_object(checksum_str, &obj); if(current->type == BLOB) { tmp_dump(&obj, filename); } else if (current->type == TREE) { struct tree subtree = {0}; - get_tree(obj.content, &subtree); + tree_from_object(&subtree, &obj); create_dir(filename); dump_tree(filename, &subtree); @@ -318,7 +316,7 @@ int load_tree(char* checksum, struct tree *tree) return WRONG_OBJECT_TYPE; } - get_tree(object.content, tree); + tree_from_object(tree, &object); free_object(&object); return 0; @@ -339,7 +337,9 @@ int load_index(struct tree *index) fread(file_content, buffer.st_size, 1, index_file); fclose(index_file); - get_tree(file_content, index); + object_t obj = { content: file_content, size: buffer.st_size, object_type: TREE }; + + tree_from_object(index, &obj); free(file_content); @@ -533,11 +533,14 @@ int is_file_ignored(char *filename) fread(content, buffer.st_size, 1, ignore_file); fclose(ignore_file); + int i = 0; + for(; filename[i] != '/'; i ++); + char *current_line = strtok(content, "\n"); while(current_line != NULL) { - if(strncmp(current_line, filename, strlen(current_line)) == 0) + if(strncmp(current_line, filename, i-1) == 0) { return 1; } @@ -561,7 +564,7 @@ int add_file_to_index(struct tree *index, char *filename) { return FILE_NOT_FOUND; } - if (!S_ISREG(st.st_mode)) + if (S_ISDIR(st.st_mode)) { DIR *dp; struct dirent *ep; @@ -589,7 +592,12 @@ int add_file_to_index(struct tree *index, char *filename) return 0; } } else { - if (add_to_index(index, filename) == FILE_NOT_FOUND) + enum file_mode mode = REG_NONX_FILE; + if(S_ISLNK(st.st_mode)) + mode = SYM_LINK; + if (st.st_mode & S_IXUSR == S_IXUSR) + mode = REG_EXE_FILE; + if (add_to_index(index, filename, mode) == FILE_NOT_FOUND) return FILE_NOT_FOUND; } } @@ -602,7 +610,7 @@ int remove_file_from_index(struct tree *index, char *filename) struct stat st = {0}; if (stat(filename, &st) != 0) return FILE_NOT_FOUND; - if (!S_ISREG(st.st_mode)) + if (S_ISDIR(st.st_mode)) { DIR *dp; struct dirent *ep; @@ -628,7 +636,7 @@ int remove_file_from_index(struct tree *index, char *filename) return 0; } } else { - remove_from_index(index, filename, 1); + remove_from_tree(index, filename, 1); } } @@ -645,7 +653,7 @@ int dump_log() FILE *log_file = fopen(LOG_FILE, "w"); char checksum[DIGEST_LENGTH * 2 + 1]; - hash_object(¤t_obj, checksum); + hash_object_str(¤t_obj, checksum); fprintf(log_file, "commit %s HEAD\n", checksum); fprintf(log_file, "Author: %s\n", current.author); fprintf(log_file, "Tree: %s\n", current.tree); @@ -659,7 +667,7 @@ int dump_log() commit_from_object(¤t, ¤t_obj); checksum[DIGEST_LENGTH * 2 + 1]; - hash_object(¤t_obj, checksum); + hash_object_str(¤t_obj, checksum); fprintf(log_file, "commit %s\n", checksum); fprintf(log_file, "Author: %s\n", current.author); fprintf(log_file, "Tree: %s\n", current.tree); diff --git a/src/fs.h b/src/fs.h index bdb8c1f..b94bc5a 100644 --- a/src/fs.h +++ b/src/fs.h @@ -60,6 +60,7 @@ int checkout_branch(char *branch); int reset_to(char* commit_checksum); int create_dir(char *dir); +void remove_dir(char *dir); int dump_tree(char *cwd, struct tree *tree); int dump_log(); int dump_branches(); diff --git a/src/includes.h b/src/includes.h index a584971..6f2fdfa 100644 --- a/src/includes.h +++ b/src/includes.h @@ -19,6 +19,9 @@ #define error_print(X, ...) #endif +#define look_for(str, delim, index) \ + for(; str[index] != delim; index ++); + #define defer(X) \ result = X; \ goto defer; \ diff --git a/src/main.c b/src/main.c index 0608237..4cfc1d6 100644 --- a/src/main.c +++ b/src/main.c @@ -9,6 +9,7 @@ #include "includes.h" #include "commit.h" #include "fs.h" +#include "objects.h" #include "tree.h" #define ARGS_MAX_SIZE 256 @@ -225,6 +226,54 @@ int log_cmd(int argc, char **argv) pclose(p); } +int cat_file(int argc, char **argv) +{ + char buf[ARGS_MAX_SIZE]; + + if(pop_arg(&argc, &argv, buf) == 1) + { + printf("usage: cgit cat-file \n"); + return 129; + } + + object_t obj = {0}; + int res = read_object(buf, &obj); + if (res != FS_OK) + { + if (res == OBJECT_DOES_NOT_EXIST) + { + printf("fatal: not a valid object name %s\n", buf); + return 128; + } + + if (res == REPO_NOT_INITIALIZED) + { + printf("Not a cgit repository\n"); + return 128; + } + } + + cat_object(STDIN_FILENO, &obj); + free_object(&obj); + + return 0; +} + +int show_index(int argc, char **argv) +{ + tree_t index = {0}; + load_index(&index); + + object_t obj = {0}; + tree_to_object(&index, &obj); + free_tree(&index); + + cat_object(STDIN_FILENO, &obj); + free_object(&obj); + + return 0; +} + int main(int argc, char **argv) { char cmd[ARGS_MAX_SIZE]; @@ -266,6 +315,30 @@ int main(int argc, char **argv) return log_cmd(argc, argv); } else if (strcmp(buf, "-h") == 0) { return print_help(); + } else if (strcmp(buf, "cat-file") == 0) + { + return cat_file(argc, argv); + } else if (strcmp(buf, "show-index") == 0) + { + return show_index(argc, argv); + } else if (strcmp(buf, "test") == 0) + { + object_t obj = {0}; + read_object("192f287aebddb0080e6ea7cb567d76d78b54dee2", &obj); + + tree_t tree = {0}; + tree_from_object(&tree, &obj); + free_object(&obj); + + debug_print("entries_size: %li", tree.entries_size); + debug_print("first_entry->filename: %s", tree.first_entry->filename); + debug_print("last_entry->filename: %s", tree.last_entry->filename); + + tree_to_object(&tree, &obj); + write_object(&obj); + + free_tree(&tree); + free_object(&obj); } else { printf("Unknown command %s, try using %s -h\n", buf, cmd); return 0; diff --git a/src/objects.c b/src/objects.c index 81aae7d..001e927 100644 --- a/src/objects.c +++ b/src/objects.c @@ -5,29 +5,33 @@ #include #include #include +#include #include #include "includes.h" +#include "fs.h" +#include "tree.h" #include "utils.h" #include "objects.h" char *object_type_str[3] = { - "blob", + "blob", "tree", "commit", }; -char* object_type_to_str(enum object_type type) +char *object_type_to_str(enum object_type type) { return object_type_str[type]; } -enum object_type str_to_object_type(char* str) +enum object_type str_to_object_type(char *str) { - if(strncmp("tree", str, 4) == 0) + if (strncmp("tree", str, 4) == 0) { return TREE; - } else if (strncmp("commit", str, 5) == 0) + } + else if (strncmp("commit", str, 5) == 0) { return COMMIT; } @@ -47,7 +51,7 @@ size_t object_size(struct object *obj) int full_object(struct object *obj, char *buffer, size_t buffer_size) { - char* hr_size = malloc(decimal_len(obj->size) + 1); + char *hr_size = malloc(decimal_len(obj->size) + 1); sprintf(hr_size, "%li", obj->size); size_t data_size = object_size(obj); @@ -58,11 +62,11 @@ int full_object(struct object *obj, char *buffer, size_t buffer_size) memcpy(writing, type, strlen(type)); writing += strlen(type); memcpy(writing, " ", 1); - writing ++; + writing++; memcpy(writing, hr_size, strlen(hr_size)); writing += strlen(hr_size); memcpy(writing, "\0", 1); - writing ++; + writing++; memcpy(writing, obj->content, obj->size); free(hr_size); @@ -70,29 +74,45 @@ int full_object(struct object *obj, char *buffer, size_t buffer_size) return 0; } -void hash_object(struct object *obj, char *result) +/// @brief Hash object and copy it in result +/// @param obj +/// @param result char array of size DIGEST_LENGTH, it is not a C-string. +void hash_object(object_t *obj, unsigned char *result) { - unsigned char md_buffer[DIGEST_LENGTH] = {0}; size_t data_size = object_size(obj); - char* data = malloc(data_size); + char data[data_size]; full_object(obj, data, data_size); - SHA1(data, data_size, md_buffer); - - for (int i = 0; i < DIGEST_LENGTH; i++) - { - sprintf((result + (2 * i)), "%.2x", md_buffer[i]); - } - - free(data); + SHA1(data, data_size, result); + return; } -int uncompress_object(struct object *obj, char* compressed, uLongf comp_size) +void hash_to_hexa(unsigned char *hash, char *result) +{ + for (int i = 0; i < DIGEST_LENGTH; i ++) + sprintf((result + (2 * i)), "%.2x", hash[i]); + + return; +} + +/// @brief Hash object and copy its hexa representation in result +/// @param obj +/// @param result A C-string of length equals DIGEST_LENGTH * 2 +void hash_object_str(object_t *obj, char *result) +{ + unsigned char md_buffer[DIGEST_LENGTH] = {0}; + hash_object(obj, md_buffer); + + hash_to_hexa(md_buffer, result); + return; +} + +int uncompress_object(struct object *obj, char *compressed, uLongf comp_size) { uLongf def_size = HEADER_MAX_SIZE; uLongf content_size = 0; - char* deflated = malloc(def_size); - int res = uncompress((Bytef *) deflated, &def_size, (Bytef *)compressed, comp_size); + char *deflated = malloc(def_size); + int res = uncompress((Bytef *)deflated, &def_size, (Bytef *)compressed, comp_size); if (res != Z_OK && res != Z_BUF_ERROR) { return res; @@ -104,8 +124,9 @@ int uncompress_object(struct object *obj, char* compressed, uLongf comp_size) content_size = strtol(hr_size, NULL, 10); def_size += content_size; deflated = realloc(deflated, def_size); - res = uncompress((Bytef *) deflated, &def_size, (Bytef *)compressed, comp_size); - if(res != Z_OK) { + res = uncompress((Bytef *)deflated, &def_size, (Bytef *)compressed, comp_size); + if (res != Z_OK) + { return res; } char *content_type_tmp = strtok(deflated, " "); @@ -119,10 +140,10 @@ int uncompress_object(struct object *obj, char* compressed, uLongf comp_size) return 0; } -int compress_object(struct object *obj, char* compressed, uLongf *comp_size) +int compress_object(struct object *obj, char *compressed, uLongf *comp_size) { size_t data_size = object_size(obj); - char* data = malloc(data_size); + char *data = malloc(data_size); full_object(obj, data, data_size); int res = compress((Bytef *)compressed, comp_size, (Bytef *)data, data_size); @@ -131,6 +152,40 @@ int compress_object(struct object *obj, char* compressed, uLongf *comp_size) return res; } +int cat_object(int fd, object_t *obj) +{ + + switch (obj->object_type) + { + case BLOB: + case COMMIT: + write(fd, obj->content, obj->size); + break; + + case TREE: + tree_t tree = {0}; + tree_from_object(&tree, obj); + + entry_t *current = tree.first_entry; + while(current != NULL) + { + char buf[DIGEST_LENGTH * 2 + 1]; + hash_to_hexa(current->checksum, buf); + dprintf(fd, "%.6o %s %s %s\n", current->mode, object_type_to_str(current->type), buf, current->filename); + current = current->next; + } + + free_tree(&tree); + break; + + default: + break; + } + + free_object; + return 0; +} + void free_object(struct object *obj) { if (obj->content != NULL) diff --git a/src/objects.h b/src/objects.h index 6a2c3c0..289503e 100644 --- a/src/objects.h +++ b/src/objects.h @@ -14,7 +14,10 @@ size_t object_size(struct object *obj); int full_object(struct object *obj, char* buffer, size_t buffer_size); int uncompress_object(struct object *obj, char* compressed, uLongf comp_size); int compress_object(struct object *obj, char* compressed, uLongf *comp_size); -void hash_object(struct object *obj, char* result); +void hash_object(object_t *obj, unsigned char *result); +void hash_object_str(struct object *obj, char* result); +void hash_to_hexa(unsigned char *hash, char *result); +int cat_object(int fd, object_t *obj); void free_object(struct object *obj); #endif // OBJECTS_H diff --git a/src/tree.c b/src/tree.c index 6fa7b00..46f02b6 100644 --- a/src/tree.c +++ b/src/tree.c @@ -1,11 +1,14 @@ #include #include #include +#include +#include #include "tree.h" #include "includes.h" #include "fs.h" #include "objects.h" +#include "types.h" #include "utils.h" void free_entry(struct entry *entry) @@ -18,7 +21,7 @@ void free_entry(struct entry *entry) } -void free_tree(struct tree *tree) +void free_tree(tree_t *tree) { struct entry *current = tree->first_entry; struct entry *next; @@ -31,7 +34,7 @@ void free_tree(struct tree *tree) } } -struct entry *find_entry(struct tree *tree, char* filename) +struct entry *find_entry(tree_t *tree, char* filename) { struct entry *current = tree->first_entry; for (int i = 0; i < tree->entries_size; ++i) @@ -45,71 +48,24 @@ struct entry *find_entry(struct tree *tree, char* filename) return NULL; } -void get_tree(char* content, struct tree *tree) -{ - char* current_line; - current_line = strtok(content, "\n"); - tree->entries_size = strtol(current_line, NULL, 10); - tree->first_entry = NULL; - tree->last_entry = NULL; - - for(int i = 0; i < tree->entries_size; i++) - { - struct entry *entry = calloc(1, sizeof(struct entry)); - current_line = strtok(NULL, "\n"); - int j = 0; - while(current_line[j] != ' ') - { - j++; - } - - current_line[j] = '\0'; - entry->type = str_to_object_type(current_line); - current_line += j + 1; - j = 0; - while(current_line[j] != ' ') - { - j++; - } - - char* checksum = calloc(j + 1, sizeof(char)); - char* filename = calloc(strlen(current_line) - j, sizeof(char)); - strncat(checksum, current_line, j); - strncat(filename, current_line + j + 1, strlen(current_line) - j); - entry->checksum = checksum; - entry->filename = filename; - entry->next = NULL; - - if(i == 0) - { - tree->first_entry = entry; - tree->last_entry = entry; - } else - { - entry->previous = tree->last_entry; - tree->last_entry->next = entry; - } - tree->last_entry = entry; - } -} - -int add_to_tree(struct tree *tree, struct object *object, char *filename) +int add_to_tree(tree_t *tree, object_t *object, char *filename, enum file_mode mode) { int new = 0; - struct entry *entry = find_entry(tree, filename); + entry_t *entry = find_entry(tree, filename); if (entry == NULL) { new = 1; - entry = calloc(sizeof(struct entry), 1); + entry = calloc(sizeof(entry_t), 1); } else { free_entry(entry); } entry->type = object->object_type; + entry->mode = mode; entry->filename = calloc(sizeof(char), strlen(filename) + 1); strncat(entry->filename, filename, strlen(filename)); - entry->checksum = calloc(sizeof(char), DIGEST_LENGTH * 2 + 1); + entry->checksum = calloc(sizeof(char), DIGEST_LENGTH); hash_object(object, entry->checksum); // int res = write_object(object); // if (res != FS_OK && res != OBJECT_ALREADY_EXIST) @@ -153,7 +109,7 @@ int add_to_tree(struct tree *tree, struct object *object, char *filename) } } -int add_to_index(struct tree *index, char *filename) +int add_to_index(tree_t *index, char *filename, enum file_mode mode) { int result = FS_OK; struct object object = {0}; @@ -164,22 +120,17 @@ int add_to_index(struct tree *index, char *filename) result = write_object(&object); if (result == FS_OK) - { - add_to_tree(index, &object, filename); - defer(FS_OK); - } + add_to_tree(index, &object, filename, mode); if (result == OBJECT_ALREADY_EXIST) - { - defer(FS_OK); - } + return FS_OK; defer: free_object(&object); return result; } -int remove_from_index(struct tree *index, char *filename, int delete) +int remove_from_tree(tree_t *index, char *filename, int delete) { struct entry *entry = find_entry(index, filename); if (entry == NULL) @@ -211,58 +162,127 @@ int remove_from_index(struct tree *index, char *filename, int delete) return FS_OK; } -int tree_to_object(struct tree *tree, struct object *object) +int tree_to_object(tree_t *tree, object_t *object) { object->object_type = TREE; - object->content = calloc(1, decimal_len(tree->entries_size) + 2); - object->size = decimal_len(tree->entries_size) + 2; - sprintf(object->content, "%li\n", tree->entries_size); + object->size = 0; + object->content = NULL; struct entry *current = tree->first_entry; for(int i = 0; i < tree->entries_size; i++) { char *type = object_type_to_str(current->type); - size_t entry_size = strlen(type) + DIGEST_LENGTH * 2 + 3 + strlen(current->filename); - char tmp[entry_size + 1]; + // Entry will be (in ASCII) + ' ' + + '\0' + + int mode_length = 6; + if (current->mode == DIRECTORY) + mode_length = 5; + size_t entry_size = mode_length + 1 + strlen(current->filename) + 1 + DIGEST_LENGTH; + char tmp[entry_size]; + sprintf(tmp, "%o %s", current->mode, current->filename); + memcpy(tmp + entry_size - DIGEST_LENGTH, current->checksum, DIGEST_LENGTH); + object->size = object->size + entry_size; object->content = realloc(object->content, object->size); - sprintf(tmp, "%s %s %s\n", type, current->checksum, current->filename); - strncat(object->content, tmp, entry_size); + memcpy((object->content) + object->size - entry_size, tmp, entry_size); current = current->next; } - object->size --; + return 0; } -int add_object_to_tree(struct tree *tree, char* filename, struct object *source) +int tree_from_object(tree_t *tree, object_t *object) +{ + tree->entries_size = 0; + tree->first_entry = NULL; + tree->last_entry = NULL; + + int i = 0, j = 0; + while (j < object->size) + { + i = j; + entry_t *entry = malloc(sizeof(entry_t)); + + look_for(object->content, ' ', j); + int pot_mode = strtol(object->content + i, NULL, 8); + switch (pot_mode) + { + case DIRECTORY: + entry->type = TREE; + break; + case REG_NONX_FILE: + case REG_EXE_FILE: + case SYM_LINK: + entry->type = BLOB; + case GIT_LINK: + break; + + default: + return INVALID_TREE; + break; + } + entry->mode = (enum file_mode) pot_mode; + + i = j + 1; + look_for(object->content, '\0', j); + if (j - i == 0) + return INVALID_TREE; + entry->filename = malloc(j - i + 1); + memcpy(entry->filename, object->content + i, j - i + 1); + + i = j + 1; + entry->checksum = malloc(DIGEST_LENGTH); + memcpy(entry->checksum, object->content + i, DIGEST_LENGTH); + j += DIGEST_LENGTH + 1; + + entry->previous = tree->last_entry; + entry->next = NULL; + + if(tree->last_entry == NULL) + { + tree->first_entry = entry; + } else + { + entry->previous->next = entry; + } + tree->last_entry = entry; + tree->entries_size ++; + + } + + return 0; +} + +int add_object_to_tree(tree_t *tree, char* filename, enum file_mode mode, object_t *source) { char top_folder_name[strlen(filename)]; char path_left[strlen(filename)]; int res = get_top_folder(filename, top_folder_name, path_left); if (res > 0) { - struct tree subtree = {0}; - struct object result = {0}; + tree_t subtree = {0}; + object_t result = {0}; result.object_type = TREE; - struct entry *top_folder = find_entry(tree, top_folder_name); + entry_t *top_folder = find_entry(tree, top_folder_name); if(top_folder != NULL) { - load_tree(top_folder->checksum, &subtree); - remove_from_index(tree, top_folder->filename, 0); + char checksum[DIGEST_LENGTH * 2 + 1]; + hash_to_hexa(top_folder->checksum, checksum); + load_tree(checksum, &subtree); + remove_from_tree(tree, top_folder->filename, 0); } - add_to_tree(&subtree, source, path_left); + add_to_tree(&subtree, source, path_left, mode); - add_object_to_tree(&subtree, path_left, source); + add_object_to_tree(&subtree, path_left, mode, source); tree_to_object(&subtree, &result); write_object(&result); - remove_from_index(tree, filename, 0); - add_to_tree(tree, &result, top_folder_name); + remove_from_tree(tree, filename, 0); + add_to_tree(tree, &result, top_folder_name, DIRECTORY); free_object(&result); free_tree(&subtree); } else { - add_to_tree(tree, source, filename); + add_to_tree(tree, source, filename, mode); write_object(source); } } diff --git a/src/tree.h b/src/tree.h index 3037c08..31b07de 100644 --- a/src/tree.h +++ b/src/tree.h @@ -4,18 +4,21 @@ #include #include "types.h" +#define INVALID_TREE (-1) + // Index file should follow the format // number of entries\n // entry1\n // entry2\n // ... -void free_tree(struct tree *index); -struct entry *find_entry(struct tree *index, char* filename); -void get_tree(char* content, struct tree *tree); -int add_to_index(struct tree *index, char *filename); -int remove_from_index(struct tree *index, char *filename, int delete); -int tree_to_object(struct tree *tree, struct object *object); -int add_object_to_tree(struct tree *tree, char* filename, struct object *source); +void free_tree(tree_t *index); +entry_t *find_entry(tree_t *index, char* filename); +void index_from_content(char* content, tree_t *tree); +int add_to_index(tree_t *index, char *filename, enum file_mode mode); +int remove_from_tree(tree_t *index, char *filename, int delete); +int tree_to_object(tree_t *tree, object_t *object); +int tree_from_object(tree_t *tree, object_t *object); +int add_object_to_tree(tree_t *tree, char* filename, enum file_mode mode, object_t *source); #endif // INDEX_H \ No newline at end of file diff --git a/src/types.h b/src/types.h index f2cf3ce..cfb855c 100644 --- a/src/types.h +++ b/src/types.h @@ -10,33 +10,46 @@ enum object_type COMMIT }; -struct object +typedef struct object { char* content; size_t size; enum object_type object_type; +} object_t; + +enum file_mode +{ + DIRECTORY = 0040000, + REG_NONX_FILE = 0100644, + REG_EXE_FILE = 0100755, + SYM_LINK = 0120000, + GIT_LINK = 0160000, }; -struct entry { - char *checksum; +/// @brief entry of a tree +/// checksum is an array of size DIGEST_LENGTH +/// filename is a C-string +typedef struct entry { + enum file_mode mode; + unsigned char *checksum; char *filename; enum object_type type; struct entry *previous; struct entry *next; -}; +} entry_t; -struct tree { +typedef struct tree { size_t entries_size; struct entry *first_entry; struct entry *last_entry; -}; +} tree_t; -struct commit +typedef struct commit { char *tree; char *parent; char *author; char *message; -}; +} commit_t; #endif // TYPES_H \ No newline at end of file