diff options
-rw-r--r-- | src/commit.c | 232 | ||||
-rw-r--r-- | src/commit.h | 7 | ||||
-rw-r--r-- | src/git/commit.h | 12 | ||||
-rw-r--r-- | src/git/common.h | 12 | ||||
-rw-r--r-- | src/git/tag.h | 6 | ||||
-rw-r--r-- | src/oid.c | 35 | ||||
-rw-r--r-- | src/person.c | 140 | ||||
-rw-r--r-- | src/person.h | 20 | ||||
-rw-r--r-- | src/repository.c | 50 | ||||
-rw-r--r-- | src/repository.h | 3 | ||||
-rw-r--r-- | src/tag.c | 35 | ||||
-rw-r--r-- | src/tree.c | 77 | ||||
-rw-r--r-- | src/tree.h | 4 | ||||
-rw-r--r-- | tests/t0401-parse.c | 23 | ||||
-rw-r--r-- | tests/t0402-details.c | 2 | ||||
-rw-r--r-- | tests/t0403-write.c | 13 | ||||
-rw-r--r-- | tests/t0902-modify.c | 4 |
17 files changed, 395 insertions, 280 deletions
diff --git a/src/commit.c b/src/commit.c index 90a30e020..a2d7221d1 100644 --- a/src/commit.c +++ b/src/commit.c @@ -23,11 +23,14 @@ * Boston, MA 02110-1301, USA. */ +#include "git/common.h" +#include "git/odb.h" +#include "git/repository.h" + #include "common.h" #include "commit.h" #include "revwalk.h" -#include "git/odb.h" -#include "git/repository.h" +#include "person.h" #define COMMIT_BASIC_PARSE 0x0 #define COMMIT_FULL_PARSE 0x1 @@ -56,8 +59,9 @@ void git_commit__free(git_commit *commit) { clear_parents(commit); - free(commit->author); - free(commit->committer); + git_person__free(commit->author); + git_person__free(commit->committer); + free(commit->message); free(commit->message_short); free(commit); @@ -73,146 +77,12 @@ const git_oid *git_commit_id(git_commit *c) return git_object_id((git_object *)c); } -int git_commit__parse(git_commit *commit) -{ - const int close_db_object = 1; - int error = 0; - - if ((error = git_object__source_open((git_object *)commit)) < 0) - return error; - - error = git_commit__parse_buffer(commit, - commit->object.source.raw.data, commit->object.source.raw.len, COMMIT_BASIC_PARSE); - - if (close_db_object) - git_object__source_close((git_object *)commit); - - return error; -} - -int git_commit__parse_full(git_commit *commit) -{ - int error; - - if (commit->full_parse) - return 0; - - if (git_object__source_open((git_object *)commit) < 0) - return GIT_ERROR; - - error = git_commit__parse_buffer(commit, - commit->object.source.raw.data, commit->object.source.raw.len, COMMIT_FULL_PARSE); - - git_object__source_close((git_object *)commit); - - commit->full_parse = 1; - return error; -} git_commit *git_commit_lookup(git_repository *repo, const git_oid *id) { return (git_commit *)git_repository_lookup(repo, id, GIT_OBJ_COMMIT); } -int git__parse_person(git_person *person, char **buffer_out, - const char *buffer_end, const char *header) -{ - const size_t header_len = strlen(header); - - int i; - char *buffer = *buffer_out; - char *line_end, *name, *email; - - line_end = memchr(buffer, '\n', buffer_end - buffer); - if (!line_end) - return GIT_EOBJCORRUPTED; - - if (buffer + (header_len + 1) > line_end) - return GIT_EOBJCORRUPTED; - - if (memcmp(buffer, header, header_len) != 0) - return GIT_EOBJCORRUPTED; - - buffer += header_len; - - - /* Parse name field */ - for (i = 0, name = person->name; - i < 64 && buffer < line_end && *buffer != '<'; - ++i) - *name++ = *buffer++; - - *(name - 1) = 0; - - while (buffer < line_end && *buffer != '<') - buffer++; - - if (++buffer >= line_end) - return GIT_EOBJCORRUPTED; - - /* Parse email field */ - for (i = 0, email = person->email; - i < 64 && buffer < line_end && *buffer != '>'; - ++i) - *email++ = *buffer++; - - *email = 0; - - while (buffer < line_end && *buffer != '>') - buffer++; - - if (++buffer >= line_end) - return GIT_EOBJCORRUPTED; - - person->time = strtol(buffer, &buffer, 10); - - if (person->time == 0) - return GIT_EOBJCORRUPTED; - - *buffer_out = (line_end + 1); - return 0; -} - -int git__write_person(git_odb_source *src, const char *header, const git_person *person) -{ - return git__source_printf(src, "%s %s <%s> %u\n", header, person->name, person->email, person->time); -} - -int git__parse_oid(git_oid *oid, char **buffer_out, - const char *buffer_end, const char *header) -{ - const size_t sha_len = GIT_OID_HEXSZ; - const size_t header_len = strlen(header); - - char *buffer = *buffer_out; - - if (buffer + (header_len + sha_len + 1) > buffer_end) - return GIT_EOBJCORRUPTED; - - if (memcmp(buffer, header, header_len) != 0) - return GIT_EOBJCORRUPTED; - - if (buffer[header_len + sha_len] != '\n') - return GIT_EOBJCORRUPTED; - - if (git_oid_mkstr(oid, buffer + header_len) < 0) - return GIT_EOBJCORRUPTED; - - *buffer_out = buffer + (header_len + sha_len + 1); - - return 0; -} - -int git__write_oid(git_odb_source *src, const char *header, const git_oid *oid) -{ - char hex_oid[41]; - - git_oid_fmt(hex_oid, oid); - hex_oid[40] = 0; - - return git__source_printf(src, "%s %s\n", header, hex_oid); -} - int git_commit__writeback(git_commit *commit, git_odb_source *src) { git_commit_parents *parent; @@ -232,12 +102,12 @@ int git_commit__writeback(git_commit *commit, git_odb_source *src) if (commit->author == NULL) return GIT_ERROR; - git__write_person(src, "author", commit->author); + git_person__write(src, "author", commit->author); if (commit->committer == NULL) return GIT_ERROR; - git__write_person(src, "committer", commit->committer); + git_person__write(src, "committer", commit->committer); if (commit->message != NULL) git__source_printf(src, "\n%s", commit->message); @@ -245,13 +115,12 @@ int git_commit__writeback(git_commit *commit, git_odb_source *src) return GIT_SUCCESS; } -int git_commit__parse_buffer(git_commit *commit, void *data, size_t len, unsigned int parse_flags) +int commit_parse_buffer(git_commit *commit, void *data, size_t len, unsigned int parse_flags) { char *buffer = (char *)data; const char *buffer_end = (char *)data + len; git_oid oid; - git_person person; if (git__parse_oid(&oid, &buffer, buffer_end, "tree ") < 0) return GIT_EOBJCORRUPTED; @@ -279,29 +148,31 @@ int git_commit__parse_buffer(git_commit *commit, void *data, size_t len, unsigne commit->parents = node; } - if (git__parse_person(&person, &buffer, buffer_end, "author ") < 0) - return GIT_EOBJCORRUPTED; if (parse_flags & COMMIT_FULL_PARSE) { if (commit->author) - free(commit->author); + git_person__free(commit->author); commit->author = git__malloc(sizeof(git_person)); - memcpy(commit->author, &person, sizeof(git_person)); - } + if (git_person__parse(commit->author, &buffer, buffer_end, "author ") < 0) + return GIT_EOBJCORRUPTED; - if (git__parse_person(&person, &buffer, buffer_end, "committer ") < 0) - return GIT_EOBJCORRUPTED; + } else { + if ((buffer = memchr(buffer, '\n', buffer_end - buffer)) == NULL) + return GIT_EOBJCORRUPTED; - commit->commit_time = person.time; + buffer++; + } - if (parse_flags & COMMIT_FULL_PARSE) { - if (commit->committer) - free(commit->committer); + /* Always parse the committer; we need the commit time */ + if (commit->committer) + git_person__free(commit->committer); - commit->committer = git__malloc(sizeof(git_person)); - memcpy(commit->committer, &person, sizeof(git_person)); - } + commit->committer = git__malloc(sizeof(git_person)); + if (git_person__parse(commit->committer, &buffer, buffer_end, "committer ") < 0) + return GIT_EOBJCORRUPTED; + + commit->commit_time = commit->committer->time; /* parse commit message */ while (buffer <= buffer_end && *buffer == '\n') @@ -329,9 +200,38 @@ int git_commit__parse_buffer(git_commit *commit, void *data, size_t len, unsigne return 0; } +int git_commit__parse(git_commit *commit) +{ + assert(commit && commit->object.source.open); + return commit_parse_buffer(commit, + commit->object.source.raw.data, commit->object.source.raw.len, COMMIT_BASIC_PARSE); +} + +int git_commit__parse_full(git_commit *commit) +{ + int error; + + if (commit->full_parse) + return 0; + + if (git_object__source_open((git_object *)commit) < 0) + return GIT_ERROR; + + error = commit_parse_buffer(commit, + commit->object.source.raw.data, commit->object.source.raw.len, COMMIT_FULL_PARSE); + + git_object__source_close((git_object *)commit); + + commit->full_parse = 1; + return error; +} + + + #define GIT_COMMIT_GETTER(_rvalue, _name) \ const _rvalue git_commit_##_name(git_commit *commit) \ {\ + assert(commit); \ if (commit->_name) \ return commit->_name; \ git_commit__parse_full(commit); \ @@ -346,6 +246,8 @@ GIT_COMMIT_GETTER(char *, message_short) time_t git_commit_time(git_commit *commit) { + assert(commit); + if (commit->commit_time) return commit->commit_time; @@ -355,26 +257,27 @@ time_t git_commit_time(git_commit *commit) void git_commit_set_tree(git_commit *commit, git_tree *tree) { + assert(commit && tree); commit->object.modified = 1; commit->tree = tree; } -void git_commit_set_author(git_commit *commit, const git_person *author) +void git_commit_set_author(git_commit *commit, const char *name, const char *email, time_t time) { + assert(commit && name && email); commit->object.modified = 1; - if (commit->author == NULL) - commit->author = git__malloc(sizeof(git_person)); - memcpy(commit->author, author, sizeof(git_person)); + git_person__free(commit->author); + commit->author = git_person__new(name, email, time); } -void git_commit_set_committer(git_commit *commit, const git_person *committer) +void git_commit_set_committer(git_commit *commit, const char *name, const char *email, time_t time) { + assert(commit && name && email); commit->object.modified = 1; - if (commit->committer == NULL) - commit->committer = git__malloc(sizeof(git_person)); - memcpy(commit->committer, committer, sizeof(git_person)); + git_person__free(commit->committer); + commit->committer = git_person__new(name, email, time); } void git_commit_set_message(git_commit *commit, const char *message) @@ -409,3 +312,4 @@ void git_commit_add_parent(git_commit *commit, git_commit *new_parent) commit->parents = node; } + diff --git a/src/commit.h b/src/commit.h index 39a7a52ff..1c765abd3 100644 --- a/src/commit.h +++ b/src/commit.h @@ -31,14 +31,7 @@ struct git_commit { void git_commit__free(git_commit *c); int git_commit__parse(git_commit *commit); int git_commit__parse_full(git_commit *commit); -int git_commit__parse_buffer(git_commit *commit, void *data, size_t len, unsigned int parse_flags); int git_commit__writeback(git_commit *commit, git_odb_source *src); -int git__parse_oid(git_oid *oid, char **buffer_out, const char *buffer_end, const char *header); -int git__parse_person(git_person *person, char **buffer_out, const char *buffer_end, const char *header); - -int git__write_oid(git_odb_source *src, const char *header, const git_oid *oid); -int git__write_person(git_odb_source *src, const char *header, const git_person *person); - #endif diff --git a/src/git/commit.h b/src/git/commit.h index 308f30f35..5d3fa0adb 100644 --- a/src/git/commit.h +++ b/src/git/commit.h @@ -108,16 +108,20 @@ GIT_EXTERN(void) git_commit_set_message(git_commit *commit, const char *message) /** * Set the committer of a commit * @param commit the commit object - * @param committer the new committer + * @param name name of the new committer + * @param email email of the new committer + * @param time time when the committer committed the commit */ -GIT_EXTERN(void) git_commit_set_committer(git_commit *commit, const git_person *committer); +GIT_EXTERN(void) git_commit_set_committer(git_commit *commit, const char *name, const char *email, time_t time); /** * Set the author of a commit * @param commit the commit object - * @param author the new author + * @param name name of the new author + * @param email email of the new author + * @param time time when the author created the commit */ -GIT_EXTERN(void) git_commit_set_author(git_commit *commit, const git_person *author); +GIT_EXTERN(void) git_commit_set_author(git_commit *commit, const char *name, const char *email, time_t time); /** * Set the tree which is pointed to by a commit diff --git a/src/git/common.h b/src/git/common.h index 6d4858d71..35408413d 100644 --- a/src/git/common.h +++ b/src/git/common.h @@ -2,6 +2,7 @@ #define INCLUDE_git_common_h__ #include "thread-utils.h" +#include <time.h> #ifdef __cplusplus # define GIT_BEGIN_DECL extern "C" { @@ -94,12 +95,13 @@ typedef struct git_repository git_repository; /** Representation of a generic object in a repository */ typedef struct git_object git_object; + /** Parsed representation of a person */ -typedef struct git_person { - char name[64]; /**< Full name */ - char email[64]; /**< Email address */ - time_t time; /**< Time when this person committed the change */ -} git_person; +typedef struct git_person git_person; + +const char *git_person_name(git_person *person); +const char *git_person_email(git_person *person); +time_t git_person_time(git_person *person); /** @} */ GIT_END_DECL diff --git a/src/git/tag.h b/src/git/tag.h index f9431db32..e1cd1ab85 100644 --- a/src/git/tag.h +++ b/src/git/tag.h @@ -100,9 +100,11 @@ GIT_EXTERN(void) git_tag_set_name(git_tag *tag, const char *name); /** * Set the tagger of a tag * @param tag The tag to modify - * @param tagger the new tagger for the tag + * @param name the name of the new tagger + * @param email the email of the new tagger + * @param time the time when the tag was created */ -GIT_EXTERN(void) git_tag_set_tagger(git_tag *tag, const git_person *tagger); +GIT_EXTERN(void) git_tag_set_tagger(git_tag *tag, const char *name, const char *email, time_t time); /** * Set the message of a tag @@ -25,6 +25,7 @@ #include "common.h" #include "git/oid.h" +#include "repository.h" #include <string.h> static signed char from_hex[] = { @@ -116,3 +117,37 @@ char *git_oid_to_string(char *out, size_t n, const git_oid *oid) return out; } +int git__parse_oid(git_oid *oid, char **buffer_out, + const char *buffer_end, const char *header) +{ + const size_t sha_len = GIT_OID_HEXSZ; + const size_t header_len = strlen(header); + + char *buffer = *buffer_out; + + if (buffer + (header_len + sha_len + 1) > buffer_end) + return GIT_EOBJCORRUPTED; + + if (memcmp(buffer, header, header_len) != 0) + return GIT_EOBJCORRUPTED; + + if (buffer[header_len + sha_len] != '\n') + return GIT_EOBJCORRUPTED; + + if (git_oid_mkstr(oid, buffer + header_len) < 0) + return GIT_EOBJCORRUPTED; + + *buffer_out = buffer + (header_len + sha_len + 1); + + return 0; +} + +int git__write_oid(git_odb_source *src, const char *header, const git_oid *oid) +{ + char hex_oid[41]; + + git_oid_fmt(hex_oid, oid); + hex_oid[40] = 0; + + return git__source_printf(src, "%s %s\n", header, hex_oid); +} diff --git a/src/person.c b/src/person.c new file mode 100644 index 000000000..0ab6a2d5a --- /dev/null +++ b/src/person.c @@ -0,0 +1,140 @@ +/* + * This file is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License, version 2, + * as published by the Free Software Foundation. + * + * In addition to the permissions in the GNU General Public License, + * the authors give you unlimited permission to link the compiled + * version of this file into combinations with other programs, + * and to distribute those combinations without any restriction + * coming from the use of this file. (The General Public License + * restrictions do apply in other respects; for example, they cover + * modification of the file, and distribution when not linked into + * a combined executable.) + * + * This file is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include "common.h" +#include "person.h" +#include "repository.h" +#include "git/common.h" + +void git_person__free(git_person *person) +{ + if (person == NULL) + return; + + free(person->name); + free(person->email); + free(person); +} + +git_person *git_person__new(const char *name, const char *email, time_t time) +{ + git_person *p; + + if ((p = git__malloc(sizeof(git_person))) == NULL) + goto cleanup; + + p->name = git__strdup(name); + p->email = git__strdup(email); + p->time = time; + + if (p->name == NULL || p->email == NULL) + goto cleanup; + + return p; + +cleanup: + git_person__free(p); + return NULL; +} + +const char *git_person_name(git_person *person) +{ + return person->name; +} + +const char *git_person_email(git_person *person) +{ + return person->email; +} + +time_t git_person_time(git_person *person) +{ + return person->time; +} + +int git_person__parse(git_person *person, char **buffer_out, + const char *buffer_end, const char *header) +{ + const size_t header_len = strlen(header); + + int name_length, email_length; + char *buffer = *buffer_out; + char *line_end, *name_end, *email_end; + + memset(person, 0x0, sizeof(git_person)); + + line_end = memchr(buffer, '\n', buffer_end - buffer); + if (!line_end) + return GIT_EOBJCORRUPTED; + + if (buffer + (header_len + 1) > line_end) + return GIT_EOBJCORRUPTED; + + if (memcmp(buffer, header, header_len) != 0) + return GIT_EOBJCORRUPTED; + + buffer += header_len; + + /* Parse name */ + if ((name_end = memchr(buffer, '<', buffer_end - buffer)) == NULL) + return GIT_EOBJCORRUPTED; + + name_length = name_end - buffer - 1; + person->name = git__malloc(name_length + 1); + memcpy(person->name, buffer, name_length); + person->name[name_length] = 0; + buffer = name_end + 1; + + if (buffer >= line_end) + return GIT_EOBJCORRUPTED; + + /* Parse email */ + if ((email_end = memchr(buffer, '>', buffer_end - buffer)) == NULL) + return GIT_EOBJCORRUPTED; + + email_length = email_end - buffer; + person->email = git__malloc(email_length + 1); + memcpy(person->email, buffer, email_length); + person->email[email_length] = 0; + buffer = email_end + 1; + + if (buffer >= line_end) + return GIT_EOBJCORRUPTED; + + person->time = strtol(buffer, &buffer, 10); + + if (person->time == 0) + return GIT_EOBJCORRUPTED; + + *buffer_out = (line_end + 1); + return 0; +} + +int git_person__write(git_odb_source *src, const char *header, const git_person *person) +{ + return git__source_printf(src, "%s %s <%s> %u\n", header, person->name, person->email, person->time); +} + + diff --git a/src/person.h b/src/person.h new file mode 100644 index 000000000..334b184eb --- /dev/null +++ b/src/person.h @@ -0,0 +1,20 @@ +#ifndef INCLUDE_person_h__ +#define INCLUDE_person_h__ + +#include "git/common.h" +#include "repository.h" +#include <time.h> + +/** Parsed representation of a person */ +struct git_person { + char *name; /**< Full name */ + char *email; /**< Email address */ + time_t time; /**< Time when this person committed the change */ +}; + +void git_person__free(git_person *person); +git_person *git_person__new(const char *name, const char *email, time_t time); +int git_person__parse(git_person *person, char **buffer_out, const char *buffer_end, const char *header); +int git_person__write(git_odb_source *src, const char *header, const git_person *person); + +#endif diff --git a/src/repository.c b/src/repository.c index 19f1c4e53..202fa04ab 100644 --- a/src/repository.c +++ b/src/repository.c @@ -32,6 +32,8 @@ static const int default_table_size = 32; static const double max_load_factor = 0.65; +static const int OBJECT_BASE_SIZE = 4096; + static const size_t object_sizes[] = { 0, sizeof(git_commit), @@ -171,14 +173,12 @@ int git__source_write(git_odb_source *source, const void *bytes, size_t len) static void prepare_write(git_object *object) { - const size_t base_size = 4096; /* 4Kb base size */ - if (object->source.write_ptr != NULL || object->source.open) git_object__source_close(object); /* TODO: proper size calculation */ - object->source.raw.data = git__malloc(base_size); - object->source.raw.len = base_size; + object->source.raw.data = git__malloc(OBJECT_BASE_SIZE); + object->source.raw.len = OBJECT_BASE_SIZE; object->source.write_ptr = object->source.raw.data; object->source.written_bytes = 0; @@ -193,11 +193,9 @@ static int write_back(git_object *object) assert(object); - if (!object->source.open) - return GIT_ERROR; - + assert(object->source.open); assert(object->modified); - + object->source.raw.len = object->source.written_bytes; git_obj_hash(&new_id, &object->source.raw); @@ -230,9 +228,6 @@ int git_object__source_open(git_object *object) if (object->source.open) git_object__source_close(object); - if (object->source.open) - return GIT_SUCCESS; - error = git_odb_read(&object->source.raw, object->repo->db, &object->id); if (error < 0) return error; @@ -245,7 +240,7 @@ void git_object__source_close(git_object *object) { assert(object); - if (!object->source.open) { + if (object->source.open) { git_obj_close(&object->source.raw); object->source.open = 0; } @@ -294,8 +289,8 @@ void git_object_free(git_object *object) { assert(object); + git_object__source_close(object); git_hashtable_remove(object->repo->objects, &object->id); - git_obj_close(&object->source.raw); switch (object->source.raw.type) { case GIT_OBJ_COMMIT: @@ -372,6 +367,7 @@ git_object *git_repository_lookup(git_repository *repo, const git_oid *id, git_o { git_object *object = NULL; git_rawobj obj_file; + int error = 0; assert(repo); @@ -397,43 +393,35 @@ git_object *git_repository_lookup(git_repository *repo, const git_oid *id, git_o /* Initialize parent object */ git_oid_cpy(&object->id, id); object->repo = repo; - object->source.open = 1; memcpy(&object->source.raw, &obj_file, sizeof(git_rawobj)); + object->source.open = 1; switch (type) { case GIT_OBJ_COMMIT: - if (git_commit__parse((git_commit *)object) < 0) { - free(object); - return NULL; - } - + error = git_commit__parse((git_commit *)object); break; case GIT_OBJ_TREE: - if (git_tree__parse((git_tree *)object) < 0) { - free(object); - return NULL; - } - + error = git_tree__parse((git_tree *)object); break; case GIT_OBJ_TAG: - if (git_tag__parse((git_tag *)object) < 0) { - free(object); - return NULL; - } - + error = git_tag__parse((git_tag *)object); break; + case GIT_OBJ_BLOB: default: /* blobs get no parsing */ break; } - git_obj_close(&object->source.raw); - object->source.open = 0; + if (error < 0) { + git_object_free(object); + return NULL; + } + git_object__source_close(object); git_hashtable_insert(repo->objects, &object->id, object); return object; } diff --git a/src/repository.h b/src/repository.h index 9a7bd24b8..0ccfc5e92 100644 --- a/src/repository.h +++ b/src/repository.h @@ -34,4 +34,7 @@ void git_object__source_close(git_object *object); int git__source_printf(git_odb_source *source, const char *format, ...); int git__source_write(git_odb_source *source, const void *bytes, size_t len); +int git__parse_oid(git_oid *oid, char **buffer_out, const char *buffer_end, const char *header); +int git__write_oid(git_odb_source *src, const char *header, const git_oid *oid); + #endif @@ -26,15 +26,16 @@ #include "common.h" #include "commit.h" #include "tag.h" +#include "person.h" #include "revwalk.h" #include "git/odb.h" #include "git/repository.h" void git_tag__free(git_tag *tag) { + git_person__free(tag->tagger); free(tag->message); free(tag->tag_name); - free(tag->tagger); free(tag); } @@ -50,6 +51,7 @@ const git_oid *git_tag_id(git_tag *c) const git_object *git_tag_target(git_tag *t) { + assert(t); return t->target; } @@ -64,6 +66,7 @@ void git_tag_set_target(git_tag *tag, git_object *target) git_otype git_tag_type(git_tag *t) { + assert(t); return t->type; } @@ -77,6 +80,7 @@ void git_tag_set_type(git_tag *tag, git_otype type) const char *git_tag_name(git_tag *t) { + assert(t); return t->tag_name; } @@ -98,19 +102,18 @@ const git_person *git_tag_tagger(git_tag *t) return t->tagger; } -void git_tag_set_tagger(git_tag *tag, const git_person *tagger) +void git_tag_set_tagger(git_tag *tag, const char *name, const char *email, time_t time) { - assert(tag && tagger); - + assert(tag && name && email); tag->object.modified = 1; - if (tag->tagger == NULL) - tag->tagger = git__malloc(sizeof(git_person)); - memcpy(tag->tagger, tagger, sizeof(git_person)); + git_person__free(tag->tagger); + tag->tagger = git_person__new(name, email, time); } const char *git_tag_message(git_tag *t) { + assert(t); return t->message; } @@ -194,11 +197,11 @@ static int parse_tag_buffer(git_tag *tag, char *buffer, const char *buffer_end) buffer = search + 1; if (tag->tagger != NULL) - free(tag->tagger); + git_person__free(tag->tagger); tag->tagger = git__malloc(sizeof(git_person)); - if (git__parse_person(tag->tagger, &buffer, buffer_end, "tagger ") != 0) + if (git_person__parse(tag->tagger, &buffer, buffer_end, "tagger ") != 0) return GIT_EOBJCORRUPTED; text_len = buffer_end - ++buffer; @@ -221,7 +224,7 @@ int git_tag__writeback(git_tag *tag, git_odb_source *src) git__write_oid(src, "object", git_object_id(tag->target)); git__source_printf(src, "type %s\n", git_obj_type_to_string(tag->type)); git__source_printf(src, "tag %s\n", tag->tag_name); - git__write_person(src, "tagger", tag->tagger); + git_person__write(src, "tagger", tag->tagger); if (tag->message != NULL) git__source_printf(src, "\n%s", tag->message); @@ -232,16 +235,8 @@ int git_tag__writeback(git_tag *tag, git_odb_source *src) int git_tag__parse(git_tag *tag) { - int error = 0; - - error = git_object__source_open((git_object *)tag); - if (error < 0) - return error; - - error = parse_tag_buffer(tag, tag->object.source.raw.data, tag->object.source.raw.data + tag->object.source.raw.len); - - git_object__source_close((git_object *)tag); - return error; + assert(tag && tag->object.source.open); + return parse_tag_buffer(tag, tag->object.source.raw.data, tag->object.source.raw.data + tag->object.source.raw.len); } git_tag *git_tag_lookup(git_repository *repo, const git_oid *id) diff --git a/src/tree.c b/src/tree.c index 28bc035d2..526f9dc31 100644 --- a/src/tree.c +++ b/src/tree.c @@ -70,17 +70,26 @@ static void entry_resort(git_tree *tree) qsort(tree->entries, tree->entry_count, sizeof(git_tree_entry *), entry_sort_cmp); } - - - -void git_tree__free(git_tree *tree) +static void free_tree_entries(git_tree *tree) { size_t i; - for (i = 0; i < tree->entry_count; ++i) + if (tree == NULL) + return; + + for (i = 0; i < tree->entry_count; ++i) { + free(tree->entries[i]->filename); free(tree->entries[i]); + } free(tree->entries); +} + + + +void git_tree__free(git_tree *tree) +{ + free_tree_entries(tree); free(tree); } @@ -111,7 +120,8 @@ void git_tree_entry_set_name(git_tree_entry *entry, const char *name) { assert(entry && entry->owner); - strncpy(entry->filename, name, GIT_TREE_MAX_FILENAME); + free(entry->filename); + entry->filename = git__strdup(name); entry_resort(entry->owner); entry->owner->object.modified = 1; } @@ -188,7 +198,7 @@ int git_tree_add_entry(git_tree *tree, const git_oid *id, const char *filename, memset(entry, 0x0, sizeof(git_tree_entry)); - strncpy(entry->filename, filename, GIT_TREE_MAX_FILENAME); + entry->filename = git__strdup(filename); git_oid_cpy(&entry->oid, id); entry->attr = attributes; entry->owner = tree; @@ -212,6 +222,7 @@ int git_tree_remove_entry_byindex(git_tree *tree, int idx) remove_ptr = tree->entries[idx]; tree->entries[idx] = tree->entries[--tree->entry_count]; + free(remove_ptr->filename); free(remove_ptr); entry_resort(tree); @@ -237,6 +248,7 @@ int git_tree_remove_entry_byname(git_tree *tree, const char *filename) int git_tree__writeback(git_tree *tree, git_odb_source *src) { size_t i; + char filemode[8]; assert(tree && src); @@ -249,38 +261,23 @@ int git_tree__writeback(git_tree *tree, git_odb_source *src) git_tree_entry *entry; entry = tree->entries[i]; - git__source_printf(src, "%06o %s\0", entry->attr, entry->filename); + sprintf(filemode, "%06o ", entry->attr); + + git__source_write(src, filemode, strlen(filemode)); + git__source_write(src, entry->filename, strlen(entry->filename) + 1); git__source_write(src, entry->oid.id, GIT_OID_RAWSZ); - } + } return GIT_SUCCESS; } -int git_tree__parse(git_tree *tree) +static int tree_parse_buffer(git_tree *tree, char *buffer, char *buffer_end) { static const size_t avg_entry_size = 40; - int error = 0; - char *buffer, *buffer_end; - - assert(!tree->object.in_memory); - if (tree->entries != NULL) { - size_t i; - - for (i = 0; i < tree->entry_count; ++i) - free(tree->entries[i]); - - free(tree->entries); - } - - error = git_object__source_open((git_object *)tree); - if (error < 0) - return error; - - buffer = tree->object.source.raw.data; - buffer_end = buffer + tree->object.source.raw.len; + free_tree_entries(tree); tree->entry_count = 0; tree->array_size = (tree->object.source.raw.len / avg_entry_size) + 1; @@ -312,7 +309,12 @@ int git_tree__parse(git_tree *tree) break; } - strncpy(entry->filename, buffer, GIT_TREE_MAX_FILENAME); + if (memchr(buffer, 0, buffer_end - buffer) == NULL) { + error = GIT_EOBJCORRUPTED; + break; + } + + entry->filename = git__strdup(buffer); while (buffer < buffer_end && *buffer != 0) buffer++; @@ -323,6 +325,19 @@ int git_tree__parse(git_tree *tree) buffer += GIT_OID_RAWSZ; } - git_object__source_close((git_object *)tree); return error; } + +int git_tree__parse(git_tree *tree) +{ + char *buffer, *buffer_end; + + assert(tree && tree->object.source.open); + assert(!tree->object.in_memory); + + buffer = tree->object.source.raw.data; + buffer_end = buffer + tree->object.source.raw.len; + + return tree_parse_buffer(tree, buffer, buffer_end); +} + diff --git a/src/tree.h b/src/tree.h index 118d2c3d6..db1c19ffe 100644 --- a/src/tree.h +++ b/src/tree.h @@ -4,11 +4,9 @@ #include <git/tree.h> #include "repository.h" -#define GIT_TREE_MAX_FILENAME 255 - struct git_tree_entry { unsigned int attr; - char filename[GIT_TREE_MAX_FILENAME]; + char *filename; git_oid oid; git_tree *owner; diff --git a/tests/t0401-parse.c b/tests/t0401-parse.c index d97aee11e..06427a185 100644 --- a/tests/t0401-parse.c +++ b/tests/t0401-parse.c @@ -1,6 +1,7 @@ #include "test_lib.h" #include "test_helpers.h" #include "commit.h" +#include "person.h" #include <git/odb.h> #include <git/commit.h> #include <git/revwalk.h> @@ -127,18 +128,20 @@ BEGIN_TEST(parse_person_test) #define TEST_PERSON_PASS(_string, _header, _name, _email, _time) { \ char *ptr = _string; \ size_t len = strlen(_string);\ - git_person person; \ - must_pass(git__parse_person(&person, &ptr, ptr + len, _header));\ - must_be_true(strncmp(_name, person.name, 63) == 0);\ - must_be_true(strncmp(_email, person.email, 63) == 0);\ + git_person person = {NULL, NULL, 0}; \ + must_pass(git_person__parse(&person, &ptr, ptr + len, _header));\ + must_be_true(strcmp(_name, person.name) == 0);\ + must_be_true(strcmp(_email, person.email) == 0);\ must_be_true(_time == person.time);\ + free(person.name); free(person.email);\ } #define TEST_PERSON_FAIL(_string, _header) { \ char *ptr = _string; \ size_t len = strlen(_string);\ - git_person person; \ - must_fail(git__parse_person(&person, &ptr, ptr + len, _header));\ + git_person person = {NULL, NULL, 0}; \ + must_fail(git_person__parse(&person, &ptr, ptr + len, _header));\ + free(person.name); free(person.email);\ } TEST_PERSON_PASS( @@ -213,6 +216,9 @@ BEGIN_TEST(parse_person_test) END_TEST +/* External declaration for testing the buffer parsing method */ +int commit_parse_buffer(git_commit *commit, void *data, size_t len, unsigned int parse_flags); + BEGIN_TEST(parse_buffer_test) const int broken_commit_count = sizeof(test_commits_broken) / sizeof(*test_commits_broken); const int working_commit_count = sizeof(test_commits_working) / sizeof(*test_commits_working); @@ -232,7 +238,7 @@ BEGIN_TEST(parse_buffer_test) memset(commit, 0x0, sizeof(git_commit)); commit->object.repo = repo; - must_fail(git_commit__parse_buffer( + must_fail(commit_parse_buffer( commit, test_commits_broken[i], strlen(test_commits_broken[i]), @@ -248,7 +254,7 @@ BEGIN_TEST(parse_buffer_test) memset(commit, 0x0, sizeof(git_commit)); commit->object.repo = repo; - must_pass(git_commit__parse_buffer( + must_pass(commit_parse_buffer( commit, test_commits_working[i], strlen(test_commits_working[i]), @@ -259,5 +265,6 @@ BEGIN_TEST(parse_buffer_test) } git_repository_free(repo); + git_odb_close(db); END_TEST diff --git a/tests/t0402-details.c b/tests/t0402-details.c index b48d9f18d..1e002942b 100644 --- a/tests/t0402-details.c +++ b/tests/t0402-details.c @@ -1,6 +1,7 @@ #include "test_lib.h" #include "test_helpers.h" #include "commit.h" +#include "person.h" #include <git/odb.h> #include <git/commit.h> @@ -28,6 +29,7 @@ BEGIN_TEST(query_details_test) repo = git_repository_alloc(db); must_be_true(repo != NULL); + for (i = 0; i < commit_count; ++i) { git_oid id; git_commit *commit; diff --git a/tests/t0403-write.c b/tests/t0403-write.c index b1d088da7..d4669e0ed 100644 --- a/tests/t0403-write.c +++ b/tests/t0403-write.c @@ -17,6 +17,9 @@ static const char *commit_ids[] = { }; static const char *tree_oid = "1810dff58d8a660512d4832e740f692884338ccd"; +#define COMMITTER_NAME "Vicent Marti" +#define COMMITTER_EMAIL "vicent@github.com" + BEGIN_TEST(writenew_test) git_odb *db; git_repository *repo; @@ -25,9 +28,6 @@ BEGIN_TEST(writenew_test) git_oid id; /* char hex_oid[41]; */ - git_person author = {"Vicent Marti", "vicent@github.com", 123456789}; - git_person committer = {"Vicent Marti", "vicent@github.com", 987654321}; - must_pass(git_odb_open(&db, odb_dir)); repo = git_repository_alloc(db); @@ -45,8 +45,8 @@ BEGIN_TEST(writenew_test) git_commit_add_parent(commit, parent); /* Set other attributes */ - git_commit_set_committer(commit, &committer); - git_commit_set_author(commit, &author); + git_commit_set_committer(commit, COMMITTER_NAME, COMMITTER_EMAIL, 123456789); + git_commit_set_author(commit, COMMITTER_NAME, COMMITTER_EMAIL, 987654321); git_commit_set_message(commit, "This commit has been created in memory\n\ This is a commit created in memory and it will be written back to disk\n"); @@ -73,6 +73,9 @@ This is a commit created in memory and it will be written back to disk\n"); must_pass(remove_loose_object(odb_dir, (git_object *)commit)); + //git_person_free(&author); + //git_person_free(&committer); + git_repository_free(repo); git_odb_close(db); diff --git a/tests/t0902-modify.c b/tests/t0902-modify.c index 60a5cd728..67ae1fa64 100644 --- a/tests/t0902-modify.c +++ b/tests/t0902-modify.c @@ -38,6 +38,8 @@ BEGIN_TEST(tree_in_memory_add_test) must_pass(git_object_write((git_object *)tree)); must_pass(remove_loose_object(odb_dir, (git_object *)tree)); + git_object_free((git_object *)tree); + git_repository_free(repo); git_odb_close(db); END_TEST @@ -91,6 +93,8 @@ BEGIN_TEST(tree_add_entry_test) */ must_pass(remove_loose_object(odb_dir, (git_object *)tree)); + + git_object_free((git_object *)tree); git_repository_free(repo); git_odb_close(db); |