From d0cd6c427a35b257373c7178d1e17d82001e125f Mon Sep 17 00:00:00 2001 From: nulltoken Date: Sun, 8 Sep 2013 18:22:28 +0200 Subject: [PATCH 1/2] path: Make direach() return EUSER on callback error --- src/fileops.c | 30 +++++++++++++++++++++--------- src/odb_pack.c | 2 +- src/path.c | 4 ++-- src/refdb_fs.c | 2 +- 4 files changed, 25 insertions(+), 13 deletions(-) diff --git a/src/fileops.c b/src/fileops.c index 92cda82e7..126d45f26 100644 --- a/src/fileops.c +++ b/src/fileops.c @@ -869,6 +869,7 @@ typedef struct { uint32_t flags; uint32_t mkdir_flags; mode_t dirmode; + int error; } cp_r_info; #define GIT_CPDIR__MKDIR_DONE_FOR_TO_ROOT (1u << 10) @@ -907,20 +908,23 @@ static int _cp_r_callback(void *ref, git_buf *from) return 0; if (git_buf_joinpath( - &info->to, info->to_root, from->ptr + info->from_prefix) < 0) - return -1; + &info->to, info->to_root, from->ptr + info->from_prefix) < 0) { + error = -1; + goto exit; + } if (p_lstat(info->to.ptr, &to_st) < 0) { if (errno != ENOENT && errno != ENOTDIR) { giterr_set(GITERR_OS, "Could not access %s while copying files", info->to.ptr); - return -1; + error = -1; + goto exit; } } else exists = true; if ((error = git_path_lstat(from->ptr, &from_st)) < 0) - return error; + goto exit; if (S_ISDIR(from_st.st_mode)) { mode_t oldmode = info->dirmode; @@ -934,13 +938,14 @@ static int _cp_r_callback(void *ref, git_buf *from) error = _cp_r_mkdir(info, from); /* recurse onto target directory */ - if (!error && (!exists || S_ISDIR(to_st.st_mode))) - error = git_path_direach(from, _cp_r_callback, info); + if (!error && (!exists || S_ISDIR(to_st.st_mode)) && + ((error = git_path_direach(from, _cp_r_callback, info)) == GIT_EUSER)) + error = info->error; if (oldmode != 0) info->dirmode = oldmode; - return error; + goto exit; } if (exists) { @@ -950,7 +955,8 @@ static int _cp_r_callback(void *ref, git_buf *from) if (p_unlink(info->to.ptr) < 0) { giterr_set(GITERR_OS, "Cannot overwrite existing file '%s'", info->to.ptr); - return -1; + error = -1; + goto exit; } } @@ -963,7 +969,7 @@ static int _cp_r_callback(void *ref, git_buf *from) /* Make container directory on demand if needed */ if ((info->flags & GIT_CPDIR_CREATE_EMPTY_DIRS) == 0 && (error = _cp_r_mkdir(info, from)) < 0) - return error; + goto exit; /* make symlink or regular file */ if (S_ISLNK(from_st.st_mode)) @@ -977,6 +983,8 @@ static int _cp_r_callback(void *ref, git_buf *from) error = git_futils_cp(from->ptr, info->to.ptr, usemode); } +exit: + info->error = error; return error; } @@ -997,6 +1005,7 @@ int git_futils_cp_r( info.flags = flags; info.dirmode = dirmode; info.from_prefix = path.size; + info.error = 0; git_buf_init(&info.to, 0); /* precalculate mkdir flags */ @@ -1018,6 +1027,9 @@ int git_futils_cp_r( git_buf_free(&path); git_buf_free(&info.to); + if (error == GIT_EUSER) + error = info.error; + return error; } diff --git a/src/odb_pack.c b/src/odb_pack.c index d24b4aa99..cadc93a65 100644 --- a/src/odb_pack.c +++ b/src/odb_pack.c @@ -336,7 +336,7 @@ static int pack_backend__refresh(git_odb_backend *_backend) git_buf_free(&path); if (error < 0) - return error; + return -1; git_vector_sort(&backend->packs); return 0; diff --git a/src/path.c b/src/path.c index 7c1ec2cd0..56b0b49ca 100644 --- a/src/path.c +++ b/src/path.c @@ -765,10 +765,10 @@ int git_path_direach( git_buf_truncate(path, wd_len); /* restore path */ - if (result < 0) { + if (result) { closedir(dir); git__free(de_buf); - return -1; + return GIT_EUSER; } } diff --git a/src/refdb_fs.c b/src/refdb_fs.c index 04516a5b0..894ff7c84 100644 --- a/src/refdb_fs.c +++ b/src/refdb_fs.c @@ -299,7 +299,7 @@ static int packed_loadloose(refdb_fs_backend *backend) git_buf_free(&refs_path); - return error; + return (error == GIT_EUSER) ? -1 : error; } static int refdb_fs_backend__exists( From 209f9b67c4f9b2c5bba26f2bdcbee10cf4e25a6b Mon Sep 17 00:00:00 2001 From: nulltoken Date: Sun, 8 Sep 2013 18:25:17 +0200 Subject: [PATCH 2/2] odb: Teach loose backend to return EAMBIGUOUS --- src/odb_loose.c | 8 ++++++-- tests-clar/refs/revparse.c | 31 +++++++++++++++++++++++++++++++ 2 files changed, 37 insertions(+), 2 deletions(-) diff --git a/src/odb_loose.c b/src/odb_loose.c index ce63f4673..4ff57158d 100644 --- a/src/odb_loose.c +++ b/src/odb_loose.c @@ -499,7 +499,7 @@ static int fn_locate_object_short_oid(void *state, git_buf *pathbuf) { } if (sstate->found > 1) - return git_odb__error_ambiguous("multiple matches in loose objects"); + return GIT_EAMBIGUOUS; return 0; } @@ -545,12 +545,16 @@ static int locate_object_short_oid( /* Explore directory to find a unique object matching short_oid */ error = git_path_direach( object_location, fn_locate_object_short_oid, &state); - if (error) + + if (error && error != GIT_EUSER) return error; if (!state.found) return git_odb__error_notfound("no matching loose object for prefix", short_oid); + if (state.found > 1) + return git_odb__error_ambiguous("multiple matches in loose objects"); + /* Convert obtained hex formatted oid to raw */ error = git_oid_fromstr(res_oid, (char *)state.res_oid); if (error) diff --git a/tests-clar/refs/revparse.c b/tests-clar/refs/revparse.c index 9657054de..37d3981bb 100644 --- a/tests-clar/refs/revparse.c +++ b/tests-clar/refs/revparse.c @@ -544,6 +544,37 @@ void test_refs_revparse__a_too_short_objectid_returns_EAMBIGUOUS(void) GIT_EAMBIGUOUS, git_revparse_single(&g_obj, g_repo, "e90")); } +/* + * $ echo "aabqhq" | git hash-object -t blob --stdin + * dea509d0b3cb8ee0650f6ca210bc83f4678851ba + * + * $ echo "aaazvc" | git hash-object -t blob --stdin + * dea509d097ce692e167dfc6a48a7a280cc5e877e + */ +void test_refs_revparse__a_not_precise_enough_objectid_returns_EAMBIGUOUS(void) +{ + git_repository *repo; + git_index *index; + git_object *obj; + + repo = cl_git_sandbox_init("testrepo"); + + cl_git_mkfile("testrepo/one.txt", "aabqhq\n"); + cl_git_mkfile("testrepo/two.txt", "aaazvc\n"); + + cl_git_pass(git_repository_index(&index, repo)); + cl_git_pass(git_index_add_bypath(index, "one.txt")); + cl_git_pass(git_index_add_bypath(index, "two.txt")); + + cl_git_fail_with(git_revparse_single(&obj, repo, "dea509d0"), GIT_EAMBIGUOUS); + + cl_git_pass(git_revparse_single(&obj, repo, "dea509d09")); + + git_object_free(obj); + git_index_free(index); + cl_git_sandbox_cleanup(); +} + void test_refs_revparse__issue_994(void) { git_repository *repo;