diff options
author | Carlos Martín Nieto <cmn@elego.de> | 2011-04-11 17:41:21 +0200 |
---|---|---|
committer | Carlos Martín Nieto <cmn@elego.de> | 2011-04-11 17:43:56 +0200 |
commit | 55c197cdd37b34c7b4877bc0434c297075e11222 (patch) | |
tree | 05dcc126d117b1753e07f0a173cf9498a38ac4f9 /src | |
parent | b075b9910c56c356d53439fd34486a905146211a (diff) | |
parent | fdd0cc9e8948bb65c9a461c58e5094a3613bd975 (diff) | |
download | libgit2-55c197cdd37b34c7b4877bc0434c297075e11222.tar.gz |
Merge upstream/development
Diffstat (limited to 'src')
-rw-r--r-- | src/backends/hiredis.c | 200 | ||||
-rw-r--r-- | src/commit.c | 6 | ||||
-rw-r--r-- | src/errors.c | 4 | ||||
-rw-r--r-- | src/filebuf.c | 2 | ||||
-rw-r--r-- | src/index.c | 15 | ||||
-rw-r--r-- | src/refs.c | 37 | ||||
-rw-r--r-- | src/repository.c | 26 | ||||
-rw-r--r-- | src/revwalk.c | 5 | ||||
-rw-r--r-- | src/signature.c | 58 | ||||
-rw-r--r-- | src/tag.c | 29 | ||||
-rw-r--r-- | src/tree.c | 5 | ||||
-rw-r--r-- | src/util.c | 79 | ||||
-rw-r--r-- | src/util.h | 2 |
13 files changed, 429 insertions, 39 deletions
diff --git a/src/backends/hiredis.c b/src/backends/hiredis.c new file mode 100644 index 000000000..707412bf6 --- /dev/null +++ b/src/backends/hiredis.c @@ -0,0 +1,200 @@ +/* + * 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 "git2/object.h" +#include "hash.h" +#include "odb.h" + +#include "git2/odb_backend.h" + +#ifdef GIT2_HIREDIS_BACKEND + +#include <hiredis/hiredis.h> + +typedef struct { + git_odb_backend parent; + + redisContext *db; +} hiredis_backend; + +int hiredis_backend__read_header(size_t *len_p, git_otype *type_p, git_odb_backend *_backend, const git_oid *oid) { + hiredis_backend *backend; + int error; + redisReply *reply; + + assert(len_p && type_p && _backend && oid); + + backend = (hiredis_backend *) _backend; + error = GIT_ERROR; + + reply = redisCommand(backend->db, "HMGET %b %s %s", oid->id, GIT_OID_RAWSZ, + "type", "size"); + + if (reply->type == REDIS_REPLY_ARRAY) { + if (reply->element[0]->type != REDIS_REPLY_NIL && + reply->element[0]->type != REDIS_REPLY_NIL) { + *type_p = (git_otype) atoi(reply->element[0]->str); + *len_p = (size_t) atoi(reply->element[1]->str); + error = GIT_SUCCESS; + } else { + error = GIT_ENOTFOUND; + } + } else { + error = GIT_ERROR; + } + + freeReplyObject(reply); + return error; +} + +int hiredis_backend__read(void **data_p, size_t *len_p, git_otype *type_p, git_odb_backend *_backend, const git_oid *oid) { + hiredis_backend *backend; + int error; + redisReply *reply; + + assert(data_p && len_p && type_p && _backend && oid); + + backend = (hiredis_backend *) _backend; + error = GIT_ERROR; + + reply = redisCommand(backend->db, "HMGET %b %s %s %s", oid->id, GIT_OID_RAWSZ, + "type", "size", "data"); + + if (reply->type == REDIS_REPLY_ARRAY) { + if (reply->element[0]->type != REDIS_REPLY_NIL && + reply->element[1]->type != REDIS_REPLY_NIL && + reply->element[2]->type != REDIS_REPLY_NIL) { + *type_p = (git_otype) atoi(reply->element[0]->str); + *len_p = (size_t) atoi(reply->element[1]->str); + *data_p = git__malloc(*len_p); + if (*data_p == NULL) { + error = GIT_ENOMEM; + } else { + memcpy(*data_p, reply->element[2]->str, *len_p); + error = GIT_SUCCESS; + } + } else { + error = GIT_ENOTFOUND; + } + } else { + error = GIT_ERROR; + } + + freeReplyObject(reply); + return error; +} + +int hiredis_backend__exists(git_odb_backend *_backend, const git_oid *oid) { + hiredis_backend *backend; + int found; + redisReply *reply; + + assert(_backend && oid); + + backend = (hiredis_backend *) _backend; + found = 0; + + reply = redisCommand(backend->db, "exists %b", oid->id, GIT_OID_RAWSZ); + if (reply->type != REDIS_REPLY_NIL && reply->type != REDIS_REPLY_ERROR) + found = 1; + + + freeReplyObject(reply); + return found; +} + +int hiredis_backend__write(git_oid *id, git_odb_backend *_backend, const void *data, size_t len, git_otype type) { + hiredis_backend *backend; + int error; + redisReply *reply; + + assert(id && _backend && data); + + backend = (hiredis_backend *) _backend; + error = GIT_ERROR; + + if ((error = git_odb_hash(id, data, len, type)) < 0) + return error; + + reply = redisCommand(backend->db, "HMSET %b " + "type %d " + "size %d " + "data %b ", id->id, GIT_OID_RAWSZ, + (int) type, len, data, len); + error = reply->type == REDIS_REPLY_ERROR ? GIT_ERROR : GIT_SUCCESS; + + freeReplyObject(reply); + return error; +} + +void hiredis_backend__free(git_odb_backend *_backend) { + hiredis_backend *backend; + assert(_backend); + backend = (hiredis_backend *) _backend; + + redisFree(backend->db); + + free(backend); +} + +int git_odb_backend_hiredis(git_odb_backend **backend_out, const char *host, int port) { + hiredis_backend *backend; + + backend = git__calloc(1, sizeof (hiredis_backend)); + if (backend == NULL) + return GIT_ENOMEM; + + + backend->db = redisConnect(host, port); + if (backend->db->err) + goto cleanup; + + backend->parent.read = &hiredis_backend__read; + backend->parent.read_header = &hiredis_backend__read_header; + backend->parent.write = &hiredis_backend__write; + backend->parent.exists = &hiredis_backend__exists; + backend->parent.free = &hiredis_backend__free; + + *backend_out = (git_odb_backend *) backend; + + return GIT_SUCCESS; +cleanup: + free(backend); + return GIT_ERROR; +} + +#else + +int git_odb_backend_hiredis(git_odb_backend ** GIT_UNUSED(backend_out), + const char *GIT_UNUSED(host), int GIT_UNUSED(port)) { + GIT_UNUSED_ARG(backend_out); + GIT_UNUSED_ARG(host); + GIT_UNUSED_ARG(port); + return GIT_ENOTIMPLEMENTED; +} + + +#endif /* HAVE_HIREDIS */ diff --git a/src/commit.c b/src/commit.c index 9fc3f0767..9621703c3 100644 --- a/src/commit.c +++ b/src/commit.c @@ -318,6 +318,7 @@ GIT_COMMIT_GETTER(const char *, message_short, commit->message_short) GIT_COMMIT_GETTER(git_time_t, time, commit->committer->when.time) GIT_COMMIT_GETTER(int, time_offset, commit->committer->when.offset) GIT_COMMIT_GETTER(unsigned int, parentcount, commit->parent_oids.length) +GIT_COMMIT_GETTER(const git_oid *, tree_oid, &commit->tree_oid); int git_commit_tree(git_tree **tree_out, git_commit *commit) @@ -338,4 +339,9 @@ int git_commit_parent(git_commit **parent, git_commit *commit, unsigned int n) return git_commit_lookup(parent, commit->object.repo, parent_oid); } +const git_oid *git_commit_parent_oid(git_commit *commit, unsigned int n) +{ + assert(commit); + return git_vector_get(&commit->parent_oids, n); +} diff --git a/src/errors.c b/src/errors.c index 5e59f8205..1ef2baadb 100644 --- a/src/errors.c +++ b/src/errors.c @@ -29,7 +29,9 @@ static struct { {GIT_EREVWALKOVER, "The revision walker is empty; there are no more commits left to iterate"}, {GIT_EINVALIDREFSTATE, "The state of the reference is not valid"}, {GIT_ENOTIMPLEMENTED, "This feature has not been implemented yet"}, - {GIT_EEXISTS, "A reference with this name already exists"} + {GIT_EEXISTS, "A reference with this name already exists"}, + {GIT_EOVERFLOW, "The given integer literal is too large to be parsed"}, + {GIT_ENOTNUM, "The given literal is not a valid number"}, }; const char *git_strerror(int num) diff --git a/src/filebuf.c b/src/filebuf.c index dff9373f6..eb93424ef 100644 --- a/src/filebuf.c +++ b/src/filebuf.c @@ -178,7 +178,7 @@ int git_filebuf_open(git_filebuf *file, const char *path, int flags) if (flags & GIT_FILEBUF_DEFLATE_CONTENTS) { /* Initialize the ZLib stream */ - if (deflateInit(&file->zs, Z_DEFAULT_COMPRESSION) != Z_OK) { + if (deflateInit(&file->zs, Z_BEST_SPEED) != Z_OK) { error = GIT_EZLIB; goto cleanup; } diff --git a/src/index.c b/src/index.c index 6a31dd5cb..68bb9e2b9 100644 --- a/src/index.c +++ b/src/index.c @@ -411,6 +411,7 @@ static git_index_tree *read_tree_internal( { git_index_tree *tree; const char *name_start, *buffer; + long count; if ((tree = git__malloc(sizeof(git_index_tree))) == NULL) return NULL; @@ -429,12 +430,22 @@ static git_index_tree *read_tree_internal( goto error_cleanup; /* Blank-terminated ASCII decimal number of entries in this tree */ - tree->entries = strtol(buffer, (char **)&buffer, 10); + if (git__strtol32(&count, buffer, &buffer, 10) < GIT_SUCCESS || + count < 0) + goto error_cleanup; + + tree->entries = (size_t)count; + if (*buffer != ' ' || ++buffer >= buffer_end) goto error_cleanup; /* Number of children of the tree, newline-terminated */ - tree->children_count = strtol(buffer, (char **)&buffer, 10); + if (git__strtol32(&count, buffer, &buffer, 10) < GIT_SUCCESS || + count < 0) + goto error_cleanup; + + tree->children_count = (size_t)count; + if (*buffer != '\n' || ++buffer >= buffer_end) goto error_cleanup; diff --git a/src/refs.c b/src/refs.c index 9661988cc..00b9ff6b2 100644 --- a/src/refs.c +++ b/src/refs.c @@ -746,7 +746,7 @@ static int packed_write_ref(reference_oid *ref, git_filebuf *file) */ static int packed_find_peel(reference_oid *ref) { - git_tag *tag; + git_object *object; int error; if (ref->ref.type & GIT_REF_HAS_PEEL) @@ -760,25 +760,32 @@ static int packed_find_peel(reference_oid *ref) return GIT_SUCCESS; /* - * Find the tag in the repository. The tag must exist, - * otherwise this reference is broken and we shouldn't - * pack it. + * Find the tagged object in the repository */ - error = git_tag_lookup(&tag, ref->ref.owner, &ref->oid); + error = git_object_lookup(&object, ref->ref.owner, &ref->oid, GIT_OBJ_ANY); if (error < GIT_SUCCESS) return GIT_EOBJCORRUPTED; /* - * Find the object pointed at by this tag + * If the tagged object is a Tag object, we need to resolve it; + * if the ref is actually a 'weak' ref, we don't need to resolve + * anything. */ - git_oid_cpy(&ref->peel_target, git_tag_target_oid(tag)); - ref->ref.type |= GIT_REF_HAS_PEEL; + if (git_object_type(object) == GIT_OBJ_TAG) { + git_tag *tag = (git_tag *)object; - /* - * The reference has now cached the resolved OID, and is - * marked at such. When written to the packfile, it'll be - * accompanied by this resolved oid - */ + /* + * Find the object pointed at by this tag + */ + git_oid_cpy(&ref->peel_target, git_tag_target_oid(tag)); + ref->ref.type |= GIT_REF_HAS_PEEL; + + /* + * The reference has now cached the resolved OID, and is + * marked at such. When written to the packfile, it'll be + * accompanied by this resolved oid + */ + } return GIT_SUCCESS; } @@ -1419,6 +1426,10 @@ int git_reference_delete(git_reference *ref) assert(ref); if (ref->type & GIT_REF_PACKED) { + /* load the existing packfile */ + if ((error = packed_load(ref->owner)) < GIT_SUCCESS) + return error; + git_hashtable_remove(ref->owner->references.packfile, ref->name); error = packed_write(ref->owner); } else { diff --git a/src/repository.c b/src/repository.c index abbbd126a..c428b00af 100644 --- a/src/repository.c +++ b/src/repository.c @@ -473,3 +473,29 @@ cleanup: return error; } +int git_repository_is_empty(git_repository *repo) +{ + git_reference *head, *branch; + int error; + + error = git_reference_lookup(&head, repo, "HEAD"); + if (error < GIT_SUCCESS) + return error; + + if (git_reference_type(head) != GIT_REF_SYMBOLIC) + return GIT_EOBJCORRUPTED; + + return git_reference_resolve(&branch, head) == GIT_SUCCESS ? 0 : 1; +} + +const char *git_repository_path(git_repository *repo) +{ + assert(repo); + return repo->path_repository; +} + +const char *git_repository_workdir(git_repository *repo) +{ + assert(repo); + return repo->path_workdir; +} diff --git a/src/revwalk.c b/src/revwalk.c index 73bb060f5..b62b09961 100644 --- a/src/revwalk.c +++ b/src/revwalk.c @@ -191,6 +191,7 @@ static int commit_quick_parse(git_revwalk *walk, commit_object *commit, git_rawo unsigned char *parents_start; int i, parents = 0; + long commit_time; buffer += STRLEN("tree ") + GIT_OID_HEXSZ + 1; @@ -227,10 +228,10 @@ static int commit_quick_parse(git_revwalk *walk, commit_object *commit, git_rawo if (buffer == NULL) return GIT_EOBJCORRUPTED; - commit->time = strtol((char *)buffer + 2, NULL, 10); - if (commit->time == 0) + if (git__strtol32(&commit_time, (char *)buffer + 2, NULL, 10) < GIT_SUCCESS) return GIT_EOBJCORRUPTED; + commit->time = (time_t)commit_time; commit->parsed = 1; return GIT_SUCCESS; } diff --git a/src/signature.c b/src/signature.c index 0c99755d4..e8014620a 100644 --- a/src/signature.c +++ b/src/signature.c @@ -65,14 +65,47 @@ git_signature *git_signature_dup(const git_signature *sig) return git_signature_new(sig->name, sig->email, sig->when.time, sig->when.offset); } +git_signature *git_signature_now(const char *name, const char *email) +{ + time_t now; + time_t offset; + struct tm *utc_tm, *local_tm; + +#ifndef GIT_WIN32 + struct tm _utc, _local; +#endif + + time(&now); + + /** + * On Win32, `gmtime_r` doesn't exist but + * `gmtime` is threadsafe, so we can use that + */ +#ifdef GIT_WIN32 + utc_tm = gmtime(&now); + local_tm = localtime(&now); +#else + utc_tm = gmtime_r(&now, &_utc); + local_tm = localtime_r(&now, &_local); +#endif + + offset = mktime(local_tm) - mktime(utc_tm); + offset /= 60; + + /* mktime takes care of setting tm_isdst correctly */ + if (local_tm->tm_isdst) + offset += 60; + + return git_signature_new(name, email, now, (int)offset); +} -static int parse_timezone_offset(const char *buffer, int *offset_out) +static int parse_timezone_offset(const char *buffer, long *offset_out) { - int offset, dec_offset; + long offset, dec_offset; int mins, hours; - const char* offset_start; - char* offset_end; + const char *offset_start; + const char *offset_end; offset_start = buffer + 1; @@ -84,7 +117,8 @@ static int parse_timezone_offset(const char *buffer, int *offset_out) if (offset_start[0] != '-' && offset_start[0] != '+') return GIT_EOBJCORRUPTED; - dec_offset = strtol(offset_start + 1, &offset_end, 10); + if (git__strtol32(&dec_offset, offset_start + 1, &offset_end, 10) < GIT_SUCCESS) + return GIT_EOBJCORRUPTED; if (offset_end - offset_start != 5) return GIT_EOBJCORRUPTED; @@ -117,7 +151,7 @@ int git_signature__parse(git_signature *sig, const char **buffer_out, int name_length, email_length; const char *buffer = *buffer_out; const char *line_end, *name_end, *email_end; - int offset = 0; + long offset = 0, time; memset(sig, 0x0, sizeof(git_signature)); @@ -139,6 +173,9 @@ int git_signature__parse(git_signature *sig, const char **buffer_out, name_length = name_end - buffer - 1; sig->name = git__malloc(name_length + 1); + if (sig->name == NULL) + return GIT_ENOMEM; + memcpy(sig->name, buffer, name_length); sig->name[name_length] = 0; buffer = name_end + 1; @@ -152,6 +189,9 @@ int git_signature__parse(git_signature *sig, const char **buffer_out, email_length = email_end - buffer; sig->email = git__malloc(email_length + 1); + if (sig->name == NULL) + return GIT_ENOMEM; + memcpy(sig->email, buffer, email_length); sig->email[email_length] = 0; buffer = email_end + 1; @@ -159,11 +199,11 @@ int git_signature__parse(git_signature *sig, const char **buffer_out, if (buffer >= line_end) return GIT_EOBJCORRUPTED; - sig->when.time = strtol(buffer, (char **)&buffer, 10); - - if (sig->when.time == 0) + if (git__strtol32(&time, buffer, &buffer, 10) < GIT_SUCCESS) return GIT_EOBJCORRUPTED; + sig->when.time = (time_t)time; + if (parse_timezone_offset(buffer, &offset) < GIT_SUCCESS) return GIT_EOBJCORRUPTED; @@ -131,12 +131,17 @@ static int parse_tag_buffer(git_tag *tag, const char *buffer, const char *buffer text_len = search - buffer; tag->tag_name = git__malloc(text_len + 1); + if (tag->tag_name == NULL) + return GIT_ENOMEM; + memcpy(tag->tag_name, buffer, text_len); tag->tag_name[text_len] = '\0'; buffer = search + 1; tag->tagger = git__malloc(sizeof(git_signature)); + if (tag->tagger == NULL) + return GIT_ENOMEM; if ((error = git_signature__parse(tag->tagger, &buffer, buffer_end, "tagger ")) != 0) { free(tag->tag_name); @@ -147,6 +152,9 @@ static int parse_tag_buffer(git_tag *tag, const char *buffer, const char *buffer text_len = buffer_end - ++buffer; tag->message = git__malloc(text_len + 1); + if (tag->message == NULL) + return GIT_ENOMEM; + memcpy(tag->message, buffer, text_len); tag->message[text_len] = '\0'; @@ -209,6 +217,17 @@ static int tag_create( return error; } + if (!git_odb_exists(repo->db, target)) + return GIT_ENOTFOUND; + + /* Try to find out what the type is */ + if (target_type == GIT_OBJ_ANY) { + size_t _unused; + error = git_odb_read_header(&_unused, &target_type, repo->db, target); + if (error < GIT_SUCCESS) + return error; + } + type_str = git_object_type2string(target_type); tagger_str_len = git_signature__write(&tagger_str, "tagger", tagger); @@ -260,7 +279,6 @@ int git_tag_create_frombuffer(git_oid *oid, git_repository *repo, const char *bu { git_tag tag; int error; - git_object *obj; assert(oid && buffer); @@ -269,15 +287,8 @@ int git_tag_create_frombuffer(git_oid *oid, git_repository *repo, const char *bu if ((error = parse_tag_buffer(&tag, buffer, buffer + strlen(buffer))) < GIT_SUCCESS) return error; - error = git_object_lookup(&obj, repo, &tag.target, tag.type); - if (error < GIT_SUCCESS) - goto cleanup; - - error = git_tag_create_o(oid, repo, tag.tag_name, obj, tag.tagger, tag.message); - - git_object_close(obj); + error = git_tag_create(oid, repo, tag.tag_name, &tag.target, tag.type, tag.tagger, tag.message); -cleanup: git_signature_free(tag.tagger); free(tag.tag_name); free(tag.message); diff --git a/src/tree.c b/src/tree.c index 693ed1caa..64f81d780 100644 --- a/src/tree.c +++ b/src/tree.c @@ -150,7 +150,8 @@ static int tree_parse_buffer(git_tree *tree, const char *buffer, const char *buf if (git_vector_insert(&tree->entries, entry) < GIT_SUCCESS) return GIT_ENOMEM; - entry->attr = strtol(buffer, (char **)&buffer, 8); + if (git__strtol32((long *)&entry->attr, buffer, &buffer, 8) < GIT_SUCCESS) + return GIT_EOBJCORRUPTED; if (*buffer++ != ' ') { error = GIT_EOBJCORRUPTED; @@ -364,7 +365,7 @@ int git_treebuilder_insert(git_tree_entry **entry_out, git_treebuilder *bld, con git_oid_cpy(&entry->oid, id); entry->attr = attributes; - if (pos != GIT_ENOTFOUND) { + if (pos == GIT_ENOTFOUND) { if (git_vector_insert(&bld->entries, entry) < 0) return GIT_ENOMEM; } diff --git a/src/util.c b/src/util.c index 995daf314..55a7ab2a9 100644 --- a/src/util.c +++ b/src/util.c @@ -2,6 +2,7 @@ #include "common.h" #include <stdarg.h> #include <stdio.h> +#include <ctype.h> void git_strarray_free(git_strarray *array) { @@ -12,6 +13,84 @@ void git_strarray_free(git_strarray *array) free(array->strings); } +int git__strtol32(long *result, const char *nptr, const char **endptr, int base) +{ + const char *p; + long n, nn; + int c, ovfl, v, neg, ndig; + + p = nptr; + neg = 0; + n = 0; + ndig = 0; + ovfl = 0; + + /* + * White space + */ + while (isspace(*p)) + p++; + + /* + * Sign + */ + if (*p == '-' || *p == '+') + if (*p++ == '-') + neg = 1; + + /* + * Base + */ + if (base == 0) { + if (*p != '0') + base = 10; + else { + base = 8; + if (p[1] == 'x' || p[1] == 'X') { + p += 2; + base = 16; + } + } + } else if (base == 16 && *p == '0') { + if (p[1] == 'x' || p[1] == 'X') + p += 2; + } else if (base < 0 || 36 < base) + goto Return; + + /* + * Non-empty sequence of digits + */ + for (;; p++,ndig++) { + c = *p; + v = base; + if ('0'<=c && c<='9') + v = c - '0'; + else if ('a'<=c && c<='z') + v = c - 'a' + 10; + else if ('A'<=c && c<='Z') + v = c - 'A' + 10; + if (v >= base) + break; + nn = n*base + v; + if (nn < n) + ovfl = 1; + n = nn; + } + +Return: + if (ndig == 0) + return GIT_ENOTNUM; + + if (endptr) + *endptr = p; + + if (ovfl) + return GIT_EOVERFLOW; + + *result = neg ? -n : n; + return GIT_SUCCESS; +} + int git__fmt(char *buf, size_t buf_sz, const char *fmt, ...) { va_list va; diff --git a/src/util.h b/src/util.h index f477b64fd..3c606493f 100644 --- a/src/util.h +++ b/src/util.h @@ -22,6 +22,8 @@ extern int git__fmt(char *, size_t, const char *, ...) extern int git__prefixcmp(const char *str, const char *prefix); extern int git__suffixcmp(const char *str, const char *suffix); +extern int git__strtol32(long *n, const char *buff, const char **end_buf, int base); + /* * The dirname() function shall take a pointer to a character string * that contains a pathname, and return a pointer to a string that is a |