diff options
Diffstat (limited to 'src/index.c')
-rw-r--r-- | src/index.c | 219 |
1 files changed, 112 insertions, 107 deletions
diff --git a/src/index.c b/src/index.c index 1d46779bf..09e7b2346 100644 --- a/src/index.c +++ b/src/index.c @@ -16,6 +16,7 @@ #include "iterator.h" #include "pathspec.h" #include "ignore.h" +#include "blob.h" #include "git2/odb.h" #include "git2/oid.h" @@ -101,8 +102,6 @@ static int parse_index(git_index *index, const char *buffer, size_t buffer_size) static bool is_index_extended(git_index *index); static int write_index(git_index *index, git_filebuf *file); -static int index_find(size_t *at_pos, git_index *index, const char *path, int stage); - static void index_entry_free(git_index_entry *entry); static void index_entry_reuc_free(git_index_reuc_entry *reuc); @@ -114,7 +113,7 @@ static int index_srch(const void *key, const void *array_member) ret = strcmp(srch_key->path, entry->path); - if (ret == 0) + if (ret == 0 && srch_key->stage != GIT_INDEX_STAGE_ANY) ret = srch_key->stage - GIT_IDXENTRY_STAGE(entry); return ret; @@ -128,7 +127,7 @@ static int index_isrch(const void *key, const void *array_member) ret = strcasecmp(srch_key->path, entry->path); - if (ret == 0) + if (ret == 0 && srch_key->stage != GIT_INDEX_STAGE_ANY) ret = srch_key->stage - GIT_IDXENTRY_STAGE(entry); return ret; @@ -261,6 +260,22 @@ static int reuc_icmp(const void *a, const void *b) return strcasecmp(info_a->path, info_b->path); } +static void index_entry_reuc_free(git_index_reuc_entry *reuc) +{ + if (!reuc) + return; + git__free(reuc->path); + git__free(reuc); +} + +static void index_entry_free(git_index_entry *entry) +{ + if (!entry) + return; + git__free(entry->path); + git__free(entry); +} + static unsigned int index_create_mode(unsigned int mode) { if (S_ISLNK(mode)) @@ -269,7 +284,7 @@ static unsigned int index_create_mode(unsigned int mode) if (S_ISDIR(mode) || (mode & S_IFMT) == (S_IFLNK | S_IFDIR)) return (S_IFLNK | S_IFDIR); - return S_IFREG | ((mode & 0100) ? 0755 : 0644); + return S_IFREG | GIT_PERMS_CANONICAL(mode); } static unsigned int index_merge_mode( @@ -306,6 +321,7 @@ void git_index__set_ignore_case(git_index *index, bool ignore_case) int git_index_open(git_index **index_out, const char *index_path) { git_index *index; + int error; assert(index_out); @@ -331,10 +347,15 @@ int git_index_open(git_index **index_out, const char *index_path) index->entries_search_path = index_srch_path; index->reuc_search = reuc_srch; + if ((index_path != NULL) && ((error = git_index_read(index, true)) < 0)) { + git_index_free(index); + return error; + } + *index_out = index; GIT_REFCOUNT_INC(index); - return (index_path != NULL) ? git_index_read(index) : 0; + return 0; } int git_index_new(git_index **out) @@ -367,11 +388,8 @@ static void index_entries_free(git_vector *entries) { size_t i; - for (i = 0; i < entries->length; ++i) { - git_index_entry *e = git_vector_get(entries, i); - git__free(e->path); - git__free(e); - } + for (i = 0; i < entries->length; ++i) + index_entry_free(git__swap(entries->contents[i], NULL)); git_vector_clear(entries); } @@ -398,7 +416,7 @@ static int create_index_error(int error, const char *msg) int git_index_set_caps(git_index *index, unsigned int caps) { - int old_ignore_case; + unsigned int old_ignore_case; assert(index); @@ -426,7 +444,7 @@ int git_index_set_caps(git_index *index, unsigned int caps) } if (old_ignore_case != index->ignore_case) { - git_index__set_ignore_case(index, index->ignore_case); + git_index__set_ignore_case(index, (bool)index->ignore_case); } return 0; @@ -439,24 +457,26 @@ unsigned int git_index_caps(const git_index *index) (index->no_symlinks ? GIT_INDEXCAP_NO_SYMLINKS : 0)); } -int git_index_read(git_index *index) +int git_index_read(git_index *index, int force) { int error = 0, updated; git_buf buffer = GIT_BUF_INIT; - git_futils_filestamp stamp = {0}; + git_futils_filestamp stamp = index->stamp; if (!index->index_file_path) return create_index_error(-1, "Failed to read index: The index is in-memory only"); - if (!index->on_disk || git_path_exists(index->index_file_path) == false) { - git_index_clear(index); - index->on_disk = 0; + index->on_disk = git_path_exists(index->index_file_path); + + if (!index->on_disk) { + if (force) + git_index_clear(index); return 0; } updated = git_futils_filestamp_check(&stamp, index->index_file_path); - if (updated <= 0) + if (updated < 0 || (!updated && !force)) return updated; error = git_futils_readbuffer(&buffer, index->index_file_path); @@ -486,15 +506,19 @@ int git_index_write(git_index *index) git_vector_sort(&index->reuc); if ((error = git_filebuf_open( - &file, index->index_file_path, GIT_FILEBUF_HASH_CONTENTS)) < 0) + &file, index->index_file_path, GIT_FILEBUF_HASH_CONTENTS, GIT_INDEX_FILE_MODE)) < 0) { + if (error == GIT_ELOCKED) + giterr_set(GITERR_INDEX, "The index is locked. This might be due to a concurrrent or crashed process"); + return error; + } if ((error = write_index(index, &file)) < 0) { git_filebuf_cleanup(&file); return error; } - if ((error = git_filebuf_commit(&file, GIT_INDEX_FILE_MODE)) < 0) + if ((error = git_filebuf_commit(&file)) < 0) return error; error = git_futils_filestamp_check(&index->stamp, index->index_file_path); @@ -505,6 +529,12 @@ int git_index_write(git_index *index) return 0; } +const char * git_index_path(git_index *index) +{ + assert(index); + return index->index_file_path; +} + int git_index_write_tree(git_oid *oid, git_index *index) { git_repository *repo; @@ -549,7 +579,7 @@ const git_index_entry *git_index_get_bypath( git_vector_sort(&index->entries); - if (index_find(&pos, index, path, stage) < 0) { + if (git_index__find(&pos, index, path, stage) < 0) { giterr_set(GITERR_INDEX, "Index does not contain %s", path); return NULL; } @@ -557,7 +587,8 @@ const git_index_entry *git_index_get_bypath( return git_index_get_byindex(index, pos); } -void git_index_entry__init_from_stat(git_index_entry *entry, struct stat *st) +void git_index_entry__init_from_stat( + git_index_entry *entry, struct stat *st, bool trust_mode) { entry->ctime.seconds = (git_time_t)st->st_ctime; entry->mtime.seconds = (git_time_t)st->st_mtime; @@ -565,7 +596,8 @@ void git_index_entry__init_from_stat(git_index_entry *entry, struct stat *st) /* entry->ctime.nanoseconds = st->st_ctimensec; */ entry->dev = st->st_rdev; entry->ino = st->st_ino; - entry->mode = index_create_mode(st->st_mode); + entry->mode = (!trust_mode && S_ISREG(st->st_mode)) ? + index_create_mode(0666) : index_create_mode(st->st_mode); entry->uid = st->st_uid; entry->gid = st->st_gid; entry->file_size = st->st_size; @@ -587,48 +619,29 @@ int git_index_entry__cmp_icase(const void *a, const void *b) return strcasecmp(entry_a->path, entry_b->path); } -static int index_entry_init(git_index_entry **entry_out, git_index *index, const char *rel_path) +static int index_entry_init( + git_index_entry **entry_out, git_index *index, const char *rel_path) { + int error = 0; git_index_entry *entry = NULL; struct stat st; git_oid oid; - const char *workdir; - git_buf full_path = GIT_BUF_INIT; - int error; if (INDEX_OWNER(index) == NULL) return create_index_error(-1, "Could not initialize index entry. " "Index is not backed up by an existing repository."); - workdir = git_repository_workdir(INDEX_OWNER(index)); - - if (!workdir) - return create_index_error(GIT_EBAREREPO, - "Could not initialize index entry. Repository is bare"); - - if ((error = git_buf_joinpath(&full_path, workdir, rel_path)) < 0) - return error; - - if ((error = git_path_lstat(full_path.ptr, &st)) < 0) { - git_buf_free(&full_path); - return error; - } - - git_buf_free(&full_path); /* done with full path */ - - /* There is no need to validate the rel_path here, since it will be - * immediately validated by the call to git_blob_create_fromfile. - */ - - /* write the blob to disk and get the oid */ - if ((error = git_blob_create_fromworkdir(&oid, INDEX_OWNER(index), rel_path)) < 0) + /* write the blob to disk and get the oid and stat info */ + error = git_blob__create_from_paths( + &oid, &st, INDEX_OWNER(index), NULL, rel_path, 0, true); + if (error < 0) return error; entry = git__calloc(1, sizeof(git_index_entry)); GITERR_CHECK_ALLOC(entry); - git_index_entry__init_from_stat(entry, &st); + git_index_entry__init_from_stat(entry, &st, !index->distrust_filemode); entry->oid = oid; entry->path = git__strdup(rel_path); @@ -670,15 +683,6 @@ static int index_entry_reuc_init(git_index_reuc_entry **reuc_out, return 0; } -static void index_entry_reuc_free(git_index_reuc_entry *reuc) -{ - if (!reuc) - return; - - git__free(reuc->path); - git__free(reuc); -} - static git_index_entry *index_entry_dup(const git_index_entry *source_entry) { git_index_entry *entry; @@ -697,14 +701,6 @@ static git_index_entry *index_entry_dup(const git_index_entry *source_entry) return entry; } -static void index_entry_free(git_index_entry *entry) -{ - if (!entry) - return; - git__free(entry->path); - git__free(entry); -} - static int index_insert(git_index *index, git_index_entry *entry, int replace) { size_t path_length, position; @@ -723,7 +719,8 @@ static int index_insert(git_index *index, git_index_entry *entry, int replace) entry->flags |= GIT_IDXENTRY_NAMEMASK; /* look if an entry with this path already exists */ - if (!index_find(&position, index, entry->path, GIT_IDXENTRY_STAGE(entry))) { + if (!git_index__find( + &position, index, entry->path, GIT_IDXENTRY_STAGE(entry))) { existing = (git_index_entry **)&index->entries.contents[position]; /* update filemode to existing values if stat is not trusted */ @@ -835,7 +832,7 @@ int git_index_remove(git_index *index, const char *path, int stage) git_vector_sort(&index->entries); - if (index_find(&position, index, path, stage) < 0) { + if (git_index__find(&position, index, path, stage) < 0) { giterr_set(GITERR_INDEX, "Index does not contain %s at stage %d", path, stage); return GIT_ENOTFOUND; @@ -891,7 +888,8 @@ int git_index_remove_directory(git_index *index, const char *dir, int stage) return error; } -static int index_find(size_t *at_pos, git_index *index, const char *path, int stage) +int git_index__find( + size_t *at_pos, git_index *index, const char *path, int stage) { struct entry_srch_key srch_key; @@ -900,7 +898,8 @@ static int index_find(size_t *at_pos, git_index *index, const char *path, int st srch_key.path = path; srch_key.stage = stage; - return git_vector_bsearch2(at_pos, &index->entries, index->entries_search, &srch_key); + return git_vector_bsearch2( + at_pos, &index->entries, index->entries_search, &srch_key); } int git_index_find(size_t *at_pos, git_index *index, const char *path) @@ -1357,14 +1356,11 @@ int git_index_reuc_remove(git_index *index, size_t position) void git_index_reuc_clear(git_index *index) { size_t i; - git_index_reuc_entry *reuc; assert(index); - git_vector_foreach(&index->reuc, i, reuc) { - git__free(reuc->path); - git__free(reuc); - } + for (i = 0; i < index->reuc.length; ++i) + index_entry_reuc_free(git__swap(index->reuc.contents[i], NULL)); git_vector_clear(&index->reuc); } @@ -1389,7 +1385,7 @@ static int read_reuc(git_index *index, const char *buffer, size_t size) while (size) { git_index_reuc_entry *lost; - len = strlen(buffer) + 1; + len = p_strnlen(buffer, size) + 1; if (size <= len) return index_error_invalid("reading reuc entries"); @@ -1409,14 +1405,18 @@ static int read_reuc(git_index *index, const char *buffer, size_t size) if (git__strtol32(&tmp, buffer, &endptr, 8) < 0 || !endptr || endptr == buffer || *endptr || - (unsigned)tmp > UINT_MAX) + (unsigned)tmp > UINT_MAX) { + index_entry_reuc_free(lost); return index_error_invalid("reading reuc entry stage"); + } lost->mode[i] = tmp; len = (endptr + 1) - buffer; - if (size <= len) + if (size <= len) { + index_entry_reuc_free(lost); return index_error_invalid("reading reuc entry stage"); + } size -= len; buffer += len; @@ -1426,8 +1426,10 @@ static int read_reuc(git_index *index, const char *buffer, size_t size) for (i = 0; i < 3; i++) { if (!lost->mode[i]) continue; - if (size < 20) + if (size < 20) { + index_entry_reuc_free(lost); return index_error_invalid("reading reuc entry oid"); + } git_oid_fromraw(&lost->oid[i], (const unsigned char *) buffer); size -= 20; @@ -1456,7 +1458,7 @@ static int read_conflict_names(git_index *index, const char *buffer, size_t size return -1; #define read_conflict_name(ptr) \ - len = strlen(buffer) + 1; \ + len = p_strnlen(buffer, size) + 1; \ if (size < len) \ return index_error_invalid("reading conflict name entries"); \ \ @@ -1583,7 +1585,8 @@ static size_t read_extension(git_index *index, const char *buffer, size_t buffer total_size = dest.extension_size + sizeof(struct index_extension); - if (buffer_size < total_size || + if (dest.extension_size > total_size || + buffer_size < total_size || buffer_size - total_size < INDEX_FOOTER_SIZE) return 0; @@ -1958,8 +1961,9 @@ int git_index_entry_stage(const git_index_entry *entry) } typedef struct read_tree_data { - git_index *index; git_vector *old_entries; + git_vector *new_entries; + git_vector_cmp entries_search; } read_tree_data; static int read_tree_cb( @@ -1990,7 +1994,7 @@ static int read_tree_cb( skey.stage = 0; if (!git_vector_bsearch2( - &pos, data->old_entries, data->index->entries_search, &skey) && + &pos, data->old_entries, data->entries_search, &skey) && (old_entry = git_vector_get(data->old_entries, pos)) != NULL && entry->mode == old_entry->mode && git_oid_equal(&entry->oid, &old_entry->oid)) @@ -2008,7 +2012,7 @@ static int read_tree_cb( entry->path = git_buf_detach(&path); git_buf_free(&path); - if (git_vector_insert(&data->index->entries, entry) < 0) { + if (git_vector_insert(data->new_entries, entry) < 0) { index_entry_free(entry); return -1; } @@ -2022,22 +2026,22 @@ int git_index_read_tree(git_index *index, const git_tree *tree) git_vector entries = GIT_VECTOR_INIT; read_tree_data data; - git_vector_sort(&index->entries); + git_vector_set_cmp(&entries, index->entries._cmp); /* match sort */ - git_vector_set_cmp(&entries, index->entries._cmp); - git_vector_swap(&entries, &index->entries); + data.old_entries = &index->entries; + data.new_entries = &entries; + data.entries_search = index->entries_search; - git_index_clear(index); - - data.index = index; - data.old_entries = &entries; + git_vector_sort(&index->entries); error = git_tree_walk(tree, GIT_TREEWALK_POST, read_tree_cb, &data); - index_entries_free(&entries); - git_vector_free(&entries); + git_vector_sort(&entries); - git_vector_sort(&index->entries); + git_index_clear(index); + + git_vector_swap(&entries, &index->entries); + git_vector_free(&entries); return error; } @@ -2059,7 +2063,7 @@ int git_index_add_all( git_iterator *wditer = NULL; const git_index_entry *wd = NULL; git_index_entry *entry; - git_pathspec_context ps; + git_pathspec ps; const char *match; size_t existing; bool no_fnmatch = (flags & GIT_INDEX_ADD_DISABLE_PATHSPEC_MATCH) != 0; @@ -2080,7 +2084,7 @@ int git_index_add_all( if (git_repository__cvar(&ignorecase, repo, GIT_CVAR_IGNORECASE) < 0) return -1; - if ((error = git_pathspec_context_init(&ps, paths)) < 0) + if ((error = git_pathspec__init(&ps, paths)) < 0) return error; /* optionally check that pathspec doesn't mention any ignored files */ @@ -2097,14 +2101,14 @@ int git_index_add_all( while (!(error = git_iterator_advance(&wd, wditer))) { /* check if path actually matches */ - if (!git_pathspec_match_path( - &ps.pathspec, wd->path, no_fnmatch, ignorecase, &match)) + if (!git_pathspec__match( + &ps.pathspec, wd->path, no_fnmatch, (bool)ignorecase, &match, NULL)) continue; /* skip ignored items that are not already in the index */ if ((flags & GIT_INDEX_ADD_FORCE) == 0 && git_iterator_current_is_ignored(wditer) && - index_find(&existing, index, wd->path, 0) < 0) + git_index__find(&existing, index, wd->path, 0) < 0) continue; /* issue notification callback if requested */ @@ -2154,7 +2158,7 @@ int git_index_add_all( cleanup: git_iterator_free(wditer); - git_pathspec_context_free(&ps); + git_pathspec__clear(&ps); return error; } @@ -2174,13 +2178,13 @@ static int index_apply_to_all( { int error = 0; size_t i; - git_pathspec_context ps; + git_pathspec ps; const char *match; git_buf path = GIT_BUF_INIT; assert(index); - if ((error = git_pathspec_context_init(&ps, paths)) < 0) + if ((error = git_pathspec__init(&ps, paths)) < 0) return error; git_vector_sort(&index->entries); @@ -2189,8 +2193,9 @@ static int index_apply_to_all( git_index_entry *entry = git_vector_get(&index->entries, i); /* check if path actually matches */ - if (!git_pathspec_match_path( - &ps.pathspec, entry->path, false, index->ignore_case, &match)) + if (!git_pathspec__match( + &ps.pathspec, entry->path, false, (bool)index->ignore_case, + &match, NULL)) continue; /* issue notification callback if requested */ @@ -2237,7 +2242,7 @@ static int index_apply_to_all( } git_buf_free(&path); - git_pathspec_context_free(&ps); + git_pathspec__clear(&ps); return error; } |