diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/config.c | 12 | ||||
| -rw-r--r-- | src/fileops.c | 2 | ||||
| -rw-r--r-- | src/index.c | 152 | ||||
| -rw-r--r-- | src/index.h | 16 | ||||
| -rw-r--r-- | src/posix.c | 9 | ||||
| -rw-r--r-- | src/posix.h | 2 | ||||
| -rw-r--r-- | src/tree-cache.c | 201 | ||||
| -rw-r--r-- | src/tree-cache.h | 31 | ||||
| -rw-r--r-- | src/tree.c | 80 | ||||
| -rw-r--r-- | src/win32/posix.h | 2 | ||||
| -rw-r--r-- | src/win32/posix_w32.c | 35 |
11 files changed, 324 insertions, 218 deletions
diff --git a/src/config.c b/src/config.c index e34acba9a..0ec710036 100644 --- a/src/config.c +++ b/src/config.c @@ -312,24 +312,20 @@ int git_config_get_string(git_config *cfg, const char *name, const char **out) int git_config_find_global(char *global_config_path) { - char *home; + const char *home; - home = p_getenv("HOME"); + home = getenv("HOME"); #ifdef GIT_WIN32 if (home == NULL) - home = p_getenv("USERPROFILE"); + home = getenv("USERPROFILE"); #endif - if (home == NULL) { - free(home); + if (home == NULL) return git__throw(GIT_EOSERR, "Failed to open global config file. Cannot locate the user's home directory"); - } git_path_join(global_config_path, home, GIT_CONFIG_FILENAME); - free(home); - if (git_futils_exists(global_config_path) < GIT_SUCCESS) return git__throw(GIT_EOSERR, "Failed to open global config file. The file does not exist"); diff --git a/src/fileops.c b/src/fileops.c index bfd63f584..203cce0a4 100644 --- a/src/fileops.c +++ b/src/fileops.c @@ -127,7 +127,7 @@ int git_futils_isfile(const char *path) int git_futils_exists(const char *path) { assert(path); - return access(path, F_OK); + return p_access(path, F_OK); } git_off_t git_futils_filesize(git_file fd) diff --git a/src/index.c b/src/index.c index f6f282d32..c7bf1a859 100644 --- a/src/index.c +++ b/src/index.c @@ -10,6 +10,7 @@ #include "common.h" #include "repository.h" #include "index.h" +#include "tree-cache.h" #include "hash.h" #include "git2/odb.h" #include "git2/blob.h" @@ -80,9 +81,6 @@ static size_t read_extension(git_index *index, const char *buffer, size_t buffer static size_t read_entry(git_index_entry *dest, const void *buffer, size_t buffer_size); static int read_header(struct index_header *dest, const void *buffer); -static int read_tree(git_index *index, const char *buffer, size_t buffer_size); -static int read_tree_internal(git_index_tree **, const char **, const char *, git_index_tree *); - static int parse_index(git_index *index, const char *buffer, size_t buffer_size); static int is_index_extended(git_index *index); static int write_index(git_index *index, git_filebuf *file); @@ -185,21 +183,6 @@ void git_index_free(git_index *index) free(index); } -static void free_tree(git_index_tree *tree) -{ - unsigned int i; - - if (tree == NULL) - return; - - for (i = 0; i < tree->children_count; ++i) - free_tree(tree->children[i]); - - free(tree->name); - free(tree->children); - free(tree); -} - void git_index_clear(git_index *index) { unsigned int i; @@ -224,7 +207,7 @@ void git_index_clear(git_index *index) git_vector_clear(&index->unmerged); index->last_modified = 0; - free_tree(index->tree); + git_tree_cache_free(index->tree); index->tree = NULL; } @@ -453,6 +436,8 @@ static int index_add(git_index *index, const char *path, int stage, int replace) if (ret) goto err; + git_tree_cache_invalidate_path(index->tree, entry->path); + return ret; err: index_entry_free(entry); @@ -485,6 +470,8 @@ static int index_add2(git_index *index, const git_index_entry *source_entry, if (ret) goto err; + git_tree_cache_invalidate_path(index->tree, entry->path); + return ret; err: index_entry_free(entry); @@ -503,7 +490,13 @@ int git_index_append2(git_index *index, const git_index_entry *source_entry) int git_index_remove(git_index *index, int position) { + git_index_entry *entry; + git_vector_sort(&index->entries); + entry = git_vector_get(&index->entries, position); + if (entry != NULL) + git_tree_cache_invalidate_path(index->tree, entry->path); + return git_vector_remove(&index->entries, (unsigned int)position); } @@ -537,125 +530,6 @@ const git_index_entry_unmerged *git_index_get_unmerged_byindex(git_index *index, return git_vector_get(&index->unmerged, n); } - -static int read_tree_internal(git_index_tree **out, - const char **buffer_in, const char *buffer_end, git_index_tree *parent) -{ - git_index_tree *tree; - const char *name_start, *buffer; - int count; - int error = GIT_SUCCESS; - - if ((tree = git__malloc(sizeof(git_index_tree))) == NULL) - return GIT_ENOMEM; - - memset(tree, 0x0, sizeof(git_index_tree)); - tree->parent = parent; - - buffer = name_start = *buffer_in; - - if ((buffer = memchr(buffer, '\0', buffer_end - buffer)) == NULL) { - error = GIT_EOBJCORRUPTED; - goto cleanup; - } - - /* NUL-terminated tree name */ - tree->name = git__strdup(name_start); - if (tree->name == NULL) { - error = GIT_ENOMEM; - goto cleanup; - } - - if (++buffer >= buffer_end) { - error = GIT_EOBJCORRUPTED; - goto cleanup; - } - - /* Blank-terminated ASCII decimal number of entries in this tree */ - if (git__strtol32(&count, buffer, &buffer, 10) < GIT_SUCCESS || count < -1) { - error = GIT_EOBJCORRUPTED; - goto cleanup; - } - - /* Invalidated TREE. Free the tree but report success */ - if (count == -1) { - /* FIXME: return buffer_end or the end position for - * this single tree entry */ - *buffer_in = buffer_end; - *out = NULL; - free_tree(tree); /* Needs to be done manually */ - return GIT_SUCCESS; - } - - tree->entries = count; - - if (*buffer != ' ' || ++buffer >= buffer_end) { - error = GIT_EOBJCORRUPTED; - goto cleanup; - } - - /* Number of children of the tree, newline-terminated */ - if (git__strtol32(&count, buffer, &buffer, 10) < GIT_SUCCESS || - count < 0) { - error = GIT_EOBJCORRUPTED; - goto cleanup; - } - - tree->children_count = count; - - if (*buffer != '\n' || ++buffer >= buffer_end) { - error = GIT_EOBJCORRUPTED; - goto cleanup; - } - - /* 160-bit SHA-1 for this tree and it's children */ - if (buffer + GIT_OID_RAWSZ > buffer_end) { - error = GIT_EOBJCORRUPTED; - goto cleanup; - } - - git_oid_fromraw(&tree->oid, (const unsigned char *)buffer); - buffer += GIT_OID_RAWSZ; - - /* Parse children: */ - if (tree->children_count > 0) { - unsigned int i; - int err; - - tree->children = git__malloc(tree->children_count * sizeof(git_index_tree *)); - if (tree->children == NULL) - goto cleanup; - - for (i = 0; i < tree->children_count; ++i) { - err = read_tree_internal(&tree->children[i], &buffer, buffer_end, tree); - - if (err < GIT_SUCCESS) - goto cleanup; - } - } - - *buffer_in = buffer; - *out = tree; - return GIT_SUCCESS; - - cleanup: - free_tree(tree); - return error; -} - -static int read_tree(git_index *index, const char *buffer, size_t buffer_size) -{ - const char *buffer_end = buffer + buffer_size; - int error; - - error = read_tree_internal(&index->tree, &buffer, buffer_end, NULL); - - if (buffer < buffer_end) - return GIT_EOBJCORRUPTED; - - return error; -} - static int read_unmerged(git_index *index, const char *buffer, size_t size) { const char *endptr; @@ -814,7 +688,7 @@ static size_t read_extension(git_index *index, const char *buffer, size_t buffer if (dest.signature[0] >= 'A' && dest.signature[0] <= 'Z') { /* tree cache */ if (memcmp(dest.signature, INDEX_EXT_TREECACHE_SIG, 4) == 0) { - if (read_tree(index, buffer + 8, dest.extension_size) < GIT_SUCCESS) + if (git_tree_cache_read(&index->tree, buffer + 8, dest.extension_size) < GIT_SUCCESS) return 0; } else if (memcmp(dest.signature, INDEX_EXT_UNMERGED_SIG, 4) == 0) { if (read_unmerged(index, buffer + 8, dest.extension_size) < GIT_SUCCESS) diff --git a/src/index.h b/src/index.h index 76633a96a..e912770b7 100644 --- a/src/index.h +++ b/src/index.h @@ -10,22 +10,10 @@ #include "fileops.h" #include "filebuf.h" #include "vector.h" +#include "tree-cache.h" #include "git2/odb.h" #include "git2/index.h" -struct git_index_tree { - char *name; - - struct git_index_tree *parent; - struct git_index_tree **children; - size_t children_count; - - size_t entries; - git_oid oid; -}; - -typedef struct git_index_tree git_index_tree; - struct git_index { git_repository *repository; char *index_file_path; @@ -34,7 +22,7 @@ struct git_index { git_vector entries; unsigned int on_disk:1; - git_index_tree *tree; + git_tree_cache *tree; git_vector unmerged; }; diff --git a/src/posix.c b/src/posix.c index fb8ce37cb..1b85b053d 100644 --- a/src/posix.c +++ b/src/posix.c @@ -39,15 +39,6 @@ int p_getcwd(char *buffer_out, size_t size) return GIT_SUCCESS; } -char* p_getenv(const char* name) -{ - char* buf = getenv(name); - if (!buf) - return buf; - - return git__strdup(buf); -} - #endif int p_read(git_file fd, void *buf, size_t cnt) diff --git a/src/posix.h b/src/posix.h index d656e8ec0..59bec2794 100644 --- a/src/posix.h +++ b/src/posix.h @@ -44,7 +44,6 @@ extern int p_write(git_file fd, const void *buf, size_t cnt); extern int p_open(const char *path, int flags); extern int p_creat(const char *path, int mode); extern int p_getcwd(char *buffer_out, size_t size); -extern char* p_getenv(const char* name); #ifndef GIT_WIN32 @@ -52,6 +51,7 @@ extern char* p_getenv(const char* name); #define p_chdir(p) chdir(p) #define p_rmdir(p) rmdir(p) #define p_chmod(p,m) chmod(p, m) +#define p_access(p,m) access(p,m) #endif diff --git a/src/tree-cache.c b/src/tree-cache.c new file mode 100644 index 000000000..5a3257520 --- /dev/null +++ b/src/tree-cache.c @@ -0,0 +1,201 @@ +/* + * Copyright (C) 2009-2011 the libgit2 contributors + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ + +#include "tree-cache.h" + +static git_tree_cache *find_child(const git_tree_cache *tree, const char *path) +{ + size_t i, dirlen; + const char *end; + + end = strchr(path, '/'); + if (end == NULL) { + end = strrchr(path, '\0'); + } + + dirlen = end - path; + + for (i = 0; i < tree->children_count; ++i) { + const char *childname = tree->children[i]->name; + + if (strlen(childname) == dirlen && !memcmp(path, childname, dirlen)) + return tree->children[i]; + } + + return NULL; +} + +void git_tree_cache_invalidate_path(git_tree_cache *tree, const char *path) +{ + const char *ptr = path, *end; + + if (tree == NULL) + return; + + tree->entries = -1; + + while (ptr != NULL) { + end = strchr(ptr, '/'); + + if (end == NULL) /* End of path */ + break; + + tree = find_child(tree, ptr); + if (tree == NULL) /* We don't have that tree */ + return; + + tree->entries = -1; + ptr = end + 1; + } +} + +const git_tree_cache *git_tree_cache_get(const git_tree_cache *tree, const char *path) +{ + const char *ptr = path, *end; + + if (tree == NULL) { + return NULL; + } + + while (1) { + end = strchr(ptr, '/'); + + tree = find_child(tree, ptr); + if (tree == NULL) { /* Can't find it */ + return NULL; + } + + if (end == NULL || end + 1 == '\0') + return tree; + + ptr = end + 1; + } +} + +static int read_tree_internal(git_tree_cache **out, + const char **buffer_in, const char *buffer_end, git_tree_cache *parent) +{ + git_tree_cache *tree = NULL; + const char *name_start, *buffer; + int count; + int error = GIT_SUCCESS; + size_t name_len; + + buffer = name_start = *buffer_in; + + if ((buffer = memchr(buffer, '\0', buffer_end - buffer)) == NULL) { + error = GIT_EOBJCORRUPTED; + goto cleanup; + } + + if (++buffer >= buffer_end) { + error = GIT_EOBJCORRUPTED; + goto cleanup; + } + + name_len = strlen(name_start); + if ((tree = git__malloc(sizeof(git_tree_cache) + name_len + 1)) == NULL) + return GIT_ENOMEM; + + memset(tree, 0x0, sizeof(git_tree_cache)); + tree->parent = parent; + + /* NUL-terminated tree name */ + memcpy(tree->name, name_start, name_len); + tree->name[name_len] = '\0'; + + /* Blank-terminated ASCII decimal number of entries in this tree */ + if (git__strtol32(&count, buffer, &buffer, 10) < GIT_SUCCESS || count < -1) { + error = GIT_EOBJCORRUPTED; + goto cleanup; + } + + tree->entries = count; + + if (*buffer != ' ' || ++buffer >= buffer_end) { + error = GIT_EOBJCORRUPTED; + goto cleanup; + } + + /* Number of children of the tree, newline-terminated */ + if (git__strtol32(&count, buffer, &buffer, 10) < GIT_SUCCESS || + count < 0) { + error = GIT_EOBJCORRUPTED; + goto cleanup; + } + + tree->children_count = count; + + if (*buffer != '\n' || ++buffer >= buffer_end) { + error = GIT_EOBJCORRUPTED; + goto cleanup; + } + + /* The SHA1 is only there if it's not invalidated */ + if (tree->entries >= 0) { + /* 160-bit SHA-1 for this tree and it's children */ + if (buffer + GIT_OID_RAWSZ > buffer_end) { + error = GIT_EOBJCORRUPTED; + goto cleanup; + } + + git_oid_fromraw(&tree->oid, (const unsigned char *)buffer); + buffer += GIT_OID_RAWSZ; + } + + /* Parse children: */ + if (tree->children_count > 0) { + unsigned int i; + int err; + + tree->children = git__malloc(tree->children_count * sizeof(git_tree_cache *)); + if (tree->children == NULL) + goto cleanup; + + for (i = 0; i < tree->children_count; ++i) { + err = read_tree_internal(&tree->children[i], &buffer, buffer_end, tree); + + if (err < GIT_SUCCESS) + goto cleanup; + } + } + + *buffer_in = buffer; + *out = tree; + return GIT_SUCCESS; + + cleanup: + git_tree_cache_free(tree); + return error; +} + +int git_tree_cache_read(git_tree_cache **tree, const char *buffer, size_t buffer_size) +{ + const char *buffer_end = buffer + buffer_size; + int error; + + error = read_tree_internal(tree, &buffer, buffer_end, NULL); + + if (buffer < buffer_end) + return GIT_EOBJCORRUPTED; + + return error; +} + +void git_tree_cache_free(git_tree_cache *tree) +{ + unsigned int i; + + if (tree == NULL) + return; + + for (i = 0; i < tree->children_count; ++i) + git_tree_cache_free(tree->children[i]); + + free(tree->children); + free(tree); +} diff --git a/src/tree-cache.h b/src/tree-cache.h new file mode 100644 index 000000000..0d9329157 --- /dev/null +++ b/src/tree-cache.h @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2009-2011 the libgit2 contributors + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ + +#ifndef INCLUDE_tree_cache_h__ +#define INCLUDE_tree_cache_h__ + +#include "common.h" +#include "git2/oid.h" + +struct git_tree_cache { + struct git_tree_cache *parent; + struct git_tree_cache **children; + size_t children_count; + + ssize_t entries; + git_oid oid; + char name[GIT_FLEX_ARRAY]; +}; + +typedef struct git_tree_cache git_tree_cache; + +int git_tree_cache_read(git_tree_cache **tree, const char *buffer, size_t buffer_size); +void git_tree_cache_invalidate_path(git_tree_cache *tree, const char *path); +const git_tree_cache *git_tree_cache_get(const git_tree_cache *tree, const char *path); +void git_tree_cache_free(git_tree_cache *tree); + +#endif diff --git a/src/tree.c b/src/tree.c index 2f9ae2ef1..0acf74ede 100644 --- a/src/tree.c +++ b/src/tree.c @@ -15,7 +15,8 @@ #define MAX_FILEMODE 0777777 #define MAX_FILEMODE_BYTES 6 -static int valid_attributes(const int attributes) { +static int valid_attributes(const int attributes) +{ return attributes >= 0 && attributes <= MAX_FILEMODE; } @@ -169,8 +170,9 @@ static int tree_parse_buffer(git_tree *tree, const char *buffer, const char *buf return GIT_ENOMEM; if (git__strtol32(&tmp, buffer, &buffer, 8) < GIT_SUCCESS || - !buffer || tmp > UINT_MAX || tmp < 0) + !buffer || !valid_attributes(tmp)) return git__throw(GIT_EOBJCORRUPTED, "Failed to parse tree. Can't parse attributes"); + entry->attr = tmp; if (*buffer++ != ' ') { @@ -204,12 +206,59 @@ int git_tree__parse(git_tree *tree, git_odb_object *obj) return tree_parse_buffer(tree, (char *)obj->raw.data, (char *)obj->raw.data + obj->raw.len); } +static unsigned int find_next_dir(const char *dirname, git_index *index, unsigned int start) +{ + unsigned int i, entries = git_index_entrycount(index); + size_t dirlen; + + dirlen = strlen(dirname); + for (i = start; i < entries; ++i) { + git_index_entry *entry = git_index_get(index, i); + if (strlen(entry->path) < dirlen || + memcmp(entry->path, dirname, dirlen) || + (dirlen > 0 && entry->path[dirlen] != '/')) { + break; + } + } + + return i; +} + +static int append_entry(git_treebuilder *bld, const char *filename, const git_oid *id, unsigned int attributes) +{ + git_tree_entry *entry; + + if ((entry = git__malloc(sizeof(git_tree_entry))) == NULL) + return GIT_ENOMEM; + + memset(entry, 0x0, sizeof(git_tree_entry)); + entry->filename = git__strdup(filename); + entry->filename_len = strlen(entry->filename); + + bld->entry_count++; + + git_oid_cpy(&entry->oid, id); + entry->attr = attributes; + + if (git_vector_insert(&bld->entries, entry) < 0) + return GIT_ENOMEM; + + return GIT_SUCCESS; +} + static int write_tree(git_oid *oid, git_index *index, const char *dirname, unsigned int start) { git_treebuilder *bld = NULL; unsigned int i, entries = git_index_entrycount(index); int error; size_t dirname_len = strlen(dirname); + const git_tree_cache *cache; + + cache = git_tree_cache_get(index->tree, dirname); + if (cache != NULL && cache->entries >= 0){ + git_oid_cpy(oid, &cache->oid); + return find_next_dir(dirname, index, start); + } error = git_treebuilder_create(&bld, NULL); if (bld == NULL) { @@ -274,14 +323,14 @@ static int write_tree(git_oid *oid, git_index *index, const char *dirname, unsig } else { last_comp = subdir; } - error = git_treebuilder_insert(NULL, bld, last_comp, &sub_oid, S_IFDIR); + error = append_entry(bld, last_comp, &sub_oid, S_IFDIR); free(subdir); if (error < GIT_SUCCESS) { error = git__rethrow(error, "Failed to insert dir"); goto cleanup; } } else { - error = git_treebuilder_insert(NULL, bld, filename, &entry->oid, entry->mode); + error = append_entry(bld, filename, &entry->oid, entry->mode); if (error < GIT_SUCCESS) { error = git__rethrow(error, "Failed to insert file"); } @@ -308,6 +357,11 @@ int git_tree_create_fromindex(git_oid *oid, git_index *index) if (index->repository == NULL) return git__throw(GIT_EBAREINDEX, "Failed to create tree. The index file is not backed up by an existing repository"); + if (index->tree != NULL && index->tree->entries >= 0) { + git_oid_cpy(oid, &index->tree->oid); + return GIT_SUCCESS; + } + /* The tree cache didn't help us */ error = write_tree(oid, index, "", 0); return (error < GIT_SUCCESS) ? git__rethrow(error, "Failed to create tree") : GIT_SUCCESS; @@ -338,29 +392,13 @@ int git_treebuilder_create(git_treebuilder **builder_p, const git_tree *source) } if (source != NULL) { - bld->entry_count = source_entries; for (i = 0; i < source->entries.length; ++i) { git_tree_entry *entry_src = source->entries.contents[i]; - git_tree_entry *entry = git__calloc(1, sizeof(git_tree_entry)); - if (entry == NULL) { + if (append_entry(bld, entry_src->filename, &entry_src->oid, entry_src->attr) < 0) { git_treebuilder_free(bld); return GIT_ENOMEM; } - - entry->filename = git__strdup(entry_src->filename); - - if (entry->filename == NULL) { - free(entry); - git_treebuilder_free(bld); - return GIT_ENOMEM; - } - - entry->filename_len = entry_src->filename_len; - git_oid_cpy(&entry->oid, &entry_src->oid); - entry->attr = entry_src->attr; - - git_vector_insert(&bld->entries, entry); } } diff --git a/src/win32/posix.h b/src/win32/posix.h index 4c45fd3e4..d82506ab5 100644 --- a/src/win32/posix.h +++ b/src/win32/posix.h @@ -43,6 +43,6 @@ extern int p_stat(const char* path, struct stat* buf); extern int p_chdir(const char* path); extern int p_chmod(const char* path, int mode); extern int p_rmdir(const char* path); - +extern int p_access(const char* path, int mode); #endif diff --git a/src/win32/posix_w32.c b/src/win32/posix_w32.c index 85a04bc0f..cc17cc71f 100644 --- a/src/win32/posix_w32.c +++ b/src/win32/posix_w32.c @@ -370,30 +370,6 @@ int p_mkstemp(char *tmp_path) return p_creat(tmp_path, 0744); } -char* p_getenv(const char* name) -{ - wchar_t* buf; - wchar_t* name_w = conv_utf8_to_utf16(name); - char* ret; - DWORD len; - - len = GetEnvironmentVariableW(name_w, NULL, 0); - if (len == 0) { - free(name_w); - return NULL; - } - - len++; /* Null Terminator */ - buf = malloc(sizeof(wchar_t) * len); - GetEnvironmentVariableW(name_w, buf, len); - - ret = conv_utf16_to_utf8(buf); - - free(name_w); - free(buf); - return ret; -} - int p_setenv(const char* name, const char* value, int overwrite) { if (overwrite != 1) @@ -401,3 +377,14 @@ int p_setenv(const char* name, const char* value, int overwrite) return (SetEnvironmentVariableA(name, value) == 0 ? GIT_EOSERR : GIT_SUCCESS); } + +int p_access(const char* path, int mode) +{ + wchar_t *buf = conv_utf8_to_utf16(path); + int ret; + + ret = _waccess(buf, mode); + free(buf); + + return ret; +} |
