diff --git a/src/commit.c b/src/commit.c index c33c812..e54183d 100644 --- a/src/commit.c +++ b/src/commit.c @@ -1,6 +1,8 @@ #include #include #include +#include +#include #include "commit.h" #include "fs.h" @@ -145,4 +147,127 @@ int commit() memset(&index, 0, sizeof(struct tree)); save_index(&index); +} + +int diff_blob(char *filename, struct object *a, struct object *b) +{ + char a_path[7 + strlen(filename)], b_path[7 + strlen(filename)]; + sprintf(a_path, "/tmp/a%s", filename); + sprintf(b_path, "/tmp/b%s", filename); + + tmp_dump(a, a_path); + tmp_dump(b, b_path); + + char cmd[1000]; + FILE *f; + + snprintf(cmd, sizeof(cmd), "diff -u %s %s", a_path, b_path); + f = popen(cmd, "w"); + pclose(f); +} + +int diff_tree(char *cwd, struct tree *tree_a, struct tree *tree_b) +{ + struct entry *current_a = NULL, *current_b = NULL; + if (tree_a == NULL) + current_a = NULL; + else + current_a = tree_a->first_entry; + + if (tree_b == NULL) + current_b = NULL; + else + current_b = tree_b->first_entry; + + while(current_a != NULL || current_b != NULL) + { + int res = 0; + if (current_a == NULL) + { + res = 1; + } else if (current_b == NULL) + { + res = -1; + } else { + res = strcmp(current_a->filename, current_b->filename); + } + size_t cwd_len = 0; + if (*cwd != '\0') + cwd_len = strlen(cwd); + size_t filename_size = cwd_len + 1; + char *filename = calloc(1, filename_size); + strncpy(filename, cwd, filename_size); + struct object a = {0}, b = {0}; + enum object_type type; + if (res == 0) + { + read_object(current_a->checksum, &a); + read_object(current_b->checksum, &b); + if (current_a->type != current_b->type) + return WRONG_OBJECT_TYPE; + filename_size += strlen(current_a->filename) + 1; + filename = realloc(filename, filename_size); + strcat(filename, "/"); + strncat(filename, current_a->filename, strlen(current_a->filename)); + type = current_a->type; + current_a = current_a->next; + current_b = current_b->next; + } else if (res < 0) + { + read_object(current_a->checksum, &a); + filename_size += strlen(current_a->filename) + 1; + filename = realloc(filename, filename_size); + strcat(filename, "/"); + strncat(filename, current_a->filename, strlen(current_a->filename)); + type = current_a->type; + current_a = current_a->next; + } else + { + read_object(current_b->checksum, &b); + filename_size += strlen(current_b->filename) + 1; + filename = realloc(filename, filename_size); + strcat(filename, "/"); + strncat(filename, current_b->filename, strlen(current_b->filename)); + type = current_b->type; + current_b = current_b->next; + } + + if (type == BLOB) + diff_blob(filename, &a, &b); + else if (type == TREE) + { + struct tree subtree_a = {0}, subtree_b = {0}; + if (res <= 0) + get_tree(a.content, &subtree_a); + + if (res >= 0) + get_tree(b.content, &subtree_b); + + init_tmp_diff_dir(filename); + diff_tree(filename, &subtree_a, &subtree_b); + free_tree(&subtree_a); + free_tree(&subtree_b); + } + free(filename); + free_object(&a); + free_object(&b); + } +} + +void diff_commit(struct commit *commit_a, struct commit *commit_b) +{ + struct object tree_obj_a, tree_obj_b; + read_object(commit_a->tree, &tree_obj_a); + read_object(commit_b->tree, &tree_obj_b); + + struct tree tree_a, tree_b; + get_tree(tree_obj_a.content, &tree_a); + get_tree(tree_obj_b.content, &tree_b); + + diff_tree("", &tree_a, &tree_b); + + free_tree(&tree_a); + free_tree(&tree_b); + free_object(&tree_obj_a); + free_object(&tree_obj_b); } \ No newline at end of file diff --git a/src/commit.h b/src/commit.h index aa1fa46..f2ce620 100644 --- a/src/commit.h +++ b/src/commit.h @@ -1,6 +1,11 @@ #ifndef COMMIT_H #define COMMIT_H 1 +#include "types.h" + +int commit_from_object(struct commit *commit, struct object *object); +void free_commit(struct commit *commit); +void diff_commit(struct commit *commit_a, struct commit *commit_b); int commit(); #endif // COMMIT_H \ No newline at end of file diff --git a/src/fs.c b/src/fs.c index ab5257d..2014e55 100644 --- a/src/fs.c +++ b/src/fs.c @@ -193,6 +193,59 @@ defer: return result; } +int create_dir(char *dir) +{ + struct stat buffer = {0}; + int result = FS_OK; + + if(stat(dir, &buffer) == 0) + { + if (!S_ISREG(buffer.st_mode)) + { + result = remove(dir); + if (result != 0) + return FS_ERROR; + } + } else { + result = mkdir(dir, DEFAULT_DIR_MODE); + if (result != 0) + return FS_ERROR; + } +} + +int init_tmp_diff_dir(char* dir) +{ + int dirlen = 0; + if (*dir != '\0') + dirlen = strlen(dir); + char path_a[dirlen + 8], path_b[dirlen + 8]; + sprintf(path_a, "/tmp/a/%s", dir); + sprintf(path_b, "/tmp/b/%s", dir); + + if (create_dir(path_a) != FS_OK) + return FS_ERROR; + if (create_dir(path_b) != FS_OK) + return FS_ERROR; + + + return FS_OK; +} + +int tmp_dump(struct object *obj, char* filename) +{ + if (obj == NULL) + { + open(filename, O_CREAT, 0644); + return FS_OK; + } + + FILE *file = fopen(filename, "w"); + fwrite(obj->content, obj->size, 1, file); + fclose(file); + + return FS_OK; +} + int load_tree(char* checksum, struct tree *tree) { struct object object; @@ -241,7 +294,7 @@ int save_index(struct tree *tree) return REPO_NOT_INITIALIZED; } - FILE *index_file = fopen(INDEX_FILE"_cpy", "w"); + FILE *index_file = fopen(INDEX_FILE, "w"); if(index_exist == NULL) { return FS_ERROR; diff --git a/src/fs.h b/src/fs.h index 2fb6508..28548f2 100644 --- a/src/fs.h +++ b/src/fs.h @@ -9,6 +9,9 @@ #define REFS_DIR LOCAL_REPO"/refs" #define HEADS_DIR REFS_DIR"/heads" #define HEAD_FILE LOCAL_REPO"/HEAD" + +#define TMP "/tmp" + #define DEFAULT_DIR_MODE 0755 #define DEFAULT_FILE_MODE 0444 @@ -34,5 +37,7 @@ int load_index(struct tree *index); int load_tree(char* checksum, struct tree *tree); int update_head(char *new_head); int get_last_commit(struct object *commit); +int tmp_dump(struct object *obj, char* filename); +int init_tmp_diff_dir(char* dir); #endif // FS_H diff --git a/src/main.c b/src/main.c index 8177a9d..2cb0d05 100644 --- a/src/main.c +++ b/src/main.c @@ -5,12 +5,42 @@ // pull/push #include +#include +#include +#include "includes.h" +#include "objects.h" +#include "types.h" #include "fs.h" +#include "tree.h" +#include "commit.h" -int main(int argc, char** argv) { +int main(int argc, char** argv) +{ + struct object a = {0}, b = {0}; + read_object("5568f9722af893d2e6214617eefb62f40c9f8c69", &a); + read_object("4640f65f9340784086a5ddee4e1a46cdc3274424", &b); - + struct commit c_a = {0}, c_b = {0}; + commit_from_object(&c_a, &a); + commit_from_object(&c_b, &b); + + diff_commit(&c_a, &c_b); + + free_commit(&c_a); + free_commit(&c_b); + free_object(&a); + free_object(&b); + + // struct tree index = {0}; + // load_index(&index); + + // add_to_index(&index, "src/commit.c"); + // add_to_index(&index, "src/commit.h"); + + // save_index(&index); + + // commit(); return 0; } \ No newline at end of file diff --git a/src/objects.c b/src/objects.c index 54bd223..561dde3 100644 --- a/src/objects.c +++ b/src/objects.c @@ -17,6 +17,11 @@ char *object_type_str[3] = { "commit", }; +char* object_type_to_str(enum object_type type) +{ + return object_type_str[type]; +} + enum object_type str_to_object_type(char* str) { if(strncmp("tree", str, 4) == 0) diff --git a/src/objects.h b/src/objects.h index 42fe12f..6a2c3c0 100644 --- a/src/objects.h +++ b/src/objects.h @@ -8,6 +8,7 @@ #define HEADER_MAX_SIZE 20 +char* object_type_to_str(enum object_type type); enum object_type str_to_object_type(char* str); size_t object_size(struct object *obj); int full_object(struct object *obj, char* buffer, size_t buffer_size); diff --git a/src/tree.c b/src/tree.c index 4912459..d696083 100644 --- a/src/tree.c +++ b/src/tree.c @@ -55,6 +55,7 @@ void get_tree(char* content, struct tree *tree) 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] != ' ') @@ -62,12 +63,19 @@ void get_tree(char* content, struct tree *tree) 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); - - struct entry *entry = calloc(1, sizeof(struct entry)); entry->checksum = checksum; entry->filename = filename; entry->next = NULL; @@ -98,6 +106,7 @@ int add_to_tree(struct tree *tree, struct object *object, char *filename) free_entry(entry); } + entry->type = object->object_type; entry->filename = calloc(sizeof(char), strlen(filename) + 1); strncat(entry->filename, filename, strlen(filename)); entry->checksum = calloc(sizeof(char), DIGEST_LENGTH * 2 + 1); @@ -153,7 +162,7 @@ int add_to_index(struct tree *index, char *filename) } add_to_tree(index, &object, filename); - + write_object(&object); free_object(&object); return FS_OK; } @@ -203,11 +212,12 @@ int tree_to_object(struct tree *tree, struct object *object) struct entry *current = tree->first_entry; for(int i = 0; i < tree->entries_size; i++) { - size_t entry_size = DIGEST_LENGTH * 2 + 2 + strlen(current->filename); + 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]; object->size = object->size + entry_size; object->content = realloc(object->content, object->size); - sprintf(tmp, "%s %s\n", current->checksum, current->filename); + sprintf(tmp, "%s %s %s\n", type, current->checksum, current->filename); strncat(object->content, tmp, entry_size); current = current->next; } @@ -224,6 +234,7 @@ int add_object_to_tree(struct tree *tree, char* filename, struct object *source) { struct tree subtree = {0}; struct object result = {0}; + result.object_type = TREE; struct entry *top_folder = find_entry(tree, top_folder_name); if(top_folder != NULL) { diff --git a/src/types.h b/src/types.h index 1cb3b98..2f41c6e 100644 --- a/src/types.h +++ b/src/types.h @@ -20,6 +20,7 @@ struct object struct entry { char *checksum; char *filename; + enum object_type type; struct entry *previous; struct entry *next; };