Implement commits
This commit is contained in:
2
Makefile
2
Makefile
@@ -1,7 +1,7 @@
|
|||||||
SRC := $(wildcard src/*.c)
|
SRC := $(wildcard src/*.c)
|
||||||
CFLAGS := -lcrypto -lm -lz
|
CFLAGS := -lcrypto -lm -lz
|
||||||
|
|
||||||
DEBUG = false
|
DEBUG ?= false
|
||||||
ifeq ($(DEBUG), true)
|
ifeq ($(DEBUG), true)
|
||||||
DEBUG_FLAG = -DDEBUG -ggdb
|
DEBUG_FLAG = -DDEBUG -ggdb
|
||||||
endif
|
endif
|
||||||
|
|||||||
12
src/cgit.c
12
src/cgit.c
@@ -1,12 +0,0 @@
|
|||||||
// Requirements
|
|
||||||
// commit
|
|
||||||
// branching
|
|
||||||
// revert
|
|
||||||
// pull/push
|
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
|
|
||||||
int main(int argc, char** argv) {
|
|
||||||
printf("%s", "Hello World!\n");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
148
src/commit.c
Normal file
148
src/commit.c
Normal file
@@ -0,0 +1,148 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "commit.h"
|
||||||
|
#include "fs.h"
|
||||||
|
#include "includes.h"
|
||||||
|
#include "objects.h"
|
||||||
|
#include "tree.h"
|
||||||
|
#include "types.h"
|
||||||
|
|
||||||
|
int commit_from_object(struct commit *commit, struct object *object)
|
||||||
|
{
|
||||||
|
char tmp[object->size + 1];
|
||||||
|
memcpy(tmp, object->content, object->size);
|
||||||
|
tmp[object->size] = '\0';
|
||||||
|
char *current_line = strtok(tmp, "\n");
|
||||||
|
commit->tree = malloc(strlen(current_line) + 1);
|
||||||
|
sprintf(commit->tree, "%s", current_line);
|
||||||
|
|
||||||
|
current_line = strtok(NULL, "\n");
|
||||||
|
commit->parent = malloc(strlen(current_line) + 1);
|
||||||
|
sprintf(commit->parent, "%s", current_line);
|
||||||
|
|
||||||
|
current_line = strtok(NULL, "\n");
|
||||||
|
commit->author = malloc(strlen(current_line) + 1);
|
||||||
|
sprintf(commit->author, "%s", current_line);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int commit_to_object(struct commit *commit, struct object *object)
|
||||||
|
{
|
||||||
|
object->object_type = COMMIT;
|
||||||
|
object->size = strlen(commit->tree) + 2;
|
||||||
|
object->content = malloc(object->size);
|
||||||
|
sprintf(object->content, "%s\n", commit->tree);
|
||||||
|
|
||||||
|
object->size += strlen(commit->parent) + 1;
|
||||||
|
object->content = realloc(object->content, object->size);
|
||||||
|
strncat(object->content, commit->parent, strlen(commit->parent));
|
||||||
|
strcat(object->content, "\n");
|
||||||
|
|
||||||
|
object->size += strlen(commit->author);
|
||||||
|
object->content = realloc(object->content, object->size);
|
||||||
|
strncat(object->content, commit->author, strlen(commit->author));
|
||||||
|
|
||||||
|
object->size --;
|
||||||
|
}
|
||||||
|
|
||||||
|
void free_commit(struct commit *commit)
|
||||||
|
{
|
||||||
|
if (commit->author != NULL)
|
||||||
|
free(commit->author);
|
||||||
|
|
||||||
|
if (commit->parent != NULL)
|
||||||
|
free(commit->parent);
|
||||||
|
|
||||||
|
if (commit->tree != NULL)
|
||||||
|
free(commit->tree);
|
||||||
|
}
|
||||||
|
|
||||||
|
int commit()
|
||||||
|
{
|
||||||
|
struct tree index = {0};
|
||||||
|
load_index(&index);
|
||||||
|
|
||||||
|
struct object last_commit = {0};
|
||||||
|
struct commit commit = {0};
|
||||||
|
char last_commit_checksum[DIGEST_LENGTH * 2 + 1] = {0};
|
||||||
|
struct tree commit_tree = {0};
|
||||||
|
get_last_commit(&last_commit);
|
||||||
|
if (last_commit.size != 0) {
|
||||||
|
hash_object(&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);
|
||||||
|
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);
|
||||||
|
|
||||||
|
free_object(&object);
|
||||||
|
current = current->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (commit.author == NULL)
|
||||||
|
{
|
||||||
|
char* author = "Antonin";
|
||||||
|
commit.author = malloc(strlen(author) + 1);
|
||||||
|
sprintf(commit.author, "%s", author);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
commit.parent = realloc(commit.parent, DIGEST_LENGTH * 2 + 1);
|
||||||
|
if (last_commit.size == 0)
|
||||||
|
{
|
||||||
|
sprintf(commit.parent, "%s", " ");
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
sprintf(commit.parent, "%s", last_commit_checksum);
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
write_object(&commit_tree_obj);
|
||||||
|
|
||||||
|
if(commit.tree != NULL)
|
||||||
|
{
|
||||||
|
free(commit.tree);
|
||||||
|
}
|
||||||
|
commit.tree = commit_tree_checksum;
|
||||||
|
|
||||||
|
debug_print("Author: %s", commit.author);
|
||||||
|
debug_print("Parent: %s", commit.parent);
|
||||||
|
debug_print("Tree: %s", commit.tree);
|
||||||
|
|
||||||
|
struct object commit_obj = {0};
|
||||||
|
commit_to_object(&commit, &commit_obj);
|
||||||
|
write_object(&commit_obj);
|
||||||
|
char commit_checksum[DIGEST_LENGTH * 2 + 1];
|
||||||
|
hash_object(&commit_obj, commit_checksum);
|
||||||
|
|
||||||
|
update_head(commit_checksum);
|
||||||
|
|
||||||
|
free_commit(&commit);
|
||||||
|
free_object(&commit_obj);
|
||||||
|
free_tree(&commit_tree);
|
||||||
|
free_object(&commit_tree_obj);
|
||||||
|
free_tree(&index);
|
||||||
|
|
||||||
|
memset(&index, 0, sizeof(struct tree));
|
||||||
|
save_index(&index);
|
||||||
|
}
|
||||||
6
src/commit.h
Normal file
6
src/commit.h
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
#ifndef COMMIT_H
|
||||||
|
#define COMMIT_H 1
|
||||||
|
|
||||||
|
int commit();
|
||||||
|
|
||||||
|
#endif // COMMIT_H
|
||||||
268
src/fs.c
268
src/fs.c
@@ -11,7 +11,7 @@
|
|||||||
|
|
||||||
#include "fs.h"
|
#include "fs.h"
|
||||||
#include "includes.h"
|
#include "includes.h"
|
||||||
#include "index.h"
|
#include "tree.h"
|
||||||
#include "objects.h"
|
#include "objects.h"
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
|
|
||||||
@@ -27,99 +27,41 @@ int index_exist()
|
|||||||
return stat(INDEX_FILE, &buffer) == 0;
|
return stat(INDEX_FILE, &buffer) == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void dump_index(struct index *index)
|
int heads_dir_exist()
|
||||||
{
|
{
|
||||||
printf("index:\n");
|
struct stat buffer;
|
||||||
printf("\tentries_size: %ld\n", index->entries_size);
|
return stat(HEADS_DIR, &buffer) == 0;
|
||||||
printf("\tentries:\n");
|
|
||||||
struct entry *current = index->first_entry;
|
|
||||||
for(int i = 0; i < index->entries_size; i ++)
|
|
||||||
{
|
|
||||||
printf("\t\tfilename: %s, checksum: %s\n", current->filename, current->checksum);
|
|
||||||
current = current->next;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int load_index(struct index *index)
|
int head_file_exist(size_t *head_size)
|
||||||
{
|
{
|
||||||
if(!local_repo_exist() || !index_exist())
|
|
||||||
{
|
|
||||||
return REPO_NOT_INITIALIZED;
|
|
||||||
}
|
|
||||||
|
|
||||||
FILE* index_file = fopen(INDEX_FILE, "r");
|
|
||||||
struct stat buffer;
|
struct stat buffer;
|
||||||
stat(INDEX_FILE, &buffer);
|
int result = stat(HEAD_FILE, &buffer) == 0;
|
||||||
|
*head_size = buffer.st_size;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
char* file_content = calloc(sizeof(char), buffer.st_size + 1);
|
int blob_from_file(char *filename, struct object *object)
|
||||||
fread(file_content, buffer.st_size, 1, index_file);
|
{
|
||||||
fclose(index_file);
|
FILE* file = fopen(filename, "r");
|
||||||
|
if (file == NULL) {
|
||||||
char* current_line;
|
error_print("File %s not found", filename);
|
||||||
current_line = strtok(file_content, "\n");
|
return FILE_NOT_FOUND;
|
||||||
index->entries_size = strtol(current_line, NULL, 10);
|
|
||||||
|
|
||||||
for(int i = 0; i < index->entries_size; i++)
|
|
||||||
{
|
|
||||||
current_line = strtok(NULL, "\n");
|
|
||||||
int j = 0;
|
|
||||||
while(current_line[j] != ' ')
|
|
||||||
{
|
|
||||||
j++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
char* checksum = calloc(sizeof(char), j + 1);
|
struct stat file_info;
|
||||||
char* filename = calloc(sizeof(char), strlen(current_line) - j);
|
if (stat(filename, &file_info) != 0)
|
||||||
strncat(checksum, current_line, j);
|
return -1;
|
||||||
strncat(filename, current_line + j + 1, strlen(current_line) - j);
|
|
||||||
|
|
||||||
struct entry *entry = malloc(sizeof(struct entry));
|
object->object_type = str_to_object_type("blob");
|
||||||
entry->checksum = checksum;
|
object->size = file_info.st_size;
|
||||||
entry->filename = filename;
|
object->content = realloc(object->content, object->size);
|
||||||
entry->next = NULL;
|
fread(object->content, 1, object->size, file);
|
||||||
|
fclose(file);
|
||||||
if(i == 0)
|
|
||||||
{
|
|
||||||
index->first_entry = entry;
|
|
||||||
} else
|
|
||||||
{
|
|
||||||
entry->previous = index->last_entry;
|
|
||||||
index->last_entry->next = entry;
|
|
||||||
}
|
|
||||||
index->last_entry = entry;
|
|
||||||
debug_print("checksum: %s, filename: %s", entry->checksum, entry->filename);
|
|
||||||
}
|
|
||||||
|
|
||||||
free(file_content);
|
|
||||||
|
|
||||||
return FS_OK;
|
return FS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
int save_index(struct index *index)
|
|
||||||
{
|
|
||||||
if(!local_repo_exist())
|
|
||||||
{
|
|
||||||
return REPO_NOT_INITIALIZED;
|
|
||||||
}
|
|
||||||
|
|
||||||
FILE *index_file = fopen(INDEX_FILE, "w");
|
|
||||||
if(index_exist == NULL)
|
|
||||||
{
|
|
||||||
return FS_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
fprintf(index_file, "%li\n", index->entries_size);
|
|
||||||
|
|
||||||
struct entry *current = index->first_entry;
|
|
||||||
for(int i = 0; i < index->entries_size; i++)
|
|
||||||
{
|
|
||||||
fprintf(index_file, "%s %s\n", current->checksum, current->filename);
|
|
||||||
current = current->next;
|
|
||||||
}
|
|
||||||
|
|
||||||
fclose(index_file);
|
|
||||||
}
|
|
||||||
|
|
||||||
int write_object(struct object *obj)
|
int write_object(struct object *obj)
|
||||||
{
|
{
|
||||||
if(!local_repo_exist())
|
if(!local_repo_exist())
|
||||||
@@ -129,12 +71,12 @@ int write_object(struct object *obj)
|
|||||||
int result = FS_OK;
|
int result = FS_OK;
|
||||||
|
|
||||||
struct stat buffer;
|
struct stat buffer;
|
||||||
if (stat(OBJECTS_REPO, &buffer) != 0)
|
if (stat(OBJECTS_DIR, &buffer) != 0)
|
||||||
{
|
{
|
||||||
mkdir(OBJECTS_REPO, DEFAULT_DIR_MODE);
|
mkdir(OBJECTS_DIR, DEFAULT_DIR_MODE);
|
||||||
}
|
}
|
||||||
|
|
||||||
DIR *objects_dir = opendir(OBJECTS_REPO);
|
DIR *objects_dir = opendir(OBJECTS_DIR);
|
||||||
int objects_dir_fd = dirfd(objects_dir);
|
int objects_dir_fd = dirfd(objects_dir);
|
||||||
|
|
||||||
char checksum[DIGEST_LENGTH * 2];
|
char checksum[DIGEST_LENGTH * 2];
|
||||||
@@ -178,15 +120,17 @@ int read_object(char *checksum, struct object *obj)
|
|||||||
int result = FS_OK;
|
int result = FS_OK;
|
||||||
|
|
||||||
struct stat buffer;
|
struct stat buffer;
|
||||||
if (stat(OBJECTS_REPO, &buffer) != 0)
|
if (stat(OBJECTS_DIR, &buffer) != 0)
|
||||||
{
|
{
|
||||||
error_print("Object dir does not exist");
|
error_print("Object dir does not exist");
|
||||||
return OBJECT_DOES_NOT_EXIST;
|
return OBJECT_DOES_NOT_EXIST;
|
||||||
}
|
}
|
||||||
|
|
||||||
DIR *objects_dir = opendir(OBJECTS_REPO);
|
DIR *objects_dir = opendir(OBJECTS_DIR);
|
||||||
int objects_dir_fd = dirfd(objects_dir);
|
int objects_dir_fd = dirfd(objects_dir);
|
||||||
|
|
||||||
|
fstatat(objects_dir_fd, checksum, &buffer, 0);
|
||||||
|
char file_content[buffer.st_size];
|
||||||
int save_file_fd = openat(objects_dir_fd, checksum, O_RDONLY, DEFAULT_FILE_MODE);
|
int save_file_fd = openat(objects_dir_fd, checksum, O_RDONLY, DEFAULT_FILE_MODE);
|
||||||
if (save_file_fd == -1)
|
if (save_file_fd == -1)
|
||||||
{
|
{
|
||||||
@@ -195,55 +139,141 @@ int read_object(char *checksum, struct object *obj)
|
|||||||
error_print("Object %s does not exist", checksum);
|
error_print("Object %s does not exist", checksum);
|
||||||
defer(OBJECT_DOES_NOT_EXIST);
|
defer(OBJECT_DOES_NOT_EXIST);
|
||||||
}
|
}
|
||||||
|
error_print("Cannot open file %s", checksum);
|
||||||
defer(FS_ERROR);
|
defer(FS_ERROR);
|
||||||
}
|
}
|
||||||
fstatat(objects_dir_fd, checksum, &buffer, 0);
|
|
||||||
char* file_content = malloc(buffer.st_size);
|
|
||||||
|
|
||||||
FILE *save_file = fdopen(save_file_fd, "r");
|
FILE *save_file = fdopen(save_file_fd, "r");
|
||||||
fread(file_content, 1, buffer.st_size, save_file);
|
fread(file_content, 1, buffer.st_size, save_file);
|
||||||
fclose(save_file);
|
fclose(save_file);
|
||||||
|
|
||||||
int res = uncompress_object(obj, file_content, buffer.st_size);
|
result = uncompress_object(obj, file_content, buffer.st_size);
|
||||||
if(res != Z_OK)
|
|
||||||
{
|
|
||||||
defer(COMPRESSION_ERROR);
|
|
||||||
}
|
|
||||||
|
|
||||||
free(file_content);
|
|
||||||
|
|
||||||
defer:
|
defer:
|
||||||
closedir(objects_dir);
|
closedir(objects_dir);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(void)
|
int load_tree(char* checksum, struct tree *tree)
|
||||||
{
|
{
|
||||||
struct index index = {0};
|
struct object object;
|
||||||
load_index(&index);
|
int res = read_object(checksum, &object);
|
||||||
|
if (res != FS_OK)
|
||||||
|
return res;
|
||||||
|
|
||||||
// struct object obj = {0};
|
if (object.object_type != TREE)
|
||||||
// obj.content = "Hello, world!\n";
|
{
|
||||||
// obj.size = strlen(obj.content);
|
error_print("Object %s is not a tree", checksum);
|
||||||
// obj.object_type = "blob";
|
return WRONG_OBJECT_TYPE;
|
||||||
|
}
|
||||||
|
|
||||||
// return write_object(&obj);
|
get_tree(object.content, tree);
|
||||||
|
free_object(&object);
|
||||||
// read_object("af5626b4a114abcb82d63db7c8082c3c4756e51b", &obj);
|
|
||||||
|
|
||||||
// debug_print("Object type is \"%s\"", obj.object_type);
|
|
||||||
// debug_print("Content size is %li", obj.size);
|
|
||||||
// debug_print("Content is %.*s", (int)obj.size, obj.content);
|
|
||||||
|
|
||||||
// free_object(&obj);
|
|
||||||
|
|
||||||
add_to_index(&index, "src/fs.c");
|
|
||||||
|
|
||||||
dump_index(&index);
|
|
||||||
|
|
||||||
save_index(&index);
|
|
||||||
|
|
||||||
free_index(&index);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int load_index(struct tree *index)
|
||||||
|
{
|
||||||
|
if(!local_repo_exist() || !index_exist())
|
||||||
|
{
|
||||||
|
return REPO_NOT_INITIALIZED;
|
||||||
|
}
|
||||||
|
|
||||||
|
FILE* index_file = fopen(INDEX_FILE, "r");
|
||||||
|
struct stat buffer;
|
||||||
|
stat(INDEX_FILE, &buffer);
|
||||||
|
|
||||||
|
char* file_content = calloc(buffer.st_size + 1, sizeof(char));
|
||||||
|
fread(file_content, buffer.st_size, 1, index_file);
|
||||||
|
fclose(index_file);
|
||||||
|
|
||||||
|
get_tree(file_content, index);
|
||||||
|
|
||||||
|
free(file_content);
|
||||||
|
|
||||||
|
return FS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int save_index(struct tree *tree)
|
||||||
|
{
|
||||||
|
if(!local_repo_exist())
|
||||||
|
{
|
||||||
|
return REPO_NOT_INITIALIZED;
|
||||||
|
}
|
||||||
|
|
||||||
|
FILE *index_file = fopen(INDEX_FILE"_cpy", "w");
|
||||||
|
if(index_exist == NULL)
|
||||||
|
{
|
||||||
|
return FS_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct object object;
|
||||||
|
tree_to_object(tree, &object);
|
||||||
|
|
||||||
|
fwrite(object.content, object.size, 1, index_file);
|
||||||
|
fclose(index_file);
|
||||||
|
free_object(&object);
|
||||||
|
}
|
||||||
|
|
||||||
|
int get_last_commit(struct object *commit)
|
||||||
|
{
|
||||||
|
size_t head_size = 0;
|
||||||
|
if(!local_repo_exist() || !head_file_exist(&head_size) || !heads_dir_exist)
|
||||||
|
{
|
||||||
|
return REPO_NOT_INITIALIZED;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(head_size == 0) return 0;
|
||||||
|
|
||||||
|
FILE *head_file = NULL;
|
||||||
|
head_file = fopen(HEAD_FILE, "r");
|
||||||
|
char head_path[head_size];
|
||||||
|
fread(head_path, head_size, 1, head_file);
|
||||||
|
fclose(head_file);
|
||||||
|
|
||||||
|
struct stat buffer = {0};
|
||||||
|
if (stat(head_path, &buffer) != 0) return 0;
|
||||||
|
|
||||||
|
char commit_checksum[buffer.st_size + 1];
|
||||||
|
memset(commit_checksum, 0, buffer.st_size + 1);
|
||||||
|
head_file = fopen(head_path, "r");
|
||||||
|
fread(commit_checksum, buffer.st_size, 1, head_file);
|
||||||
|
fclose(head_file);
|
||||||
|
|
||||||
|
int res = read_object(commit_checksum, commit);
|
||||||
|
if (res != 0) return FS_ERROR;
|
||||||
|
|
||||||
|
if (commit->object_type != COMMIT) return WRONG_OBJECT_TYPE;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int update_head(char *new_head)
|
||||||
|
{
|
||||||
|
size_t head_size = 0;
|
||||||
|
if(!local_repo_exist() || !head_file_exist(&head_size) || !heads_dir_exist)
|
||||||
|
{
|
||||||
|
return REPO_NOT_INITIALIZED;
|
||||||
|
}
|
||||||
|
|
||||||
|
FILE *file;
|
||||||
|
|
||||||
|
if(head_size != 0) {
|
||||||
|
FILE *head_file = fopen(HEAD_FILE, "r");
|
||||||
|
char branch[head_size];
|
||||||
|
fread(branch, head_size, 1, head_file);
|
||||||
|
fclose(head_file);
|
||||||
|
file = fopen(branch, "w");
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
FILE *head_file = fopen(HEAD_FILE, "w");
|
||||||
|
fprintf(head_file, "%s/master", HEADS_DIR);
|
||||||
|
fclose(head_file);
|
||||||
|
file = fopen(HEADS_DIR"/master", "w");
|
||||||
|
}
|
||||||
|
|
||||||
|
fwrite(new_head, strlen(new_head), 1, file);
|
||||||
|
fclose(file);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
18
src/fs.h
18
src/fs.h
@@ -1,11 +1,14 @@
|
|||||||
#ifndef FS_H
|
#ifndef FS_H
|
||||||
#define FS_H 1
|
#define FS_H 1
|
||||||
|
|
||||||
#include "objects.h"
|
#include "types.h"
|
||||||
|
|
||||||
#define LOCAL_REPO ".cgit"
|
#define LOCAL_REPO ".cgit"
|
||||||
#define INDEX_FILE LOCAL_REPO"/index"
|
#define INDEX_FILE LOCAL_REPO"/index"
|
||||||
#define OBJECTS_REPO LOCAL_REPO"/objects"
|
#define OBJECTS_DIR LOCAL_REPO"/objects"
|
||||||
|
#define REFS_DIR LOCAL_REPO"/refs"
|
||||||
|
#define HEADS_DIR REFS_DIR"/heads"
|
||||||
|
#define HEAD_FILE LOCAL_REPO"/HEAD"
|
||||||
#define DEFAULT_DIR_MODE 0755
|
#define DEFAULT_DIR_MODE 0755
|
||||||
#define DEFAULT_FILE_MODE 0444
|
#define DEFAULT_FILE_MODE 0444
|
||||||
|
|
||||||
@@ -15,13 +18,20 @@
|
|||||||
#define REPO_NOT_INITIALIZED (-10)
|
#define REPO_NOT_INITIALIZED (-10)
|
||||||
#define OBJECT_ALREADY_EXIST (-20)
|
#define OBJECT_ALREADY_EXIST (-20)
|
||||||
#define OBJECT_DOES_NOT_EXIST (-21)
|
#define OBJECT_DOES_NOT_EXIST (-21)
|
||||||
#define FILE_NOT_FOUND (-22)
|
#define WRONG_OBJECT_TYPE (-22)
|
||||||
#define ENTRY_NOT_FOUND (-23)
|
#define FILE_NOT_FOUND (-30)
|
||||||
|
#define ENTRY_NOT_FOUND (-31)
|
||||||
|
|
||||||
int local_repo_exist();
|
int local_repo_exist();
|
||||||
int index_exist();
|
int index_exist();
|
||||||
|
|
||||||
|
int blob_from_file(char *filename, struct object *object);
|
||||||
int write_object(struct object *obj);
|
int write_object(struct object *obj);
|
||||||
int read_object(char *checksum, struct object *obj);
|
int read_object(char *checksum, struct object *obj);
|
||||||
|
int save_index(struct tree *tree);
|
||||||
|
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);
|
||||||
|
|
||||||
#endif // FS_H
|
#endif // FS_H
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
#ifndef INCLUDES_H
|
#ifndef INCLUDES_H
|
||||||
#define INCLUDES_H
|
#define INCLUDES_H
|
||||||
|
|
||||||
|
#define DIGEST_LENGTH 20
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
#define debug_print(X, ...) \
|
#define debug_print(X, ...) \
|
||||||
printf("[DEBUG] %s:%d: ", __FILE__, __LINE__); \
|
printf("[DEBUG] %s:%d: ", __FILE__, __LINE__); \
|
||||||
|
|||||||
133
src/index.c
133
src/index.c
@@ -1,133 +0,0 @@
|
|||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
#include "index.h"
|
|
||||||
#include "includes.h"
|
|
||||||
#include "fs.h"
|
|
||||||
|
|
||||||
void free_entry(struct entry *entry)
|
|
||||||
{
|
|
||||||
if (entry->checksum != NULL)
|
|
||||||
free(entry->checksum);
|
|
||||||
|
|
||||||
if (entry->filename != NULL)
|
|
||||||
free(entry->filename);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void free_index(struct index *index)
|
|
||||||
{
|
|
||||||
struct entry *current = index->first_entry;
|
|
||||||
struct entry *next;
|
|
||||||
while(current != NULL)
|
|
||||||
{
|
|
||||||
free_entry(current);
|
|
||||||
next = current->next;
|
|
||||||
free(current);
|
|
||||||
current = next;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct entry *find_entry(struct index *index, char* filename)
|
|
||||||
{
|
|
||||||
struct entry *current = index->first_entry;
|
|
||||||
for (int i = 0; i < index->entries_size; i ++)
|
|
||||||
{
|
|
||||||
if (strncmp(filename, current->filename, strlen(filename)) == 0) {
|
|
||||||
return current;
|
|
||||||
}
|
|
||||||
current = current->next;
|
|
||||||
}
|
|
||||||
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
int add_to_index(struct index *index, char *filename)
|
|
||||||
{
|
|
||||||
if(!local_repo_exist() || !index_exist())
|
|
||||||
{
|
|
||||||
return REPO_NOT_INITIALIZED;
|
|
||||||
}
|
|
||||||
|
|
||||||
int result = FS_OK;
|
|
||||||
int new = 0;
|
|
||||||
|
|
||||||
struct entry *entry = find_entry(index, filename);
|
|
||||||
if (entry == NULL)
|
|
||||||
{
|
|
||||||
new = 1;
|
|
||||||
entry = calloc(sizeof(struct entry), 1);
|
|
||||||
} else {
|
|
||||||
free_entry(entry);
|
|
||||||
}
|
|
||||||
|
|
||||||
struct object object = {0};
|
|
||||||
if (blob_from_file(filename, &object) != 0)
|
|
||||||
{
|
|
||||||
return FILE_NOT_FOUND;
|
|
||||||
}
|
|
||||||
|
|
||||||
entry->filename = calloc(sizeof(char), strlen(filename) + 1);
|
|
||||||
strncat(entry->filename, filename, strlen(filename));
|
|
||||||
entry->checksum = calloc(sizeof(char), DIGEST_LENGTH * 2 + 1);
|
|
||||||
hash_object(&object, entry->checksum);
|
|
||||||
int res = write_object(&object);
|
|
||||||
if (res != FS_OK && res != OBJECT_ALREADY_EXIST)
|
|
||||||
{
|
|
||||||
defer(FS_ERROR);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(new)
|
|
||||||
{
|
|
||||||
if(index->entries_size == 0)
|
|
||||||
{
|
|
||||||
index->first_entry = entry;
|
|
||||||
index->last_entry = entry;
|
|
||||||
} else
|
|
||||||
{
|
|
||||||
entry->previous = index->last_entry;
|
|
||||||
index->last_entry->next = entry;
|
|
||||||
index->last_entry = entry;
|
|
||||||
}
|
|
||||||
index->entries_size = index->entries_size + 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
defer:
|
|
||||||
free_object(&object);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
int remove_from_index(struct index *index, char *filename)
|
|
||||||
{
|
|
||||||
if (!local_repo_exist() || !index_exist())
|
|
||||||
{
|
|
||||||
return REPO_NOT_INITIALIZED;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct entry *entry = find_entry(index, filename);
|
|
||||||
if (entry == NULL)
|
|
||||||
{
|
|
||||||
return ENTRY_NOT_FOUND;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(index->first_entry == entry)
|
|
||||||
{
|
|
||||||
index->first_entry = entry->next;
|
|
||||||
} else
|
|
||||||
{
|
|
||||||
entry->previous->next = entry->next;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (index->last_entry == entry)
|
|
||||||
{
|
|
||||||
index->last_entry = entry->previous;
|
|
||||||
} else
|
|
||||||
{
|
|
||||||
entry->next->previous = entry->previous;
|
|
||||||
}
|
|
||||||
|
|
||||||
index->entries_size = index->entries_size - 1;
|
|
||||||
free_entry(entry);
|
|
||||||
free(entry);
|
|
||||||
return FS_OK;
|
|
||||||
}
|
|
||||||
28
src/index.h
28
src/index.h
@@ -1,28 +0,0 @@
|
|||||||
#ifndef INDEX_H
|
|
||||||
#define INDEX_H
|
|
||||||
|
|
||||||
#include <stddef.h>
|
|
||||||
|
|
||||||
// Index file should follow the format
|
|
||||||
// number of entries\n
|
|
||||||
// entry1\n
|
|
||||||
// entry2\n
|
|
||||||
// ...
|
|
||||||
struct entry {
|
|
||||||
char *checksum;
|
|
||||||
char *filename;
|
|
||||||
struct entry *previous;
|
|
||||||
struct entry *next;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct index {
|
|
||||||
size_t entries_size;
|
|
||||||
struct entry *first_entry;
|
|
||||||
struct entry *last_entry;
|
|
||||||
};
|
|
||||||
|
|
||||||
void free_index(struct index *index);
|
|
||||||
int add_to_index(struct index *index, char *filename);
|
|
||||||
int remove_from_index(struct index *index, char *filename);
|
|
||||||
|
|
||||||
#endif // INDEX_H
|
|
||||||
37
src/main.c
Normal file
37
src/main.c
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
// Requirements
|
||||||
|
// commit
|
||||||
|
// branching
|
||||||
|
// revert
|
||||||
|
// pull/push
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include "commit.h"
|
||||||
|
|
||||||
|
int main(int argc, char** argv) {
|
||||||
|
// struct object obj = {0};
|
||||||
|
// obj.content = "Hello, world!\n";
|
||||||
|
// obj.size = strlen(obj.content);
|
||||||
|
// obj.object_type = "blob";
|
||||||
|
|
||||||
|
// return write_object(&obj);
|
||||||
|
|
||||||
|
// read_object("af5626b4a114abcb82d63db7c8082c3c4756e51b", &obj);
|
||||||
|
|
||||||
|
// debug_print("Object type is \"%s\"", obj.object_type);
|
||||||
|
// debug_print("Content size is %li", obj.size);
|
||||||
|
// debug_print("Content is %.*s", (int)obj.size, obj.content);
|
||||||
|
|
||||||
|
// free_object(&obj);
|
||||||
|
|
||||||
|
// add_to_index(&index, "src/fs.c");
|
||||||
|
// add_to_index(&index, "src/test/foo");
|
||||||
|
// add_to_index(&index, ".gitignore");
|
||||||
|
// add_to_index(&index, "src/fs.h");
|
||||||
|
|
||||||
|
// dump_index(&tree);
|
||||||
|
|
||||||
|
commit();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
@@ -11,9 +11,28 @@
|
|||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
#include "objects.h"
|
#include "objects.h"
|
||||||
|
|
||||||
|
char *object_type_str[3] = {
|
||||||
|
"blob",
|
||||||
|
"tree",
|
||||||
|
"commit",
|
||||||
|
};
|
||||||
|
|
||||||
|
enum object_type str_to_object_type(char* str)
|
||||||
|
{
|
||||||
|
if(strncmp("tree", str, 4) == 0)
|
||||||
|
{
|
||||||
|
return TREE;
|
||||||
|
} else if (strncmp("commit", str, 5) == 0)
|
||||||
|
{
|
||||||
|
return COMMIT;
|
||||||
|
}
|
||||||
|
|
||||||
|
return BLOB;
|
||||||
|
}
|
||||||
|
|
||||||
size_t header_size(struct object *obj)
|
size_t header_size(struct object *obj)
|
||||||
{
|
{
|
||||||
return strlen(obj->object_type) + 2 + decimal_len(obj->size);
|
return strlen(object_type_str[obj->object_type]) + 2 + decimal_len(obj->size);
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t object_size(struct object *obj)
|
size_t object_size(struct object *obj)
|
||||||
@@ -30,8 +49,9 @@ int full_object(struct object *obj, char *buffer, size_t buffer_size)
|
|||||||
assert(data_size <= buffer_size);
|
assert(data_size <= buffer_size);
|
||||||
|
|
||||||
char *writing = buffer;
|
char *writing = buffer;
|
||||||
memcpy(writing, obj->object_type, strlen(obj->object_type));
|
char *type = object_type_str[obj->object_type];
|
||||||
writing += strlen(obj->object_type);
|
memcpy(writing, type, strlen(type));
|
||||||
|
writing += strlen(type);
|
||||||
memcpy(writing, " ", 1);
|
memcpy(writing, " ", 1);
|
||||||
writing ++;
|
writing ++;
|
||||||
memcpy(writing, hr_size, strlen(hr_size));
|
memcpy(writing, hr_size, strlen(hr_size));
|
||||||
@@ -86,8 +106,7 @@ int uncompress_object(struct object *obj, char* compressed, uLongf comp_size)
|
|||||||
char *content_type_tmp = strtok(deflated, " ");
|
char *content_type_tmp = strtok(deflated, " ");
|
||||||
|
|
||||||
obj->size = content_size;
|
obj->size = content_size;
|
||||||
obj->object_type = malloc(strlen(content_type_tmp) + 1);
|
obj->object_type = str_to_object_type(content_type_tmp);
|
||||||
strncpy(obj->object_type, content_type_tmp, strlen(content_type_tmp) + 1);
|
|
||||||
obj->content = malloc(obj->size);
|
obj->content = malloc(obj->size);
|
||||||
memcpy(obj->content, deflated + header_size, obj->size);
|
memcpy(obj->content, deflated + header_size, obj->size);
|
||||||
free(deflated);
|
free(deflated);
|
||||||
@@ -107,25 +126,6 @@ int compress_object(struct object *obj, char* compressed, uLongf *comp_size)
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
int blob_from_file(char *filename, struct object *object)
|
|
||||||
{
|
|
||||||
FILE* file = fopen(filename, "r");
|
|
||||||
if (file == NULL)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
struct stat file_info;
|
|
||||||
if (stat(filename, &file_info) != 0)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
object->object_type = "blob";
|
|
||||||
object->size = file_info.st_size;
|
|
||||||
object->content = realloc(object->content, object->size);
|
|
||||||
fread(object->content, 1, object->size, file);
|
|
||||||
fclose(file);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void free_object(struct object *obj)
|
void free_object(struct object *obj)
|
||||||
{
|
{
|
||||||
if (obj->content != NULL)
|
if (obj->content != NULL)
|
||||||
|
|||||||
@@ -4,22 +4,16 @@
|
|||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <zconf.h>
|
#include <zconf.h>
|
||||||
|
|
||||||
#define DIGEST_LENGTH 20
|
#include "types.h"
|
||||||
|
|
||||||
#define HEADER_MAX_SIZE 20
|
#define HEADER_MAX_SIZE 20
|
||||||
|
|
||||||
struct object
|
enum object_type str_to_object_type(char* str);
|
||||||
{
|
|
||||||
char* content;
|
|
||||||
size_t size;
|
|
||||||
char* object_type;
|
|
||||||
};
|
|
||||||
|
|
||||||
size_t object_size(struct object *obj);
|
size_t object_size(struct object *obj);
|
||||||
int full_object(struct object *obj, char* buffer, size_t buffer_size);
|
int full_object(struct object *obj, char* buffer, size_t buffer_size);
|
||||||
int uncompress_object(struct object *obj, char* compressed, uLongf comp_size);
|
int uncompress_object(struct object *obj, char* compressed, uLongf comp_size);
|
||||||
int compress_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(struct object *obj, char* result);
|
||||||
int blob_from_file(char *filename, struct object *object);
|
|
||||||
void free_object(struct object *obj);
|
void free_object(struct object *obj);
|
||||||
|
|
||||||
#endif // OBJECTS_H
|
#endif // OBJECTS_H
|
||||||
|
|||||||
248
src/tree.c
Normal file
248
src/tree.c
Normal file
@@ -0,0 +1,248 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "tree.h"
|
||||||
|
#include "includes.h"
|
||||||
|
#include "fs.h"
|
||||||
|
#include "objects.h"
|
||||||
|
#include "utils.h"
|
||||||
|
|
||||||
|
void free_entry(struct entry *entry)
|
||||||
|
{
|
||||||
|
if (entry->checksum != NULL)
|
||||||
|
free(entry->checksum);
|
||||||
|
|
||||||
|
if (entry->filename != NULL)
|
||||||
|
free(entry->filename);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void free_tree(struct tree *tree)
|
||||||
|
{
|
||||||
|
struct entry *current = tree->first_entry;
|
||||||
|
struct entry *next;
|
||||||
|
while(current != NULL)
|
||||||
|
{
|
||||||
|
free_entry(current);
|
||||||
|
next = current->next;
|
||||||
|
free(current);
|
||||||
|
current = next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct entry *find_entry(struct tree *tree, char* filename)
|
||||||
|
{
|
||||||
|
struct entry *current = tree->first_entry;
|
||||||
|
for (int i = 0; i < tree->entries_size; ++i)
|
||||||
|
{
|
||||||
|
if (strcmp(filename, current->filename) == 0) {
|
||||||
|
return current;
|
||||||
|
}
|
||||||
|
current = current->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
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++)
|
||||||
|
{
|
||||||
|
current_line = strtok(NULL, "\n");
|
||||||
|
int 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;
|
||||||
|
|
||||||
|
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 new = 0;
|
||||||
|
struct entry *entry = find_entry(tree, filename);
|
||||||
|
if (entry == NULL)
|
||||||
|
{
|
||||||
|
new = 1;
|
||||||
|
entry = calloc(sizeof(struct entry), 1);
|
||||||
|
} else {
|
||||||
|
free_entry(entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
entry->filename = calloc(sizeof(char), strlen(filename) + 1);
|
||||||
|
strncat(entry->filename, filename, strlen(filename));
|
||||||
|
entry->checksum = calloc(sizeof(char), DIGEST_LENGTH * 2 + 1);
|
||||||
|
hash_object(object, entry->checksum);
|
||||||
|
// int res = write_object(object);
|
||||||
|
// if (res != FS_OK && res != OBJECT_ALREADY_EXIST)
|
||||||
|
// {
|
||||||
|
// return res;
|
||||||
|
// }
|
||||||
|
|
||||||
|
if(new)
|
||||||
|
{
|
||||||
|
if (tree->entries_size == 0)
|
||||||
|
{
|
||||||
|
tree->first_entry = entry;
|
||||||
|
tree->last_entry = entry;
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
struct entry *current = tree->first_entry;
|
||||||
|
while (current != NULL && (strncmp(current->filename, entry->filename, strlen(entry->filename)) < 0))
|
||||||
|
{
|
||||||
|
current = current->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (current == NULL)
|
||||||
|
{
|
||||||
|
tree->last_entry->next = entry;
|
||||||
|
entry->previous = tree->last_entry;
|
||||||
|
tree->last_entry = entry;
|
||||||
|
} else {
|
||||||
|
if(current == tree->first_entry)
|
||||||
|
{
|
||||||
|
tree->first_entry = entry;
|
||||||
|
} else {
|
||||||
|
current->previous->next = entry;
|
||||||
|
entry->previous = current->previous;
|
||||||
|
}
|
||||||
|
|
||||||
|
entry->next = current;
|
||||||
|
current->previous = entry;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
tree->entries_size ++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int add_to_index(struct tree *index, char *filename)
|
||||||
|
{
|
||||||
|
struct object object = {0};
|
||||||
|
if (blob_from_file(filename, &object) != FS_OK)
|
||||||
|
{
|
||||||
|
return FILE_NOT_FOUND;
|
||||||
|
}
|
||||||
|
|
||||||
|
add_to_tree(index, &object, filename);
|
||||||
|
|
||||||
|
free_object(&object);
|
||||||
|
return FS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int remove_from_index(struct tree *index, char *filename)
|
||||||
|
{
|
||||||
|
if (!local_repo_exist() || !index_exist())
|
||||||
|
{
|
||||||
|
return REPO_NOT_INITIALIZED;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct entry *entry = find_entry(index, filename);
|
||||||
|
if (entry == NULL)
|
||||||
|
{
|
||||||
|
return ENTRY_NOT_FOUND;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(index->first_entry == entry)
|
||||||
|
{
|
||||||
|
index->first_entry = entry->next;
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
entry->previous->next = entry->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (index->last_entry == entry)
|
||||||
|
{
|
||||||
|
index->last_entry = entry->previous;
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
entry->next->previous = entry->previous;
|
||||||
|
}
|
||||||
|
|
||||||
|
index->entries_size = index->entries_size - 1;
|
||||||
|
free_entry(entry);
|
||||||
|
free(entry);
|
||||||
|
return FS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int tree_to_object(struct tree *tree, struct object *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);
|
||||||
|
|
||||||
|
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 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);
|
||||||
|
strncat(object->content, tmp, entry_size);
|
||||||
|
current = current->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
object->size --;
|
||||||
|
}
|
||||||
|
|
||||||
|
int add_object_to_tree(struct tree *tree, char* filename, struct object *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};
|
||||||
|
struct entry *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);
|
||||||
|
}
|
||||||
|
|
||||||
|
add_to_tree(&subtree, source, path_left);
|
||||||
|
|
||||||
|
add_object_to_tree(&subtree, path_left, source);
|
||||||
|
|
||||||
|
tree_to_object(&subtree, &result);
|
||||||
|
write_object(&result);
|
||||||
|
remove_from_index(tree, filename);
|
||||||
|
add_to_tree(tree, &result, top_folder_name);
|
||||||
|
free_object(&result);
|
||||||
|
free_tree(&subtree);
|
||||||
|
} else {
|
||||||
|
add_to_tree(tree, source, filename);
|
||||||
|
write_object(source);
|
||||||
|
}
|
||||||
|
}
|
||||||
22
src/tree.h
Normal file
22
src/tree.h
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
#ifndef INDEX_H
|
||||||
|
#define INDEX_H
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
#include "types.h"
|
||||||
|
|
||||||
|
// 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_tree(struct tree *tree, struct object *object, char *filename);
|
||||||
|
int add_to_index(struct tree *index, char *filename);
|
||||||
|
int remove_from_index(struct tree *index, char *filename);
|
||||||
|
int tree_to_object(struct tree *tree, struct object *object);
|
||||||
|
int add_object_to_tree(struct tree *tree, char* filename, struct object *source);
|
||||||
|
|
||||||
|
#endif // INDEX_H
|
||||||
40
src/types.h
Normal file
40
src/types.h
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
#ifndef TYPES_H
|
||||||
|
#define TYPES_H 1
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
enum object_type
|
||||||
|
{
|
||||||
|
BLOB,
|
||||||
|
TREE,
|
||||||
|
COMMIT
|
||||||
|
};
|
||||||
|
|
||||||
|
struct object
|
||||||
|
{
|
||||||
|
char* content;
|
||||||
|
size_t size;
|
||||||
|
enum object_type object_type;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct entry {
|
||||||
|
char *checksum;
|
||||||
|
char *filename;
|
||||||
|
struct entry *previous;
|
||||||
|
struct entry *next;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct tree {
|
||||||
|
size_t entries_size;
|
||||||
|
struct entry *first_entry;
|
||||||
|
struct entry *last_entry;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct commit
|
||||||
|
{
|
||||||
|
char *tree;
|
||||||
|
char *parent;
|
||||||
|
char *author;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // TYPES_H
|
||||||
13
src/utils.c
13
src/utils.c
@@ -1,4 +1,5 @@
|
|||||||
#include <math.h>
|
#include <math.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
|
|
||||||
@@ -9,3 +10,15 @@ int decimal_len(size_t size)
|
|||||||
|
|
||||||
return floor(log10(size)) + 1;
|
return floor(log10(size)) + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int get_top_folder(char* path, char* top_folder, char* left)
|
||||||
|
{
|
||||||
|
int i = 0;
|
||||||
|
for (;path[i] != '/' && path[i] != '\0'; i++);
|
||||||
|
if (path[i] == '\0') return 0;
|
||||||
|
path[i] = '\0';
|
||||||
|
sprintf(top_folder, "%s", path);
|
||||||
|
sprintf(left, "%s", path + i + 1);
|
||||||
|
path[i] = '/';
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|||||||
@@ -4,5 +4,6 @@
|
|||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
|
||||||
int decimal_len(size_t size);
|
int decimal_len(size_t size);
|
||||||
|
int get_top_folder(char* path, char* top_folder, char* left);
|
||||||
|
|
||||||
#endif // UTILS_H
|
#endif // UTILS_H
|
||||||
Reference in New Issue
Block a user