From 4b8e27c81e78cb0d8ad941c22a9b40835e0319db Mon Sep 17 00:00:00 2001 From: nulltoken Date: Wed, 15 Dec 2010 18:25:15 +0100 Subject: [PATCH 01/10] Very first git_repository_init() draft. --- src/git2/repository.h | 3 + src/repository.c | 129 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 132 insertions(+) diff --git a/src/git2/repository.h b/src/git2/repository.h index 24b411b64..8a171cf3a 100644 --- a/src/git2/repository.h +++ b/src/git2/repository.h @@ -162,6 +162,9 @@ GIT_EXTERN(int) git_repository_newobject(git_object **object, git_repository *re */ GIT_EXTERN(void) git_repository_free(git_repository *repo); +//TODO: Add comments. +GIT_EXTERN(int) git_repository_init(git_repository** repo_out, const char* path, unsigned is_bare); + /** @} */ GIT_END_DECL #endif diff --git a/src/repository.c b/src/repository.c index 098d09858..3214a5673 100644 --- a/src/repository.c +++ b/src/repository.c @@ -58,6 +58,14 @@ static struct { { "REF_DELTA", 0, 0 } /* 7 = GIT_OBJ_REF_DELTA */ }; +typedef struct git_repository_init_results { + char *path_repository; + char *path_workdir; + + unsigned is_bare:1; + unsigned has_been_reinit:1; +} git_repository_init_results; + /*********************************************************** * * MISCELANEOUS HELPER FUNCTIONS @@ -722,3 +730,124 @@ int git_object_typeisloose(git_otype type) return git_objects_table[type].loose; } + + +void git_repository_init__results_free(git_repository_init_results* init_results) +{ + if (init_results == NULL) + return; + + if (init_results->path_workdir) + free(init_results->path_workdir); + if (init_results->path_repository) + free(init_results->path_repository); + + free(init_results); +} + +git_repository_init_results *git_repository_init_results__alloc() +{ + git_repository_init_results *results = git__malloc(sizeof(git_repository_init_results)); + if (!results) + return NULL; + + memset(results, 0x0, sizeof(git_repository_init_results)); + + return results; +} + +int git_repository_init__reinit(git_repository_init_results* results) +{ + /* To be implemented */ + + results->has_been_reinit = 1; + return GIT_SUCCESS; +} + +int git_repository_init__create_structure(git_repository_init_results* results) +{ + char temp_path[GIT_PATH_MAX]; + int path_len; + + char* git_dir = results->path_repository; + + path_len = strlen(git_dir); + strcpy(temp_path, git_dir); + + /* Does HEAD file already exist ? */ + strcpy(temp_path + path_len, GIT_HEAD_FILE); + if (!gitfo_exists(temp_path)) + { + return git_repository_init__reinit(results); + } + + /* To be implemented */ + + return GIT_SUCCESS; +} + +int git_repository_init__assign_folders(git_repository_init_results* results, const char* path) +{ + const int MAX_GITDIR_TREE_STRUCTURE_PATH_LENGTH = 66; // TODO: How many ? + char temp_path[GIT_PATH_MAX]; + int path_len; + + path_len = strlen(path); + strcpy(temp_path, path); + + /* Ensure path has a trailing slash */ + if (temp_path[path_len - 1] != '/') { + temp_path[path_len] = '/'; + temp_path[path_len + 1] = 0; + + path_len = path_len + 1; + } + + assert(path_len < GIT_PATH_MAX - MAX_GITDIR_TREE_STRUCTURE_PATH_LENGTH); + + if (results->is_bare) + { + results->path_workdir = NULL; + } + else + { + results->path_workdir = git__strdup(temp_path); + strcpy(temp_path + path_len - 1, GIT_FOLDER); + path_len = path_len + strlen(GIT_FOLDER) - 1; /* Skip the leading slash from the constant */ + } + + results->path_repository = git__strdup(temp_path); + + return GIT_SUCCESS; +} + +int git_repository_init(git_repository** repo_out, const char* path, unsigned is_bare) +{ + git_repository_init_results* results; + int error = GIT_SUCCESS; + + assert(repo_out && path); + + results = git_repository_init_results__alloc(); + if (results == NULL) + return GIT_ENOMEM; + + results->is_bare = is_bare; + + error = git_repository_init__assign_folders(results, path); + if (error < GIT_SUCCESS) + goto cleanup; + + error = git_repository_init__create_structure(results); + if (error < GIT_SUCCESS) + goto cleanup; + + //TODO: Uncomment when the structure has been properly created + //error = git_repository_open(repo_out, results->path_repository); + //if (error < GIT_SUCCESS) + // goto cleanup; + +cleanup: + git_repository_init__results_free(results); + return error; +} \ No newline at end of file From 08190e2ad10cf528ec01868cfc66ddd5d6ad228e Mon Sep 17 00:00:00 2001 From: nulltoken Date: Thu, 16 Dec 2010 14:31:24 +0100 Subject: [PATCH 02/10] Simplified git_repository_init_results struct. --- src/repository.c | 35 ++++++++++------------------------- 1 file changed, 10 insertions(+), 25 deletions(-) diff --git a/src/repository.c b/src/repository.c index 3214a5673..2ffac4589 100644 --- a/src/repository.c +++ b/src/repository.c @@ -60,7 +60,6 @@ static struct { typedef struct git_repository_init_results { char *path_repository; - char *path_workdir; unsigned is_bare:1; unsigned has_been_reinit:1; @@ -737,23 +736,16 @@ void git_repository_init__results_free(git_repository_init_results* init_results if (init_results == NULL) return; - if (init_results->path_workdir) - free(init_results->path_workdir); if (init_results->path_repository) free(init_results->path_repository); - - free(init_results); } -git_repository_init_results *git_repository_init_results__alloc() +void git_repository_init__zero_init_results(git_repository_init_results* results) { - git_repository_init_results *results = git__malloc(sizeof(git_repository_init_results)); if (!results) - return NULL; + return; memset(results, 0x0, sizeof(git_repository_init_results)); - - return results; } int git_repository_init__reinit(git_repository_init_results* results) @@ -786,7 +778,7 @@ int git_repository_init__create_structure(git_repository_init_results* results) return GIT_SUCCESS; } -int git_repository_init__assign_folders(git_repository_init_results* results, const char* path) +int git_repository_init__assign_git_directory(git_repository_init_results* results, const char* path) { const int MAX_GITDIR_TREE_STRUCTURE_PATH_LENGTH = 66; // TODO: How many ? char temp_path[GIT_PATH_MAX]; @@ -805,13 +797,8 @@ int git_repository_init__assign_folders(git_repository_init_results* results, co assert(path_len < GIT_PATH_MAX - MAX_GITDIR_TREE_STRUCTURE_PATH_LENGTH); - if (results->is_bare) + if (!results->is_bare) { - results->path_workdir = NULL; - } - else - { - results->path_workdir = git__strdup(temp_path); strcpy(temp_path + path_len - 1, GIT_FOLDER); path_len = path_len + strlen(GIT_FOLDER) - 1; /* Skip the leading slash from the constant */ } @@ -823,22 +810,20 @@ int git_repository_init__assign_folders(git_repository_init_results* results, co int git_repository_init(git_repository** repo_out, const char* path, unsigned is_bare) { - git_repository_init_results* results; + git_repository_init_results results; int error = GIT_SUCCESS; assert(repo_out && path); - results = git_repository_init_results__alloc(); - if (results == NULL) - return GIT_ENOMEM; + git_repository_init__zero_init_results(&results); - results->is_bare = is_bare; + results.is_bare = is_bare; - error = git_repository_init__assign_folders(results, path); + error = git_repository_init__assign_git_directory(&results, path); if (error < GIT_SUCCESS) goto cleanup; - error = git_repository_init__create_structure(results); + error = git_repository_init__create_structure(&results); if (error < GIT_SUCCESS) goto cleanup; @@ -848,6 +833,6 @@ int git_repository_init(git_repository** repo_out, const char* path, unsigned is // goto cleanup; cleanup: - git_repository_init__results_free(results); + git_repository_init__results_free(&results); return error; } \ No newline at end of file From 1a5204a788c63fb50a42430a02c3dc9df727c5f4 Mon Sep 17 00:00:00 2001 From: nulltoken Date: Fri, 17 Dec 2010 10:08:01 +0100 Subject: [PATCH 03/10] Added gitfo_mkdir_recurs() placeholder. --- src/fileops.c | 5 +++++ src/fileops.h | 1 + 2 files changed, 6 insertions(+) diff --git a/src/fileops.c b/src/fileops.c index 0633f9b21..9fe017c93 100644 --- a/src/fileops.c +++ b/src/fileops.c @@ -310,3 +310,8 @@ int gitfo_dirent( closedir(dir); return GIT_SUCCESS; } + +int gitfo_mkdir_recurs(const char *path, int mode) +{ + return gitfo_mkdir(path, mode); +} \ No newline at end of file diff --git a/src/fileops.h b/src/fileops.h index 618bddd5b..6656cdf43 100644 --- a/src/fileops.h +++ b/src/fileops.h @@ -58,6 +58,7 @@ extern int gitfo_exists(const char *path); extern int gitfo_open(const char *path, int flags); extern int gitfo_creat(const char *path, int mode); extern int gitfo_isdir(const char *path); +extern int gitfo_mkdir_recurs(const char *path, int mode); #define gitfo_close(fd) close(fd) extern int gitfo_read(git_file fd, void *buf, size_t cnt); From 58fcfc26e08b9b3ed607e32e5eb2fe8a95a8a19c Mon Sep 17 00:00:00 2001 From: nulltoken Date: Fri, 17 Dec 2010 10:36:58 +0100 Subject: [PATCH 04/10] Removed unnecessary git_repository_init_results handling. --- src/repository.c | 22 +--------------------- 1 file changed, 1 insertion(+), 21 deletions(-) diff --git a/src/repository.c b/src/repository.c index 2ffac4589..6f1445dd6 100644 --- a/src/repository.c +++ b/src/repository.c @@ -730,24 +730,6 @@ int git_object_typeisloose(git_otype type) return git_objects_table[type].loose; } - -void git_repository_init__results_free(git_repository_init_results* init_results) -{ - if (init_results == NULL) - return; - - if (init_results->path_repository) - free(init_results->path_repository); -} - -void git_repository_init__zero_init_results(git_repository_init_results* results) -{ - if (!results) - return; - - memset(results, 0x0, sizeof(git_repository_init_results)); -} - int git_repository_init__reinit(git_repository_init_results* results) { /* To be implemented */ @@ -815,8 +797,6 @@ int git_repository_init(git_repository** repo_out, const char* path, unsigned is assert(repo_out && path); - git_repository_init__zero_init_results(&results); - results.is_bare = is_bare; error = git_repository_init__assign_git_directory(&results, path); @@ -833,6 +813,6 @@ int git_repository_init(git_repository** repo_out, const char* path, unsigned is // goto cleanup; cleanup: - git_repository_init__results_free(&results); + free(results.path_repository); return error; } \ No newline at end of file From a67a096a9efdca1af66abc39c4bc276ebdaa8e47 Mon Sep 17 00:00:00 2001 From: nulltoken Date: Fri, 17 Dec 2010 10:41:56 +0100 Subject: [PATCH 05/10] Added creation of 'objects' and 'refs' directories. --- src/repository.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/repository.c b/src/repository.c index 6f1445dd6..4e5e7e699 100644 --- a/src/repository.c +++ b/src/repository.c @@ -35,6 +35,7 @@ #define GIT_FOLDER "/.git/" #define GIT_OBJECTS_FOLDER "objects/" +#define GIT_REFS_FOLDER "refs/" #define GIT_INDEX_FILE "index" #define GIT_HEAD_FILE "HEAD" @@ -742,9 +743,14 @@ int git_repository_init__create_structure(git_repository_init_results* results) { char temp_path[GIT_PATH_MAX]; int path_len; + const int mode = 0755; /* or 0777 ? */ char* git_dir = results->path_repository; + //TODO : Ensure the parent tree structure already exists by recursively building it through gitfo_mkdir_recurs(). + if (gitfo_mkdir_recurs(git_dir, mode)) + return GIT_ERROR; + path_len = strlen(git_dir); strcpy(temp_path, git_dir); @@ -755,6 +761,15 @@ int git_repository_init__create_structure(git_repository_init_results* results) return git_repository_init__reinit(results); } + strcpy(temp_path + path_len, GIT_OBJECTS_FOLDER); + if (gitfo_mkdir(temp_path, mode)) + return GIT_ERROR; + + strcpy(temp_path + path_len, GIT_REFS_FOLDER); + if (gitfo_mkdir(temp_path, mode)) + return GIT_ERROR; + + /* To be implemented */ return GIT_SUCCESS; From f0b2bfe52743e98e241405008744d39f12e521b3 Mon Sep 17 00:00:00 2001 From: nulltoken Date: Fri, 17 Dec 2010 14:24:47 +0100 Subject: [PATCH 06/10] Made gitfo_mkdir_recurs() more tolerant. Doesn't err any more when the directory already exists. --- src/fileops.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/fileops.c b/src/fileops.c index 9fe017c93..8cdfb0345 100644 --- a/src/fileops.c +++ b/src/fileops.c @@ -313,5 +313,12 @@ int gitfo_dirent( int gitfo_mkdir_recurs(const char *path, int mode) { - return gitfo_mkdir(path, mode); + int error; + + error = gitfo_mkdir(path, mode); + + if (errno == EEXIST) + return GIT_SUCCESS; + + return error; } \ No newline at end of file From e1f8cad0c98693c170bdd741747d07db8adb4367 Mon Sep 17 00:00:00 2001 From: nulltoken Date: Fri, 17 Dec 2010 14:45:02 +0100 Subject: [PATCH 07/10] Added basic HEAD file creation. --- src/git2/repository.h | 19 ++++++++++++++++--- src/repository.c | 40 ++++++++++++++++++++++++++++++++++------ 2 files changed, 50 insertions(+), 9 deletions(-) diff --git a/src/git2/repository.h b/src/git2/repository.h index 8a171cf3a..195a8aa29 100644 --- a/src/git2/repository.h +++ b/src/git2/repository.h @@ -59,7 +59,7 @@ GIT_BEGIN_DECL * * @param repository pointer to the repo which will be opened * @param path the path to the repository - * @return 0 on sucess; error code otherwise + * @return 0 on success; error code otherwise */ GIT_EXTERN(int) git_repository_open(git_repository **repository, const char *path); @@ -88,7 +88,7 @@ GIT_EXTERN(int) git_repository_open(git_repository **repository, const char *pat * Equivalent to $GIT_WORK_TREE. * If NULL, the repository is assumed to be bare. * - * @return 0 on sucess; error code otherwise + * @return 0 on success; error code otherwise */ GIT_EXTERN(int) git_repository_open2(git_repository **repository, const char *git_dir, @@ -162,7 +162,20 @@ GIT_EXTERN(int) git_repository_newobject(git_object **object, git_repository *re */ GIT_EXTERN(void) git_repository_free(git_repository *repo); -//TODO: Add comments. +/** + * Creates a new Git repository. + * + * Limits: + * - Reinit of an existing directory is not implemented yet. Will blindly return GIT_SUCCESS. + * - The parent directory structure of the repository has to already exist. Recursive building of the parent tree structure is not implmented yet. + * - Config file creation handling is not implemented yet. + * + * @param repo_out pointer to the repo which will be created or reinitialized + * @param path the path to the repository + * @param is_bare if true, a Git repository without a working directory is created at the pointed path. + * If false, provided path will be considered as the working directory into which the .git directory will be created. + * @return 0 on success; error code otherwise + */ GIT_EXTERN(int) git_repository_init(git_repository** repo_out, const char* path, unsigned is_bare); /** @} */ diff --git a/src/repository.c b/src/repository.c index 4e5e7e699..df154828f 100644 --- a/src/repository.c +++ b/src/repository.c @@ -739,7 +739,24 @@ int git_repository_init__reinit(git_repository_init_results* results) return GIT_SUCCESS; } -int git_repository_init__create_structure(git_repository_init_results* results) +int git_repository_init__create_head(const char* head_path) +{ + git_file fd; + int error = GIT_SUCCESS; + const char* head_content = "ref: refs/heads/master\n"; + if ((fd = gitfo_creat(head_path, S_IREAD | S_IWRITE)) < 0) + return GIT_ERROR; + + error = gitfo_write(fd, (void*)head_content, strlen(head_content)); + if (error < GIT_SUCCESS) + goto cleanup; + +cleanup: + gitfo_close(fd); + return error; +} + +int git_repository_init__create_structure_or_reinit(git_repository_init_results* results) { char temp_path[GIT_PATH_MAX]; int path_len; @@ -756,15 +773,27 @@ int git_repository_init__create_structure(git_repository_init_results* results) /* Does HEAD file already exist ? */ strcpy(temp_path + path_len, GIT_HEAD_FILE); + + if (!gitfo_exists(temp_path) && gitfo_isdir(temp_path) < GIT_SUCCESS) + { + /* Something very wrong has happened to this repository :-) */ + return GIT_ERROR; + } + if (!gitfo_exists(temp_path)) { return git_repository_init__reinit(results); } + if (git_repository_init__create_head(temp_path) < GIT_SUCCESS) + return GIT_ERROR; + + /* Creates the '/objects/' directory */ strcpy(temp_path + path_len, GIT_OBJECTS_FOLDER); if (gitfo_mkdir(temp_path, mode)) return GIT_ERROR; + /* Creates the '/refs/' directory */ strcpy(temp_path + path_len, GIT_REFS_FOLDER); if (gitfo_mkdir(temp_path, mode)) return GIT_ERROR; @@ -818,14 +847,13 @@ int git_repository_init(git_repository** repo_out, const char* path, unsigned is if (error < GIT_SUCCESS) goto cleanup; - error = git_repository_init__create_structure(&results); + error = git_repository_init__create_structure_or_reinit(&results); if (error < GIT_SUCCESS) goto cleanup; - //TODO: Uncomment when the structure has been properly created - //error = git_repository_open(repo_out, results->path_repository); - //if (error < GIT_SUCCESS) - // goto cleanup; + error = git_repository_open(repo_out, results.path_repository); + if (error < GIT_SUCCESS) + goto cleanup; cleanup: free(results.path_repository); From d13e7e02a8b3fdcfe0e633fcbfc2521f502eb74e Mon Sep 17 00:00:00 2001 From: nulltoken Date: Fri, 17 Dec 2010 15:58:30 +0100 Subject: [PATCH 08/10] Added a comment reminding that the gitfo_mkdir_recurs() is far from being fully implemented. --- src/fileops.c | 1 + src/git2/repository.h | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/fileops.c b/src/fileops.c index 8cdfb0345..97b2f0739 100644 --- a/src/fileops.c +++ b/src/fileops.c @@ -313,6 +313,7 @@ int gitfo_dirent( int gitfo_mkdir_recurs(const char *path, int mode) { + //TODO: Implement recursive building of the parent tree structure (This would have to work on both Linux and Windows). int error; error = gitfo_mkdir(path, mode); diff --git a/src/git2/repository.h b/src/git2/repository.h index 195a8aa29..4c7ba8ded 100644 --- a/src/git2/repository.h +++ b/src/git2/repository.h @@ -167,7 +167,7 @@ GIT_EXTERN(void) git_repository_free(git_repository *repo); * * Limits: * - Reinit of an existing directory is not implemented yet. Will blindly return GIT_SUCCESS. - * - The parent directory structure of the repository has to already exist. Recursive building of the parent tree structure is not implmented yet. + * - The parent directory structure of the repository has to already exist. Recursive building of the parent tree structure is not implemented yet. * - Config file creation handling is not implemented yet. * * @param repo_out pointer to the repo which will be created or reinitialized From 2899093835b3aac641e594f717142fcce065c479 Mon Sep 17 00:00:00 2001 From: nulltoken Date: Fri, 17 Dec 2010 20:03:20 +0100 Subject: [PATCH 09/10] Prettified HEAD symlink generation. --- src/repository.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/repository.c b/src/repository.c index df154828f..0759c0c26 100644 --- a/src/repository.c +++ b/src/repository.c @@ -39,6 +39,10 @@ #define GIT_INDEX_FILE "index" #define GIT_HEAD_FILE "HEAD" +#define GIT_SYMREF "ref: " +#define GIT_REFS_HEADS "refs/heads/" +#define GIT_BRANCH_MASTER "master" + static const int default_table_size = 32; static const double max_load_factor = 0.65; @@ -743,11 +747,15 @@ int git_repository_init__create_head(const char* head_path) { git_file fd; int error = GIT_SUCCESS; - const char* head_content = "ref: refs/heads/master\n"; + char head_symlink[50]; + int len; + + len = sprintf(head_symlink, "%s %s%s\n", GIT_SYMREF, GIT_REFS_HEADS, GIT_BRANCH_MASTER); + if ((fd = gitfo_creat(head_path, S_IREAD | S_IWRITE)) < 0) return GIT_ERROR; - error = gitfo_write(fd, (void*)head_content, strlen(head_content)); + error = gitfo_write(fd, (void*)head_symlink, strlen(head_symlink)); if (error < GIT_SUCCESS) goto cleanup; From 1c2c7c0d1663bcdd279a0a73f6673ab5f81f7ec5 Mon Sep 17 00:00:00 2001 From: nulltoken Date: Sun, 19 Dec 2010 15:08:53 +0100 Subject: [PATCH 10/10] Added creation of ref/heads/ and refs/tags/ directories. --- src/repository.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/repository.c b/src/repository.c index 0759c0c26..94f67f497 100644 --- a/src/repository.c +++ b/src/repository.c @@ -41,6 +41,7 @@ #define GIT_SYMREF "ref: " #define GIT_REFS_HEADS "refs/heads/" +#define GIT_REFS_TAGS "refs/tags/" #define GIT_BRANCH_MASTER "master" static const int default_table_size = 32; @@ -806,6 +807,16 @@ int git_repository_init__create_structure_or_reinit(git_repository_init_results* if (gitfo_mkdir(temp_path, mode)) return GIT_ERROR; + /* Creates the '/refs/heads/' directory */ + strcpy(temp_path + path_len, GIT_REFS_HEADS); + if (gitfo_mkdir(temp_path, mode)) + return GIT_ERROR; + + /* Creates the '/refs/tags/' directory */ + strcpy(temp_path + path_len, GIT_REFS_TAGS); + if (gitfo_mkdir(temp_path, mode)) + return GIT_ERROR; + /* To be implemented */