diff options
-rw-r--r-- | src/iterator.c | 61 | ||||
-rw-r--r-- | src/iterator.h | 2 | ||||
-rw-r--r-- | tests/iterator/workdir.c | 46 |
3 files changed, 98 insertions, 11 deletions
diff --git a/src/iterator.c b/src/iterator.c index 6e7300af3..0bd67c7d4 100644 --- a/src/iterator.c +++ b/src/iterator.c @@ -1015,6 +1015,7 @@ typedef struct { struct stat st; size_t path_len; iterator_pathlist_search_t match; + git_oid id; char path[GIT_FLEX_ARRAY]; } filesystem_iterator_entry; @@ -1265,7 +1266,32 @@ GIT_INLINE(bool) filesystem_iterator_is_dot_git( return (len == 4 || path[len - 5] == '/'); } -static filesystem_iterator_entry *filesystem_iterator_entry_init( +static int filesystem_iterator_entry_hash( + filesystem_iterator *iter, + filesystem_iterator_entry *entry) +{ + git_buf fullpath = GIT_BUF_INIT; + int error; + + if (S_ISDIR(entry->st.st_mode)) { + memset(&entry->id, 0, GIT_OID_RAWSZ); + return 0; + } + + if (iter->base.type == GIT_ITERATOR_TYPE_WORKDIR) + return git_repository_hashfile(&entry->id, + iter->base.repo, entry->path, GIT_OBJ_BLOB, NULL); + + if (!(error = git_buf_joinpath(&fullpath, iter->root, entry->path))) + error = git_odb_hashfile(&entry->id, fullpath.ptr, GIT_OBJ_BLOB); + + git_buf_dispose(&fullpath); + return error; +} + +static int filesystem_iterator_entry_init( + filesystem_iterator_entry **out, + filesystem_iterator *iter, filesystem_iterator_frame *frame, const char *path, size_t path_len, @@ -1274,15 +1300,19 @@ static filesystem_iterator_entry *filesystem_iterator_entry_init( { filesystem_iterator_entry *entry; size_t entry_size; + int error = 0; + + *out = NULL; /* Make sure to append two bytes, one for the path's null * termination, one for a possible trailing '/' for folders. */ - if (GIT_ADD_SIZET_OVERFLOW(&entry_size, - sizeof(filesystem_iterator_entry), path_len) || - GIT_ADD_SIZET_OVERFLOW(&entry_size, entry_size, 2) || - (entry = git_pool_malloc(&frame->entry_pool, entry_size)) == NULL) - return NULL; + GITERR_CHECK_ALLOC_ADD(&entry_size, + sizeof(filesystem_iterator_entry), path_len); + GITERR_CHECK_ALLOC_ADD(&entry_size, entry_size, 2); + + entry = git_pool_malloc(&frame->entry_pool, entry_size); + GITERR_CHECK_ALLOC(entry); entry->path_len = path_len; entry->match = pathlist_match; @@ -1295,7 +1325,13 @@ static filesystem_iterator_entry *filesystem_iterator_entry_init( entry->path[entry->path_len] = '\0'; - return entry; + if (iter->base.flags & GIT_ITERATOR_INCLUDE_HASH) + error = filesystem_iterator_entry_hash(iter, entry); + + if (!error) + *out = entry; + + return error; } static int filesystem_iterator_frame_push( @@ -1418,9 +1454,9 @@ static int filesystem_iterator_frame_push( else if (dir_expected) continue; - entry = filesystem_iterator_entry_init(new_frame, - path, path_len, &statbuf, pathlist_match); - GITERR_CHECK_ALLOC(entry); + if ((error = filesystem_iterator_entry_init(&entry, + iter, new_frame, path, path_len, &statbuf, pathlist_match)) < 0) + goto done; git_vector_insert(&new_frame->entries, entry); } @@ -1460,7 +1496,7 @@ static void filesystem_iterator_set_current( iter->entry.ctime.seconds = entry->st.st_ctime; iter->entry.mtime.seconds = entry->st.st_mtime; -#if defined(GIT_USE_NSEC) +#if defined(GIT_USE_NSEC) iter->entry.ctime.nanoseconds = entry->st.st_ctime_nsec; iter->entry.mtime.nanoseconds = entry->st.st_mtime_nsec; #else @@ -1475,6 +1511,9 @@ static void filesystem_iterator_set_current( iter->entry.gid = entry->st.st_gid; iter->entry.file_size = entry->st.st_size; + if (iter->base.flags & GIT_ITERATOR_INCLUDE_HASH) + git_oid_cpy(&iter->entry.id, &entry->id); + iter->entry.path = entry->path; iter->current_is_ignored = GIT_IGNORE_UNCHECKED; diff --git a/src/iterator.h b/src/iterator.h index a6497d87b..fe358f16c 100644 --- a/src/iterator.h +++ b/src/iterator.h @@ -41,6 +41,8 @@ typedef enum { GIT_ITERATOR_INCLUDE_CONFLICTS = (1u << 6), /** descend into symlinked directories */ GIT_ITERATOR_DESCEND_SYMLINKS = (1u << 7), + /** hash files in workdir or filesystem iterators */ + GIT_ITERATOR_INCLUDE_HASH = (1u << 8), } git_iterator_flag_t; typedef enum { diff --git a/tests/iterator/workdir.c b/tests/iterator/workdir.c index a16acd722..889fcd6c0 100644 --- a/tests/iterator/workdir.c +++ b/tests/iterator/workdir.c @@ -3,6 +3,7 @@ #include "repository.h" #include "fileops.h" #include "../submodule/submodule_helpers.h" +#include "../merge/merge_helpers.h" #include "iterator_helpers.h" #include <stdarg.h> @@ -1474,3 +1475,48 @@ void test_iterator_workdir__pathlist_with_directory_include_trees(void) git_vector_free(&filelist); } +void test_iterator_workdir__hash_when_requested(void) +{ + git_iterator *iter; + const git_index_entry *entry; + git_iterator_options iter_opts = GIT_ITERATOR_OPTIONS_INIT; + git_oid expected_id = {{0}}; + size_t i; + + struct merge_index_entry expected[] = { + { 0100644, "ffb36e513f5fdf8a6ba850a20142676a2ac4807d", 0, "asparagus.txt" }, + { 0100644, "68f6182f4c85d39e1309d97c7e456156dc9c0096", 0, "beef.txt" }, + { 0100644, "4b7c5650008b2e747fe1809eeb5a1dde0e80850a", 0, "bouilli.txt" }, + { 0100644, "c4e6cca3ec6ae0148ed231f97257df8c311e015f", 0, "gravy.txt" }, + { 0100644, "7c7e08f9559d9e1551b91e1cf68f1d0066109add", 0, "oyster.txt" }, + { 0100644, "898d12687fb35be271c27c795a6b32c8b51da79e", 0, "veal.txt" }, + }; + + g_repo = cl_git_sandbox_init("merge-recursive"); + + /* do the iteration normally, ensure there are no hashes */ + cl_git_pass(git_iterator_for_workdir(&iter, g_repo, NULL, NULL, &iter_opts)); + + for (i = 0; i < sizeof(expected) / sizeof(struct merge_index_entry); i++) { + cl_git_pass(git_iterator_advance(&entry, iter)); + + cl_assert_equal_oid(&expected_id, &entry->id); + cl_assert_equal_s(expected[i].path, entry->path); + } + cl_assert_equal_i(GIT_ITEROVER, git_iterator_advance(&entry, iter)); + git_iterator_free(iter); + + /* do the iteration requesting hashes */ + iter_opts.flags |= GIT_ITERATOR_INCLUDE_HASH; + cl_git_pass(git_iterator_for_workdir(&iter, g_repo, NULL, NULL, &iter_opts)); + + for (i = 0; i < sizeof(expected) / sizeof(struct merge_index_entry); i++) { + cl_git_pass(git_iterator_advance(&entry, iter)); + + cl_git_pass(git_oid_fromstr(&expected_id, expected[i].oid_str)); + cl_assert_equal_oid(&expected_id, &entry->id); + cl_assert_equal_s(expected[i].path, entry->path); + } + cl_assert_equal_i(GIT_ITEROVER, git_iterator_advance(&entry, iter)); + git_iterator_free(iter); +} |